From ee17516afd6a3e790b4a0eb9981c2866f9dcfa0a Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 20 Dec 2021 20:03:42 +0200 Subject: [PATCH 01/53] docs/Single-server-VictoriaMetrics.md: mention that recording rules in vmalert can be used for reducing the number of time series --- README.md | 2 +- docs/README.md | 2 +- docs/Single-server-VictoriaMetrics.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8d7e7d558..05a1a256c 100644 --- a/README.md +++ b/README.md @@ -1177,7 +1177,7 @@ See [these docs](https://docs.victoriametrics.com/guides/guide-vmcluster-multipl * `-downsampling.period=30d:5m,180d:1h` instructs VictoriaMetrics to deduplicate samples older than 30 days with 5 minutes interval and to deduplicate samples older than 180 days with 1 hour interval. -Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsampling doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series. +Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsampling doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series. It is possible to use recording rules in [vmalert](https://docs.victoriametrics.com/vmalert.html) in order to reduce the number of time series. See [these docs](https://docs.victoriametrics.com/vmalert.html#downsampling-and-aggregation-via-vmalert). The downsampling can be evaluated for free by downloading and using enterprise binaries from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases). diff --git a/docs/README.md b/docs/README.md index 8d7e7d558..05a1a256c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1177,7 +1177,7 @@ See [these docs](https://docs.victoriametrics.com/guides/guide-vmcluster-multipl * `-downsampling.period=30d:5m,180d:1h` instructs VictoriaMetrics to deduplicate samples older than 30 days with 5 minutes interval and to deduplicate samples older than 180 days with 1 hour interval. -Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsampling doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series. +Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsampling doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series. It is possible to use recording rules in [vmalert](https://docs.victoriametrics.com/vmalert.html) in order to reduce the number of time series. See [these docs](https://docs.victoriametrics.com/vmalert.html#downsampling-and-aggregation-via-vmalert). The downsampling can be evaluated for free by downloading and using enterprise binaries from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases). diff --git a/docs/Single-server-VictoriaMetrics.md b/docs/Single-server-VictoriaMetrics.md index 0c71fcd56..703f835a5 100644 --- a/docs/Single-server-VictoriaMetrics.md +++ b/docs/Single-server-VictoriaMetrics.md @@ -1181,7 +1181,7 @@ See [these docs](https://docs.victoriametrics.com/guides/guide-vmcluster-multipl * `-downsampling.period=30d:5m,180d:1h` instructs VictoriaMetrics to deduplicate samples older than 30 days with 5 minutes interval and to deduplicate samples older than 180 days with 1 hour interval. -Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsampling doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series. +Downsampling is applied independently per each time series. It can reduce disk space usage and improve query performance if it is applied to time series with big number of samples per each series. The downsampling doesn't improve query performance if the database contains big number of time series with small number of samples per each series (aka [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate)), since downsampling doesn't reduce the number of time series. So the majority of time is spent on searching for the matching time series. It is possible to use recording rules in [vmalert](https://docs.victoriametrics.com/vmalert.html) in order to reduce the number of time series. See [these docs](https://docs.victoriametrics.com/vmalert.html#downsampling-and-aggregation-via-vmalert). The downsampling can be evaluated for free by downloading and using enterprise binaries from [the releases page](https://github.com/VictoriaMetrics/VictoriaMetrics/releases). From d44cc14c6bb839ee6afaf045011a976d4fd385e0 Mon Sep 17 00:00:00 2001 From: Denys Holius <5650611+denisgolius@users.noreply.github.com> Date: Tue, 21 Dec 2021 12:09:14 +0200 Subject: [PATCH 02/53] added packer build for DigitalOcean Droplets (#1917) * added packer build for DigitalOcean Droplets * fixed typo * added packer RELEASE_GUIDE.md, Makefile * Apply suggestions from code review Co-authored-by: Roman Khavronenko * added corrections amd improvements * added packer link & templating for sed version * fixed typo Co-authored-by: Aliaksandr Valialkin Co-authored-by: Roman Khavronenko --- .dockerignore | 1 + .gitignore | 1 + .../one-click-droplet-default/.gitignore | 2 + .../one-click-droplet-default/Makefile | 8 + .../one-click-droplet-default/README.md | 54 ++ .../RELEASE_GUIDE.md | 26 + .../files/etc/systemd/system/vmsingle.service | 29 + .../files/etc/update-motd.d/99-one-click | 36 + .../etc/victoriametrics/single/scrape.yml | 7 + .../single/victoriametrics.conf | 1 + .../lib/cloud/scripts/per-instance/001_onboot | 10 + .../scripts/01-setup.sh | 15 + .../scripts/02-firewall.sh | 16 + .../scripts/04-install-victoriametrics.sh | 13 + .../scripts/89-cleanup-logs.sh | 7 + .../scripts/90-cleanup.sh | 44 ++ .../scripts/99-img-check.sh | 682 ++++++++++++++++++ .../one-click-droplet-default/template.json | 73 ++ .../template.pkr.hcl | 80 ++ .../digitialocean/one-click-droplet/Makefile | 9 + .../digitialocean/one-click-droplet/README.md | 54 ++ .../one-click-droplet/RELEASE_GUIDE.md | 28 + .../files/etc/systemd/system/vmsingle.service | 29 + .../files/etc/update-motd.d/99-one-click | 36 + .../files/etc/update-motd.d/99-one-click.tpl | 36 + .../etc/victoriametrics/single/scrape.yml | 7 + .../single/victoriametrics.conf | 1 + .../lib/cloud/scripts/per-instance/001_onboot | 10 + .../one-click-droplet/scripts/01-setup.sh | 15 + .../one-click-droplet/scripts/02-firewall.sh | 16 + .../scripts/04-install-victoriametrics.sh | 13 + .../scripts/89-cleanup-logs.sh | 7 + .../one-click-droplet/scripts/90-cleanup.sh | 44 ++ .../one-click-droplet/scripts/99-img-check.sh | 682 ++++++++++++++++++ .../one-click-droplet/template.json | 73 ++ .../one-click-droplet/template.pkr.hcl | 80 ++ 36 files changed, 2245 insertions(+) create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/.gitignore create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/Makefile create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/README.md create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/RELEASE_GUIDE.md create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/systemd/system/vmsingle.service create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/update-motd.d/99-one-click create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/victoriametrics/single/scrape.yml create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/victoriametrics/single/victoriametrics.conf create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/files/var/lib/cloud/scripts/per-instance/001_onboot create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/scripts/01-setup.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/scripts/02-firewall.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/scripts/04-install-victoriametrics.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/scripts/89-cleanup-logs.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/scripts/90-cleanup.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet-default/scripts/99-img-check.sh create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/template.json create mode 100644 deployment/marketplace/digitialocean/one-click-droplet-default/template.pkr.hcl create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/Makefile create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/README.md create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/RELEASE_GUIDE.md create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/files/etc/systemd/system/vmsingle.service create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/files/etc/update-motd.d/99-one-click create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/files/etc/update-motd.d/99-one-click.tpl create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/files/etc/victoriametrics/single/scrape.yml create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/files/etc/victoriametrics/single/victoriametrics.conf create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/files/var/lib/cloud/scripts/per-instance/001_onboot create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/scripts/01-setup.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/scripts/02-firewall.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/scripts/04-install-victoriametrics.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/scripts/89-cleanup-logs.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/scripts/90-cleanup.sh create mode 100755 deployment/marketplace/digitialocean/one-click-droplet/scripts/99-img-check.sh create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/template.json create mode 100644 deployment/marketplace/digitialocean/one-click-droplet/template.pkr.hcl diff --git a/.dockerignore b/.dockerignore index 85c355aab..99ef4637d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -4,3 +4,4 @@ gocache-for-docker victoria-metrics-data vmstorage-data vmselect-cache +.vscode diff --git a/.gitignore b/.gitignore index 2009d0602..9aa07d068 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.pprof /bin .idea +.vscode *.test *.swp /gocache-for-docker diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/.gitignore b/deployment/marketplace/digitialocean/one-click-droplet-default/.gitignore new file mode 100644 index 000000000..855e0b52b --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/.gitignore @@ -0,0 +1,2 @@ +.vscode/* +.vscode \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/Makefile b/deployment/marketplace/digitialocean/one-click-droplet-default/Makefile new file mode 100644 index 000000000..f04bd8d1e --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/Makefile @@ -0,0 +1,8 @@ +RELEASE_NAME := vm-oneclick-droplet +VM_VERSION ?= $(shell git describe --abbrev=0 --tags) + +.PHONY: $(MAKECMDGOALS) + +release-victoria-metrics-digitalocean-oneclick-droplet: + sed -i -e "s/VM_VERSION/${VM_VERSION}/g" ./files/etc/update-motd.d/99-one-click + packer build template.pkr.hcl \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/README.md b/deployment/marketplace/digitialocean/one-click-droplet-default/README.md new file mode 100644 index 000000000..5d5ebbd37 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/README.md @@ -0,0 +1,54 @@ +## Application summary + +VictoriaMetrics is a fast and scalable open source time series database and monitoring solution. + +## Description + +VictoriaMetrics is a free [open source time series database](https://en.wikipedia.org/wiki/Time_series_database) (TSDB) and monitoring solution, designed to collect, store and process real-time metrics. + +It supports the [Prometheus](https://en.wikipedia.org/wiki/Prometheus_(software)) pull model and various push protocols ([Graphite](https://en.wikipedia.org/wiki/Graphite_(software)), [InfluxDB](https://en.wikipedia.org/wiki/InfluxDB), OpenTSDB) for data ingestion. It is optimized for storage with high-latency IO, low IOPS and time series with [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). + +For reading the data and evaluating alerting rules, VictoriaMetrics supports the PromQL, [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html) and Graphite query languages. VictoriaMetrics Single is fully autonomous and can be used as a long-term storage for time series. + +[VictoriaMetrics Single](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html) = Hassle-free monitoring solution. Easily handles 10M+ of active time series on a single instance. Perfect for small and medium environments. + +## Getting started after deploying VictoriaMetrics Single + +### Config + +VictoriaMetrics configuration is located at `/etc/victoriametrics/single/scrape.yml` on the droplet. +This One Click app uses 8428, 2003, 4242 and 8089 ports to accept metrics from different protocols. It's recommended to disable ports for protocols which are not needed. [Ubuntu firewall](https://help.ubuntu.com/community/UFW) can be used to easily disable access for specific ports. + +### Scraping metrics + +VictoriaMetrics supports metrics scraping in the same way as Prometheus does. Check the configuration file to edit scraping targets. See more details about scraping at [How to scrape Prometheus exporters](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-scrape-prometheus-exporters-such-as-node-exporter). + +### Sending metrics + +Besides scraping, VictoriaMetrics accepts write requests for various ingestion protocols. This One Click app supports the following protocols: +- [Datadog](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-datadog-agent), [Influx (telegraph)](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-influxdb-compatible-agents-such-as-telegraf), [JSON](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-import-data-in-json-line-format), [CSV](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-import-csv-data), [Prometheus](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-import-data-in-prometheus-exposition-format) on port :8428 +- [Graphite (statsd)](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-graphite-compatible-agents-such-as-statsd) on port :2003 tcp/udp +- [OpenTSDB](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-opentsdb-compatible-agents) on port :4242 +- Influx (telegraph) on port :8089 tcp/udp + +See more details and examples in [official documentation](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html). + +### UI + +VictoriaMetrics provides a [User Interface (UI)](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#vmui) for query troubleshooting and exploration. The UI is available at `http://your_droplet_public_ipv4:8428/vmui`. It lets users explore query results via graphs and tables. + +To check it, open the following in your browser `http://your_droplet_public_ipv4:8428/vmui` and then enter `vm_app_uptime_seconds` to the Query Field to Execute the Query. + +Run the following command to query and retrieve a result from VictoriaMetrics Single with `curl`: + +```bash +curl -sg http://your_droplet_public_ipv4:8428/api/v1/query_range?query=vm_app_uptime_seconds | jq +``` + +### Accessing + +Once the Droplet is created, you can use DigitalOcean's web console to start a session or SSH directly to the server as root: + +```bash +ssh root@your_droplet_public_ipv4 +``` \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/RELEASE_GUIDE.md b/deployment/marketplace/digitialocean/one-click-droplet-default/RELEASE_GUIDE.md new file mode 100644 index 000000000..4e917a3eb --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/RELEASE_GUIDE.md @@ -0,0 +1,26 @@ +## Release guide for DigitalOcean 1-ClickApp Droplet + +### Build image + +To build the snapshot in DigitalOcean account you will need API Token. +API Token can be generated on [https://cloud.digitalocean.com/account/api/tokens](https://cloud.digitalocean.com/account/api/tokens) or use already generated from OnePassword. + +Set variable `DIGITALOCEAN_API_TOKEN` for environment: + +```bash +export DIGITALOCEAN_API_TOKEN="your_token_here" +``` +or set it by with make: + +```bash +make release-victoria-metrics-digitalocean-oneclick-droplet DIGITALOCEAN_API_TOKEN="your_token_here" +``` + +### Update information on Vendor Portal + +After packer build finished you need to update a product page. + +1. Go to [https://cloud.digitalocean.com/vendorportal](https://cloud.digitalocean.com/vendorportal). +2. Choose a product that you need to update. +3. Enter newer information for this release and choose a droplet's snapshot which was builded recently. +4. Submit updates for approve on DigitalOcean Marketplace. \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/systemd/system/vmsingle.service b/deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/systemd/system/vmsingle.service new file mode 100644 index 000000000..601e72386 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/systemd/system/vmsingle.service @@ -0,0 +1,29 @@ +[Unit] +Description=VictoriaMetrics is a fast, cost-effective and scalable monitoring solution and time series database. +# https://docs.victoriametrics.com +After=network.target + +[Service] +Type=simple +User=victoriametrics +Group=victoriametrics +WorkingDirectory=/var/lib/victoria-metrics-data +StartLimitBurst=5 +StartLimitInterval=0 +Restart=on-failure +RestartSec=5 +EnvironmentFile=-/etc/victoriametrics/single/victoriametrics.conf +ExecStart=/usr/bin/victoria-metrics-prod $ARGS +ExecStop=/bin/kill -s SIGTERM $MAINPID +ExecReload=/bin/kill -HUP $MAINPID +# See docs https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#tuning +ProtectSystem=full +LimitNOFILE=1048576 +LimitNPROC=1048576 +LimitCORE=infinity +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=vmsingle + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/update-motd.d/99-one-click b/deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/update-motd.d/99-one-click new file mode 100755 index 000000000..1f747b6c2 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/files/etc/update-motd.d/99-one-click @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Configured as part of the DigitalOcean 1-Click Image build process + +myip=$(hostname -I | awk '{print$1}') +cat < /root/.bash_history +unset HISTFILE +apt-get -y autoremove +apt-get -y autoclean +find /var/log -mtime -1 -type f -exec truncate -s 0 {} \; +rm -rf /var/log/*.gz /var/log/*.[0-9] /var/log/*-???????? +rm -rf /var/lib/cloud/instances/* +rm -f /root/.ssh/authorized_keys /etc/ssh/*key* +touch /etc/ssh/revoked_keys +chmod 600 /etc/ssh/revoked_keys + +# Securely erase the unused portion of the filesystem +GREEN='\033[0;32m' +NC='\033[0m' +printf "\n${GREEN}Writing zeros to the remaining disk space to securely +erase the unused portion of the file system. +Depending on your disk size this may take several minutes. +The secure erase will complete successfully when you see:${NC} + dd: writing to '/zerofile': No space left on device\n +Beginning secure erase now\n" + +dd if=/dev/zero of=/zerofile & + PID=$! + while [ -d /proc/$PID ] + do + printf "." + sleep 5 + done +sync; rm /zerofile; sync +cat /dev/null > /var/log/lastlog; cat /dev/null > /var/log/wtmp diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/scripts/99-img-check.sh b/deployment/marketplace/digitialocean/one-click-droplet-default/scripts/99-img-check.sh new file mode 100755 index 000000000..00b547641 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/scripts/99-img-check.sh @@ -0,0 +1,682 @@ +#!/bin/bash + +# DigitalOcean Marketplace Image Validation Tool +# © 2021 DigitalOcean LLC. +# This code is licensed under Apache 2.0 license (see LICENSE.md for details) + +VERSION="v. 1.6" +RUNDATE=$( date ) + +# Script should be run with SUDO +if [ "$EUID" -ne 0 ] + then echo "[Error] - This script must be run with sudo or as the root user." + exit 1 +fi + +STATUS=0 +PASS=0 +WARN=0 +FAIL=0 + +# $1 == command to check for +# returns: 0 == true, 1 == false +cmdExists() { + if command -v "$1" > /dev/null 2>&1; then + return 0 + else + return 1 + fi +} + +function getDistro { + if [ -f /etc/os-release ]; then + # freedesktop.org and systemd + . /etc/os-release + OS=$NAME + VER=$VERSION_ID +elif type lsb_release >/dev/null 2>&1; then + # linuxbase.org + OS=$(lsb_release -si) + VER=$(lsb_release -sr) +elif [ -f /etc/lsb-release ]; then + # For some versions of Debian/Ubuntu without lsb_release command + . /etc/lsb-release + OS=$DISTRIB_ID + VER=$DISTRIB_RELEASE +elif [ -f /etc/debian_version ]; then + # Older Debian/Ubuntu/etc. + OS=Debian + VER=$(cat /etc/debian_version) +elif [ -f /etc/SuSe-release ]; then + # Older SuSE/etc. + : +elif [ -f /etc/redhat-release ]; then + # Older Red Hat, CentOS, etc. + VER=$( cat /etc/redhat-release | cut -d" " -f3 | cut -d "." -f1) + d=$( cat /etc/redhat-release | cut -d" " -f1 | cut -d "." -f1) + if [[ $d == "CentOS" ]]; then + OS="CentOS Linux" + fi +else + # Fall back to uname, e.g. "Linux ", also works for BSD, etc. + OS=$(uname -s) + VER=$(uname -r) +fi +} +function loadPasswords { +SHADOW=$(cat /etc/shadow) +} + +function checkAgent { + # Check for the presence of the do-agent in the filesystem + if [ -d /var/opt/digitalocean/do-agent ];then + echo -en "\e[41m[FAIL]\e[0m DigitalOcean Monitoring Agent detected.\n" + ((FAIL++)) + STATUS=2 + if [[ $OS == "CentOS Linux" ]]; then + echo "The agent can be removed with 'sudo yum remove do-agent' " + elif [[ $OS == "Ubuntu" ]]; then + echo "The agent can be removed with 'sudo apt-get purge do-agent' " + fi + else + echo -en "\e[32m[PASS]\e[0m DigitalOcean Monitoring agent was not found\n" + ((PASS++)) + fi +} + +function checkLogs { + cp_ignore="/var/log/cpanel-install.log" + echo -en "\nChecking for log files in /var/log\n\n" + # Check if there are log archives or log files that have not been recently cleared. + for f in /var/log/*-????????; do + [[ -e $f ]] || break + if [ $f != $cp_ignore ]; then + echo -en "\e[93m[WARN]\e[0m Log archive ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + done + for f in /var/log/*.[0-9];do + [[ -e $f ]] || break + echo -en "\e[93m[WARN]\e[0m Log archive ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + done + for f in /var/log/*.log; do + [[ -e $f ]] || break + if [[ "${f}" = '/var/log/lfd.log' && "$( cat "${f}" | egrep -v '/var/log/messages has been reset| Watching /var/log/messages' | wc -c)" -gt 50 ]]; then + if [ $f != $cp_ignore ]; then + echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + elif [[ "${f}" != '/var/log/lfd.log' && "$( cat "${f}" | wc -c)" -gt 50 ]]; then + if [ $f != $cp_ignore ]; then + echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + fi + done +} +function checkTMP { + # Check the /tmp directory to ensure it is empty. Warn on any files found. + return 1 +} +function checkRoot { + user="root" + uhome="/root" + for usr in $SHADOW + do + IFS=':' read -r -a u <<< "$usr" + if [[ "${u[0]}" == "${user}" ]]; then + if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then + echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account.\n" + ((FAIL++)) + STATUS=2 + fi + fi + done + if [ -d ${uhome}/ ]; then + if [ -d ${uhome}/.ssh/ ]; then + if ls ${uhome}/.ssh/*> /dev/null 2>&1; then + for key in ${uhome}/.ssh/* + do + if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then + + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + fi + elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then + if [ "$( cat "${key}" | wc -c)" -gt 0 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory at \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + else + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a populated known_hosts file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + fi + done + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n" + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n" + fi + if [ -f /root/.bash_history ];then + + BH_S=$( cat /root/.bash_history | wc -c) + + if [[ $BH_S -lt 200 ]]; then + echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n" + ((FAIL++)) + STATUS=2 + fi + + return 1; + else + echo -en "\e[32m[PASS]\e[0m The Root User's Bash History is not present\n" + ((PASS++)) + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n" + fi + echo -en "\n\n" + return 1 +} + +function checkUsers { + # Check each user-created account + for user in $(awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd;) + do + # Skip some other non-user system accounts + if [[ $user == "centos" ]]; then + : + elif [[ $user == "nfsnobody" ]]; then + : + else + echo -en "\nChecking user: ${user}...\n" + for usr in $SHADOW + do + IFS=':' read -r -a u <<< "$usr" + if [[ "${u[0]}" == "${user}" ]]; then + if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then + echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account. Only system users are allowed on the image.\n" + ((FAIL++)) + STATUS=2 + fi + fi + done + #echo "User Found: ${user}" + uhome="/home/${user}" + if [ -d "${uhome}/" ]; then + if [ -d "${uhome}/.ssh/" ]; then + if ls "${uhome}/.ssh/*"> /dev/null 2>&1; then + for key in ${uhome}/.ssh/* + do + if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + fi + elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then + if [ "$( cat "${key}" | wc -c)" -gt 0 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then + + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory named \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + + else + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a known_hosts file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + fi + + + done + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n" + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n" + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n" + fi + + # Check for an uncleared .bash_history for this user + if [ -f "${uhome}/.bash_history" ]; then + BH_S=$( cat "${uhome}/.bash_history" | wc -c ) + + if [[ $BH_S -lt 200 ]]; then + echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n" + ((FAIL++)) + STATUS=2 + + fi + echo -en "\n\n" + fi + fi + done +} +function checkFirewall { + + if [[ $OS == "Ubuntu" ]]; then + fw="ufw" + ufwa=$(ufw status |head -1| sed -e "s/^Status:\ //") + if [[ $ufwa == "active" ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + elif [[ $OS == "CentOS Linux" ]]; then + if [ -f /usr/lib/systemd/system/csf.service ]; then + fw="csf" + if [[ $(systemctl status $fw >/dev/null 2>&1) ]]; then + + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + elif cmdExists "firewall-cmd"; then + if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + else + fw="firewalld" + if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + fi + elif [[ "$OS" =~ Debian.* ]]; then + # user could be using a number of different services for managing their firewall + # we will check some of the most common + if cmdExists 'ufw'; then + fw="ufw" + ufwa=$(ufw status |head -1| sed -e "s/^Status:\ //") + if [[ $ufwa == "active" ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + elif cmdExists "firewall-cmd"; then + fw="firewalld" + if [[ $(systemctl is-active --quiet $fw) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + else + # user could be using vanilla iptables, check if kernel module is loaded + fw="iptables" + if [[ $(lsmod | grep -q '^ip_tables' 2>/dev/null) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + fi + fi + +} +function checkUpdates { + if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then + # Ensure /tmp exists and has the proper permissions before + # checking for security updates + # https://github.com/digitalocean/marketplace-partners/issues/94 + if [[ ! -d /tmp ]]; then + mkdir /tmp + fi + chmod 1777 /tmp + + echo -en "\nUpdating apt package database to check for security updates, this may take a minute...\n\n" + apt-get -y update > /dev/null + + uc=$(apt-get --just-print upgrade | grep -i "security" | wc -l) + if [[ $uc -gt 0 ]]; then + update_count=$(( ${uc} / 2 )) + else + update_count=0 + fi + + if [[ $update_count -gt 0 ]]; then + echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n" + echo -en + echo -en "Here is a list of the security updates that are not installed:\n" + sleep 2 + apt-get --just-print upgrade | grep -i security | awk '{print $2}' | awk '!seen[$0]++' + echo -en + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n\n" + fi + elif [[ $OS == "CentOS Linux" ]]; then + echo -en "\nChecking for available security updates, this may take a minute...\n\n" + + update_count=$(yum check-update --security --quiet | wc -l) + if [[ $update_count -gt 0 ]]; then + echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n" + ((PASS++)) + fi + else + echo "Error encountered" + exit 1 + fi + + return 1; +} +function checkCloudInit { + + if hash cloud-init 2>/dev/null; then + CI="\e[32m[PASS]\e[0m Cloud-init is installed.\n" + ((PASS++)) + else + CI="\e[41m[FAIL]\e[0m No valid verison of cloud-init was found.\n" + ((FAIL++)) + STATUS=2 + fi + return 1 +} +function checkMongoDB { + # Check if MongoDB is installed + # If it is, verify the version is allowed (non-SSPL) + + if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then + + if [[ -f "/usr/bin/mongod" ]]; then + version=$(/usr/bin/mongod --version --quiet | grep "db version" | sed -e "s/^db\ version\ v//") + + if version_gt $version 4.0.0; then + if version_gt $version 4.0.3; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present, ${version}" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed, ${version} is not under the SSPL" + ((PASS++)) + fi + else + if version_gt $version 3.6.8; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present, ${version}" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed, ${version} is not under the SSPL" + ((PASS++)) + fi + fi + + + else + echo -en "\e[32m[PASS]\e[0m MongoDB is not installed" + ((PASS++)) + fi + + elif [[ $OS == "CentOS Linux" ]]; then + + if [[ -f "/usr/bin/mongod" ]]; then + version=$(/usr/bin/mongod --version --quiet | grep "db version" | sed -e "s/^db\ version\ v//") + + + if version_gt $version 4.0.0; then + if version_gt $version 4.0.3; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed is not under the SSPL" + ((PASS++)) + fi + else + if version_gt $version 3.6.8; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed is not under the SSPL" + ((PASS++)) + fi + fi + + + + else + echo -en "\e[32m[PASS]\e[0m MongoDB is not installed" + ((PASS++)) + fi + + else + echo "ERROR: Unable to identify distribution" + ((FAIL++)) + STATUS 2 + return 1 + fi + + +} + +function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } + + +clear +echo "DigitalOcean Marketplace Image Validation Tool ${VERSION}" +echo "Executed on: ${RUNDATE}" +echo "Checking local system for Marketplace compatibility..." + +getDistro + +echo -en "\n\e[1mDistribution:\e[0m ${OS}\n" +echo -en "\e[1mVersion:\e[0m ${VER}\n\n" + +ost=0 +osv=0 + +if [[ $OS == "Ubuntu" ]]; then + ost=1 + if [[ $VER == "20.04" ]]; then + osv=1 + elif [[ $VER == "18.04" ]]; then + osv=1 + elif [[ $VER == "16.04" ]]; then + osv=1 + else + osv=0 + fi + +elif [[ "$OS" =~ Debian.* ]]; then + ost=1 + case "$VER" in + 9) + osv=1 + ;; + 10) + osv=1 + ;; + *) + osv=2 + ;; + esac + +elif [[ $OS == "CentOS Linux" ]]; then + ost=1 + if [[ $VER == "8" ]]; then + osv=1 + elif [[ $VER == "7" ]]; then + osv=1 + elif [[ $VER == "6" ]]; then + osv=1 + else + osv=2 + fi +else + ost=0 +fi + +if [[ $ost == 1 ]]; then + echo -en "\e[32m[PASS]\e[0m Supported Operating System Detected: ${OS}\n" + ((PASS++)) +else + echo -en "\e[41m[FAIL]\e[0m ${OS} is not a supported Operating System\n" + ((FAIL++)) + STATUS=2 +fi + +if [[ $osv == 1 ]]; then + echo -en "\e[32m[PASS]\e[0m Supported Release Detected: ${VER}\n" + ((PASS++)) +elif [[ $ost == 1 ]]; then + echo -en "\e[41m[FAIL]\e[0m ${OS} ${VER} is not a supported Operating System Version\n" + ((FAIL++)) + STATUS=2 +else + echo "Exiting..." + exit 1 +fi + +checkCloudInit + +echo -en "${CI}" + +checkFirewall + +echo -en "${FW_VER}" + +checkUpdates + +loadPasswords + +checkLogs + +echo -en "\n\nChecking all user-created accounts...\n" +checkUsers + +echo -en "\n\nChecking the root account...\n" +checkRoot + +checkAgent + +checkMongoDB + + +# Summary +echo -en "\n\n---------------------------------------------------------------------------------------------------\n" + +if [[ $STATUS == 0 ]]; then + echo -en "Scan Complete.\n\e[32mAll Tests Passed!\e[0m\n" +elif [[ $STATUS == 1 ]]; then + echo -en "Scan Complete. \n\e[93mSome non-critical tests failed. Please review these items.\e[0m\e[0m\n" +else + echo -en "Scan Complete. \n\e[41mOne or more tests failed. Please review these items and re-test.\e[0m\n" +fi +echo "---------------------------------------------------------------------------------------------------" +echo -en "\e[1m${PASS} Tests PASSED\e[0m\n" +echo -en "\e[1m${WARN} WARNINGS\e[0m\n" +echo -en "\e[1m${FAIL} Tests FAILED\e[0m\n" +echo -en "---------------------------------------------------------------------------------------------------\n" + +if [[ $STATUS == 0 ]]; then + echo -en "We did not detect any issues with this image. Please be sure to manually ensure that all software installed on the base system is functional, secure and properly configured (or facilities for configuration on first-boot have been created).\n\n" + exit 0 +elif [[ $STATUS == 1 ]]; then + echo -en "Please review all [WARN] items above and ensure they are intended or resolved. If you do not have a specific requirement, we recommend resolving these items before image submission\n\n" + exit 0 +else + echo -en "Some critical tests failed. These items must be resolved and this scan re-run before you submit your image to the DigitalOcean Marketplace.\n\n" + exit 1 +fi \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/template.json b/deployment/marketplace/digitialocean/one-click-droplet-default/template.json new file mode 100644 index 000000000..fe9b0e08f --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/template.json @@ -0,0 +1,73 @@ + +{ + "variables": { + "do_api_token": "{{env `DIGITALOCEAN_API_TOKEN`}}", + "image_name": "vm-single-20-04-snapshot-{{timestamp}}", + "apt_packages": "curl git wget software-properties-common net-tools", + "application_name": "vm-single", + "application_version": "{{ env `VM_VERSION` }}" + }, + "sensitive-variables": ["do_api_token"], + "builders": [ + { + "type": "digitalocean", + "api_token": "{{user `do_api_token`}}", + "image": "ubuntu-20-04-x64", + "region": "nyc3", + "size": "s-1vcpu-1gb", + "ssh_username": "root", + "snapshot_name": "{{user `image_name`}}" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ + "cloud-init status --wait" + ] + }, + { + "type": "file", + "source": "files/etc/", + "destination": "/etc/" + }, + { + "type": "file", + "source": "files/var/", + "destination": "/var/" + }, + { + "type": "shell", + "environment_vars": [ + "DEBIAN_FRONTEND=noninteractive", + "LC_ALL=C", + "LANG=en_US.UTF-8", + "LC_CTYPE=en_US.UTF-8" + ], + "inline": [ + "apt -qqy update", + "apt -qqy -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' install {{user `apt_packages`}}", + "apt-get -qqy clean" + ] + }, + { + "type": "shell", + "environment_vars": [ + "application_name={{user `application_name`}}", + "application_version={{user `application_version`}}", + "DEBIAN_FRONTEND=noninteractive", + "LC_ALL=C", + "LANG=en_US.UTF-8", + "LC_CTYPE=en_US.UTF-8" + ], + "scripts": [ + "scripts/01-setup.sh", + "scripts/02-firewall.sh", + "scripts/04-install-victoriametrics.sh", + "scripts/89-cleanup-logs.sh", + "scripts/90-cleanup.sh", + "scripts/99-img-check.sh" + ] + } + ] +} diff --git a/deployment/marketplace/digitialocean/one-click-droplet-default/template.pkr.hcl b/deployment/marketplace/digitialocean/one-click-droplet-default/template.pkr.hcl new file mode 100644 index 000000000..e904476eb --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet-default/template.pkr.hcl @@ -0,0 +1,80 @@ +variable "token" { + type = string + default = "${env("DIGITALOCEAN_API_TOKEN")}" + description = "DigitalOcean API token used to create droplets." +} + +variable "image_id" { + type = string + default = "ubuntu-20-04-x64" + description = "DigitalOcean linux image ID." +} + +variable "victoriametrics_version" { + type = string + default = "${env("VM_VERSION")}" + description = "Version number of the desired VictoriaMetrics binary." +} + +variable "image_name" { + type = string + default = "victoriametrics-snapshot-{{timestamp}}" + description = "Name of the snapshot created on DigitalOcean." +} + +source "digitalocean" "default" { + api_token = "${var.token}" + image = "${var.image_id}" + region = "nyc3" + size = "s-1vcpu-1gb" + snapshot_name = "${var.image_name}" + ssh_username = "root" +} + +build { + sources = ["source.digitalocean.default"] + + provisioner "file" { + destination = "/etc/" + source = "files/etc/" + } + + provisioner "file" { + destination = "/var/" + source = "files/var/" + } + + # Setup instance configuration + provisioner "shell" { + environment_vars = [ + "DEBIAN_FRONTEND=noninteractive" + ] + scripts = [ + "scripts/01-setup.sh", + "scripts/02-firewall.sh", + ] + } + + # Install VictoriaMetrics + provisioner "shell" { + environment_vars = [ + "VM_VER=${var.victoriametrics_version}", + "DEBIAN_FRONTEND=noninteractive" + ] + scripts = [ + "scripts/04-install-victoriametrics.sh", + ] + } + + # Cleanup and validate instance + provisioner "shell" { + environment_vars = [ + "DEBIAN_FRONTEND=noninteractive" + ] + scripts = [ + "scripts/89-cleanup-logs.sh", + "scripts/90-cleanup.sh", + "scripts/99-img-check.sh" + ] + } +} diff --git a/deployment/marketplace/digitialocean/one-click-droplet/Makefile b/deployment/marketplace/digitialocean/one-click-droplet/Makefile new file mode 100644 index 000000000..8d67f78f0 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/Makefile @@ -0,0 +1,9 @@ +RELEASE_NAME := vm-oneclick-droplet +VM_VERSION ?= $(shell git describe --abbrev=0 --tags) + +.PHONY: $(MAKECMDGOALS) + +release-victoria-metrics-digitalocean-oneclick-droplet: + cp ./files/etc/update-motd.d/99-one-click.tpl ./files/etc/update-motd.d/99-one-click + sed -i -e "s/VM_VERSION/${VM_VERSION}/g" ./files/etc/update-motd.d/99-one-click + packer build template.pkr.hcl \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet/README.md b/deployment/marketplace/digitialocean/one-click-droplet/README.md new file mode 100644 index 000000000..5d5ebbd37 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/README.md @@ -0,0 +1,54 @@ +## Application summary + +VictoriaMetrics is a fast and scalable open source time series database and monitoring solution. + +## Description + +VictoriaMetrics is a free [open source time series database](https://en.wikipedia.org/wiki/Time_series_database) (TSDB) and monitoring solution, designed to collect, store and process real-time metrics. + +It supports the [Prometheus](https://en.wikipedia.org/wiki/Prometheus_(software)) pull model and various push protocols ([Graphite](https://en.wikipedia.org/wiki/Graphite_(software)), [InfluxDB](https://en.wikipedia.org/wiki/InfluxDB), OpenTSDB) for data ingestion. It is optimized for storage with high-latency IO, low IOPS and time series with [high churn rate](https://docs.victoriametrics.com/FAQ.html#what-is-high-churn-rate). + +For reading the data and evaluating alerting rules, VictoriaMetrics supports the PromQL, [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html) and Graphite query languages. VictoriaMetrics Single is fully autonomous and can be used as a long-term storage for time series. + +[VictoriaMetrics Single](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html) = Hassle-free monitoring solution. Easily handles 10M+ of active time series on a single instance. Perfect for small and medium environments. + +## Getting started after deploying VictoriaMetrics Single + +### Config + +VictoriaMetrics configuration is located at `/etc/victoriametrics/single/scrape.yml` on the droplet. +This One Click app uses 8428, 2003, 4242 and 8089 ports to accept metrics from different protocols. It's recommended to disable ports for protocols which are not needed. [Ubuntu firewall](https://help.ubuntu.com/community/UFW) can be used to easily disable access for specific ports. + +### Scraping metrics + +VictoriaMetrics supports metrics scraping in the same way as Prometheus does. Check the configuration file to edit scraping targets. See more details about scraping at [How to scrape Prometheus exporters](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-scrape-prometheus-exporters-such-as-node-exporter). + +### Sending metrics + +Besides scraping, VictoriaMetrics accepts write requests for various ingestion protocols. This One Click app supports the following protocols: +- [Datadog](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-datadog-agent), [Influx (telegraph)](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-influxdb-compatible-agents-such-as-telegraf), [JSON](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-import-data-in-json-line-format), [CSV](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-import-csv-data), [Prometheus](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-import-data-in-prometheus-exposition-format) on port :8428 +- [Graphite (statsd)](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-graphite-compatible-agents-such-as-statsd) on port :2003 tcp/udp +- [OpenTSDB](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#how-to-send-data-from-opentsdb-compatible-agents) on port :4242 +- Influx (telegraph) on port :8089 tcp/udp + +See more details and examples in [official documentation](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html). + +### UI + +VictoriaMetrics provides a [User Interface (UI)](https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#vmui) for query troubleshooting and exploration. The UI is available at `http://your_droplet_public_ipv4:8428/vmui`. It lets users explore query results via graphs and tables. + +To check it, open the following in your browser `http://your_droplet_public_ipv4:8428/vmui` and then enter `vm_app_uptime_seconds` to the Query Field to Execute the Query. + +Run the following command to query and retrieve a result from VictoriaMetrics Single with `curl`: + +```bash +curl -sg http://your_droplet_public_ipv4:8428/api/v1/query_range?query=vm_app_uptime_seconds | jq +``` + +### Accessing + +Once the Droplet is created, you can use DigitalOcean's web console to start a session or SSH directly to the server as root: + +```bash +ssh root@your_droplet_public_ipv4 +``` \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet/RELEASE_GUIDE.md b/deployment/marketplace/digitialocean/one-click-droplet/RELEASE_GUIDE.md new file mode 100644 index 000000000..109720052 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/RELEASE_GUIDE.md @@ -0,0 +1,28 @@ +## Release guide for DigitalOcean 1-ClickApp Droplet + +### Build image + +To build the snapshot in DigitalOcean account you will need API Token and [packer](https://learn.hashicorp.com/tutorials/packer/get-started-install-cli). + +API Token can be generated on [https://cloud.digitalocean.com/account/api/tokens](https://cloud.digitalocean.com/account/api/tokens) or use already generated from OnePassword. + +Set variable `DIGITALOCEAN_API_TOKEN` for environment: + +```bash +export DIGITALOCEAN_API_TOKEN="your_token_here" +``` + +or set it by with make: + +```bash +make release-victoria-metrics-digitalocean-oneclick-droplet DIGITALOCEAN_API_TOKEN="your_token_here" +``` + +### Update information on Vendor Portal + +After packer build finished you need to update a product page. + +1. Go to [https://cloud.digitalocean.com/vendorportal](https://cloud.digitalocean.com/vendorportal). +2. Choose a product that you need to update. +3. Enter newer information for this release and choose a droplet's snapshot which was builded recently. +4. Submit updates for approve on DigitalOcean Marketplace. diff --git a/deployment/marketplace/digitialocean/one-click-droplet/files/etc/systemd/system/vmsingle.service b/deployment/marketplace/digitialocean/one-click-droplet/files/etc/systemd/system/vmsingle.service new file mode 100644 index 000000000..601e72386 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/files/etc/systemd/system/vmsingle.service @@ -0,0 +1,29 @@ +[Unit] +Description=VictoriaMetrics is a fast, cost-effective and scalable monitoring solution and time series database. +# https://docs.victoriametrics.com +After=network.target + +[Service] +Type=simple +User=victoriametrics +Group=victoriametrics +WorkingDirectory=/var/lib/victoria-metrics-data +StartLimitBurst=5 +StartLimitInterval=0 +Restart=on-failure +RestartSec=5 +EnvironmentFile=-/etc/victoriametrics/single/victoriametrics.conf +ExecStart=/usr/bin/victoria-metrics-prod $ARGS +ExecStop=/bin/kill -s SIGTERM $MAINPID +ExecReload=/bin/kill -HUP $MAINPID +# See docs https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html#tuning +ProtectSystem=full +LimitNOFILE=1048576 +LimitNPROC=1048576 +LimitCORE=infinity +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=vmsingle + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet/files/etc/update-motd.d/99-one-click b/deployment/marketplace/digitialocean/one-click-droplet/files/etc/update-motd.d/99-one-click new file mode 100755 index 000000000..1f747b6c2 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/files/etc/update-motd.d/99-one-click @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Configured as part of the DigitalOcean 1-Click Image build process + +myip=$(hostname -I | awk '{print$1}') +cat < /root/.bash_history +unset HISTFILE +apt-get -y autoremove +apt-get -y autoclean +find /var/log -mtime -1 -type f -exec truncate -s 0 {} \; +rm -rf /var/log/*.gz /var/log/*.[0-9] /var/log/*-???????? +rm -rf /var/lib/cloud/instances/* +rm -f /root/.ssh/authorized_keys /etc/ssh/*key* +touch /etc/ssh/revoked_keys +chmod 600 /etc/ssh/revoked_keys + +# Securely erase the unused portion of the filesystem +GREEN='\033[0;32m' +NC='\033[0m' +printf "\n${GREEN}Writing zeros to the remaining disk space to securely +erase the unused portion of the file system. +Depending on your disk size this may take several minutes. +The secure erase will complete successfully when you see:${NC} + dd: writing to '/zerofile': No space left on device\n +Beginning secure erase now\n" + +dd if=/dev/zero of=/zerofile & + PID=$! + while [ -d /proc/$PID ] + do + printf "." + sleep 5 + done +sync; rm /zerofile; sync +cat /dev/null > /var/log/lastlog; cat /dev/null > /var/log/wtmp diff --git a/deployment/marketplace/digitialocean/one-click-droplet/scripts/99-img-check.sh b/deployment/marketplace/digitialocean/one-click-droplet/scripts/99-img-check.sh new file mode 100755 index 000000000..00b547641 --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/scripts/99-img-check.sh @@ -0,0 +1,682 @@ +#!/bin/bash + +# DigitalOcean Marketplace Image Validation Tool +# © 2021 DigitalOcean LLC. +# This code is licensed under Apache 2.0 license (see LICENSE.md for details) + +VERSION="v. 1.6" +RUNDATE=$( date ) + +# Script should be run with SUDO +if [ "$EUID" -ne 0 ] + then echo "[Error] - This script must be run with sudo or as the root user." + exit 1 +fi + +STATUS=0 +PASS=0 +WARN=0 +FAIL=0 + +# $1 == command to check for +# returns: 0 == true, 1 == false +cmdExists() { + if command -v "$1" > /dev/null 2>&1; then + return 0 + else + return 1 + fi +} + +function getDistro { + if [ -f /etc/os-release ]; then + # freedesktop.org and systemd + . /etc/os-release + OS=$NAME + VER=$VERSION_ID +elif type lsb_release >/dev/null 2>&1; then + # linuxbase.org + OS=$(lsb_release -si) + VER=$(lsb_release -sr) +elif [ -f /etc/lsb-release ]; then + # For some versions of Debian/Ubuntu without lsb_release command + . /etc/lsb-release + OS=$DISTRIB_ID + VER=$DISTRIB_RELEASE +elif [ -f /etc/debian_version ]; then + # Older Debian/Ubuntu/etc. + OS=Debian + VER=$(cat /etc/debian_version) +elif [ -f /etc/SuSe-release ]; then + # Older SuSE/etc. + : +elif [ -f /etc/redhat-release ]; then + # Older Red Hat, CentOS, etc. + VER=$( cat /etc/redhat-release | cut -d" " -f3 | cut -d "." -f1) + d=$( cat /etc/redhat-release | cut -d" " -f1 | cut -d "." -f1) + if [[ $d == "CentOS" ]]; then + OS="CentOS Linux" + fi +else + # Fall back to uname, e.g. "Linux ", also works for BSD, etc. + OS=$(uname -s) + VER=$(uname -r) +fi +} +function loadPasswords { +SHADOW=$(cat /etc/shadow) +} + +function checkAgent { + # Check for the presence of the do-agent in the filesystem + if [ -d /var/opt/digitalocean/do-agent ];then + echo -en "\e[41m[FAIL]\e[0m DigitalOcean Monitoring Agent detected.\n" + ((FAIL++)) + STATUS=2 + if [[ $OS == "CentOS Linux" ]]; then + echo "The agent can be removed with 'sudo yum remove do-agent' " + elif [[ $OS == "Ubuntu" ]]; then + echo "The agent can be removed with 'sudo apt-get purge do-agent' " + fi + else + echo -en "\e[32m[PASS]\e[0m DigitalOcean Monitoring agent was not found\n" + ((PASS++)) + fi +} + +function checkLogs { + cp_ignore="/var/log/cpanel-install.log" + echo -en "\nChecking for log files in /var/log\n\n" + # Check if there are log archives or log files that have not been recently cleared. + for f in /var/log/*-????????; do + [[ -e $f ]] || break + if [ $f != $cp_ignore ]; then + echo -en "\e[93m[WARN]\e[0m Log archive ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + done + for f in /var/log/*.[0-9];do + [[ -e $f ]] || break + echo -en "\e[93m[WARN]\e[0m Log archive ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + done + for f in /var/log/*.log; do + [[ -e $f ]] || break + if [[ "${f}" = '/var/log/lfd.log' && "$( cat "${f}" | egrep -v '/var/log/messages has been reset| Watching /var/log/messages' | wc -c)" -gt 50 ]]; then + if [ $f != $cp_ignore ]; then + echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + elif [[ "${f}" != '/var/log/lfd.log' && "$( cat "${f}" | wc -c)" -gt 50 ]]; then + if [ $f != $cp_ignore ]; then + echo -en "\e[93m[WARN]\e[0m un-cleared log file, ${f} found\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + fi + done +} +function checkTMP { + # Check the /tmp directory to ensure it is empty. Warn on any files found. + return 1 +} +function checkRoot { + user="root" + uhome="/root" + for usr in $SHADOW + do + IFS=':' read -r -a u <<< "$usr" + if [[ "${u[0]}" == "${user}" ]]; then + if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then + echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account.\n" + ((FAIL++)) + STATUS=2 + fi + fi + done + if [ -d ${uhome}/ ]; then + if [ -d ${uhome}/.ssh/ ]; then + if ls ${uhome}/.ssh/*> /dev/null 2>&1; then + for key in ${uhome}/.ssh/* + do + if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then + + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + fi + elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then + if [ "$( cat "${key}" | wc -c)" -gt 0 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory at \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + else + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a populated known_hosts file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + fi + done + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n" + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n" + fi + if [ -f /root/.bash_history ];then + + BH_S=$( cat /root/.bash_history | wc -c) + + if [[ $BH_S -lt 200 ]]; then + echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n" + ((FAIL++)) + STATUS=2 + fi + + return 1; + else + echo -en "\e[32m[PASS]\e[0m The Root User's Bash History is not present\n" + ((PASS++)) + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n" + fi + echo -en "\n\n" + return 1 +} + +function checkUsers { + # Check each user-created account + for user in $(awk -F: '$3 >= 1000 && $1 != "nobody" {print $1}' /etc/passwd;) + do + # Skip some other non-user system accounts + if [[ $user == "centos" ]]; then + : + elif [[ $user == "nfsnobody" ]]; then + : + else + echo -en "\nChecking user: ${user}...\n" + for usr in $SHADOW + do + IFS=':' read -r -a u <<< "$usr" + if [[ "${u[0]}" == "${user}" ]]; then + if [[ ${u[1]} == "!" ]] || [[ ${u[1]} == "!!" ]] || [[ ${u[1]} == "*" ]]; then + echo -en "\e[32m[PASS]\e[0m User ${user} has no password set.\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m User ${user} has a password set on their account. Only system users are allowed on the image.\n" + ((FAIL++)) + STATUS=2 + fi + fi + done + #echo "User Found: ${user}" + uhome="/home/${user}" + if [ -d "${uhome}/" ]; then + if [ -d "${uhome}/.ssh/" ]; then + if ls "${uhome}/.ssh/*"> /dev/null 2>&1; then + for key in ${uhome}/.ssh/* + do + if [ "${key}" == "${uhome}/.ssh/authorized_keys" ]; then + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a populated authorized_keys file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + fi + elif [ "${key}" == "${uhome}/.ssh/id_rsa" ]; then + if [ "$( cat "${key}" | wc -c)" -gt 0 ]; then + echo -en "\e[41m[FAIL]\e[0m User \e[1m${user}\e[0m has a private key file in \e[93m${key}\e[0m\n" + akey=$(cat ${key}) + echo "File Contents:" + echo $akey + echo "--------------" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has empty private key file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + elif [ "${key}" != "${uhome}/.ssh/known_hosts" ]; then + + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a file in their .ssh directory named \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + + else + if [ "$( cat "${key}" | wc -c)" -gt 50 ]; then + echo -en "\e[93m[WARN]\e[0m User \e[1m${user}\e[0m has a known_hosts file in \e[93m${key}\e[0m\n" + ((WARN++)) + if [[ $STATUS != 2 ]]; then + STATUS=1 + fi + fi + fi + + + done + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m has no SSH keys present\n" + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have an .ssh directory\n" + fi + else + echo -en "\e[32m[ OK ]\e[0m User \e[1m${user}\e[0m does not have a directory in /home\n" + fi + + # Check for an uncleared .bash_history for this user + if [ -f "${uhome}/.bash_history" ]; then + BH_S=$( cat "${uhome}/.bash_history" | wc -c ) + + if [[ $BH_S -lt 200 ]]; then + echo -en "\e[32m[PASS]\e[0m ${user}'s Bash History appears to have been cleared\n" + ((PASS++)) + else + echo -en "\e[41m[FAIL]\e[0m ${user}'s Bash History should be cleared to prevent sensitive information from leaking\n" + ((FAIL++)) + STATUS=2 + + fi + echo -en "\n\n" + fi + fi + done +} +function checkFirewall { + + if [[ $OS == "Ubuntu" ]]; then + fw="ufw" + ufwa=$(ufw status |head -1| sed -e "s/^Status:\ //") + if [[ $ufwa == "active" ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + elif [[ $OS == "CentOS Linux" ]]; then + if [ -f /usr/lib/systemd/system/csf.service ]; then + fw="csf" + if [[ $(systemctl status $fw >/dev/null 2>&1) ]]; then + + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + elif cmdExists "firewall-cmd"; then + if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + else + fw="firewalld" + if [[ $(systemctl is-active firewalld >/dev/null 2>&1 && echo 1 || echo 0) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + fi + elif [[ "$OS" =~ Debian.* ]]; then + # user could be using a number of different services for managing their firewall + # we will check some of the most common + if cmdExists 'ufw'; then + fw="ufw" + ufwa=$(ufw status |head -1| sed -e "s/^Status:\ //") + if [[ $ufwa == "active" ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + elif cmdExists "firewall-cmd"; then + fw="firewalld" + if [[ $(systemctl is-active --quiet $fw) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + else + # user could be using vanilla iptables, check if kernel module is loaded + fw="iptables" + if [[ $(lsmod | grep -q '^ip_tables' 2>/dev/null) ]]; then + FW_VER="\e[32m[PASS]\e[0m Firewall service (${fw}) is active\n" + ((PASS++)) + else + FW_VER="\e[93m[WARN]\e[0m No firewall is configured. Ensure ${fw} is installed and configured\n" + ((WARN++)) + fi + fi + fi + +} +function checkUpdates { + if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then + # Ensure /tmp exists and has the proper permissions before + # checking for security updates + # https://github.com/digitalocean/marketplace-partners/issues/94 + if [[ ! -d /tmp ]]; then + mkdir /tmp + fi + chmod 1777 /tmp + + echo -en "\nUpdating apt package database to check for security updates, this may take a minute...\n\n" + apt-get -y update > /dev/null + + uc=$(apt-get --just-print upgrade | grep -i "security" | wc -l) + if [[ $uc -gt 0 ]]; then + update_count=$(( ${uc} / 2 )) + else + update_count=0 + fi + + if [[ $update_count -gt 0 ]]; then + echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n" + echo -en + echo -en "Here is a list of the security updates that are not installed:\n" + sleep 2 + apt-get --just-print upgrade | grep -i security | awk '{print $2}' | awk '!seen[$0]++' + echo -en + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n\n" + fi + elif [[ $OS == "CentOS Linux" ]]; then + echo -en "\nChecking for available security updates, this may take a minute...\n\n" + + update_count=$(yum check-update --security --quiet | wc -l) + if [[ $update_count -gt 0 ]]; then + echo -en "\e[41m[FAIL]\e[0m There are ${update_count} security updates available for this image that have not been installed.\n" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m There are no pending security updates for this image.\n" + ((PASS++)) + fi + else + echo "Error encountered" + exit 1 + fi + + return 1; +} +function checkCloudInit { + + if hash cloud-init 2>/dev/null; then + CI="\e[32m[PASS]\e[0m Cloud-init is installed.\n" + ((PASS++)) + else + CI="\e[41m[FAIL]\e[0m No valid verison of cloud-init was found.\n" + ((FAIL++)) + STATUS=2 + fi + return 1 +} +function checkMongoDB { + # Check if MongoDB is installed + # If it is, verify the version is allowed (non-SSPL) + + if [[ $OS == "Ubuntu" ]] || [[ "$OS" =~ Debian.* ]]; then + + if [[ -f "/usr/bin/mongod" ]]; then + version=$(/usr/bin/mongod --version --quiet | grep "db version" | sed -e "s/^db\ version\ v//") + + if version_gt $version 4.0.0; then + if version_gt $version 4.0.3; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present, ${version}" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed, ${version} is not under the SSPL" + ((PASS++)) + fi + else + if version_gt $version 3.6.8; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present, ${version}" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed, ${version} is not under the SSPL" + ((PASS++)) + fi + fi + + + else + echo -en "\e[32m[PASS]\e[0m MongoDB is not installed" + ((PASS++)) + fi + + elif [[ $OS == "CentOS Linux" ]]; then + + if [[ -f "/usr/bin/mongod" ]]; then + version=$(/usr/bin/mongod --version --quiet | grep "db version" | sed -e "s/^db\ version\ v//") + + + if version_gt $version 4.0.0; then + if version_gt $version 4.0.3; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed is not under the SSPL" + ((PASS++)) + fi + else + if version_gt $version 3.6.8; then + echo -en "\e[41m[FAIL]\e[0m An SSPL version of MongoDB is present" + ((FAIL++)) + STATUS=2 + else + echo -en "\e[32m[PASS]\e[0m The version of MongoDB installed is not under the SSPL" + ((PASS++)) + fi + fi + + + + else + echo -en "\e[32m[PASS]\e[0m MongoDB is not installed" + ((PASS++)) + fi + + else + echo "ERROR: Unable to identify distribution" + ((FAIL++)) + STATUS 2 + return 1 + fi + + +} + +function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } + + +clear +echo "DigitalOcean Marketplace Image Validation Tool ${VERSION}" +echo "Executed on: ${RUNDATE}" +echo "Checking local system for Marketplace compatibility..." + +getDistro + +echo -en "\n\e[1mDistribution:\e[0m ${OS}\n" +echo -en "\e[1mVersion:\e[0m ${VER}\n\n" + +ost=0 +osv=0 + +if [[ $OS == "Ubuntu" ]]; then + ost=1 + if [[ $VER == "20.04" ]]; then + osv=1 + elif [[ $VER == "18.04" ]]; then + osv=1 + elif [[ $VER == "16.04" ]]; then + osv=1 + else + osv=0 + fi + +elif [[ "$OS" =~ Debian.* ]]; then + ost=1 + case "$VER" in + 9) + osv=1 + ;; + 10) + osv=1 + ;; + *) + osv=2 + ;; + esac + +elif [[ $OS == "CentOS Linux" ]]; then + ost=1 + if [[ $VER == "8" ]]; then + osv=1 + elif [[ $VER == "7" ]]; then + osv=1 + elif [[ $VER == "6" ]]; then + osv=1 + else + osv=2 + fi +else + ost=0 +fi + +if [[ $ost == 1 ]]; then + echo -en "\e[32m[PASS]\e[0m Supported Operating System Detected: ${OS}\n" + ((PASS++)) +else + echo -en "\e[41m[FAIL]\e[0m ${OS} is not a supported Operating System\n" + ((FAIL++)) + STATUS=2 +fi + +if [[ $osv == 1 ]]; then + echo -en "\e[32m[PASS]\e[0m Supported Release Detected: ${VER}\n" + ((PASS++)) +elif [[ $ost == 1 ]]; then + echo -en "\e[41m[FAIL]\e[0m ${OS} ${VER} is not a supported Operating System Version\n" + ((FAIL++)) + STATUS=2 +else + echo "Exiting..." + exit 1 +fi + +checkCloudInit + +echo -en "${CI}" + +checkFirewall + +echo -en "${FW_VER}" + +checkUpdates + +loadPasswords + +checkLogs + +echo -en "\n\nChecking all user-created accounts...\n" +checkUsers + +echo -en "\n\nChecking the root account...\n" +checkRoot + +checkAgent + +checkMongoDB + + +# Summary +echo -en "\n\n---------------------------------------------------------------------------------------------------\n" + +if [[ $STATUS == 0 ]]; then + echo -en "Scan Complete.\n\e[32mAll Tests Passed!\e[0m\n" +elif [[ $STATUS == 1 ]]; then + echo -en "Scan Complete. \n\e[93mSome non-critical tests failed. Please review these items.\e[0m\e[0m\n" +else + echo -en "Scan Complete. \n\e[41mOne or more tests failed. Please review these items and re-test.\e[0m\n" +fi +echo "---------------------------------------------------------------------------------------------------" +echo -en "\e[1m${PASS} Tests PASSED\e[0m\n" +echo -en "\e[1m${WARN} WARNINGS\e[0m\n" +echo -en "\e[1m${FAIL} Tests FAILED\e[0m\n" +echo -en "---------------------------------------------------------------------------------------------------\n" + +if [[ $STATUS == 0 ]]; then + echo -en "We did not detect any issues with this image. Please be sure to manually ensure that all software installed on the base system is functional, secure and properly configured (or facilities for configuration on first-boot have been created).\n\n" + exit 0 +elif [[ $STATUS == 1 ]]; then + echo -en "Please review all [WARN] items above and ensure they are intended or resolved. If you do not have a specific requirement, we recommend resolving these items before image submission\n\n" + exit 0 +else + echo -en "Some critical tests failed. These items must be resolved and this scan re-run before you submit your image to the DigitalOcean Marketplace.\n\n" + exit 1 +fi \ No newline at end of file diff --git a/deployment/marketplace/digitialocean/one-click-droplet/template.json b/deployment/marketplace/digitialocean/one-click-droplet/template.json new file mode 100644 index 000000000..fe9b0e08f --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/template.json @@ -0,0 +1,73 @@ + +{ + "variables": { + "do_api_token": "{{env `DIGITALOCEAN_API_TOKEN`}}", + "image_name": "vm-single-20-04-snapshot-{{timestamp}}", + "apt_packages": "curl git wget software-properties-common net-tools", + "application_name": "vm-single", + "application_version": "{{ env `VM_VERSION` }}" + }, + "sensitive-variables": ["do_api_token"], + "builders": [ + { + "type": "digitalocean", + "api_token": "{{user `do_api_token`}}", + "image": "ubuntu-20-04-x64", + "region": "nyc3", + "size": "s-1vcpu-1gb", + "ssh_username": "root", + "snapshot_name": "{{user `image_name`}}" + } + ], + "provisioners": [ + { + "type": "shell", + "inline": [ + "cloud-init status --wait" + ] + }, + { + "type": "file", + "source": "files/etc/", + "destination": "/etc/" + }, + { + "type": "file", + "source": "files/var/", + "destination": "/var/" + }, + { + "type": "shell", + "environment_vars": [ + "DEBIAN_FRONTEND=noninteractive", + "LC_ALL=C", + "LANG=en_US.UTF-8", + "LC_CTYPE=en_US.UTF-8" + ], + "inline": [ + "apt -qqy update", + "apt -qqy -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' install {{user `apt_packages`}}", + "apt-get -qqy clean" + ] + }, + { + "type": "shell", + "environment_vars": [ + "application_name={{user `application_name`}}", + "application_version={{user `application_version`}}", + "DEBIAN_FRONTEND=noninteractive", + "LC_ALL=C", + "LANG=en_US.UTF-8", + "LC_CTYPE=en_US.UTF-8" + ], + "scripts": [ + "scripts/01-setup.sh", + "scripts/02-firewall.sh", + "scripts/04-install-victoriametrics.sh", + "scripts/89-cleanup-logs.sh", + "scripts/90-cleanup.sh", + "scripts/99-img-check.sh" + ] + } + ] +} diff --git a/deployment/marketplace/digitialocean/one-click-droplet/template.pkr.hcl b/deployment/marketplace/digitialocean/one-click-droplet/template.pkr.hcl new file mode 100644 index 000000000..e904476eb --- /dev/null +++ b/deployment/marketplace/digitialocean/one-click-droplet/template.pkr.hcl @@ -0,0 +1,80 @@ +variable "token" { + type = string + default = "${env("DIGITALOCEAN_API_TOKEN")}" + description = "DigitalOcean API token used to create droplets." +} + +variable "image_id" { + type = string + default = "ubuntu-20-04-x64" + description = "DigitalOcean linux image ID." +} + +variable "victoriametrics_version" { + type = string + default = "${env("VM_VERSION")}" + description = "Version number of the desired VictoriaMetrics binary." +} + +variable "image_name" { + type = string + default = "victoriametrics-snapshot-{{timestamp}}" + description = "Name of the snapshot created on DigitalOcean." +} + +source "digitalocean" "default" { + api_token = "${var.token}" + image = "${var.image_id}" + region = "nyc3" + size = "s-1vcpu-1gb" + snapshot_name = "${var.image_name}" + ssh_username = "root" +} + +build { + sources = ["source.digitalocean.default"] + + provisioner "file" { + destination = "/etc/" + source = "files/etc/" + } + + provisioner "file" { + destination = "/var/" + source = "files/var/" + } + + # Setup instance configuration + provisioner "shell" { + environment_vars = [ + "DEBIAN_FRONTEND=noninteractive" + ] + scripts = [ + "scripts/01-setup.sh", + "scripts/02-firewall.sh", + ] + } + + # Install VictoriaMetrics + provisioner "shell" { + environment_vars = [ + "VM_VER=${var.victoriametrics_version}", + "DEBIAN_FRONTEND=noninteractive" + ] + scripts = [ + "scripts/04-install-victoriametrics.sh", + ] + } + + # Cleanup and validate instance + provisioner "shell" { + environment_vars = [ + "DEBIAN_FRONTEND=noninteractive" + ] + scripts = [ + "scripts/89-cleanup-logs.sh", + "scripts/90-cleanup.sh", + "scripts/99-img-check.sh" + ] + } +} From 5dc9ab58296ee268e407d16aebf962b4cc5824bd Mon Sep 17 00:00:00 2001 From: Denys Holius <5650611+denisgolius@users.noreply.github.com> Date: Tue, 21 Dec 2021 12:11:15 +0200 Subject: [PATCH 03/53] bump revision of dashboards to latest (#1986) --- docs/guides/getting-started-with-vm-operator.md | 4 ++-- docs/guides/k8s-monitoring-via-vm-cluster.md | 4 ++-- docs/guides/k8s-monitoring-via-vm-single.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/guides/getting-started-with-vm-operator.md b/docs/guides/getting-started-with-vm-operator.md index 4a8ff83ee..b63f35e22 100644 --- a/docs/guides/getting-started-with-vm-operator.md +++ b/docs/guides/getting-started-with-vm-operator.md @@ -282,11 +282,11 @@ cat < Date: Tue, 21 Dec 2021 16:36:09 +0200 Subject: [PATCH 04/53] =?UTF-8?q?vmagent:=20add=20error=20log=20for=20skip?= =?UTF-8?q?ped=20data=20block=20when=20rejected=20by=20receiv=E2=80=A6=20(?= =?UTF-8?q?#1956)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * vmagent: add error log for skipped data block when rejected by receiving side Previously, rejected data blocks were silently dropped - only metrics were update. From operational perspective, having an additional logging for such cases is preferable. https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1911 Signed-off-by: hagen1778 * vmagent: throttle log messages about skipped blocks The new type of logger was added to logger pacakge. This new type supposed to control number of logged messages by time. Signed-off-by: hagen1778 * lib/logger: make LogThrottler public, so its methods can be inspected by external packages Co-authored-by: Aliaksandr Valialkin --- app/vmagent/remotewrite/client.go | 11 +++++ lib/logger/throttler.go | 72 +++++++++++++++++++++++++++++++ lib/logger/throttler_test.go | 40 +++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 lib/logger/throttler.go create mode 100644 lib/logger/throttler_test.go diff --git a/app/vmagent/remotewrite/client.go b/app/vmagent/remotewrite/client.go index 5a4f5ea53..0493758b8 100644 --- a/app/vmagent/remotewrite/client.go +++ b/app/vmagent/remotewrite/client.go @@ -295,6 +295,17 @@ again: } metrics.GetOrCreateCounter(fmt.Sprintf(`vmagent_remotewrite_requests_total{url=%q, status_code="%d"}`, c.sanitizedURL, statusCode)).Inc() if statusCode == 409 || statusCode == 400 { + body, err := ioutil.ReadAll(resp.Body) + _ = resp.Body.Close() + l := logger.WithThrottler("remoteWriteRejected", 5*time.Second) + if err != nil { + l.Errorf("sending a block with size %d bytes to %q was rejected (skipping the block): status code %d; "+ + "failed to read response body: %s", + len(block), c.sanitizedURL, statusCode, err) + } else { + l.Errorf("sending a block with size %d bytes to %q was rejected (skipping the block): status code %d; response body: %s", + len(block), c.sanitizedURL, statusCode, string(body)) + } // Just drop block on 409 and 400 status codes like Prometheus does. // See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/873 // and https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1149 diff --git a/lib/logger/throttler.go b/lib/logger/throttler.go new file mode 100644 index 000000000..da1e9edab --- /dev/null +++ b/lib/logger/throttler.go @@ -0,0 +1,72 @@ +package logger + +import ( + "sync" + "time" +) + +var ( + logThrottlerRegistryMu = sync.Mutex{} + logThrottlerRegistry = make(map[string]*LogThrottler) +) + +// WithThrottler returns a logger throttled by time - only one message in throttle duration will be logged. +// +// New logger is created only once for each unique name passed. +// The function is thread-safe. +func WithThrottler(name string, throttle time.Duration) *LogThrottler { + logThrottlerRegistryMu.Lock() + defer logThrottlerRegistryMu.Unlock() + + lt, ok := logThrottlerRegistry[name] + if ok { + return lt + } + + lt = newLogThrottler(throttle) + lt.warnF = Warnf + lt.errorF = Errorf + logThrottlerRegistry[name] = lt + return lt +} + +// LogThrottler is a logger, which throttles log messages passed to Warnf and Errorf. +// +// LogThrottler must be created via WithThrottler() call. +type LogThrottler struct { + ch chan struct{} + + warnF func(format string, args ...interface{}) + errorF func(format string, args ...interface{}) +} + +func newLogThrottler(throttle time.Duration) *LogThrottler { + lt := &LogThrottler{ + ch: make(chan struct{}, 1), + } + go func() { + for { + <-lt.ch + time.Sleep(throttle) + } + }() + return lt +} + +// Errorf logs error message. +func (lt *LogThrottler) Errorf(format string, args ...interface{}) { + select { + case lt.ch <- struct{}{}: + lt.errorF(format, args...) + default: + } +} + +// Warnf logs warn message. +func (lt *LogThrottler) Warnf(format string, args ...interface{}) { + select { + case lt.ch <- struct{}{}: + lt.warnF(format, args...) + default: + } +} diff --git a/lib/logger/throttler_test.go b/lib/logger/throttler_test.go new file mode 100644 index 000000000..53f3c81a6 --- /dev/null +++ b/lib/logger/throttler_test.go @@ -0,0 +1,40 @@ +package logger + +import ( + "testing" + "time" +) + +func TestLoggerWithThrottler(t *testing.T) { + lName := "test" + lThrottle := 50 * time.Millisecond + + lt := WithThrottler(lName, lThrottle) + var i int + lt.warnF = func(format string, args ...interface{}) { + i++ + } + + lt.Warnf("") + lt.Warnf("") + lt.Warnf("") + + if i != 1 { + t.Fatalf("expected logger will be throttled to 1; got %d instead", i) + } + + time.Sleep(lThrottle * 2) // wait to throttle to fade off + // the same logger supposed to be return for the same name + WithThrottler(lName, lThrottle).Warnf("") + if i != 2 { + t.Fatalf("expected logger to have 2 iterations; got %d instead", i) + } + + logThrottlerRegistryMu.Lock() + registeredN := len(logThrottlerRegistry) + logThrottlerRegistryMu.Unlock() + + if registeredN != 1 { + t.Fatalf("expected only 1 logger to be registered; got %d", registeredN) + } +} From 3cfb90b227bffc4dade6fa59af82a26c63f7e025 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Tue, 21 Dec 2021 16:40:35 +0200 Subject: [PATCH 05/53] docs/CHANGELOG.md: document 34fdc8881b607259782b9bcc2c7b4842dee20536 Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1911 --- docs/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3290c6917..dd7c3d8dc 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,8 @@ sort: 15 ## tip +* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent.html): log error message when remote storage returns 400 or 409 http errors. This should simplify detection and debugging of this case. See [this issue](vmagent_remotewrite_packets_dropped_total). + ## [v1.71.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.71.0) From ce333f28d8f72054d3ff6ef33345e411ac627825 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Tue, 21 Dec 2021 17:03:25 +0200 Subject: [PATCH 06/53] all: use logger.WithThrottler() where appropriate --- app/vmagent/remotewrite/remotewrite.go | 2 ++ lib/storage/metric_name.go | 2 ++ lib/storage/partition.go | 3 ++- lib/storage/storage.go | 4 +++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/vmagent/remotewrite/remotewrite.go b/app/vmagent/remotewrite/remotewrite.go index f8d1805db..b5e57377e 100644 --- a/app/vmagent/remotewrite/remotewrite.go +++ b/app/vmagent/remotewrite/remotewrite.go @@ -390,6 +390,8 @@ var labelsHashBufPool bytesutil.ByteBufferPool func logSkippedSeries(labels []prompbmarshal.Label, flagName string, flagValue int) { select { case <-logSkippedSeriesTicker.C: + // Do not use logger.WithThrottler() here, since this will increase CPU usage + // because every call to logSkippedSeries will result to a call to labelsToString. logger.Warnf("skip series %s because %s=%d reached", labelsToString(labels), flagName, flagValue) default: } diff --git a/lib/storage/metric_name.go b/lib/storage/metric_name.go index e997006d5..f16ddd929 100644 --- a/lib/storage/metric_name.go +++ b/lib/storage/metric_name.go @@ -511,6 +511,8 @@ func trackDroppedLabels(labels, droppedLabels []prompb.Label) { atomic.AddUint64(&MetricsWithDroppedLabels, 1) select { case <-droppedLabelsLogTicker.C: + // Do not call logger.WithThrottler() here, since this will result in increased CPU usage + // because labelsToString() will be called with each trackDroppedLAbels call. logger.Warnf("dropping %d labels for %s; dropped labels: %s; either reduce the number of labels for this metric "+ "or increase -maxLabelsPerTimeseries=%d command-line flag value", len(droppedLabels), labelsToString(labels), labelsToString(droppedLabels), maxLabelsPerTimeseries) diff --git a/lib/storage/partition.go b/lib/storage/partition.go index 93fc92ac8..52c104847 100644 --- a/lib/storage/partition.go +++ b/lib/storage/partition.go @@ -841,7 +841,8 @@ func (pt *partition) ForceMergeAllParts() error { maxOutBytes := fs.MustGetFreeSpace(pt.bigPartsPath) if newPartSize > maxOutBytes { freeSpaceNeededBytes := newPartSize - maxOutBytes - logger.Warnf("cannot initiate force merge for the partition %s; additional space needed: %d bytes", pt.name, freeSpaceNeededBytes) + logger.WithThrottler("forceMerge", time.Minute).Warnf("cannot initiate force merge for the partition %s; additional space needed: %d bytes", + pt.name, freeSpaceNeededBytes) return nil } diff --git a/lib/storage/storage.go b/lib/storage/storage.go index e10df1a80..5123edb7b 100644 --- a/lib/storage/storage.go +++ b/lib/storage/storage.go @@ -1808,7 +1808,7 @@ func (s *Storage) add(rows []rawRow, dstMrs []*MetricRow, mrs []MetricRow, preci atomic.AddUint64(&s.slowRowInserts, slowInsertsCount) } if firstWarn != nil { - logger.Warnf("warn occurred during rows addition: %s", firstWarn) + logger.WithThrottler("storageAddRows", 5*time.Second).Warnf("warn occurred during rows addition: %s", firstWarn) } dstMrs = dstMrs[:j] rows = rows[:j] @@ -1843,6 +1843,8 @@ func (s *Storage) isSeriesCardinalityExceeded(metricID uint64, metricNameRaw []b func logSkippedSeries(metricNameRaw []byte, flagName string, flagValue int) { select { case <-logSkippedSeriesTicker.C: + // Do not use logger.WithThrottler() here, since this will result in increased CPU load + // because of getUserReadableMetricName() calls per each logSkippedSeries call. logger.Warnf("skip series %s because %s=%d reached", getUserReadableMetricName(metricNameRaw), flagName, flagValue) default: } From 4b40acd96491067c8ee73f61fce09641764d2f20 Mon Sep 17 00:00:00 2001 From: Yury Molodov Date: Tue, 21 Dec 2021 21:19:33 +0300 Subject: [PATCH 07/53] vmui: add custom start range (#1989) * feat: add custom start range * app/vmselect/vmui: `make vmui-update` Co-authored-by: Aliaksandr Valialkin --- app/vmselect/vmui/asset-manifest.json | 4 +- app/vmselect/vmui/index.html | 2 +- app/vmselect/vmui/static/js/main.23f635e5.js | 2 - app/vmselect/vmui/static/js/main.2587cf95.js | 2 + ...CENSE.txt => main.2587cf95.js.LICENSE.txt} | 0 .../Configurator/Query/QueryConfigurator.tsx | 4 +- .../Time/TimeDurationSelector.tsx | 99 +++++++++++ .../Home/Configurator/Time/TimeSelector.tsx | 155 +++++++----------- .../packages/vmui/src/state/common/reducer.ts | 26 ++- app/vmui/packages/vmui/src/utils/time.ts | 2 +- 10 files changed, 188 insertions(+), 108 deletions(-) delete mode 100644 app/vmselect/vmui/static/js/main.23f635e5.js create mode 100644 app/vmselect/vmui/static/js/main.2587cf95.js rename app/vmselect/vmui/static/js/{main.23f635e5.js.LICENSE.txt => main.2587cf95.js.LICENSE.txt} (100%) create mode 100644 app/vmui/packages/vmui/src/components/Home/Configurator/Time/TimeDurationSelector.tsx diff --git a/app/vmselect/vmui/asset-manifest.json b/app/vmselect/vmui/asset-manifest.json index eafbcb81d..ea725366a 100644 --- a/app/vmselect/vmui/asset-manifest.json +++ b/app/vmselect/vmui/asset-manifest.json @@ -1,12 +1,12 @@ { "files": { "main.css": "./static/css/main.a33903a8.css", - "main.js": "./static/js/main.23f635e5.js", + "main.js": "./static/js/main.2587cf95.js", "static/js/27.85f0e2b0.chunk.js": "./static/js/27.85f0e2b0.chunk.js", "index.html": "./index.html" }, "entrypoints": [ "static/css/main.a33903a8.css", - "static/js/main.23f635e5.js" + "static/js/main.2587cf95.js" ] } \ No newline at end of file diff --git a/app/vmselect/vmui/index.html b/app/vmselect/vmui/index.html index 2fac696d8..3d65eb4ce 100644 --- a/app/vmselect/vmui/index.html +++ b/app/vmselect/vmui/index.html @@ -1 +1 @@ -VM UI
\ No newline at end of file +VM UI
\ No newline at end of file diff --git a/app/vmselect/vmui/static/js/main.23f635e5.js b/app/vmselect/vmui/static/js/main.23f635e5.js deleted file mode 100644 index 61b1f27bb..000000000 --- a/app/vmselect/vmui/static/js/main.23f635e5.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see main.23f635e5.js.LICENSE.txt */ -!function(){var e={4575:function(e){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.default=e.exports,e.exports.__esModule=!0},3913:function(e){function t(e,t){for(var n=0;n0?c(w,--y):0,m--,10===b&&(m=1,v--),b}function O(){return b=y2||T(b)>3?"":" "}function D(e,t){for(;--t&&O()&&!(b<48||b>102||b>57&&b<65||b>70&&b<97););return P(e,M()+(t<6&&32==C()&&32==O()))}function j(e){for(;O();)switch(b){case e:return y;case 34:case 39:34!==e&&39!==e&&j(b);break;case 40:41===e&&j(e);break;case 92:O()}return y}function _(e,t){for(;O()&&e+b!==57&&(e+b!==84||47!==C()););return"/*"+P(t,y-1)+"*"+o(47===e?e:O())}function N(e){for(;!T(C());)O();return P(e,y)}var L="-ms-",I="-moz-",z="-webkit-",B="comm",F="rule",$="decl",W="@keyframes";function H(e,t){for(var n="",r=h(e),i=0;i6)switch(c(e,t+1)){case 109:if(45!==c(e,t+4))break;case 102:return l(e,/(.+:)(.+)-([^]+)/,"$1-webkit-$2-$3$1"+I+(108==c(e,t+3)?"$3":"$2-$3"))+e;case 115:return~u(e,"stretch")?q(l(e,"stretch","fill-available"),t)+e:e}break;case 4949:if(115!==c(e,t+1))break;case 6444:switch(c(e,d(e)-3-(~u(e,"!important")&&10))){case 107:return l(e,":",":"+z)+e;case 101:return l(e,/(.+:)([^;!]+)(;|!.+)?/,"$1"+z+(45===c(e,14)?"inline-":"")+"box$3$1"+z+"$2$3$1"+L+"$2box$3")+e}break;case 5936:switch(c(e,t+11)){case 114:return z+e+L+l(e,/[svh]\w+-[tblr]{2}/,"tb")+e;case 108:return z+e+L+l(e,/[svh]\w+-[tblr]{2}/,"tb-rl")+e;case 45:return z+e+L+l(e,/[svh]\w+-[tblr]{2}/,"lr")+e}return z+e+L+e+e}return e}function U(e){return Z(Q("",null,null,null,[""],e=E(e),0,[0],e))}function Q(e,t,n,r,i,a,s,c,f){for(var h=0,v=0,m=s,g=0,y=0,b=0,w=1,x=1,k=1,P=0,T="",E=i,Z=a,j=r,L=T;x;)switch(b=P,P=O()){case 40:if(108!=b&&58==L.charCodeAt(m-1)){-1!=u(L+=l(A(P),"&","&\f"),"&\f")&&(k=-1);break}case 34:case 39:case 91:L+=A(P);break;case 9:case 10:case 13:case 32:L+=R(b);break;case 92:L+=D(M()-1,7);continue;case 47:switch(C()){case 42:case 47:p(Y(_(O(),M()),t,n),f);break;default:L+="/"}break;case 123*w:c[h++]=d(L)*k;case 125*w:case 59:case 0:switch(P){case 0:case 125:x=0;case 59+v:y>0&&d(L)-m&&p(y>32?G(L+";",r,n,m-1):G(l(L," ","")+";",r,n,m-2),f);break;case 59:L+=";";default:if(p(j=X(L,t,n,h,v,i,c,T,E=[],Z=[],m),a),123===P)if(0===v)Q(L,t,j,j,E,a,m,c,Z);else switch(g){case 100:case 109:case 115:Q(e,j,j,r&&p(X(e,j,j,0,0,i,c,T,i,E=[],m),Z),i,Z,m,c,r?E:Z);break;default:Q(L,j,j,j,[""],Z,0,c,Z)}}h=v=y=0,w=k=1,T=L="",m=s;break;case 58:m=1+d(L),y=b;default:if(w<1)if(123==P)--w;else if(125==P&&0==w++&&125==S())continue;switch(L+=o(P),P*w){case 38:k=v>0?1:(L+="\f",-1);break;case 44:c[h++]=(d(L)-1)*k,k=1;break;case 64:45===C()&&(L+=A(O())),g=C(),v=m=d(T=L+=N(M())),P++;break;case 45:45===b&&2==d(L)&&(w=0)}}return a}function X(e,t,n,r,o,a,u,c,d,p,v){for(var m=o-1,g=0===o?a:[""],y=h(g),b=0,w=0,k=0;b0?g[S]+" "+O:l(O,/&\f/g,g[S])))&&(d[k++]=C);return x(e,t,n,0===o?F:c,d,p,v)}function Y(e,t,n){return x(e,t,n,B,o(b),f(e,2,-2),0)}function G(e,t,n,r){return x(e,t,n,$,f(e,0,r),f(e,r+1,-1),r)}var K=function(e,t,n){for(var r=0,i=0;r=i,i=C(),38===r&&12===i&&(t[n]=1),!T(i);)O();return P(e,y)},J=function(e,t){return Z(function(e,t){var n=-1,r=44;do{switch(T(r)){case 0:38===r&&12===C()&&(t[n]=1),e[n]+=K(y-1,t,n);break;case 2:e[n]+=A(r);break;case 4:if(44===r){e[++n]=58===C()?"&\f":"",t[n]=e[n].length;break}default:e[n]+=o(r)}}while(r=O());return e}(E(e),t))},ee=new WeakMap,te=function(e){if("rule"===e.type&&e.parent&&!(e.length<1)){for(var t=e.value,n=e.parent,r=e.column===n.column&&e.line===n.line;"rule"!==n.type;)if(!(n=n.parent))return;if((1!==e.props.length||58===t.charCodeAt(0)||ee.get(n))&&!r){ee.set(e,!0);for(var i=[],o=J(t,i),a=n.props,s=0,l=0;s-1&&!e.return)switch(e.type){case $:e.return=q(e.value,e.length);break;case W:return H([k(e,{value:l(e.value,"@","@"+z)})],r);case F:if(e.length)return function(e,t){return e.map(t).join("")}(e.props,(function(t){switch(function(e,t){return(e=t.exec(e))?e[0]:e}(t,/(::plac\w+|:read-\w+)/)){case":read-only":case":read-write":return H([k(e,{props:[l(t,/:(read-\w+)/,":-moz-$1")]})],r);case"::placeholder":return H([k(e,{props:[l(t,/:(plac\w+)/,":-webkit-input-$1")]}),k(e,{props:[l(t,/:(plac\w+)/,":-moz-$1")]}),k(e,{props:[l(t,/:(plac\w+)/,L+"input-$1")]})],r)}return""}))}}],ie=function(e){var t=e.key;if("css"===t){var n=document.querySelectorAll("style[data-emotion]:not([data-s])");Array.prototype.forEach.call(n,(function(e){-1!==e.getAttribute("data-emotion").indexOf(" ")&&(document.head.appendChild(e),e.setAttribute("data-s",""))}))}var i=e.stylisPlugins||re;var o,a,s={},l=[];o=e.container||document.head,Array.prototype.forEach.call(document.querySelectorAll('style[data-emotion^="'+t+' "]'),(function(e){for(var t=e.getAttribute("data-emotion").split(" "),n=1;n=4;++r,i-=4)t=1540483477*(65535&(t=255&e.charCodeAt(r)|(255&e.charCodeAt(++r))<<8|(255&e.charCodeAt(++r))<<16|(255&e.charCodeAt(++r))<<24))+(59797*(t>>>16)<<16),n=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&n)+(59797*(n>>>16)<<16);switch(i){case 3:n^=(255&e.charCodeAt(r+2))<<16;case 2:n^=(255&e.charCodeAt(r+1))<<8;case 1:n=1540483477*(65535&(n^=255&e.charCodeAt(r)))+(59797*(n>>>16)<<16)}return(((n=1540483477*(65535&(n^=n>>>13))+(59797*(n>>>16)<<16))^n>>>15)>>>0).toString(36)},i={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},o=n(3390),a=/[A-Z]|^ms/g,s=/_EMO_([^_]+?)_([^]*?)_EMO_/g,l=function(e){return 45===e.charCodeAt(1)},u=function(e){return null!=e&&"boolean"!==typeof e},c=(0,o.Z)((function(e){return l(e)?e:e.replace(a,"-$&").toLowerCase()})),f=function(e,t){switch(e){case"animation":case"animationName":if("string"===typeof t)return t.replace(s,(function(e,t,n){return h={name:t,styles:n,next:h},t}))}return 1===i[e]||l(e)||"number"!==typeof t||0===t?t:t+"px"};function d(e,t,n){if(null==n)return"";if(void 0!==n.__emotion_styles)return n;switch(typeof n){case"boolean":return"";case"object":if(1===n.anim)return h={name:n.name,styles:n.styles,next:h},n.name;if(void 0!==n.styles){var r=n.next;if(void 0!==r)for(;void 0!==r;)h={name:r.name,styles:r.styles,next:h},r=r.next;return n.styles+";"}return function(e,t,n){var r="";if(Array.isArray(n))for(var i=0;i0&&void 0!==arguments[0]?arguments[0]:"light")?{main:m[200],light:m[50],dark:m[400]}:{main:m[700],light:m[400],dark:m[800]}}(n),M=e.secondary||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:h[200],light:h[50],dark:h[400]}:{main:h[500],light:h[300],dark:h[700]}}(n),P=e.error||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:p[500],light:p[300],dark:p[700]}:{main:p[700],light:p[400],dark:p[800]}}(n),T=e.info||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:g[400],light:g[300],dark:g[700]}:{main:g[700],light:g[500],dark:g[900]}}(n),E=e.success||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:y[400],light:y[300],dark:y[700]}:{main:y[800],light:y[500],dark:y[900]}}(n),Z=e.warning||function(){return"dark"===(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"light")?{main:v[400],light:v[300],dark:v[700]}:{main:"#ed6c02",light:v[500],dark:v[900]}}(n);function A(e){return(0,c.mi)(e,x.text.primary)>=s?x.text.primary:w.text.primary}var R=function(e){var t=e.color,n=e.name,i=e.mainShade,o=void 0===i?500:i,a=e.lightShade,s=void 0===a?300:a,l=e.darkShade,c=void 0===l?700:l;if(!(t=(0,r.Z)({},t)).main&&t[o]&&(t.main=t[o]),!t.hasOwnProperty("main"))throw new Error((0,u.Z)(11,n?" (".concat(n,")"):"",o));if("string"!==typeof t.main)throw new Error((0,u.Z)(12,n?" (".concat(n,")"):"",JSON.stringify(t.main)));return k(t,"light",s,S),k(t,"dark",c,S),t.contrastText||(t.contrastText=A(t.main)),t},D={dark:x,light:w};return(0,o.Z)((0,r.Z)({common:f,mode:n,primary:R({color:C,name:"primary"}),secondary:R({color:M,name:"secondary",mainShade:"A400",lightShade:"A200",darkShade:"A700"}),error:R({color:P,name:"error"}),warning:R({color:Z,name:"warning"}),info:R({color:T,name:"info"}),success:R({color:E,name:"success"}),grey:d,contrastThreshold:s,getContrastText:A,augmentColor:R,tonalOffset:S},D[n]),O)}var O=["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","fontWeightBold","htmlFontSize","allVariants","pxToRem"];var C={textTransform:"uppercase"},M='"Roboto", "Helvetica", "Arial", sans-serif';function P(e,t){var n="function"===typeof t?t(e):t,a=n.fontFamily,s=void 0===a?M:a,l=n.fontSize,u=void 0===l?14:l,c=n.fontWeightLight,f=void 0===c?300:c,d=n.fontWeightRegular,h=void 0===d?400:d,p=n.fontWeightMedium,v=void 0===p?500:p,m=n.fontWeightBold,g=void 0===m?700:m,y=n.htmlFontSize,b=void 0===y?16:y,w=n.allVariants,x=n.pxToRem,k=(0,i.Z)(n,O);var S=u/14,P=x||function(e){return"".concat(e/b*S,"rem")},T=function(e,t,n,i,o){return(0,r.Z)({fontFamily:s,fontWeight:e,fontSize:P(t),lineHeight:n},s===M?{letterSpacing:"".concat((a=i/t,Math.round(1e5*a)/1e5),"em")}:{},o,w);var a},E={h1:T(f,96,1.167,-1.5),h2:T(f,60,1.2,-.5),h3:T(h,48,1.167,0),h4:T(h,34,1.235,.25),h5:T(h,24,1.334,0),h6:T(v,20,1.6,.15),subtitle1:T(h,16,1.75,.15),subtitle2:T(v,14,1.57,.1),body1:T(h,16,1.5,.15),body2:T(h,14,1.43,.15),button:T(v,14,1.75,.4,C),caption:T(h,12,1.66,.4),overline:T(h,12,2.66,1,C)};return(0,o.Z)((0,r.Z)({htmlFontSize:b,pxToRem:P,fontFamily:s,fontSize:u,fontWeightLight:f,fontWeightRegular:h,fontWeightMedium:v,fontWeightBold:g},E),k,{clone:!1})}function T(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(.2,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(.14,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(.12,")")].join(",")}var E=["none",T(0,2,1,-1,0,1,1,0,0,1,3,0),T(0,3,1,-2,0,2,2,0,0,1,5,0),T(0,3,3,-2,0,3,4,0,0,1,8,0),T(0,2,4,-1,0,4,5,0,0,1,10,0),T(0,3,5,-1,0,5,8,0,0,1,14,0),T(0,3,5,-1,0,6,10,0,0,1,18,0),T(0,4,5,-2,0,7,10,1,0,2,16,1),T(0,5,5,-3,0,8,10,1,0,3,14,2),T(0,5,6,-3,0,9,12,1,0,3,16,2),T(0,6,6,-3,0,10,14,1,0,4,18,3),T(0,6,7,-4,0,11,15,1,0,4,20,3),T(0,7,8,-4,0,12,17,2,0,5,22,4),T(0,7,8,-4,0,13,19,2,0,5,24,4),T(0,7,9,-4,0,14,21,2,0,5,26,4),T(0,8,9,-5,0,15,22,2,0,6,28,5),T(0,8,10,-5,0,16,24,2,0,6,30,5),T(0,8,11,-5,0,17,26,2,0,6,32,5),T(0,9,11,-5,0,18,28,2,0,7,34,6),T(0,9,12,-6,0,19,29,2,0,7,36,6),T(0,10,13,-6,0,20,31,3,0,8,38,7),T(0,10,13,-6,0,21,33,3,0,8,40,7),T(0,10,14,-6,0,22,35,3,0,8,42,7),T(0,11,14,-7,0,23,36,3,0,9,44,8),T(0,11,15,-7,0,24,38,3,0,9,46,8)],Z=n(5829),A={mobileStepper:1e3,speedDial:1050,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500},R=["breakpoints","mixins","spacing","palette","transitions","typography","shape"];function D(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.mixins,n=void 0===t?{}:t,s=e.palette,u=void 0===s?{}:s,c=e.transitions,f=void 0===c?{}:c,d=e.typography,h=void 0===d?{}:d,p=(0,i.Z)(e,R),v=S(u),m=(0,a.Z)(e),g=(0,o.Z)(m,{mixins:l(m.breakpoints,m.spacing,n),palette:v,shadows:E.slice(),typography:P(v,h),transitions:(0,Z.ZP)(f),zIndex:(0,r.Z)({},A)});g=(0,o.Z)(g,p);for(var y=arguments.length,b=new Array(y>1?y-1:0),w=1;w0&&void 0!==arguments[0]?arguments[0]:["all"],i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=i.duration,s=void 0===a?n.standard:a,u=i.easing,c=void 0===u?t.easeInOut:u,f=i.delay,d=void 0===f?0:f;(0,r.Z)(i,o);return(Array.isArray(e)?e:[e]).map((function(e){return"".concat(e," ").concat("string"===typeof s?s:l(s)," ").concat(c," ").concat("string"===typeof d?d:l(d))})).join(",")}},e,{easing:t,duration:n})}},2248:function(e,t,n){"use strict";var r=(0,n(7458).Z)();t.Z=r},8564:function(e,t,n){"use strict";n.d(t,{ZP:function(){return M},FO:function(){return S},Dz:function(){return O}});var r=n(3433),i=n(7462),o=n(3366),a=n(297),s=n(9456),l=n(3649),u=n(114),c=["variant"];function f(e){return 0===e.length}function d(e){var t=e.variant,n=(0,o.Z)(e,c),r=t||"";return Object.keys(n).sort().forEach((function(t){r+="color"===t?f(r)?e[t]:(0,u.Z)(e[t]):"".concat(f(r)?t:(0,u.Z)(t)).concat((0,u.Z)(e[t].toString()))})),r}var h=["name","slot","skipVariantsResolver","skipSx","overridesResolver"],p=["theme"],v=["theme"];function m(e){return 0===Object.keys(e).length}var g=function(e,t){return t.components&&t.components[e]&&t.components[e].styleOverrides?t.components[e].styleOverrides:null},y=function(e,t){var n=[];t&&t.components&&t.components[e]&&t.components[e].variants&&(n=t.components[e].variants);var r={};return n.forEach((function(e){var t=d(e.props);r[t]=e.style})),r},b=function(e,t,n,r){var i,o,a=e.ownerState,s=void 0===a?{}:a,l=[],u=null==n||null==(i=n.components)||null==(o=i[r])?void 0:o.variants;return u&&u.forEach((function(n){var r=!0;Object.keys(n.props).forEach((function(t){s[t]!==n.props[t]&&e[t]!==n.props[t]&&(r=!1)})),r&&l.push(t[d(n.props)])})),l};function w(e){return"ownerState"!==e&&"theme"!==e&&"sx"!==e&&"as"!==e}var x=(0,s.Z)();var k=n(2248),S=function(e){return w(e)&&"classes"!==e},O=w,C=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.defaultTheme,n=void 0===t?x:t,s=e.rootShouldForwardProp,u=void 0===s?w:s,c=e.slotShouldForwardProp,f=void 0===c?w:c;return function(e){var t,s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=s.name,d=s.slot,x=s.skipVariantsResolver,k=s.skipSx,S=s.overridesResolver,O=(0,o.Z)(s,h),C=void 0!==x?x:d&&"Root"!==d||!1,M=k||!1;var P=w;"Root"===d?P=u:d&&(P=f);var T=(0,a.ZP)(e,(0,i.Z)({shouldForwardProp:P,label:t},O)),E=function(e){for(var t=arguments.length,a=new Array(t>1?t-1:0),s=1;s0){var h=new Array(d).fill("");(f=[].concat((0,r.Z)(e),(0,r.Z)(h))).raw=[].concat((0,r.Z)(e.raw),(0,r.Z)(h))}else"function"===typeof e&&(f=function(t){var r=t.theme,a=(0,o.Z)(t,v);return e((0,i.Z)({theme:m(r)?n:r},a))});var w=T.apply(void 0,[f].concat((0,r.Z)(u)));return w};return E}}({defaultTheme:k.Z,rootShouldForwardProp:S}),M=C},5469:function(e,t,n){"use strict";n.d(t,{Z:function(){return a}});var r=n(4290),i=n(6728);var o=n(2248);function a(e){return function(e){var t=e.props,n=e.name,o=e.defaultTheme,a=(0,i.Z)(o);return(0,r.Z)({theme:a,name:n,props:t})}({props:e.props,name:e.name,defaultTheme:o.Z})}},1615:function(e,t,n){"use strict";var r=n(114);t.Z=r.Z},1171:function(e,t,n){"use strict";n.d(t,{Z:function(){return y}});var r=n(7462),i=n(7313),o=n(3366),a=(n(5192),n(3061)),s=n(317),l=n(1615),u=n(5469),c=n(8564),f=n(2131);function d(e){return(0,f.Z)("MuiSvgIcon",e)}(0,n(655).Z)("MuiSvgIcon",["root","colorPrimary","colorSecondary","colorAction","colorError","colorDisabled","fontSizeInherit","fontSizeSmall","fontSizeMedium","fontSizeLarge"]);var h=n(6417),p=["children","className","color","component","fontSize","htmlColor","titleAccess","viewBox"],v=(0,c.ZP)("svg",{name:"MuiSvgIcon",slot:"Root",overridesResolver:function(e,t){var n=e.ownerState;return[t.root,"inherit"!==n.color&&t["color".concat((0,l.Z)(n.color))],t["fontSize".concat((0,l.Z)(n.fontSize))]]}})((function(e){var t,n,r=e.theme,i=e.ownerState;return{userSelect:"none",width:"1em",height:"1em",display:"inline-block",fill:"currentColor",flexShrink:0,transition:r.transitions.create("fill",{duration:r.transitions.duration.shorter}),fontSize:{inherit:"inherit",small:r.typography.pxToRem(20),medium:r.typography.pxToRem(24),large:r.typography.pxToRem(35)}[i.fontSize],color:null!=(t=null==(n=r.palette[i.color])?void 0:n.main)?t:{action:r.palette.action.active,disabled:r.palette.action.disabled,inherit:void 0}[i.color]}})),m=i.forwardRef((function(e,t){var n=(0,u.Z)({props:e,name:"MuiSvgIcon"}),i=n.children,c=n.className,f=n.color,m=void 0===f?"inherit":f,g=n.component,y=void 0===g?"svg":g,b=n.fontSize,w=void 0===b?"medium":b,x=n.htmlColor,k=n.titleAccess,S=n.viewBox,O=void 0===S?"0 0 24 24":S,C=(0,o.Z)(n,p),M=(0,r.Z)({},n,{color:m,component:y,fontSize:w,viewBox:O}),P=function(e){var t=e.color,n=e.fontSize,r=e.classes,i={root:["root","inherit"!==t&&"color".concat((0,l.Z)(t)),"fontSize".concat((0,l.Z)(n))]};return(0,s.Z)(i,d,r)}(M);return(0,h.jsxs)(v,(0,r.Z)({as:y,className:(0,a.default)(P.root,c),ownerState:M,focusable:"false",viewBox:O,color:x,"aria-hidden":!k||void 0,role:k?"img":void 0,ref:t},C,{children:[i,k?(0,h.jsx)("title",{children:k}):null]}))}));m.muiName="SvgIcon";var g=m;function y(e,t){var n=function(n,i){return(0,h.jsx)(g,(0,r.Z)({"data-testid":"".concat(t,"Icon"),ref:i},n,{children:e}))};return n.muiName=g.muiName,i.memo(i.forwardRef(n))}},8706:function(e,t,n){"use strict";var r=n(4312);t.Z=r.Z},6415:function(e,t,n){"use strict";n.r(t),n.d(t,{capitalize:function(){return r.Z},createChainedFunction:function(){return i},createSvgIcon:function(){return o.Z},debounce:function(){return a.Z},deprecatedPropType:function(){return s},isMuiElement:function(){return l.Z},ownerDocument:function(){return u.Z},ownerWindow:function(){return c.Z},requirePropFactory:function(){return f},setRef:function(){return d},unstable_ClassNameGenerator:function(){return w.Z},unstable_useEnhancedEffect:function(){return h.Z},unstable_useId:function(){return p.Z},unsupportedProp:function(){return v},useControlled:function(){return m.Z},useEventCallback:function(){return g.Z},useForkRef:function(){return y.Z},useIsFocusVisible:function(){return b.Z}});var r=n(1615),i=n(4246).Z,o=n(1171),a=n(8706);var s=function(e,t){return function(){return null}},l=n(7816),u=n(6106),c=n(3533);n(7462);var f=function(e,t){return function(){return null}},d=n(9265).Z,h=n(4993),p=n(7677);var v=function(e,t,n,r,i){return null},m=n(522),g=n(3236),y=n(6983),b=n(9127),w=n(672)},7816:function(e,t,n){"use strict";n.d(t,{Z:function(){return i}});var r=n(7313);var i=function(e,t){return r.isValidElement(e)&&-1!==t.indexOf(e.type.muiName)}},6106:function(e,t,n){"use strict";var r=n(9081);t.Z=r.Z},3533:function(e,t,n){"use strict";var r=n(3282);t.Z=r.Z},522:function(e,t,n){"use strict";n.d(t,{Z:function(){return o}});var r=n(9439),i=n(7313);var o=function(e){var t=e.controlled,n=e.default,o=(e.name,e.state,i.useRef(void 0!==t).current),a=i.useState(n),s=(0,r.Z)(a,2),l=s[0],u=s[1];return[o?t:l,i.useCallback((function(e){o||u(e)}),[])]}},4993:function(e,t,n){"use strict";var r=n(2678);t.Z=r.Z},3236:function(e,t,n){"use strict";var r=n(2780);t.Z=r.Z},6983:function(e,t,n){"use strict";var r=n(7472);t.Z=r.Z},7677:function(e,t,n){"use strict";var r=n(3362);t.Z=r.Z},9127:function(e,t,n){"use strict";n.d(t,{Z:function(){return d}});var r,i=n(7313),o=!0,a=!1,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function l(e){e.metaKey||e.altKey||e.ctrlKey||(o=!0)}function u(){o=!1}function c(){"hidden"===this.visibilityState&&a&&(o=!0)}function f(e){var t=e.target;try{return t.matches(":focus-visible")}catch(n){}return o||function(e){var t=e.type,n=e.tagName;return!("INPUT"!==n||!s[t]||e.readOnly)||"TEXTAREA"===n&&!e.readOnly||!!e.isContentEditable}(t)}var d=function(){var e=i.useCallback((function(e){var t;null!=e&&((t=e.ownerDocument).addEventListener("keydown",l,!0),t.addEventListener("mousedown",u,!0),t.addEventListener("pointerdown",u,!0),t.addEventListener("touchstart",u,!0),t.addEventListener("visibilitychange",c,!0))}),[]),t=i.useRef(!1);return{isFocusVisibleRef:t,onFocus:function(e){return!!f(e)&&(t.current=!0,!0)},onBlur:function(){return!!t.current&&(a=!0,window.clearTimeout(r),r=window.setTimeout((function(){a=!1}),100),t.current=!1,!0)},ref:e}}},5693:function(e,t,n){"use strict";var r=n(7313).createContext(null);t.Z=r},201:function(e,t,n){"use strict";n.d(t,{Z:function(){return o}});var r=n(7313),i=n(5693);function o(){return r.useContext(i.Z)}},297:function(e,t,n){"use strict";n.d(t,{ZP:function(){return b}});var r=n(7313),i=n(7462),o=n(3390),a=/^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|suppressHydrationWarning|valueLink|accept|acceptCharset|accessKey|action|allow|allowUserMedia|allowPaymentRequest|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|decoding|default|defer|dir|disabled|disablePictureInPicture|download|draggable|encType|enterKeyHint|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loading|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|translate|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|incremental|fallback|inert|itemProp|itemScope|itemType|itemID|itemRef|on|option|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class|autofocus)|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/,s=(0,o.Z)((function(e){return a.test(e)||111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&e.charCodeAt(2)<91})),l=n(1639),u=n(4911),c=n(4544),f=s,d=function(e){return"theme"!==e},h=function(e){return"string"===typeof e&&e.charCodeAt(0)>96?f:d},p=function(e,t,n){var r;if(t){var i=t.shouldForwardProp;r=e.__emotion_forwardProp&&i?function(t){return e.__emotion_forwardProp(t)&&i(t)}:i}return"function"!==typeof r&&n&&(r=e.__emotion_forwardProp),r},v=function(){return null},m=function e(t,n){var o,a,s=t.__emotion_real===t,f=s&&t.__emotion_base||t;void 0!==n&&(o=n.label,a=n.target);var d=p(t,n,s),m=d||h(f),g=!m("as");return function(){var y=arguments,b=s&&void 0!==t.__emotion_styles?t.__emotion_styles.slice(0):[];if(void 0!==o&&b.push("label:"+o+";"),null==y[0]||void 0===y[0].raw)b.push.apply(b,y);else{0,b.push(y[0][0]);for(var w=y.length,x=1;x0&&void 0!==arguments[0]?arguments[0]:{},n=null==t||null==(e=t.keys)?void 0:e.reduce((function(e,n){return e[t.up(n)]={},e}),{});return n||{}}function s(e,t){return e.reduce((function(e,t){var n=e[t];return(!n||0===Object.keys(n).length)&&delete e[t],e}),t)}function l(e){var t,n=e.values,r=e.breakpoints,i=e.base||function(e,t){if("object"!==typeof e)return{};var n={},r=Object.keys(t);return Array.isArray(e)?r.forEach((function(t,r){r1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return Math.min(Math.max(t,e),n)}function o(e){if(e.type)return e;if("#"===e.charAt(0))return o(function(e){e=e.substr(1);var t=new RegExp(".{1,".concat(e.length>=6?2:1,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map((function(e){return e+e}))),n?"rgb".concat(4===n.length?"a":"","(").concat(n.map((function(e,t){return t<3?parseInt(e,16):Math.round(parseInt(e,16)/255*1e3)/1e3})).join(", "),")"):""}(e));var t=e.indexOf("("),n=e.substring(0,t);if(-1===["rgb","rgba","hsl","hsla","color"].indexOf(n))throw new Error((0,r.Z)(9,e));var i,a=e.substring(t+1,e.length-1);if("color"===n){if(i=(a=a.split(" ")).shift(),4===a.length&&"/"===a[3].charAt(0)&&(a[3]=a[3].substr(1)),-1===["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].indexOf(i))throw new Error((0,r.Z)(10,i))}else a=a.split(",");return{type:n,values:a=a.map((function(e){return parseFloat(e)})),colorSpace:i}}function a(e){var t=e.type,n=e.colorSpace,r=e.values;return-1!==t.indexOf("rgb")?r=r.map((function(e,t){return t<3?parseInt(e,10):e})):-1!==t.indexOf("hsl")&&(r[1]="".concat(r[1],"%"),r[2]="".concat(r[2],"%")),r=-1!==t.indexOf("color")?"".concat(n," ").concat(r.join(" ")):"".concat(r.join(", ")),"".concat(t,"(").concat(r,")")}function s(e){var t="hsl"===(e=o(e)).type?o(function(e){var t=(e=o(e)).values,n=t[0],r=t[1]/100,i=t[2]/100,s=r*Math.min(i,1-i),l=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(e+n/30)%12;return i-s*Math.max(Math.min(t-3,9-t,1),-1)},u="rgb",c=[Math.round(255*l(0)),Math.round(255*l(8)),Math.round(255*l(4))];return"hsla"===e.type&&(u+="a",c.push(t[3])),a({type:u,values:c})}(e)).values:e.values;return t=t.map((function(t){return"color"!==e.type&&(t/=255),t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4)})),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function l(e,t){var n=s(e),r=s(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function u(e,t){return e=o(e),t=i(t),"rgb"!==e.type&&"hsl"!==e.type||(e.type+="a"),"color"===e.type?e.values[3]="/".concat(t):e.values[3]=t,a(e)}function c(e,t){if(e=o(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb")||-1!==e.type.indexOf("color"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return a(e)}function f(e,t){if(e=o(e),t=i(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;else if(-1!==e.type.indexOf("color"))for(var r=0;r<3;r+=1)e.values[r]+=(1-e.values[r])*t;return a(e)}function d(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return s(e)>.5?c(e,t):f(e,t)}},9456:function(e,t,n){"use strict";n.d(t,{Z:function(){return d}});var r=n(7462),i=n(3366),o=n(3019),a=["values","unit","step"];function s(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:900,lg:1200,xl:1536}:t,o=e.unit,s=void 0===o?"px":o,l=e.step,u=void 0===l?5:l,c=(0,i.Z)(e,a),f=Object.keys(n);function d(e){var t="number"===typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(s,")")}function h(e){var t="number"===typeof n[e]?n[e]:e;return"@media (max-width:".concat(t-u/100).concat(s,")")}function p(e,t){var r=f.indexOf(t);return"@media (min-width:".concat("number"===typeof n[e]?n[e]:e).concat(s,") and ")+"(max-width:".concat((-1!==r&&"number"===typeof n[f[r]]?n[f[r]]:t)-u/100).concat(s,")")}return(0,r.Z)({keys:f,values:n,up:d,down:h,between:p,only:function(e){return f.indexOf(e)+10&&void 0!==arguments[0]?arguments[0]:8;if(e.mui)return e;var t=(0,u.hB)({spacing:e}),n=function(){for(var e=arguments.length,n=new Array(e),r=0;r0&&void 0!==arguments[0]?arguments[0]:{},t=e.breakpoints,n=void 0===t?{}:t,a=e.palette,u=void 0===a?{}:a,d=e.spacing,h=e.shape,p=void 0===h?{}:h,v=(0,i.Z)(e,f),m=s(n),g=c(d),y=(0,o.Z)({breakpoints:m,direction:"ltr",components:{},palette:(0,r.Z)({mode:"light"},u),spacing:g,shape:(0,r.Z)({},l,p)},v),b=arguments.length,w=new Array(b>1?b-1:0),x=1;x2){if(!u[e])return[e];e=u[e]}var t=e.split(""),n=(0,r.Z)(t,2),i=n[0],o=n[1],a=s[i],c=l[o]||"";return Array.isArray(c)?c.map((function(e){return a+e})):[a+c]})),f=["m","mt","mr","mb","ml","mx","my","margin","marginTop","marginRight","marginBottom","marginLeft","marginX","marginY","marginInline","marginInlineStart","marginInlineEnd","marginBlock","marginBlockStart","marginBlockEnd"],d=["p","pt","pr","pb","pl","px","py","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingX","paddingY","paddingInline","paddingInlineStart","paddingInlineEnd","paddingBlock","paddingBlockStart","paddingBlockEnd"],h=[].concat(f,d);function p(e,t,n,r){var i=(0,o.D)(e,t)||n;return"number"===typeof i?function(e){return"string"===typeof e?e:i*e}:Array.isArray(i)?function(e){return"string"===typeof e?e:i[e]}:"function"===typeof i?i:function(){}}function v(e){return p(e,"spacing",8)}function m(e,t){if("string"===typeof t||null==t)return t;var n=e(Math.abs(t));return t>=0?n:"number"===typeof n?-n:"-".concat(n)}function g(e,t,n,r){if(-1===t.indexOf(n))return null;var o=function(e,t){return function(n){return e.reduce((function(e,r){return e[r]=m(t,n),e}),{})}}(c(n),r),a=e[n];return(0,i.k9)(e,a,o)}function y(e,t){var n=v(e.theme);return Object.keys(e).map((function(r){return g(e,t,r,n)})).reduce(a.Z,{})}function b(e){return y(e,f)}function w(e){return y(e,d)}function x(e){return y(e,h)}b.propTypes={},b.filterProps=f,w.propTypes={},w.filterProps=d,x.propTypes={},x.filterProps=h;var k=x},6428:function(e,t,n){"use strict";n.d(t,{D:function(){return a}});var r=n(4942),i=n(114),o=n(4929);function a(e,t){return t&&"string"===typeof t?t.split(".").reduce((function(e,t){return e&&e[t]?e[t]:null}),e):null}function s(e,t,n){var r,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:n;return r="function"===typeof e?e(n):Array.isArray(e)?e[n]||i:a(e,n)||i,t&&(r=t(r)),r}t.Z=function(e){var t=e.prop,n=e.cssProperty,l=void 0===n?e.prop:n,u=e.themeKey,c=e.transform,f=function(e){if(null==e[t])return null;var n=e[t],f=a(e.theme,u)||{};return(0,o.k9)(e,n,(function(e){var n=s(f,c,e);return e===n&&"string"===typeof e&&(n=s(f,c,"".concat(t).concat("default"===e?"":(0,i.Z)(e)),e)),!1===l?n:(0,r.Z)({},l,n)}))};return f.propTypes={},f.filterProps=[t],f}},3649:function(e,t,n){"use strict";var r=n(4942),i=n(7330),o=n(9716),a=n(4929);function s(e){var t=e||{},n=t.sx,l=t.theme,u=void 0===l?{}:l;if(!n)return null;function c(e){var t=e;if("function"===typeof e)t=e(u);else if("object"!==typeof e)return e;var n=(0,a.W8)(u.breakpoints),l=Object.keys(n),c=n;return Object.keys(t).forEach((function(e){var n,l,f=(n=t[e],l=u,"function"===typeof n?n(l):n);if(null!==f&&void 0!==f)if("object"===typeof f)if(o.G[e])c=(0,i.Z)(c,(0,o.Z)(e,f,u));else{var d=(0,a.k9)({theme:u},f,(function(t){return(0,r.Z)({},e,t)}));!function(){for(var e=arguments.length,t=new Array(e),n=0;n0&&void 0!==arguments[0]?arguments[0]:o;return(0,i.Z)(e)}},4290:function(e,t,n){"use strict";n.d(t,{Z:function(){return i}});var r=n(9023);function i(e){var t=e.theme,n=e.name,i=e.props;return t&&t.components&&t.components[n]&&t.components[n].defaultProps?(0,r.Z)(t.components[n].defaultProps,i):i}},4976:function(e,t,n){"use strict";var r=n(201);function i(e){return 0===Object.keys(e).length}t.Z=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=(0,r.Z)();return!t||i(t)?e:t}},114:function(e,t,n){"use strict";n.d(t,{Z:function(){return i}});var r=n(7219);function i(e){if("string"!==typeof e)throw new Error((0,r.Z)(7));return e.charAt(0).toUpperCase()+e.slice(1)}},4246:function(e,t,n){"use strict";function r(){for(var e=arguments.length,t=new Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:166;function r(){for(var r=this,i=arguments.length,o=new Array(i),a=0;a2&&void 0!==arguments[2]?arguments[2]:{clone:!0},a=n.clone?(0,r.Z)({},e):e;return i(e)&&i(t)&&Object.keys(t).forEach((function(r){"__proto__"!==r&&(i(t[r])&&r in e&&i(e[r])?a[r]=o(e[r],t[r],n):a[r]=t[r])})),a}},7219:function(e,t,n){"use strict";function r(e){for(var t="https://mui.com/production-error/?code="+e,n=1;n-1?i(n):n}},9962:function(e,t,n){"use strict";var r=n(1199),i=n(8476),o=i("%Function.prototype.apply%"),a=i("%Function.prototype.call%"),s=i("%Reflect.apply%",!0)||r.call(a,o),l=i("%Object.getOwnPropertyDescriptor%",!0),u=i("%Object.defineProperty%",!0),c=i("%Math.max%");if(u)try{u({},"a",{value:1})}catch(d){u=null}e.exports=function(e){var t=s(r,a,arguments);if(l&&u){var n=l(t,"length");n.configurable&&u(t,"length",{value:1+c(0,e.length-(arguments.length-1))})}return t};var f=function(){return s(r,o,arguments)};u?u(e.exports,"apply",{value:f}):e.exports.apply=f},3061:function(e,t,n){"use strict";function r(e){var t,n,i="";if("string"===typeof e||"number"===typeof e)i+=e;else if("object"===typeof e)if(Array.isArray(e))for(t=0;t=t?e:""+Array(t+1-r.length).join(n)+e},y={s:g,z:function(e){var t=-e.utcOffset(),n=Math.abs(t),r=Math.floor(n/60),i=n%60;return(t<=0?"+":"-")+g(r,2,"0")+":"+g(i,2,"0")},m:function e(t,n){if(t.date()68?1900:2e3)},s=function(e){return function(t){this[e]=+t}},l=[/[+-]\d\d:?(\d\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if("Z"===e)return 0;var t=e.match(/([+-]|\d\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:"+"===t[0]?-n:n}(e)}],u=function(e){var t=o[e];return t&&(t.indexOf?t:t.s.concat(t.f))},c=function(e,t){var n,r=o.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?"pm":"PM");return n},f={A:[i,function(e){this.afternoon=c(e,!1)}],a:[i,function(e){this.afternoon=c(e,!0)}],S:[/\d/,function(e){this.milliseconds=100*+e}],SS:[n,function(e){this.milliseconds=10*+e}],SSS:[/\d{3}/,function(e){this.milliseconds=+e}],s:[r,s("seconds")],ss:[r,s("seconds")],m:[r,s("minutes")],mm:[r,s("minutes")],H:[r,s("hours")],h:[r,s("hours")],HH:[r,s("hours")],hh:[r,s("hours")],D:[r,s("day")],DD:[n,s("day")],Do:[i,function(e){var t=o.ordinal,n=e.match(/\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\[|\]/g,"")===e&&(this.day=r)}],M:[r,s("month")],MM:[n,s("month")],MMM:[i,function(e){var t=u("months"),n=(u("monthsShort")||t.map((function(e){return e.substr(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[i,function(e){var t=u("months").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\d+/,s("year")],YY:[n,function(e){this.year=a(e)}],YYYY:[/\d{4}/,s("year")],Z:l,ZZ:l};function d(n){var r,i;r=n,i=o&&o.formats;for(var a=(n=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),s=a.length,l=0;l-1)return new Date(("X"===t?1e3:1)*e);var r=d(t)(e),i=r.year,o=r.month,a=r.day,s=r.hours,l=r.minutes,u=r.seconds,c=r.milliseconds,f=r.zone,h=new Date,p=a||(i||o?1:h.getDate()),v=i||h.getFullYear(),m=0;i&&!o||(m=o>0?o-1:h.getMonth());var g=s||0,y=l||0,b=u||0,w=c||0;return f?new Date(Date.UTC(v,m,p,g,y,b,w+60*f.offset*1e3)):n?new Date(Date.UTC(v,m,p,g,y,b,w)):new Date(v,m,p,g,y,b,w)}catch(e){return new Date("")}}(t,s,r),this.init(),f&&!0!==f&&(this.$L=this.locale(f).$L),c&&t!=this.format(s)&&(this.$d=new Date("")),o={}}else if(s instanceof Array)for(var h=s.length,p=1;p<=h;p+=1){a[1]=s[p-1];var v=n.apply(this,a);if(v.isValid()){this.$d=v.$d,this.$L=v.$L,this.init();break}p===h&&(this.$d=new Date(""))}else i.call(this,e)}}}()},6446:function(e){e.exports=function(){"use strict";var e,t,n=1e3,r=6e4,i=36e5,o=864e5,a=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,s=31536e6,l=2592e6,u=/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/,c={years:s,months:l,days:o,hours:i,minutes:r,seconds:n,milliseconds:1,weeks:6048e5},f=function(e){return e instanceof y},d=function(e,t,n){return new y(e,n,t.$l)},h=function(e){return t.p(e)+"s"},p=function(e){return e<0},v=function(e){return p(e)?Math.ceil(e):Math.floor(e)},m=function(e){return Math.abs(e)},g=function(e,t){return e?p(e)?{negative:!0,format:""+m(e)+t}:{negative:!1,format:""+e+t}:{negative:!1,format:""}},y=function(){function p(e,t,n){var r=this;if(this.$d={},this.$l=n,void 0===e&&(this.$ms=0,this.parseFromMilliseconds()),t)return d(e*c[h(t)],this);if("number"==typeof e)return this.$ms=e,this.parseFromMilliseconds(),this;if("object"==typeof e)return Object.keys(e).forEach((function(t){r.$d[h(t)]=e[t]})),this.calMilliseconds(),this;if("string"==typeof e){var i=e.match(u);if(i){var o=i.slice(2).map((function(e){return null!=e?Number(e):0}));return this.$d.years=o[0],this.$d.months=o[1],this.$d.weeks=o[2],this.$d.days=o[3],this.$d.hours=o[4],this.$d.minutes=o[5],this.$d.seconds=o[6],this.calMilliseconds(),this}}return this}var m=p.prototype;return m.calMilliseconds=function(){var e=this;this.$ms=Object.keys(this.$d).reduce((function(t,n){return t+(e.$d[n]||0)*c[n]}),0)},m.parseFromMilliseconds=function(){var e=this.$ms;this.$d.years=v(e/s),e%=s,this.$d.months=v(e/l),e%=l,this.$d.days=v(e/o),e%=o,this.$d.hours=v(e/i),e%=i,this.$d.minutes=v(e/r),e%=r,this.$d.seconds=v(e/n),e%=n,this.$d.milliseconds=e},m.toISOString=function(){var e=g(this.$d.years,"Y"),t=g(this.$d.months,"M"),n=+this.$d.days||0;this.$d.weeks&&(n+=7*this.$d.weeks);var r=g(n,"D"),i=g(this.$d.hours,"H"),o=g(this.$d.minutes,"M"),a=this.$d.seconds||0;this.$d.milliseconds&&(a+=this.$d.milliseconds/1e3);var s=g(a,"S"),l=e.negative||t.negative||r.negative||i.negative||o.negative||s.negative,u=i.format||o.format||s.format?"T":"",c=(l?"-":"")+"P"+e.format+t.format+r.format+u+i.format+o.format+s.format;return"P"===c||"-P"===c?"P0D":c},m.toJSON=function(){return this.toISOString()},m.format=function(e){var n=e||"YYYY-MM-DDTHH:mm:ss",r={Y:this.$d.years,YY:t.s(this.$d.years,2,"0"),YYYY:t.s(this.$d.years,4,"0"),M:this.$d.months,MM:t.s(this.$d.months,2,"0"),D:this.$d.days,DD:t.s(this.$d.days,2,"0"),H:this.$d.hours,HH:t.s(this.$d.hours,2,"0"),m:this.$d.minutes,mm:t.s(this.$d.minutes,2,"0"),s:this.$d.seconds,ss:t.s(this.$d.seconds,2,"0"),SSS:t.s(this.$d.milliseconds,3,"0")};return n.replace(a,(function(e,t){return t||String(r[e])}))},m.as=function(e){return this.$ms/c[h(e)]},m.get=function(e){var t=this.$ms,n=h(e);return"milliseconds"===n?t%=1e3:t="weeks"===n?v(t/c[n]):this.$d[n],0===t?0:t},m.add=function(e,t,n){var r;return r=t?e*c[h(t)]:f(e)?e.$ms:d(e,this).$ms,d(this.$ms+r*(n?-1:1),this)},m.subtract=function(e,t){return this.add(e,t,!0)},m.locale=function(e){var t=this.clone();return t.$l=e,t},m.clone=function(){return d(this.$ms,this)},m.humanize=function(t){return e().add(this.$ms,"ms").locale(this.$l).fromNow(!t)},m.milliseconds=function(){return this.get("milliseconds")},m.asMilliseconds=function(){return this.as("milliseconds")},m.seconds=function(){return this.get("seconds")},m.asSeconds=function(){return this.as("seconds")},m.minutes=function(){return this.get("minutes")},m.asMinutes=function(){return this.as("minutes")},m.hours=function(){return this.get("hours")},m.asHours=function(){return this.as("hours")},m.days=function(){return this.get("days")},m.asDays=function(){return this.as("days")},m.weeks=function(){return this.get("weeks")},m.asWeeks=function(){return this.as("weeks")},m.months=function(){return this.get("months")},m.asMonths=function(){return this.as("months")},m.years=function(){return this.get("years")},m.asYears=function(){return this.as("years")},p}();return function(n,r,i){e=i,t=i().$utils(),i.duration=function(e,t){var n=i.locale();return d(e,{$l:n},t)},i.isDuration=f;var o=r.prototype.add,a=r.prototype.subtract;r.prototype.add=function(e,t){return f(e)&&(e=e.asMilliseconds()),o.bind(this)(e,t)},r.prototype.subtract=function(e,t){return f(e)&&(e=e.asMilliseconds()),a.bind(this)(e,t)}}}()},8743:function(e){e.exports=function(){"use strict";return function(e,t,n){t.prototype.isBetween=function(e,t,r,i){var o=n(e),a=n(t),s="("===(i=i||"()")[0],l=")"===i[1];return(s?this.isAfter(o,r):!this.isBefore(o,r))&&(l?this.isBefore(a,r):!this.isAfter(a,r))||(s?this.isBefore(o,r):!this.isAfter(o,r))&&(l?this.isAfter(a,r):!this.isBefore(a,r))}}}()},3825:function(e){e.exports=function(){"use strict";var e={LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"};return function(t,n,r){var i=n.prototype,o=i.format;r.en.formats=e,i.format=function(t){void 0===t&&(t="YYYY-MM-DDTHH:mm:ssZ");var n=this.$locale().formats,r=function(t,n){return t.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,r,i){var o=i&&i.toUpperCase();return r||n[i]||e[i]||n[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))}(t,void 0===n?{}:n);return o.call(this,r)}}}()},1635:function(e){e.exports=function(){"use strict";var e="minute",t=/[+-]\d\d(?::?\d\d)?/g,n=/([+-]|\d\d)/g;return function(r,i,o){var a=i.prototype;o.utc=function(e){return new i({date:e,utc:!0,args:arguments})},a.utc=function(t){var n=o(this.toDate(),{locale:this.$L,utc:!0});return t?n.add(this.utcOffset(),e):n},a.local=function(){return o(this.toDate(),{locale:this.$L,utc:!1})};var s=a.parse;a.parse=function(e){e.utc&&(this.$u=!0),this.$utils().u(e.$offset)||(this.$offset=e.$offset),s.call(this,e)};var l=a.init;a.init=function(){if(this.$u){var e=this.$d;this.$y=e.getUTCFullYear(),this.$M=e.getUTCMonth(),this.$D=e.getUTCDate(),this.$W=e.getUTCDay(),this.$H=e.getUTCHours(),this.$m=e.getUTCMinutes(),this.$s=e.getUTCSeconds(),this.$ms=e.getUTCMilliseconds()}else l.call(this)};var u=a.utcOffset;a.utcOffset=function(r,i){var o=this.$utils().u;if(o(r))return this.$u?0:o(this.$offset)?u.call(this):this.$offset;if("string"==typeof r&&null===(r=function(e){void 0===e&&(e="");var r=e.match(t);if(!r)return null;var i=(""+r[0]).match(n)||["-",0,0],o=i[0],a=60*+i[1]+ +i[2];return 0===a?0:"+"===o?a:-a}(r)))return this;var a=Math.abs(r)<=16?60*r:r,s=this;if(i)return s.$offset=a,s.$u=0===r,s;if(0!==r){var l=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();(s=this.local().add(a+l,e)).$offset=a,s.$x.$localOffset=l}else s=this.utc();return s};var c=a.format;a.format=function(e){var t=e||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return c.call(this,t)},a.valueOf=function(){var e=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||(new Date).getTimezoneOffset());return this.$d.valueOf()-6e4*e},a.isUTC=function(){return!!this.$u},a.toISOString=function(){return this.toDate().toISOString()},a.toString=function(){return this.toDate().toUTCString()};var f=a.toDate;a.toDate=function(e){return"s"===e&&this.$offset?o(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():f.call(this)};var d=a.diff;a.diff=function(e,t,n){if(e&&this.$u===e.$u)return d.call(this,e,t,n);var r=this.local(),i=o(e).local();return d.call(r,i,t,n)}}}()},2781:function(e){"use strict";var t="Function.prototype.bind called on incompatible ",n=Array.prototype.slice,r=Object.prototype.toString,i="[object Function]";e.exports=function(e){var o=this;if("function"!==typeof o||r.call(o)!==i)throw new TypeError(t+o);for(var a,s=n.call(arguments,1),l=function(){if(this instanceof a){var t=o.apply(this,s.concat(n.call(arguments)));return Object(t)===t?t:this}return o.apply(e,s.concat(n.call(arguments)))},u=Math.max(0,o.length-s.length),c=[],f=0;f1&&"boolean"!==typeof t)throw new a('"allowMissing" argument must be a boolean');var n=M(e),r=n.length>0?n[0]:"",o=P("%"+r+"%",t),s=o.name,u=o.value,c=!1,f=o.alias;f&&(r=f[0],x(n,w([0,1],f)));for(var d=1,h=!0;d=n.length){var y=l(u,p);u=(h=!!y)&&"get"in y&&!("originalValue"in y.get)?y.get:u[p]}else h=b(u,p),u=u[p];h&&!c&&(v[s]=u)}}return u}},5520:function(e,t,n){"use strict";var r="undefined"!==typeof Symbol&&Symbol,i=n(541);e.exports=function(){return"function"===typeof r&&("function"===typeof Symbol&&("symbol"===typeof r("foo")&&("symbol"===typeof Symbol("bar")&&i())))}},541:function(e){"use strict";e.exports=function(){if("function"!==typeof Symbol||"function"!==typeof Object.getOwnPropertySymbols)return!1;if("symbol"===typeof Symbol.iterator)return!0;var e={},t=Symbol("test"),n=Object(t);if("string"===typeof t)return!1;if("[object Symbol]"!==Object.prototype.toString.call(t))return!1;if("[object Symbol]"!==Object.prototype.toString.call(n))return!1;for(t in e[t]=42,e)return!1;if("function"===typeof Object.keys&&0!==Object.keys(e).length)return!1;if("function"===typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(e).length)return!1;var r=Object.getOwnPropertySymbols(e);if(1!==r.length||r[0]!==t)return!1;if(!Object.prototype.propertyIsEnumerable.call(e,t))return!1;if("function"===typeof Object.getOwnPropertyDescriptor){var i=Object.getOwnPropertyDescriptor(e,t);if(42!==i.value||!0!==i.enumerable)return!1}return!0}},7838:function(e,t,n){"use strict";var r=n(1199);e.exports=r.call(Function.call,Object.prototype.hasOwnProperty)},7861:function(e,t,n){"use strict";var r=n(2535),i={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},o={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},a={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},s={};function l(e){return r.isMemo(e)?a:s[e.$$typeof]||i}s[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},s[r.Memo]=a;var u=Object.defineProperty,c=Object.getOwnPropertyNames,f=Object.getOwnPropertySymbols,d=Object.getOwnPropertyDescriptor,h=Object.getPrototypeOf,p=Object.prototype;e.exports=function e(t,n,r){if("string"!==typeof n){if(p){var i=h(n);i&&i!==p&&e(t,i,r)}var a=c(n);f&&(a=a.concat(f(n)));for(var s=l(t),v=l(n),m=0;m=t||n<0||f&&e-u>=o}function x(){var e=p();if(w(e))return k(e);s=setTimeout(x,function(e){var n=t-(e-l);return f?h(n,o-(e-u)):n}(e))}function k(e){return s=void 0,g&&r?y(e):(r=i=void 0,a)}function S(){var e=p(),n=w(e);if(r=arguments,i=this,l=e,n){if(void 0===s)return b(l);if(f)return s=setTimeout(x,t),y(l)}return void 0===s&&(s=setTimeout(x,t)),a}return t=m(t)||0,v(n)&&(c=!!n.leading,o=(f="maxWait"in n)?d(m(n.maxWait)||0,t):o,g="trailing"in n?!!n.trailing:g),S.cancel=function(){void 0!==s&&clearTimeout(s),u=0,r=l=i=s=void 0},S.flush=function(){return void 0===s?a:k(p())},S}},4007:function(e,t,n){var r="__lodash_hash_undefined__",i="[object Function]",o="[object GeneratorFunction]",a=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,s=/^\w*$/,l=/^\./,u=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,c=/\\(\\)?/g,f=/^\[object .+?Constructor\]$/,d="object"==typeof n.g&&n.g&&n.g.Object===Object&&n.g,h="object"==typeof self&&self&&self.Object===Object&&self,p=d||h||Function("return this")();var v=Array.prototype,m=Function.prototype,g=Object.prototype,y=p["__core-js_shared__"],b=function(){var e=/[^.]+$/.exec(y&&y.keys&&y.keys.IE_PROTO||"");return e?"Symbol(src)_1."+e:""}(),w=m.toString,x=g.hasOwnProperty,k=g.toString,S=RegExp("^"+w.call(x).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),O=p.Symbol,C=v.splice,M=L(p,"Map"),P=L(Object,"create"),T=O?O.prototype:void 0,E=T?T.toString:void 0;function Z(e){var t=-1,n=e?e.length:0;for(this.clear();++t-1},A.prototype.set=function(e,t){var n=this.__data__,r=D(n,e);return r<0?n.push([e,t]):n[r][1]=t,this},R.prototype.clear=function(){this.__data__={hash:new Z,map:new(M||A),string:new Z}},R.prototype.delete=function(e){return N(this,e).delete(e)},R.prototype.get=function(e){return N(this,e).get(e)},R.prototype.has=function(e){return N(this,e).has(e)},R.prototype.set=function(e,t){return N(this,e).set(e,t),this};var I=B((function(e){var t;e=null==(t=e)?"":function(e){if("string"==typeof e)return e;if(W(e))return E?E.call(e):"";var t=e+"";return"0"==t&&1/e==-1/0?"-0":t}(t);var n=[];return l.test(e)&&n.push(""),e.replace(u,(function(e,t,r,i){n.push(r?i.replace(c,"$1"):t||e)})),n}));function z(e){if("string"==typeof e||W(e))return e;var t=e+"";return"0"==t&&1/e==-1/0?"-0":t}function B(e,t){if("function"!=typeof e||t&&"function"!=typeof t)throw new TypeError("Expected a function");var n=function n(){var r=arguments,i=t?t.apply(this,r):r[0],o=n.cache;if(o.has(i))return o.get(i);var a=e.apply(this,r);return n.cache=o.set(i,a),a};return n.cache=new(B.Cache||R),n}B.Cache=R;var F=Array.isArray;function $(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function W(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==k.call(e)}e.exports=function(e,t,n){var r=null==e?void 0:j(e,t);return void 0===r?n:r}},2061:function(e,t,n){var r="Expected a function",i=/^\s+|\s+$/g,o=/^[-+]0x[0-9a-f]+$/i,a=/^0b[01]+$/i,s=/^0o[0-7]+$/i,l=parseInt,u="object"==typeof n.g&&n.g&&n.g.Object===Object&&n.g,c="object"==typeof self&&self&&self.Object===Object&&self,f=u||c||Function("return this")(),d=Object.prototype.toString,h=Math.max,p=Math.min,v=function(){return f.Date.now()};function m(e,t,n){var i,o,a,s,l,u,c=0,f=!1,d=!1,m=!0;if("function"!=typeof e)throw new TypeError(r);function b(t){var n=i,r=o;return i=o=void 0,c=t,s=e.apply(r,n)}function w(e){return c=e,l=setTimeout(k,t),f?b(e):s}function x(e){var n=e-u;return void 0===u||n>=t||n<0||d&&e-c>=a}function k(){var e=v();if(x(e))return S(e);l=setTimeout(k,function(e){var n=t-(e-u);return d?p(n,a-(e-c)):n}(e))}function S(e){return l=void 0,m&&i?b(e):(i=o=void 0,s)}function O(){var e=v(),n=x(e);if(i=arguments,o=this,u=e,n){if(void 0===l)return w(u);if(d)return l=setTimeout(k,t),b(u)}return void 0===l&&(l=setTimeout(k,t)),s}return t=y(t)||0,g(n)&&(f=!!n.leading,a=(d="maxWait"in n)?h(y(n.maxWait)||0,t):a,m="trailing"in n?!!n.trailing:m),O.cancel=function(){void 0!==l&&clearTimeout(l),c=0,i=u=o=l=void 0},O.flush=function(){return void 0===l?s:S(v())},O}function g(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function y(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&"[object Symbol]"==d.call(e)}(e))return NaN;if(g(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=g(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(i,"");var n=a.test(e);return n||s.test(e)?l(e.slice(2),n?2:8):o.test(e)?NaN:+e}e.exports=function(e,t,n){var i=!0,o=!0;if("function"!=typeof e)throw new TypeError(r);return g(n)&&(i="leading"in n?!!n.leading:i,o="trailing"in n?!!n.trailing:o),m(e,t,{leading:i,maxWait:t,trailing:o})}},2985:function(e,t,n){"use strict";var r=n(4575).default,i=n(3913).default,o=n(9808),a=Symbol("max"),s=Symbol("length"),l=Symbol("lengthCalculator"),u=Symbol("allowStale"),c=Symbol("maxAge"),f=Symbol("dispose"),d=Symbol("noDisposeOnSet"),h=Symbol("lruList"),p=Symbol("cache"),v=Symbol("updateAgeOnGet"),m=function(){return 1},g=function(){function e(t){if(r(this,e),"number"===typeof t&&(t={max:t}),t||(t={}),t.max&&("number"!==typeof t.max||t.max<0))throw new TypeError("max must be a non-negative number");this[a]=t.max||1/0;var n=t.length||m;if(this[l]="function"!==typeof n?m:n,this[u]=t.stale||!1,t.maxAge&&"number"!==typeof t.maxAge)throw new TypeError("maxAge must be a number");this[c]=t.maxAge||0,this[f]=t.dispose,this[d]=t.noDisposeOnSet||!1,this[v]=t.updateAgeOnGet||!1,this.reset()}return i(e,[{key:"max",get:function(){return this[a]},set:function(e){if("number"!==typeof e||e<0)throw new TypeError("max must be a non-negative number");this[a]=e||1/0,w(this)}},{key:"allowStale",get:function(){return this[u]},set:function(e){this[u]=!!e}},{key:"maxAge",get:function(){return this[c]},set:function(e){if("number"!==typeof e)throw new TypeError("maxAge must be a non-negative number");this[c]=e,w(this)}},{key:"lengthCalculator",get:function(){return this[l]},set:function(e){var t=this;"function"!==typeof e&&(e=m),e!==this[l]&&(this[l]=e,this[s]=0,this[h].forEach((function(e){e.length=t[l](e.value,e.key),t[s]+=e.length}))),w(this)}},{key:"length",get:function(){return this[s]}},{key:"itemCount",get:function(){return this[h].length}},{key:"rforEach",value:function(e,t){t=t||this;for(var n=this[h].tail;null!==n;){var r=n.prev;S(this,e,n,t),n=r}}},{key:"forEach",value:function(e,t){t=t||this;for(var n=this[h].head;null!==n;){var r=n.next;S(this,e,n,t),n=r}}},{key:"keys",value:function(){return this[h].toArray().map((function(e){return e.key}))}},{key:"values",value:function(){return this[h].toArray().map((function(e){return e.value}))}},{key:"reset",value:function(){var e=this;this[f]&&this[h]&&this[h].length&&this[h].forEach((function(t){return e[f](t.key,t.value)})),this[p]=new Map,this[h]=new o,this[s]=0}},{key:"dump",value:function(){var e=this;return this[h].map((function(t){return!b(e,t)&&{k:t.key,v:t.value,e:t.now+(t.maxAge||0)}})).toArray().filter((function(e){return e}))}},{key:"dumpLru",value:function(){return this[h]}},{key:"set",value:function(e,t,n){if((n=n||this[c])&&"number"!==typeof n)throw new TypeError("maxAge must be a number");var r=n?Date.now():0,i=this[l](t,e);if(this[p].has(e)){if(i>this[a])return x(this,this[p].get(e)),!1;var o=this[p].get(e).value;return this[f]&&(this[d]||this[f](e,o.value)),o.now=r,o.maxAge=n,o.value=t,this[s]+=i-o.length,o.length=i,this.get(e),w(this),!0}var u=new k(e,t,i,r,n);return u.length>this[a]?(this[f]&&this[f](e,t),!1):(this[s]+=u.length,this[h].unshift(u),this[p].set(e,this[h].head),w(this),!0)}},{key:"has",value:function(e){if(!this[p].has(e))return!1;var t=this[p].get(e).value;return!b(this,t)}},{key:"get",value:function(e){return y(this,e,!0)}},{key:"peek",value:function(e){return y(this,e,!1)}},{key:"pop",value:function(){var e=this[h].tail;return e?(x(this,e),e.value):null}},{key:"del",value:function(e){x(this,this[p].get(e))}},{key:"load",value:function(e){this.reset();for(var t=Date.now(),n=e.length-1;n>=0;n--){var r=e[n],i=r.e||0;if(0===i)this.set(r.k,r.v);else{var o=i-t;o>0&&this.set(r.k,r.v,o)}}}},{key:"prune",value:function(){var e=this;this[p].forEach((function(t,n){return y(e,n,!1)}))}}]),e}(),y=function(e,t,n){var r=e[p].get(t);if(r){var i=r.value;if(b(e,i)){if(x(e,r),!e[u])return}else n&&(e[v]&&(r.value.now=Date.now()),e[h].unshiftNode(r));return i.value}},b=function(e,t){if(!t||!t.maxAge&&!e[c])return!1;var n=Date.now()-t.now;return t.maxAge?n>t.maxAge:e[c]&&n>e[c]},w=function(e){if(e[s]>e[a])for(var t=e[h].tail;e[s]>e[a]&&null!==t;){var n=t.prev;x(e,t),t=n}},x=function(e,t){if(t){var n=t.value;e[f]&&e[f](n.key,n.value),e[s]-=n.length,e[p].delete(n.key),e[h].removeNode(t)}},k=i((function e(t,n,i,o,a){r(this,e),this.key=t,this.value=n,this.length=i,this.now=o,this.maxAge=a||0})),S=function(e,t,n,r){var i=n.value;b(e,i)&&(x(e,n),e[u]||(i=void 0)),i&&t.call(r,i.value,i.key,e)};e.exports=g},1733:function(e,t,n){var r,i;r=function(){var e,t,n="2.0.6",r={},i={},o={currentLocale:"en",zeroFormat:null,nullFormat:null,defaultFormat:"0,0",scalePercentBy100:!0},a={currentLocale:o.currentLocale,zeroFormat:o.zeroFormat,nullFormat:o.nullFormat,defaultFormat:o.defaultFormat,scalePercentBy100:o.scalePercentBy100};function s(e,t){this._input=e,this._value=t}return(e=function(n){var i,o,l,u;if(e.isNumeral(n))i=n.value();else if(0===n||"undefined"===typeof n)i=0;else if(null===n||t.isNaN(n))i=null;else if("string"===typeof n)if(a.zeroFormat&&n===a.zeroFormat)i=0;else if(a.nullFormat&&n===a.nullFormat||!n.replace(/[^0-9]+/g,"").length)i=null;else{for(o in r)if((u="function"===typeof r[o].regexps.unformat?r[o].regexps.unformat():r[o].regexps.unformat)&&n.match(u)){l=r[o].unformat;break}i=(l=l||e._.stringToNumber)(n)}else i=Number(n)||null;return new s(n,i)}).version=n,e.isNumeral=function(e){return e instanceof s},e._=t={numberToFormat:function(t,n,r){var o,a,s,l,u,c,f,d=i[e.options.currentLocale],h=!1,p=!1,v=0,m="",g=1e12,y=1e9,b=1e6,w=1e3,x="",k=!1;if(t=t||0,a=Math.abs(t),e._.includes(n,"(")?(h=!0,n=n.replace(/[\(|\)]/g,"")):(e._.includes(n,"+")||e._.includes(n,"-"))&&(u=e._.includes(n,"+")?n.indexOf("+"):t<0?n.indexOf("-"):-1,n=n.replace(/[\+|\-]/g,"")),e._.includes(n,"a")&&(o=!!(o=n.match(/a(k|m|b|t)?/))&&o[1],e._.includes(n," a")&&(m=" "),n=n.replace(new RegExp(m+"a[kmbt]?"),""),a>=g&&!o||"t"===o?(m+=d.abbreviations.trillion,t/=g):a=y&&!o||"b"===o?(m+=d.abbreviations.billion,t/=y):a=b&&!o||"m"===o?(m+=d.abbreviations.million,t/=b):(a=w&&!o||"k"===o)&&(m+=d.abbreviations.thousand,t/=w)),e._.includes(n,"[.]")&&(p=!0,n=n.replace("[.]",".")),s=t.toString().split(".")[0],l=n.split(".")[1],c=n.indexOf(","),v=(n.split(".")[0].split(",")[0].match(/0/g)||[]).length,l?(e._.includes(l,"[")?(l=(l=l.replace("]","")).split("["),x=e._.toFixed(t,l[0].length+l[1].length,r,l[1].length)):x=e._.toFixed(t,l.length,r),s=x.split(".")[0],x=e._.includes(x,".")?d.delimiters.decimal+x.split(".")[1]:"",p&&0===Number(x.slice(1))&&(x="")):s=e._.toFixed(t,0,r),m&&!o&&Number(s)>=1e3&&m!==d.abbreviations.trillion)switch(s=String(Number(s)/1e3),m){case d.abbreviations.thousand:m=d.abbreviations.million;break;case d.abbreviations.million:m=d.abbreviations.billion;break;case d.abbreviations.billion:m=d.abbreviations.trillion}if(e._.includes(s,"-")&&(s=s.slice(1),k=!0),s.length0;S--)s="0"+s;return c>-1&&(s=s.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1"+d.delimiters.thousands)),0===n.indexOf(".")&&(s=""),f=s+x+(m||""),h?f=(h&&k?"(":"")+f+(h&&k?")":""):u>=0?f=0===u?(k?"-":"+")+f:f+(k?"-":"+"):k&&(f="-"+f),f},stringToNumber:function(e){var t,n,r,o=i[a.currentLocale],s=e,l={thousand:3,million:6,billion:9,trillion:12};if(a.zeroFormat&&e===a.zeroFormat)n=0;else if(a.nullFormat&&e===a.nullFormat||!e.replace(/[^0-9]+/g,"").length)n=null;else{for(t in n=1,"."!==o.delimiters.decimal&&(e=e.replace(/\./g,"").replace(o.delimiters.decimal,".")),l)if(r=new RegExp("[^a-zA-Z]"+o.abbreviations[t]+"(?:\\)|(\\"+o.currency.symbol+")?(?:\\))?)?$"),s.match(r)){n*=Math.pow(10,l[t]);break}n*=(e.split("-").length+Math.min(e.split("(").length-1,e.split(")").length-1))%2?1:-1,e=e.replace(/[^0-9\.]+/g,""),n*=Number(e)}return n},isNaN:function(e){function t(t){return e.apply(this,arguments)}return t.toString=function(){return e.toString()},t}((function(e){return"number"===typeof e&&isNaN(e)})),includes:function(e,t){return-1!==e.indexOf(t)},insert:function(e,t,n){return e.slice(0,n)+t+e.slice(n)},reduce:function(e,t){if(null===this)throw new TypeError("Array.prototype.reduce called on null or undefined");if("function"!==typeof t)throw new TypeError(t+" is not a function");var n,r=Object(e),i=r.length>>>0,o=0;if(3===arguments.length)n=arguments[2];else{for(;o=i)throw new TypeError("Reduce of empty array with no initial value");n=r[o++]}for(;or?e:r}),1)},toFixed:function(e,t,n,r){var i,o,a,s,l=e.toString().split("."),u=t-(r||0);return i=2===l.length?Math.min(Math.max(l[1].length,u),t):u,a=Math.pow(10,i),s=(n(e+"e+"+i)/a).toFixed(i),r>t-i&&(o=new RegExp("\\.?0{1,"+(r-(t-i))+"}$"),s=s.replace(o,"")),s}},e.options=a,e.formats=r,e.locales=i,e.locale=function(e){return e&&(a.currentLocale=e.toLowerCase()),a.currentLocale},e.localeData=function(e){if(!e)return i[a.currentLocale];if(e=e.toLowerCase(),!i[e])throw new Error("Unknown locale : "+e);return i[e]},e.reset=function(){for(var e in o)a[e]=o[e]},e.zeroFormat=function(e){a.zeroFormat="string"===typeof e?e:null},e.nullFormat=function(e){a.nullFormat="string"===typeof e?e:null},e.defaultFormat=function(e){a.defaultFormat="string"===typeof e?e:"0.0"},e.register=function(e,t,n){if(t=t.toLowerCase(),this[e+"s"][t])throw new TypeError(t+" "+e+" already registered.");return this[e+"s"][t]=n,n},e.validate=function(t,n){var r,i,o,a,s,l,u,c;if("string"!==typeof t&&(t+="",console.warn&&console.warn("Numeral.js: Value is not string. It has been co-erced to: ",t)),(t=t.trim()).match(/^\d+$/))return!0;if(""===t)return!1;try{u=e.localeData(n)}catch(f){u=e.localeData(e.locale())}return o=u.currency.symbol,s=u.abbreviations,r=u.delimiters.decimal,i="."===u.delimiters.thousands?"\\.":u.delimiters.thousands,(null===(c=t.match(/^[^\d]+/))||(t=t.substr(1),c[0]===o))&&(null===(c=t.match(/[^\d]+$/))||(t=t.slice(0,-1),c[0]===s.thousand||c[0]===s.million||c[0]===s.billion||c[0]===s.trillion))&&(l=new RegExp(i+"{2}"),!t.match(/[^\d.,]/g)&&!((a=t.split(r)).length>2)&&(a.length<2?!!a[0].match(/^\d+.*\d$/)&&!a[0].match(l):1===a[0].length?!!a[0].match(/^\d+$/)&&!a[0].match(l)&&!!a[1].match(/^\d+$/):!!a[0].match(/^\d+.*\d$/)&&!a[0].match(l)&&!!a[1].match(/^\d+$/)))},e.fn=s.prototype={clone:function(){return e(this)},format:function(t,n){var i,o,s,l=this._value,u=t||a.defaultFormat;if(n=n||Math.round,0===l&&null!==a.zeroFormat)o=a.zeroFormat;else if(null===l&&null!==a.nullFormat)o=a.nullFormat;else{for(i in r)if(u.match(r[i].regexps.format)){s=r[i].format;break}o=(s=s||e._.numberToFormat)(l,u,n)}return o},value:function(){return this._value},input:function(){return this._input},set:function(e){return this._value=Number(e),this},add:function(e){var n=t.correctionFactor.call(null,this._value,e);function r(e,t,r,i){return e+Math.round(n*t)}return this._value=t.reduce([this._value,e],r,0)/n,this},subtract:function(e){var n=t.correctionFactor.call(null,this._value,e);function r(e,t,r,i){return e-Math.round(n*t)}return this._value=t.reduce([e],r,Math.round(this._value*n))/n,this},multiply:function(e){function n(e,n,r,i){var o=t.correctionFactor(e,n);return Math.round(e*o)*Math.round(n*o)/Math.round(o*o)}return this._value=t.reduce([this._value,e],n,1),this},divide:function(e){function n(e,n,r,i){var o=t.correctionFactor(e,n);return Math.round(e*o)/Math.round(n*o)}return this._value=t.reduce([this._value,e],n),this},difference:function(t){return Math.abs(e(this._value).subtract(t).value())}},e.register("locale","en",{delimiters:{thousands:",",decimal:"."},abbreviations:{thousand:"k",million:"m",billion:"b",trillion:"t"},ordinal:function(e){var t=e%10;return 1===~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th"},currency:{symbol:"$"}}),e.register("format","bps",{regexps:{format:/(BPS)/,unformat:/(BPS)/},format:function(t,n,r){var i,o=e._.includes(n," BPS")?" ":"";return t*=1e4,n=n.replace(/\s?BPS/,""),i=e._.numberToFormat(t,n,r),e._.includes(i,")")?((i=i.split("")).splice(-1,0,o+"BPS"),i=i.join("")):i=i+o+"BPS",i},unformat:function(t){return+(1e-4*e._.stringToNumber(t)).toFixed(15)}}),function(){var t={base:1e3,suffixes:["B","KB","MB","GB","TB","PB","EB","ZB","YB"]},n={base:1024,suffixes:["B","KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"]},r=t.suffixes.concat(n.suffixes.filter((function(e){return t.suffixes.indexOf(e)<0}))).join("|");r="("+r.replace("B","B(?!PS)")+")",e.register("format","bytes",{regexps:{format:/([0\s]i?b)/,unformat:new RegExp(r)},format:function(r,i,o){var a,s,l,u=e._.includes(i,"ib")?n:t,c=e._.includes(i," b")||e._.includes(i," ib")?" ":"";for(i=i.replace(/\s?i?b/,""),a=0;a<=u.suffixes.length;a++)if(s=Math.pow(u.base,a),l=Math.pow(u.base,a+1),null===r||0===r||r>=s&&r0&&(r/=s);break}return e._.numberToFormat(r,i,o)+c},unformat:function(r){var i,o,a=e._.stringToNumber(r);if(a){for(i=t.suffixes.length-1;i>=0;i--){if(e._.includes(r,t.suffixes[i])){o=Math.pow(t.base,i);break}if(e._.includes(r,n.suffixes[i])){o=Math.pow(n.base,i);break}}a*=o||1}return a}})}(),e.register("format","currency",{regexps:{format:/(\$)/},format:function(t,n,r){var i,o,a=e.locales[e.options.currentLocale],s={before:n.match(/^([\+|\-|\(|\s|\$]*)/)[0],after:n.match(/([\+|\-|\)|\s|\$]*)$/)[0]};for(n=n.replace(/\s?\$\s?/,""),i=e._.numberToFormat(t,n,r),t>=0?(s.before=s.before.replace(/[\-\(]/,""),s.after=s.after.replace(/[\-\)]/,"")):t<0&&!e._.includes(s.before,"-")&&!e._.includes(s.before,"(")&&(s.before="-"+s.before),o=0;o=0;o--)switch(s.after[o]){case"$":i=o===s.after.length-1?i+a.currency.symbol:e._.insert(i,a.currency.symbol,-(s.after.length-(1+o)));break;case" ":i=o===s.after.length-1?i+" ":e._.insert(i," ",-(s.after.length-(1+o)+a.currency.symbol.length-1))}return i}}),e.register("format","exponential",{regexps:{format:/(e\+|e-)/,unformat:/(e\+|e-)/},format:function(t,n,r){var i=("number"!==typeof t||e._.isNaN(t)?"0e+0":t.toExponential()).split("e");return n=n.replace(/e[\+|\-]{1}0/,""),e._.numberToFormat(Number(i[0]),n,r)+"e"+i[1]},unformat:function(t){var n=e._.includes(t,"e+")?t.split("e+"):t.split("e-"),r=Number(n[0]),i=Number(n[1]);function o(t,n,r,i){var o=e._.correctionFactor(t,n);return t*o*(n*o)/(o*o)}return i=e._.includes(t,"e-")?i*=-1:i,e._.reduce([r,Math.pow(10,i)],o,1)}}),e.register("format","ordinal",{regexps:{format:/(o)/},format:function(t,n,r){var i=e.locales[e.options.currentLocale],o=e._.includes(n," o")?" ":"";return n=n.replace(/\s?o/,""),o+=i.ordinal(t),e._.numberToFormat(t,n,r)+o}}),e.register("format","percentage",{regexps:{format:/(%)/,unformat:/(%)/},format:function(t,n,r){var i,o=e._.includes(n," %")?" ":"";return e.options.scalePercentBy100&&(t*=100),n=n.replace(/\s?\%/,""),i=e._.numberToFormat(t,n,r),e._.includes(i,")")?((i=i.split("")).splice(-1,0,o+"%"),i=i.join("")):i=i+o+"%",i},unformat:function(t){var n=e._.stringToNumber(t);return e.options.scalePercentBy100?.01*n:n}}),e.register("format","time",{regexps:{format:/(:)/,unformat:/(:)/},format:function(e,t,n){var r=Math.floor(e/60/60),i=Math.floor((e-60*r*60)/60),o=Math.round(e-60*r*60-60*i);return r+":"+(i<10?"0"+i:i)+":"+(o<10?"0"+o:o)},unformat:function(e){var t=e.split(":"),n=0;return 3===t.length?(n+=60*Number(t[0])*60,n+=60*Number(t[1]),n+=Number(t[2])):2===t.length&&(n+=60*Number(t[0]),n+=Number(t[1])),Number(n)}}),e},void 0===(i="function"===typeof r?r.call(t,n,t,e):r)||(e.exports=i)},1843:function(e){"use strict";var t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable;function i(e){if(null===e||void 0===e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(i){return!1}}()?Object.assign:function(e,o){for(var a,s,l=i(e),u=1;u0))throw new TypeError('options "indent" must be "\\t", an integer > 0, or `null`');if("undefined"===typeof t)return"undefined";if(null===t)return"null";if("boolean"===typeof t)return t?"true":"false";if("string"===typeof t)return _(t,s);if("number"===typeof t)return 0===t?1/0/t>0?"0":"-0":String(t);if("bigint"===typeof t)return String(t)+"n";var v="undefined"===typeof s.depth?5:s.depth;if("undefined"===typeof r&&(r=0),r>=v&&v>0&&"object"===typeof t)return E(t)?"[Array]":"[Object]";var b=function(e,t){var n;if("\t"===e.indent)n="\t";else{if(!("number"===typeof e.indent&&e.indent>0))return null;n=Array(e.indent+1).join(" ")}return{base:n,prev:Array(t+1).join(n)}}(s,r);if("undefined"===typeof i)i=[];else if(j(i,t)>=0)return"[Circular]";function k(t,n,o){if(n&&(i=i.slice()).push(n),o){var a={depth:s.depth};return R(s,"quoteStyle")&&(a.quoteStyle=s.quoteStyle),e(t,a,r+1,i)}return e(t,s,r+1,i)}if("function"===typeof t){var O=function(e){if(e.name)return e.name;var t=g.call(m.call(e),/^function\s*([\w$]+)/);if(t)return t[1];return null}(t),A=F(t,k);return"[Function"+(O?": "+O:" (anonymous)")+"]"+(A.length>0?" { "+A.join(", ")+" }":"")}if(Z(t)){var N=x?String(t).replace(/^(Symbol\(.*\))_[^)]*$/,"$1"):w.call(t);return"object"!==typeof t||x?N:L(N)}if(function(e){if(!e||"object"!==typeof e)return!1;if("undefined"!==typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"===typeof e.nodeName&&"function"===typeof e.getAttribute}(t)){for(var $="<"+String(t.nodeName).toLowerCase(),W=t.attributes||[],H=0;H"}if(E(t)){if(0===t.length)return"[]";var V=F(t,k);return b&&!function(e){for(var t=0;t=0)return!1;return!0}(V)?"["+B(V,b)+"]":"[ "+V.join(", ")+" ]"}if(function(e){return"[object Error]"===D(e)&&(!M||!("object"===typeof e&&M in e))}(t)){var q=F(t,k);return 0===q.length?"["+String(t)+"]":"{ ["+String(t)+"] "+q.join(", ")+" }"}if("object"===typeof t&&l){if(C&&"function"===typeof t[C])return t[C]();if("symbol"!==l&&"function"===typeof t.inspect)return t.inspect()}if(function(e){if(!o||!e||"object"!==typeof e)return!1;try{o.call(e);try{u.call(e)}catch($){return!0}return e instanceof Map}catch(t){}return!1}(t)){var U=[];return a.call(t,(function(e,n){U.push(k(n,t,!0)+" => "+k(e,t))})),z("Map",o.call(t),U,b)}if(function(e){if(!u||!e||"object"!==typeof e)return!1;try{u.call(e);try{o.call(e)}catch(t){return!0}return e instanceof Set}catch(n){}return!1}(t)){var Q=[];return c.call(t,(function(e){Q.push(k(e,t))})),z("Set",u.call(t),Q,b)}if(function(e){if(!f||!e||"object"!==typeof e)return!1;try{f.call(e,f);try{d.call(e,d)}catch($){return!0}return e instanceof WeakMap}catch(t){}return!1}(t))return I("WeakMap");if(function(e){if(!d||!e||"object"!==typeof e)return!1;try{d.call(e,d);try{f.call(e,f)}catch($){return!0}return e instanceof WeakSet}catch(t){}return!1}(t))return I("WeakSet");if(function(e){if(!h||!e||"object"!==typeof e)return!1;try{return h.call(e),!0}catch(t){}return!1}(t))return I("WeakRef");if(function(e){return"[object Number]"===D(e)&&(!M||!("object"===typeof e&&M in e))}(t))return L(k(Number(t)));if(function(e){if(!e||"object"!==typeof e||!y)return!1;try{return y.call(e),!0}catch(t){}return!1}(t))return L(k(y.call(t)));if(function(e){return"[object Boolean]"===D(e)&&(!M||!("object"===typeof e&&M in e))}(t))return L(p.call(t));if(function(e){return"[object String]"===D(e)&&(!M||!("object"===typeof e&&M in e))}(t))return L(k(String(t)));if(!function(e){return"[object Date]"===D(e)&&(!M||!("object"===typeof e&&M in e))}(t)&&!function(e){return"[object RegExp]"===D(e)&&(!M||!("object"===typeof e&&M in e))}(t)){var X=F(t,k),Y=S?S(t)===Object.prototype:t instanceof Object||t.constructor===Object,G=t instanceof Object?"":"null prototype",K=!Y&&M&&Object(t)===t&&M in t?D(t).slice(8,-1):G?"Object":"",J=(Y||"function"!==typeof t.constructor?"":t.constructor.name?t.constructor.name+" ":"")+(K||G?"["+[].concat(K||[],G||[]).join(": ")+"] ":"");return 0===X.length?J+"{}":b?J+"{"+B(X,b)+"}":J+"{ "+X.join(", ")+" }"}return String(t)};var A=Object.prototype.hasOwnProperty||function(e){return e in this};function R(e,t){return A.call(e,t)}function D(e){return v.call(e)}function j(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,r=e.length;nt.maxStringLength){var n=e.length-t.maxStringLength,r="... "+n+" more character"+(n>1?"s":"");return _(e.slice(0,t.maxStringLength),t)+r}return P(e.replace(/(['\\])/g,"\\$1").replace(/[\x00-\x1f]/g,N),"single",t)}function N(e){var t=e.charCodeAt(0),n={8:"b",9:"t",10:"n",12:"f",13:"r"}[t];return n?"\\"+n:"\\x"+(t<16?"0":"")+t.toString(16).toUpperCase()}function L(e){return"Object("+e+")"}function I(e){return e+" { ? }"}function z(e,t,n,r){return e+" ("+t+") {"+(r?B(n,r):n.join(", "))+"}"}function B(e,t){if(0===e.length)return"";var n="\n"+t.prev+t.base;return n+e.join(","+n)+"\n"+t.prev}function F(e,t){var n=E(e),r=[];if(n){r.length=e.length;for(var i=0;i-1?e.split(","):e},u=function(e,t,n,r){if(e){var o=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,a=/(\[[^[\]]*])/g,s=n.depth>0&&/(\[[^[\]]*])/.exec(o),u=s?o.slice(0,s.index):o,c=[];if(u){if(!n.plainObjects&&i.call(Object.prototype,u)&&!n.allowPrototypes)return;c.push(u)}for(var f=0;n.depth>0&&null!==(s=a.exec(o))&&f=0;--o){var a,s=e[o];if("[]"===s&&n.parseArrays)a=[].concat(i);else{a=n.plainObjects?Object.create(null):{};var u="["===s.charAt(0)&&"]"===s.charAt(s.length-1)?s.slice(1,-1):s,c=parseInt(u,10);n.parseArrays||""!==u?!isNaN(c)&&s!==u&&String(c)===u&&c>=0&&n.parseArrays&&c<=n.arrayLimit?(a=[])[c]=i:a[u]=i:a={0:i}}i=a}return i}(c,t,n,r)}};e.exports=function(e,t){var n=function(e){if(!e)return a;if(null!==e.decoder&&void 0!==e.decoder&&"function"!==typeof e.decoder)throw new TypeError("Decoder has to be a function.");if("undefined"!==typeof e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var t="undefined"===typeof e.charset?a.charset:e.charset;return{allowDots:"undefined"===typeof e.allowDots?a.allowDots:!!e.allowDots,allowPrototypes:"boolean"===typeof e.allowPrototypes?e.allowPrototypes:a.allowPrototypes,allowSparse:"boolean"===typeof e.allowSparse?e.allowSparse:a.allowSparse,arrayLimit:"number"===typeof e.arrayLimit?e.arrayLimit:a.arrayLimit,charset:t,charsetSentinel:"boolean"===typeof e.charsetSentinel?e.charsetSentinel:a.charsetSentinel,comma:"boolean"===typeof e.comma?e.comma:a.comma,decoder:"function"===typeof e.decoder?e.decoder:a.decoder,delimiter:"string"===typeof e.delimiter||r.isRegExp(e.delimiter)?e.delimiter:a.delimiter,depth:"number"===typeof e.depth||!1===e.depth?+e.depth:a.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"===typeof e.interpretNumericEntities?e.interpretNumericEntities:a.interpretNumericEntities,parameterLimit:"number"===typeof e.parameterLimit?e.parameterLimit:a.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"===typeof e.plainObjects?e.plainObjects:a.plainObjects,strictNullHandling:"boolean"===typeof e.strictNullHandling?e.strictNullHandling:a.strictNullHandling}}(t);if(""===e||null===e||"undefined"===typeof e)return n.plainObjects?Object.create(null):{};for(var c="string"===typeof e?function(e,t){var n,u={},c=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,f=t.parameterLimit===1/0?void 0:t.parameterLimit,d=c.split(t.delimiter,f),h=-1,p=t.charset;if(t.charsetSentinel)for(n=0;n-1&&(m=o(m)?[m]:m),i.call(u,v)?u[v]=r.combine(u[v],m):u[v]=m}return u}(e,n):e,f=n.plainObjects?Object.create(null):{},d=Object.keys(c),h=0;h0?O.join(",")||null:void 0}];else if(l(d))D=d;else{var _=Object.keys(O);D=h?_.sort(h):_}for(var N=0;N0?w+b:""}},9837:function(e,t,n){"use strict";var r=n(5609),i=Object.prototype.hasOwnProperty,o=Array.isArray,a=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),s=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},r=0;r1;){var t=e.pop(),n=t.obj[t.prop];if(o(n)){for(var r=[],i=0;i=48&&c<=57||c>=65&&c<=90||c>=97&&c<=122||o===r.RFC1738&&(40===c||41===c)?l+=s.charAt(u):c<128?l+=a[c]:c<2048?l+=a[192|c>>6]+a[128|63&c]:c<55296||c>=57344?l+=a[224|c>>12]+a[128|c>>6&63]+a[128|63&c]:(u+=1,c=65536+((1023&c)<<10|1023&s.charCodeAt(u)),l+=a[240|c>>18]+a[128|c>>12&63]+a[128|c>>6&63]+a[128|63&c])}return l},isBuffer:function(e){return!(!e||"object"!==typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(o(e)){for(var n=[],r=0;r