From 5cc0b194d3676ce54c9bbb9af407ff9c4f61d6f4 Mon Sep 17 00:00:00 2001
From: Philipp Heckel <pheckel@datto.com>
Date: Thu, 2 Jun 2022 10:50:05 -0400
Subject: [PATCH] Add --trace and --no-log-dates; add docs

---
 cmd/app.go               |   9 +-
 cmd/subscribe_windows.go |   2 +-
 docs/config.md           | 168 ++++++++++++++---------
 go.mod                   |  10 +-
 go.sum                   |  18 +--
 log/log.go               |   5 +
 server/ntfy.service      |   2 +-
 server/server.go         |   2 +-
 web/package-lock.json    | 287 ++++++++++++++++++++-------------------
 9 files changed, 286 insertions(+), 217 deletions(-)

diff --git a/cmd/app.go b/cmd/app.go
index adac9d7..975fd2f 100644
--- a/cmd/app.go
+++ b/cmd/app.go
@@ -17,6 +17,8 @@ var commands = make([]*cli.Command, 0)
 
 var flagsDefault = []cli.Flag{
 	&cli.BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"NTFY_DEBUG"}, Usage: "enable debug logging"},
+	&cli.BoolFlag{Name: "trace", EnvVars: []string{"NTFY_TRACE"}, Usage: "enable tracing (very verbose, be careful)"},
+	&cli.BoolFlag{Name: "no-log-dates", Aliases: []string{"no_log_dates"}, EnvVars: []string{"NTFY_NO_LOG_DATES"}, Usage: "disable the date/time prefix"},
 	altsrc.NewStringFlag(&cli.StringFlag{Name: "log-level", Aliases: []string{"log_level"}, Value: log.InfoLevel.String(), EnvVars: []string{"NTFY_LOG_LEVEL"}, Usage: "set log level"}),
 }
 
@@ -38,10 +40,15 @@ func New() *cli.App {
 }
 
 func initLogFunc(c *cli.Context) error {
-	if c.Bool("debug") {
+	if c.Bool("trace") {
+		log.SetLevel(log.TraceLevel)
+	} else if c.Bool("debug") {
 		log.SetLevel(log.DebugLevel)
 	} else {
 		log.SetLevel(log.ToLevel(c.String("log-level")))
 	}
+	if c.Bool("no-log-dates") {
+		log.DisableDates()
+	}
 	return nil
 }
diff --git a/cmd/subscribe_windows.go b/cmd/subscribe_windows.go
index 129e8f5..e8f1a27 100644
--- a/cmd/subscribe_windows.go
+++ b/cmd/subscribe_windows.go
@@ -10,6 +10,6 @@ var (
 	scriptLauncher = []string{"cmd.exe", "/Q", "/C"}
 )
 
-func defaultConfigFile() string {
+func defaultClientConfigFile() string {
 	return defaultClientConfigFileWindows()
 }
diff --git a/docs/config.md b/docs/config.md
index 9b0aa07..fc1c115 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -708,6 +708,23 @@ are enabled):
 * `visitor-email-limit-burst` is the initial bucket of emails each visitor has. This defaults to 16.
 * `visitor-email-limit-replenish` is the rate at which the bucket is refilled (one email per x). Defaults to 1h.
 
+### Firebase limits
+If [Firebase is configured](#firebase-fcm), all messages are also published to a Firebase topic (unless `Firebase: no` 
+is set). Firebase enforces [its own limits](https://firebase.google.com/docs/cloud-messaging/concept-options#topics_throttling)
+on how many messages can be published. Unfortunately these limits are a little vague and can change depending on the time 
+of day. In practice, I have only ever observed `429 Quota exceeded` responses from Firebase if **too many messages are published to 
+the same topic**. 
+
+In ntfy, if Firebase responds with a 429 after publishing to a topic, the visitor (= IP address) who published the message
+is **banned from publishing to Firebase for 10 minutes** (not configurable). Because publishing to Firebase happens asynchronously,
+there is no indication of the user that this has happened. Non-Firebase subscribers (WebSocket or HTTP stream) are not affected.
+After the 10 minutes are up, messages forwarding to Firebase is resumed for this visitor.
+
+If this ever happens, there will be a log message that looks something like this:
+```
+WARN Firebase quota exceeded (likely for topic), temporarily denying Firebase access to visitor
+```
+
 ## Tuning for scale
 If you're running ntfy for your home server, you probably don't need to worry about scale at all. In its default config,
 if it's not behind a proxy, the ntfy server can keep about **as many connections as the open file limit allows**.
@@ -807,6 +824,26 @@ and [here](https://easyengine.io/tutorials/nginx/block-wp-login-php-bruteforce-a
     maxretry = 10
     ```
 
+## Debugging/tracing
+If something's not working right, you can debug/trace through what the ntfy server is doing by setting the `log-level`
+to `DEBUG` or `TRACE`. The `DEBUG` setting will output information about each published message, but not the message 
+contents. The `TRACE` setting will also print the message contents. 
+
+!!! warning
+    Both options are very verbose and should only be enabled in production for short periods of time. Otherwise, 
+    you're going to run out of disk space pretty quickly.
+
+You can also hot-reload the `log-level` by sending the `SIGHUP` signal to the process (or by calling 
+`systemctl reload ntfy` if it's running inside systemd). You can do so by calling `kill -HUP $(pidof ntfy)`. 
+If succesfull, you'll see something like this:
+
+```
+$ ntfy serve
+2022/06/02 10:29:28 INFO Listening on :2586[http] :1025[smtp], log level is INFO
+2022/06/02 10:29:34 INFO Partially hot reloading configuration ...
+2022/06/02 10:29:34 INFO Log level is TRACE
+```
+
 ## Config options
 Each config option can be set in the config file `/etc/ntfy/server.yml` (e.g. `listen-http: :80`) or as a
 CLI option (e.g. `--listen-http :80`. Here's a list of all available options. Alternatively, you can set an environment
@@ -817,43 +854,44 @@ variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`).
     `cache_duration` and `cache-duration` are both supported. This is to support stricter YAML parsers that do 
     not support dashes.
 
-| Config option                              | Env variable                                    | Format                                              | Default      | Description                                                                                                                                                                                                                     |
-|--------------------------------------------|-------------------------------------------------|-----------------------------------------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `base-url`                                 | `NTFY_BASE_URL`                                 | *URL*                                               | -            | Public facing base URL of the service (e.g. `https://ntfy.sh`)                                                                                                                                                                  |
-| `listen-http`                              | `NTFY_LISTEN_HTTP`                              | `[host]:port`                                       | `:80`        | Listen address for the HTTP web server                                                                                                                                                                                          |
-| `listen-https`                             | `NTFY_LISTEN_HTTPS`                             | `[host]:port`                                       | -            | Listen address for the HTTPS web server. If set, you also need to set `key-file` and `cert-file`.                                                                                                                               |
-| `listen-unix`                              | `NTFY_LISTEN_UNIX`                              | *filename*                                          | -            | Path to a Unix socket to listen on                                                                                                                                                                                              |
-| `key-file`                                 | `NTFY_KEY_FILE`                                 | *filename*                                          | -            | HTTPS/TLS private key file, only used if `listen-https` is set.                                                                                                                                                                 |
-| `cert-file`                                | `NTFY_CERT_FILE`                                | *filename*                                          | -            | HTTPS/TLS certificate file, only used if `listen-https` is set.                                                                                                                                                                 |
-| `firebase-key-file`                        | `NTFY_FIREBASE_KEY_FILE`                        | *filename*                                          | -            | If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app. This is optional and only required to save battery when using the Android app. See [Firebase (FCM](#firebase-fcm).                        |
-| `cache-file`                               | `NTFY_CACHE_FILE`                               | *filename*                                          | -            | If set, messages are cached in a local SQLite database instead of only in-memory. This allows for service restarts without losing messages in support of the since= parameter. See [message cache](#message-cache).             |
-| `cache-duration`                           | `NTFY_CACHE_DURATION`                           | *duration*                                          | 12h          | Duration for which messages will be buffered before they are deleted. This is required to support the `since=...` and `poll=1` parameter. Set this to `0` to disable the cache entirely.                                        |
-| `auth-file`                                | `NTFY_AUTH_FILE`                                | *filename*                                          | -            | Auth database file used for access control. If set, enables authentication and access control. See [access control](#access-control).                                                                                           |
-| `auth-default-access`                      | `NTFY_AUTH_DEFAULT_ACCESS`                      | `read-write`, `read-only`, `write-only`, `deny-all` | `read-write` | Default permissions if no matching entries in the auth database are found. Default is `read-write`.                                                                                                                             |
-| `behind-proxy`                             | `NTFY_BEHIND_PROXY`                             | *bool*                                              | false        | If set, the X-Forwarded-For header is used to determine the visitor IP address instead of the remote address of the connection.                                                                                                 |
-| `attachment-cache-dir`                     | `NTFY_ATTACHMENT_CACHE_DIR`                     | *directory*                                         | -            | Cache directory for attached files. To enable attachments, this has to be set.                                                                                                                                                  |
-| `attachment-total-size-limit`              | `NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT`              | *size*                                              | 5G           | Limit of the on-disk attachment cache directory. If the limits is exceeded, new attachments will be rejected.                                                                                                                   |
-| `attachment-file-size-limit`               | `NTFY_ATTACHMENT_FILE_SIZE_LIMIT`               | *size*                                              | 15M          | Per-file attachment size limit (e.g. 300k, 2M, 100M). Larger attachment will be rejected.                                                                                                                                       |
-| `attachment-expiry-duration`               | `NTFY_ATTACHMENT_EXPIRY_DURATION`               | *duration*                                          | 3h           | Duration after which uploaded attachments will be deleted (e.g. 3h, 20h). Strongly affects `visitor-attachment-total-size-limit`.                                                                                               |
-| `smtp-sender-addr`                         | `NTFY_SMTP_SENDER_ADDR`                         | `host:port`                                         | -            | SMTP server address to allow email sending                                                                                                                                                                                      |
-| `smtp-sender-user`                         | `NTFY_SMTP_SENDER_USER`                         | *string*                                            | -            | SMTP user; only used if e-mail sending is enabled                                                                                                                                                                               |
-| `smtp-sender-pass`                         | `NTFY_SMTP_SENDER_PASS`                         | *string*                                            | -            | SMTP password; only used if e-mail sending is enabled                                                                                                                                                                           |
-| `smtp-sender-from`                         | `NTFY_SMTP_SENDER_FROM`                         | *e-mail address*                                    | -            | SMTP sender e-mail address; only used if e-mail sending is enabled                                                                                                                                                              |
-| `smtp-server-listen`                       | `NTFY_SMTP_SERVER_LISTEN`                       | `[ip]:port`                                         | -            | Defines the IP address and port the SMTP server will listen on, e.g. `:25` or `1.2.3.4:25`                                                                                                                                      |
-| `smtp-server-domain`                       | `NTFY_SMTP_SERVER_DOMAIN`                       | *domain name*                                       | -            | SMTP server e-mail domain, e.g. `ntfy.sh`                                                                                                                                                                                       |
-| `smtp-server-addr-prefix`                  | `NTFY_SMTP_SERVER_ADDR_PREFIX`                  | `[ip]:port`                                         | -            | Optional prefix for the e-mail addresses to prevent spam, e.g. `ntfy-`                                                                                                                                                          |
-| `keepalive-interval`                       | `NTFY_KEEPALIVE_INTERVAL`                       | *duration*                                          | 45s          | Interval in which keepalive messages are sent to the client. This is to prevent intermediaries closing the connection for inactivity. Note that the Android app has a hardcoded timeout at 77s, so it should be less than that. |
-| `manager-interval`                         | `$NTFY_MANAGER_INTERVAL`                        | *duration*                                          | 1m           | Interval in which the manager prunes old messages, deletes topics and prints the stats.                                                                                                                                         |
-| `web-root`                                 | `NTFY_WEB_ROOT`                                 | `app`, `home` or `disable`                          | `app`        | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable)                                                                                                                                  |
-| `global-topic-limit`                       | `NTFY_GLOBAL_TOPIC_LIMIT`                       | *number*                                            | 15,000       | Rate limiting: Total number of topics before the server rejects new topics.                                                                                                                                                     |
-| `visitor-subscription-limit`               | `NTFY_VISITOR_SUBSCRIPTION_LIMIT`               | *number*                                            | 30           | Rate limiting: Number of subscriptions per visitor (IP address)                                                                                                                                                                 |
-| `visitor-attachment-total-size-limit`      | `NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT`      | *size*                                              | 100M         | Rate limiting: Total storage limit used for attachments per visitor, for all attachments combined. Storage is freed after attachments expire. See `attachment-expiry-duration`.                                                 |
-| `visitor-attachment-daily-bandwidth-limit` | `NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT` | *size*                                              | 500M         | Rate limiting: Total daily attachment download/upload traffic limit per visitor. This is to protect your bandwidth costs from exploding.                                                                                        |
-| `visitor-request-limit-burst`              | `NTFY_VISITOR_REQUEST_LIMIT_BURST`              | *number*                                            | 60           | Rate limiting: Allowed GET/PUT/POST requests per second, per visitor. This setting is the initial bucket of requests each visitor has                                                                                           |
-| `visitor-request-limit-replenish`          | `NTFY_VISITOR_REQUEST_LIMIT_REPLENISH`          | *duration*                                          | 5s           | Rate limiting: Strongly related to `visitor-request-limit-burst`: The rate at which the bucket is refilled                                                                                                                      |
-| `visitor-request-limit-exempt-hosts`       | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS`       | *comma-separated host/IP list*                      | -            | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting                                                                                                                                                |
-| `visitor-email-limit-burst`                | `NTFY_VISITOR_EMAIL_LIMIT_BURST`                | *number*                                            | 16           | Rate limiting:Initial limit of e-mails per visitor                                                                                                                                                                              |
-| `visitor-email-limit-replenish`            | `NTFY_VISITOR_EMAIL_LIMIT_REPLENISH`            | *duration*                                          | 1h           | Rate limiting: Strongly related to `visitor-email-limit-burst`: The rate at which the bucket is refilled                                                                                                                        |
+| Config option                              | Env variable                                    | Format                                              | Default           | Description                                                                                                                                                                                                                     |
+|--------------------------------------------|-------------------------------------------------|-----------------------------------------------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `base-url`                                 | `NTFY_BASE_URL`                                 | *URL*                                               | -                 | Public facing base URL of the service (e.g. `https://ntfy.sh`)                                                                                                                                                                  |
+| `listen-http`                              | `NTFY_LISTEN_HTTP`                              | `[host]:port`                                       | `:80`             | Listen address for the HTTP web server                                                                                                                                                                                          |
+| `listen-https`                             | `NTFY_LISTEN_HTTPS`                             | `[host]:port`                                       | -                 | Listen address for the HTTPS web server. If set, you also need to set `key-file` and `cert-file`.                                                                                                                               |
+| `listen-unix`                              | `NTFY_LISTEN_UNIX`                              | *filename*                                          | -                 | Path to a Unix socket to listen on                                                                                                                                                                                              |
+| `key-file`                                 | `NTFY_KEY_FILE`                                 | *filename*                                          | -                 | HTTPS/TLS private key file, only used if `listen-https` is set.                                                                                                                                                                 |
+| `cert-file`                                | `NTFY_CERT_FILE`                                | *filename*                                          | -                 | HTTPS/TLS certificate file, only used if `listen-https` is set.                                                                                                                                                                 |
+| `firebase-key-file`                        | `NTFY_FIREBASE_KEY_FILE`                        | *filename*                                          | -                 | If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app. This is optional and only required to save battery when using the Android app. See [Firebase (FCM](#firebase-fcm).                        |
+| `cache-file`                               | `NTFY_CACHE_FILE`                               | *filename*                                          | -                 | If set, messages are cached in a local SQLite database instead of only in-memory. This allows for service restarts without losing messages in support of the since= parameter. See [message cache](#message-cache).             |
+| `cache-duration`                           | `NTFY_CACHE_DURATION`                           | *duration*                                          | 12h               | Duration for which messages will be buffered before they are deleted. This is required to support the `since=...` and `poll=1` parameter. Set this to `0` to disable the cache entirely.                                        |
+| `auth-file`                                | `NTFY_AUTH_FILE`                                | *filename*                                          | -                 | Auth database file used for access control. If set, enables authentication and access control. See [access control](#access-control).                                                                                           |
+| `auth-default-access`                      | `NTFY_AUTH_DEFAULT_ACCESS`                      | `read-write`, `read-only`, `write-only`, `deny-all` | `read-write`      | Default permissions if no matching entries in the auth database are found. Default is `read-write`.                                                                                                                             |
+| `behind-proxy`                             | `NTFY_BEHIND_PROXY`                             | *bool*                                              | false             | If set, the X-Forwarded-For header is used to determine the visitor IP address instead of the remote address of the connection.                                                                                                 |
+| `attachment-cache-dir`                     | `NTFY_ATTACHMENT_CACHE_DIR`                     | *directory*                                         | -                 | Cache directory for attached files. To enable attachments, this has to be set.                                                                                                                                                  |
+| `attachment-total-size-limit`              | `NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT`              | *size*                                              | 5G                | Limit of the on-disk attachment cache directory. If the limits is exceeded, new attachments will be rejected.                                                                                                                   |
+| `attachment-file-size-limit`               | `NTFY_ATTACHMENT_FILE_SIZE_LIMIT`               | *size*                                              | 15M               | Per-file attachment size limit (e.g. 300k, 2M, 100M). Larger attachment will be rejected.                                                                                                                                       |
+| `attachment-expiry-duration`               | `NTFY_ATTACHMENT_EXPIRY_DURATION`               | *duration*                                          | 3h                | Duration after which uploaded attachments will be deleted (e.g. 3h, 20h). Strongly affects `visitor-attachment-total-size-limit`.                                                                                               |
+| `smtp-sender-addr`                         | `NTFY_SMTP_SENDER_ADDR`                         | `host:port`                                         | -                 | SMTP server address to allow email sending                                                                                                                                                                                      |
+| `smtp-sender-user`                         | `NTFY_SMTP_SENDER_USER`                         | *string*                                            | -                 | SMTP user; only used if e-mail sending is enabled                                                                                                                                                                               |
+| `smtp-sender-pass`                         | `NTFY_SMTP_SENDER_PASS`                         | *string*                                            | -                 | SMTP password; only used if e-mail sending is enabled                                                                                                                                                                           |
+| `smtp-sender-from`                         | `NTFY_SMTP_SENDER_FROM`                         | *e-mail address*                                    | -                 | SMTP sender e-mail address; only used if e-mail sending is enabled                                                                                                                                                              |
+| `smtp-server-listen`                       | `NTFY_SMTP_SERVER_LISTEN`                       | `[ip]:port`                                         | -                 | Defines the IP address and port the SMTP server will listen on, e.g. `:25` or `1.2.3.4:25`                                                                                                                                      |
+| `smtp-server-domain`                       | `NTFY_SMTP_SERVER_DOMAIN`                       | *domain name*                                       | -                 | SMTP server e-mail domain, e.g. `ntfy.sh`                                                                                                                                                                                       |
+| `smtp-server-addr-prefix`                  | `NTFY_SMTP_SERVER_ADDR_PREFIX`                  | `[ip]:port`                                         | -                 | Optional prefix for the e-mail addresses to prevent spam, e.g. `ntfy-`                                                                                                                                                          |
+| `keepalive-interval`                       | `NTFY_KEEPALIVE_INTERVAL`                       | *duration*                                          | 45s               | Interval in which keepalive messages are sent to the client. This is to prevent intermediaries closing the connection for inactivity. Note that the Android app has a hardcoded timeout at 77s, so it should be less than that. |
+| `manager-interval`                         | `$NTFY_MANAGER_INTERVAL`                        | *duration*                                          | 1m                | Interval in which the manager prunes old messages, deletes topics and prints the stats.                                                                                                                                         |
+| `global-topic-limit`                       | `NTFY_GLOBAL_TOPIC_LIMIT`                       | *number*                                            | 15,000            | Rate limiting: Total number of topics before the server rejects new topics.                                                                                                                                                     |
+| `upstream-base-url`                        | `NTFY_UPSTREAM_BASE_URL`                        | *URL*                                               | `https://ntfy.sh` | Forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers                                                                                                                   |
+| `visitor-attachment-total-size-limit`      | `NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT`      | *size*                                              | 100M              | Rate limiting: Total storage limit used for attachments per visitor, for all attachments combined. Storage is freed after attachments expire. See `attachment-expiry-duration`.                                                 |
+| `visitor-attachment-daily-bandwidth-limit` | `NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT` | *size*                                              | 500M              | Rate limiting: Total daily attachment download/upload traffic limit per visitor. This is to protect your bandwidth costs from exploding.                                                                                        |
+| `visitor-email-limit-burst`                | `NTFY_VISITOR_EMAIL_LIMIT_BURST`                | *number*                                            | 16                | Rate limiting:Initial limit of e-mails per visitor                                                                                                                                                                              |
+| `visitor-email-limit-replenish`            | `NTFY_VISITOR_EMAIL_LIMIT_REPLENISH`            | *duration*                                          | 1h                | Rate limiting: Strongly related to `visitor-email-limit-burst`: The rate at which the bucket is refilled                                                                                                                        |
+| `visitor-request-limit-burst`              | `NTFY_VISITOR_REQUEST_LIMIT_BURST`              | *number*                                            | 60                | Rate limiting: Allowed GET/PUT/POST requests per second, per visitor. This setting is the initial bucket of requests each visitor has                                                                                           |
+| `visitor-request-limit-replenish`          | `NTFY_VISITOR_REQUEST_LIMIT_REPLENISH`          | *duration*                                          | 5s                | Rate limiting: Strongly related to `visitor-request-limit-burst`: The rate at which the bucket is refilled                                                                                                                      |
+| `visitor-request-limit-exempt-hosts`       | `NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS`       | *comma-separated host/IP list*                      | -                 | Rate limiting: List of hostnames and IPs to be exempt from request rate limiting                                                                                                                                                |
+| `visitor-subscription-limit`               | `NTFY_VISITOR_SUBSCRIPTION_LIMIT`               | *number*                                            | 30                | Rate limiting: Number of subscriptions per visitor (IP address)                                                                                                                                                                 |
+| `web-root`                                 | `NTFY_WEB_ROOT`                                 | `app`, `home` or `disable`                          | `app`             | Sets web root to landing page (home), web app (app) or disables the web app entirely (disable)                                                                                                                                  |
 
 The format for a *duration* is: `<number>(smh)`, e.g. 30s, 20m or 1h.   
 The format for a *size* is: `<number>(GMK)`, e.g. 1G, 200M or 4000k.
@@ -881,42 +919,46 @@ DESCRIPTION:
      ntfy serve --listen-http :8080  # Starts server with alternate port
 
 OPTIONS:
-   --config value, -c value                                                                            config file (default: /etc/ntfy/server.yml) [$NTFY_CONFIG_FILE]
+   --attachment-cache-dir value, --attachment_cache_dir value                                          cache directory for attached files [$NTFY_ATTACHMENT_CACHE_DIR]
+   --attachment-expiry-duration value, --attachment_expiry_duration value, -X value                    duration after which uploaded attachments will be deleted (e.g. 3h, 20h) (default: 3h) [$NTFY_ATTACHMENT_EXPIRY_DURATION]
+   --attachment-file-size-limit value, --attachment_file_size_limit value, -Y value                    per-file attachment size limit (e.g. 300k, 2M, 100M) (default: 15M) [$NTFY_ATTACHMENT_FILE_SIZE_LIMIT]
+   --attachment-total-size-limit value, --attachment_total_size_limit value, -A value                  limit of the on-disk attachment cache (default: 5G) [$NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT]
+   --auth-default-access value, --auth_default_access value, -p value                                  default permissions if no matching entries in the auth database are found (default: "read-write") [$NTFY_AUTH_DEFAULT_ACCESS]
+   --auth-file value, --auth_file value, -H value                                                      auth database file used for access control [$NTFY_AUTH_FILE]
    --base-url value, --base_url value, -B value                                                        externally visible base URL for this host (e.g. https://ntfy.sh) [$NTFY_BASE_URL]
-   --listen-http value, --listen_http value, -l value                                                  ip:port used to as HTTP listen address (default: ":80") [$NTFY_LISTEN_HTTP]
-   --listen-https value, --listen_https value, -L value                                                ip:port used to as HTTPS listen address [$NTFY_LISTEN_HTTPS]
-   --listen-unix value, --listen_unix value, -U value                                                  listen on unix socket path [$NTFY_LISTEN_UNIX]
-   --key-file value, --key_file value, -K value                                                        private key file, if listen-https is set [$NTFY_KEY_FILE]
+   --behind-proxy, --behind_proxy, -P                                                                  if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting) (default: false) [$NTFY_BEHIND_PROXY]
+   --cache-duration since, --cache_duration since, -b since                                            buffer messages for this time to allow since requests (default: 12h0m0s) [$NTFY_CACHE_DURATION]
+   --cache-file value, --cache_file value, -C value                                                    cache file used for message caching [$NTFY_CACHE_FILE]
    --cert-file value, --cert_file value, -E value                                                      certificate file, if listen-https is set [$NTFY_CERT_FILE]
+   --config value, -c value                                                                            config file (default: /etc/ntfy/server.yml) [$NTFY_CONFIG_FILE]
+   --debug, -d                                                                                         enable debug logging (default: false) [$NTFY_DEBUG]
    --firebase-key-file value, --firebase_key_file value, -F value                                      Firebase credentials file; if set additionally publish to FCM topic [$NTFY_FIREBASE_KEY_FILE]
-   --cache-file value, --cache_file value, -C value                                                    cache file used for message caching [$NTFY_CACHE_FILE]
-   --cache-duration since, --cache_duration since, -b since                                            buffer messages for this time to allow since requests (default: 12h0m0s) [$NTFY_CACHE_DURATION]
-   --auth-file value, --auth_file value, -H value                                                      auth database file used for access control [$NTFY_AUTH_FILE]
-   --auth-default-access value, --auth_default_access value, -p value                                  default permissions if no matching entries in the auth database are found (default: "read-write") [$NTFY_AUTH_DEFAULT_ACCESS]
-   --attachment-cache-dir value, --attachment_cache_dir value                                          cache directory for attached files [$NTFY_ATTACHMENT_CACHE_DIR]
-   --attachment-total-size-limit value, --attachment_total_size_limit value, -A value                  limit of the on-disk attachment cache (default: 5G) [$NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT]
-   --attachment-file-size-limit value, --attachment_file_size_limit value, -Y value                    per-file attachment size limit (e.g. 300k, 2M, 100M) (default: 15M) [$NTFY_ATTACHMENT_FILE_SIZE_LIMIT]
-   --attachment-expiry-duration value, --attachment_expiry_duration value, -X value                    duration after which uploaded attachments will be deleted (e.g. 3h, 20h) (default: 3h) [$NTFY_ATTACHMENT_EXPIRY_DURATION]
+   --global-topic-limit value, --global_topic_limit value, -T value                                    total number of topics allowed (default: 15000) [$NTFY_GLOBAL_TOPIC_LIMIT]
    --keepalive-interval value, --keepalive_interval value, -k value                                    interval of keepalive messages (default: 45s) [$NTFY_KEEPALIVE_INTERVAL]
+   --key-file value, --key_file value, -K value                                                        private key file, if listen-https is set [$NTFY_KEY_FILE]
+   --listen-http value, --listen_http value, -l value                                                  ip:port used to as HTTP listen address (default: ":80") [$NTFY_LISTEN_HTTP]
+   --listen-https value, --listen_https value, -L value                                                ip:port used to as HTTPS listen address [$NTFY_LISTEN_HTTPS]
+   --listen-unix value, --listen_unix value, -U value                                                  listen on unix socket path [$NTFY_LISTEN_UNIX]
+   --log-level value, --log_level value                                                                set log level (default: "INFO") [$NTFY_LOG_LEVEL]
    --manager-interval value, --manager_interval value, -m value                                        interval of for message pruning and stats printing (default: 1m0s) [$NTFY_MANAGER_INTERVAL]
-   --web-root value, --web_root value                                                                  sets web root to landing page (home), web app (app) or disabled (disable) (default: "app") [$NTFY_WEB_ROOT]
+   --no-log-dates, --no_log_dates                                                                      disable the date/time prefix (default: false) [$NTFY_NO_LOG_DATES]
    --smtp-sender-addr value, --smtp_sender_addr value                                                  SMTP server address (host:port) for outgoing emails [$NTFY_SMTP_SENDER_ADDR]
-   --smtp-sender-user value, --smtp_sender_user value                                                  SMTP user (if e-mail sending is enabled) [$NTFY_SMTP_SENDER_USER]
-   --smtp-sender-pass value, --smtp_sender_pass value                                                  SMTP password (if e-mail sending is enabled) [$NTFY_SMTP_SENDER_PASS]
    --smtp-sender-from value, --smtp_sender_from value                                                  SMTP sender address (if e-mail sending is enabled) [$NTFY_SMTP_SENDER_FROM]
-   --smtp-server-listen value, --smtp_server_listen value                                              SMTP server address (ip:port) for incoming emails, e.g. :25 [$NTFY_SMTP_SERVER_LISTEN]
-   --smtp-server-domain value, --smtp_server_domain value                                              SMTP domain for incoming e-mail, e.g. ntfy.sh [$NTFY_SMTP_SERVER_DOMAIN]
+   --smtp-sender-pass value, --smtp_sender_pass value                                                  SMTP password (if e-mail sending is enabled) [$NTFY_SMTP_SENDER_PASS]
+   --smtp-sender-user value, --smtp_sender_user value                                                  SMTP user (if e-mail sending is enabled) [$NTFY_SMTP_SENDER_USER]
    --smtp-server-addr-prefix value, --smtp_server_addr_prefix value                                    SMTP email address prefix for topics to prevent spam (e.g. 'ntfy-') [$NTFY_SMTP_SERVER_ADDR_PREFIX]
-   --global-topic-limit value, --global_topic_limit value, -T value                                    total number of topics allowed (default: 15000) [$NTFY_GLOBAL_TOPIC_LIMIT]
-   --visitor-subscription-limit value, --visitor_subscription_limit value                              number of subscriptions per visitor (default: 30) [$NTFY_VISITOR_SUBSCRIPTION_LIMIT]
-   --visitor-attachment-total-size-limit value, --visitor_attachment_total_size_limit value            total storage limit used for attachments per visitor (default: "100M") [$NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT]
+   --smtp-server-domain value, --smtp_server_domain value                                              SMTP domain for incoming e-mail, e.g. ntfy.sh [$NTFY_SMTP_SERVER_DOMAIN]
+   --smtp-server-listen value, --smtp_server_listen value                                              SMTP server address (ip:port) for incoming emails, e.g. :25 [$NTFY_SMTP_SERVER_LISTEN]
+   --trace                                                                                             enable tracing (very verbose, be careful) (default: false) [$NTFY_TRACE]
+   --upstream-base-url value, --upstream_base_url value                                                forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers [$NTFY_UPSTREAM_BASE_URL]
    --visitor-attachment-daily-bandwidth-limit value, --visitor_attachment_daily_bandwidth_limit value  total daily attachment download/upload bandwidth limit per visitor (default: "500M") [$NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT]
-   --visitor-request-limit-burst value, --visitor_request_limit_burst value                            initial limit of requests per visitor (default: 60) [$NTFY_VISITOR_REQUEST_LIMIT_BURST]
-   --visitor-request-limit-replenish value, --visitor_request_limit_replenish value                    interval at which burst limit is replenished (one per x) (default: 5s) [$NTFY_VISITOR_REQUEST_LIMIT_REPLENISH]
-   --visitor-request-limit-exempt-hosts value, --visitor_request_limit_exempt_hosts value              hostnames and/or IP addresses of hosts that will be exempt from the visitor request limit [$NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS]
+   --visitor-attachment-total-size-limit value, --visitor_attachment_total_size_limit value            total storage limit used for attachments per visitor (default: "100M") [$NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT]
    --visitor-email-limit-burst value, --visitor_email_limit_burst value                                initial limit of e-mails per visitor (default: 16) [$NTFY_VISITOR_EMAIL_LIMIT_BURST]
    --visitor-email-limit-replenish value, --visitor_email_limit_replenish value                        interval at which burst limit is replenished (one per x) (default: 1h0m0s) [$NTFY_VISITOR_EMAIL_LIMIT_REPLENISH]
-   --behind-proxy, --behind_proxy, -P                                                                  if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting) (default: false) [$NTFY_BEHIND_PROXY]
-   --help, -h                                                                                          show help (default: false)
+   --visitor-request-limit-burst value, --visitor_request_limit_burst value                            initial limit of requests per visitor (default: 60) [$NTFY_VISITOR_REQUEST_LIMIT_BURST]
+   --visitor-request-limit-exempt-hosts value, --visitor_request_limit_exempt_hosts value              hostnames and/or IP addresses of hosts that will be exempt from the visitor request limit [$NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS]
+   --visitor-request-limit-replenish value, --visitor_request_limit_replenish value                    interval at which burst limit is replenished (one per x) (default: 5s) [$NTFY_VISITOR_REQUEST_LIMIT_REPLENISH]
+   --visitor-subscription-limit value, --visitor_subscription_limit value                              number of subscriptions per visitor (default: 30) [$NTFY_VISITOR_SUBSCRIPTION_LIMIT]
+   --web-root value, --web_root value                                                                  sets web root to landing page (home), web app (app) or disabled (disable) (default: "app") [$NTFY_WEB_ROOT]
 ```
 
diff --git a/go.mod b/go.mod
index 3c2fed0..6c36e8f 100644
--- a/go.mod
+++ b/go.mod
@@ -16,10 +16,10 @@ require (
 	github.com/urfave/cli/v2 v2.8.1
 	golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
 	golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 // indirect
-	golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
+	golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f
 	golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
 	golang.org/x/time v0.0.0-20220411224347-583f2d630306
-	google.golang.org/api v0.81.0
+	google.golang.org/api v0.82.0
 	gopkg.in/yaml.v2 v2.4.0
 )
 
@@ -44,14 +44,14 @@ require (
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
 	go.opencensus.io v0.23.0 // indirect
-	golang.org/x/net v0.0.0-20220526153639-5463443f8c37 // indirect
+	golang.org/x/net v0.0.0-20220531201128-c960675eff93 // indirect
 	golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
 	golang.org/x/text v0.3.7 // indirect
 	golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/appengine/v2 v2.0.1 // indirect
-	google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
-	google.golang.org/grpc v1.46.2 // indirect
+	google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 // indirect
+	google.golang.org/grpc v1.47.0 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
 	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
 )
diff --git a/go.sum b/go.sum
index a188110..e0f0204 100644
--- a/go.sum
+++ b/go.sum
@@ -341,9 +341,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
 golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
 golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
+golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -377,8 +377,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
 golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
+golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -560,8 +561,8 @@ google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRR
 google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
 google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
-google.golang.org/api v0.81.0 h1:o8WF5AvfidafWbFjsRyupxyEQJNUWxLZJCK5NXrxZZ8=
-google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko=
+google.golang.org/api v0.82.0 h1:h6EGeZuzhoKSS7BUznzkW+2wHZ+4Ubd6rsVvvh3dRkw=
+google.golang.org/api v0.82.0/go.mod h1:Ld58BeTlL9DIYr2M2ajvoSqmGLei0BMn+kVBmkam1os=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -655,10 +656,10 @@ google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX
 google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
 google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
 google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
 google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 h1:a221mAAEAzq4Lz6ZWRkcS8ptb2mxoxYSt4N68aRyQHM=
 google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
+google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8 h1:qRu95HZ148xXw+XeZ3dvqe85PxH4X8+jIo0iRPKcEnM=
+google.golang.org/genproto v0.0.0-20220602131408-e326c6e8e9c8/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -688,8 +689,9 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
 google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=
 google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
+google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
diff --git a/log/log.go b/log/log.go
index f105f72..5dac232 100644
--- a/log/log.go
+++ b/log/log.go
@@ -83,6 +83,11 @@ func SetLevel(newLevel Level) {
 	level = newLevel
 }
 
+// DisableDates disables the date/time prefix
+func DisableDates() {
+	log.SetFlags(0)
+}
+
 // ToLevel converts a string to a Level. It returns InfoLevel if the string
 // does not match any known log levels.
 func ToLevel(s string) Level {
diff --git a/server/ntfy.service b/server/ntfy.service
index f32ed89..8bf250a 100644
--- a/server/ntfy.service
+++ b/server/ntfy.service
@@ -5,7 +5,7 @@ After=network.target
 [Service]
 User=ntfy
 Group=ntfy
-ExecStart=/usr/bin/ntfy serve
+ExecStart=/usr/bin/ntfy serve --no-log-dates
 ExecReload=/bin/kill --signal HUP $MAINPID
 Restart=on-failure
 AmbientCapabilities=CAP_NET_BIND_SERVICE
diff --git a/server/server.go b/server/server.go
index 9829921..ebbc118 100644
--- a/server/server.go
+++ b/server/server.go
@@ -490,7 +490,7 @@ func (s *Server) sendToFirebase(v *visitor, m *message) {
 func (s *Server) sendEmail(v *visitor, m *message, email string) {
 	log.Debug("%s Sending email to %s", logMessagePrefix(v, m), email)
 	if err := s.smtpSender.Send(v, m, email); err != nil {
-		log.Warn("%s Unable to send email: %v", logMessagePrefix(v, m), err.Error())
+		log.Warn("%s Unable to send email to %s: %v", logMessagePrefix(v, m), email, err.Error())
 	}
 }
 
diff --git a/web/package-lock.json b/web/package-lock.json
index 9853d84..a7671db 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -2004,6 +2004,24 @@
         "postcss": "^8.3"
       }
     },
+    "node_modules/@csstools/postcss-trigonometric-functions": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.1.tgz",
+      "integrity": "sha512-G78CY/+GePc6dDCTUbwI6TTFQ5fs3N9POHhI6v0QzteGpf6ylARiJUNz9HrRKi4eVYBNXjae1W2766iUEFxHlw==",
+      "dependencies": {
+        "postcss-value-parser": "^4.2.0"
+      },
+      "engines": {
+        "node": "^14 || >=16"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/csstools"
+      },
+      "peerDependencies": {
+        "postcss": "^8.4"
+      }
+    },
     "node_modules/@csstools/postcss-unset-value": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.1.tgz",
@@ -3854,9 +3872,9 @@
       "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
     },
     "node_modules/@types/node": {
-      "version": "17.0.36",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz",
-      "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA=="
+      "version": "17.0.38",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz",
+      "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g=="
     },
     "node_modules/@types/parse-json": {
       "version": "4.0.0",
@@ -3889,9 +3907,9 @@
       "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
     },
     "node_modules/@types/react": {
-      "version": "18.0.9",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.9.tgz",
-      "integrity": "sha512-9bjbg1hJHUm4De19L1cHiW0Jvx3geel6Qczhjd0qY5VKVE2X5+x77YxAepuCwVh4vrgZJdgEJw48zrhRIeF4Nw==",
+      "version": "18.0.10",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.10.tgz",
+      "integrity": "sha512-dIugadZuIPrRzvIEevIu7A1smqOAjkSMv8qOfwPt9Ve6i6JT/FQcCHyk2qIAxwsQNKZt5/oGR0T4z9h2dXRAkg==",
       "dependencies": {
         "@types/prop-types": "*",
         "@types/scheduler": "*",
@@ -5357,9 +5375,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001344",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz",
-      "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==",
+      "version": "1.0.30001346",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001346.tgz",
+      "integrity": "sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ==",
       "funding": [
         {
           "type": "opencollective",
@@ -5719,9 +5737,9 @@
       "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
     },
     "node_modules/core-js": {
-      "version": "3.22.7",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz",
-      "integrity": "sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg==",
+      "version": "3.22.8",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.8.tgz",
+      "integrity": "sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA==",
       "hasInstallScript": true,
       "funding": {
         "type": "opencollective",
@@ -5729,9 +5747,9 @@
       }
     },
     "node_modules/core-js-compat": {
-      "version": "3.22.7",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.7.tgz",
-      "integrity": "sha512-uI9DAQKKiiE/mclIC5g4AjRpio27g+VMRhe6rQoz+q4Wm4L6A/fJhiLtBw+sfOpDG9wZ3O0pxIw7GbfOlBgjOA==",
+      "version": "3.22.8",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.8.tgz",
+      "integrity": "sha512-pQnwg4xtuvc2Bs/5zYQPaEYYSuTxsF7LBWF0SvnVhthZo/Qe+rJpcEekrdNK5DWwDJ0gv0oI9NNX5Mppdy0ctg==",
       "dependencies": {
         "browserslist": "^4.20.3",
         "semver": "7.0.0"
@@ -5750,9 +5768,9 @@
       }
     },
     "node_modules/core-js-pure": {
-      "version": "3.22.7",
-      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.7.tgz",
-      "integrity": "sha512-wTriFxiZI+C8msGeh7fJcbC/a0V8fdInN1oS2eK79DMBGs8iIJiXhtFJCiT3rBa8w6zroHWW3p8ArlujZ/Mz+w==",
+      "version": "3.22.8",
+      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.8.tgz",
+      "integrity": "sha512-bOxbZIy9S5n4OVH63XaLVXZ49QKicjowDx/UELyJ68vxfCRpYsbyh/WNZNfEfAk+ekA8vSjt+gCDpvh672bc3w==",
       "hasInstallScript": true,
       "funding": {
         "type": "opencollective",
@@ -6617,9 +6635,9 @@
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.142",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.142.tgz",
-      "integrity": "sha512-ea8Q1YX0JRp4GylOmX4gFHIizi0j9GfRW4EkaHnkZp0agRCBB4ZGeCv17IEzIvBkiYVwfoKVhKZJbTfqCRdQdg=="
+      "version": "1.4.144",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.144.tgz",
+      "integrity": "sha512-R3RV3rU1xWwFJlSClVWDvARaOk6VUO/FubHLodIASDB3Mc2dzuWvNdfOgH9bwHUTqT79u92qw60NWfwUdzAqdg=="
     },
     "node_modules/emittery": {
       "version": "0.8.1",
@@ -6835,7 +6853,7 @@
     "node_modules/escodegen/node_modules/prelude-ls": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
       "engines": {
         "node": ">= 0.8.0"
       }
@@ -7012,7 +7030,7 @@
     "node_modules/eslint-module-utils/node_modules/p-locate": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+      "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
       "dependencies": {
         "p-limit": "^1.1.0"
       },
@@ -7023,7 +7041,7 @@
     "node_modules/eslint-module-utils/node_modules/p-try": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-      "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
+      "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==",
       "engines": {
         "node": ">=4"
       }
@@ -7031,7 +7049,7 @@
     "node_modules/eslint-module-utils/node_modules/path-exists": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+      "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
       "engines": {
         "node": ">=4"
       }
@@ -8635,9 +8653,9 @@
       }
     },
     "node_modules/i18next": {
-      "version": "21.8.5",
-      "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.8.5.tgz",
-      "integrity": "sha512-uI5LVG10SBHLVOclr6yY1aCimmrzeZ0dwD73Sio61E8gQEwRmKI7/M8RKM084mNNy7VscKtxzSwELrso8BKv1g==",
+      "version": "21.8.6",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.8.6.tgz",
+      "integrity": "sha512-tD0umB5lcYXJiD06m/XOEgdvDkFD17m13BP2tmSLralYhGPdmmPK6rErcmhc37t/6mubKdso30NLpPIomHaKnw==",
       "funding": [
         {
           "type": "individual",
@@ -11818,7 +11836,7 @@
     "node_modules/node-int64": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
-      "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="
     },
     "node_modules/node-releases": {
       "version": "2.0.5",
@@ -11836,7 +11854,7 @@
     "node_modules/normalize-range": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -11882,7 +11900,7 @@
     "node_modules/object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -12029,7 +12047,7 @@
     "node_modules/once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
       "dependencies": {
         "wrappy": "1"
       }
@@ -12198,7 +12216,7 @@
     "node_modules/path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -12219,7 +12237,7 @@
     "node_modules/path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
     },
     "node_modules/path-type": {
       "version": "4.0.0",
@@ -12232,7 +12250,7 @@
     "node_modules/performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
     },
     "node_modules/picocolors": {
       "version": "1.0.0",
@@ -12379,7 +12397,7 @@
     "node_modules/pkg-up/node_modules/path-exists": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-      "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
+      "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
       "engines": {
         "node": ">=4"
       }
@@ -13271,11 +13289,11 @@
       }
     },
     "node_modules/postcss-preset-env": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.6.0.tgz",
-      "integrity": "sha512-5cnzpSFZnQJOlBu85xn4Nnluy/WjIST/ugn+gOVcKnmFJ+GLtkfRhmJPo/TW9UDpG7oyA467kvDOO8mtcpOL4g==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.7.0.tgz",
+      "integrity": "sha512-2Q9YARQju+j2BVgAyDnW1pIWIMlaHZqbaGISPMmalznNlWcNFIZFQsJfRLXS+WHmHJDCmV7wIWpVf9JNKR4Elw==",
       "dependencies": {
-        "@csstools/postcss-cascade-layers": "^1.0.1",
+        "@csstools/postcss-cascade-layers": "^1.0.2",
         "@csstools/postcss-color-function": "^1.1.0",
         "@csstools/postcss-font-format-keywords": "^1.0.0",
         "@csstools/postcss-hwb-function": "^1.0.1",
@@ -13285,16 +13303,17 @@
         "@csstools/postcss-oklab-function": "^1.1.0",
         "@csstools/postcss-progressive-custom-properties": "^1.3.0",
         "@csstools/postcss-stepped-value-functions": "^1.0.0",
+        "@csstools/postcss-trigonometric-functions": "^1.0.0",
         "@csstools/postcss-unset-value": "^1.0.1",
         "autoprefixer": "^10.4.7",
         "browserslist": "^4.20.3",
         "css-blank-pseudo": "^3.0.3",
         "css-has-pseudo": "^3.0.4",
         "css-prefers-color-scheme": "^6.0.3",
-        "cssdb": "^6.6.1",
+        "cssdb": "^6.6.2",
         "postcss-attribute-case-insensitive": "^5.0.0",
         "postcss-clamp": "^4.1.0",
-        "postcss-color-functional-notation": "^4.2.2",
+        "postcss-color-functional-notation": "^4.2.3",
         "postcss-color-hex-alpha": "^8.0.3",
         "postcss-color-rebeccapurple": "^7.0.2",
         "postcss-custom-media": "^8.0.0",
@@ -13312,7 +13331,7 @@
         "postcss-lab-function": "^4.2.0",
         "postcss-logical": "^5.0.4",
         "postcss-media-minmax": "^5.0.0",
-        "postcss-nesting": "^10.1.6",
+        "postcss-nesting": "^10.1.7",
         "postcss-opacity-percentage": "^1.1.2",
         "postcss-overflow-shorthand": "^3.0.3",
         "postcss-page-break": "^3.0.4",
@@ -13626,7 +13645,7 @@
     "node_modules/q": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+      "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
       "engines": {
         "node": ">=0.6.0",
         "teleport": ">=0.2.0"
@@ -14381,9 +14400,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "2.75.4",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.4.tgz",
-      "integrity": "sha512-JgZiJMJkKImMZJ8ZY1zU80Z2bA/TvrL/7D9qcBCrfl2bP+HUaIw0QHUroB4E3gBpFl6CRFM1YxGbuYGtdAswbQ==",
+      "version": "2.75.5",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.5.tgz",
+      "integrity": "sha512-JzNlJZDison3o2mOxVmb44Oz7t74EfSd1SQrplQk0wSaXV7uLQXtVdHbxlcT3w+8tZ1TL4r/eLfc7nAbz38BBA==",
       "bin": {
         "rollup": "dist/bin/rollup"
       },
@@ -15421,14 +15440,14 @@
       }
     },
     "node_modules/terser-webpack-plugin": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz",
-      "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==",
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz",
+      "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==",
       "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.7",
         "jest-worker": "^27.4.5",
         "schema-utils": "^3.1.1",
         "serialize-javascript": "^6.0.0",
-        "source-map": "^0.6.1",
         "terser": "^5.7.2"
       },
       "engines": {
@@ -15453,14 +15472,6 @@
         }
       }
     },
-    "node_modules/terser-webpack-plugin/node_modules/source-map": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
     "node_modules/terser/node_modules/commander": {
       "version": "2.20.3",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -15891,9 +15902,9 @@
       }
     },
     "node_modules/watchpack": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
-      "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
       "dependencies": {
         "glob-to-regexp": "^0.4.1",
         "graceful-fs": "^4.1.2"
@@ -15919,9 +15930,9 @@
       }
     },
     "node_modules/webpack": {
-      "version": "5.72.1",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz",
-      "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==",
+      "version": "5.73.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz",
+      "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==",
       "dependencies": {
         "@types/eslint-scope": "^3.7.3",
         "@types/estree": "^0.0.51",
@@ -16036,9 +16047,9 @@
       }
     },
     "node_modules/webpack-dev-server": {
-      "version": "4.9.0",
-      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz",
-      "integrity": "sha512-+Nlb39iQSOSsFv0lWUuUTim3jDQO8nhK3E68f//J2r5rIcp4lULHXz2oZ0UVdEeWXEh5lSzYUlzarZhDAeAVQw==",
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.1.tgz",
+      "integrity": "sha512-CTMfu2UMdR/4OOZVHRpdy84pNopOuigVIsRbGX3LVDMWNP8EUgC5mUBMErbwBlHTEX99ejZJpVqrir6EXAEajA==",
       "dependencies": {
         "@types/bonjour": "^3.5.9",
         "@types/connect-history-api-fallback": "^1.3.5",
@@ -16064,7 +16075,7 @@
         "schema-utils": "^4.0.0",
         "selfsigned": "^2.0.1",
         "serve-index": "^1.9.1",
-        "sockjs": "^0.3.21",
+        "sockjs": "^0.3.24",
         "spdy": "^4.0.2",
         "webpack-dev-middleware": "^5.3.1",
         "ws": "^8.4.2"
@@ -18067,6 +18078,14 @@
         "postcss-value-parser": "^4.2.0"
       }
     },
+    "@csstools/postcss-trigonometric-functions": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.1.tgz",
+      "integrity": "sha512-G78CY/+GePc6dDCTUbwI6TTFQ5fs3N9POHhI6v0QzteGpf6ylARiJUNz9HrRKi4eVYBNXjae1W2766iUEFxHlw==",
+      "requires": {
+        "postcss-value-parser": "^4.2.0"
+      }
+    },
     "@csstools/postcss-unset-value": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.1.tgz",
@@ -19347,9 +19366,9 @@
       "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
     },
     "@types/node": {
-      "version": "17.0.36",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz",
-      "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA=="
+      "version": "17.0.38",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz",
+      "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g=="
     },
     "@types/parse-json": {
       "version": "4.0.0",
@@ -19382,9 +19401,9 @@
       "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
     },
     "@types/react": {
-      "version": "18.0.9",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.9.tgz",
-      "integrity": "sha512-9bjbg1hJHUm4De19L1cHiW0Jvx3geel6Qczhjd0qY5VKVE2X5+x77YxAepuCwVh4vrgZJdgEJw48zrhRIeF4Nw==",
+      "version": "18.0.10",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.10.tgz",
+      "integrity": "sha512-dIugadZuIPrRzvIEevIu7A1smqOAjkSMv8qOfwPt9Ve6i6JT/FQcCHyk2qIAxwsQNKZt5/oGR0T4z9h2dXRAkg==",
       "requires": {
         "@types/prop-types": "*",
         "@types/scheduler": "*",
@@ -20486,9 +20505,9 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30001344",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz",
-      "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g=="
+      "version": "1.0.30001346",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001346.tgz",
+      "integrity": "sha512-q6ibZUO2t88QCIPayP/euuDREq+aMAxFE5S70PkrLh0iTDj/zEhgvJRKC2+CvXY6EWc6oQwUR48lL5vCW6jiXQ=="
     },
     "case-sensitive-paths-webpack-plugin": {
       "version": "2.4.0",
@@ -20759,14 +20778,14 @@
       "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
     },
     "core-js": {
-      "version": "3.22.7",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz",
-      "integrity": "sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg=="
+      "version": "3.22.8",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.8.tgz",
+      "integrity": "sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA=="
     },
     "core-js-compat": {
-      "version": "3.22.7",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.7.tgz",
-      "integrity": "sha512-uI9DAQKKiiE/mclIC5g4AjRpio27g+VMRhe6rQoz+q4Wm4L6A/fJhiLtBw+sfOpDG9wZ3O0pxIw7GbfOlBgjOA==",
+      "version": "3.22.8",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.8.tgz",
+      "integrity": "sha512-pQnwg4xtuvc2Bs/5zYQPaEYYSuTxsF7LBWF0SvnVhthZo/Qe+rJpcEekrdNK5DWwDJ0gv0oI9NNX5Mppdy0ctg==",
       "requires": {
         "browserslist": "^4.20.3",
         "semver": "7.0.0"
@@ -20780,9 +20799,9 @@
       }
     },
     "core-js-pure": {
-      "version": "3.22.7",
-      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.7.tgz",
-      "integrity": "sha512-wTriFxiZI+C8msGeh7fJcbC/a0V8fdInN1oS2eK79DMBGs8iIJiXhtFJCiT3rBa8w6zroHWW3p8ArlujZ/Mz+w=="
+      "version": "3.22.8",
+      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.8.tgz",
+      "integrity": "sha512-bOxbZIy9S5n4OVH63XaLVXZ49QKicjowDx/UELyJ68vxfCRpYsbyh/WNZNfEfAk+ekA8vSjt+gCDpvh672bc3w=="
     },
     "core-util-is": {
       "version": "1.0.3",
@@ -21393,9 +21412,9 @@
       }
     },
     "electron-to-chromium": {
-      "version": "1.4.142",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.142.tgz",
-      "integrity": "sha512-ea8Q1YX0JRp4GylOmX4gFHIizi0j9GfRW4EkaHnkZp0agRCBB4ZGeCv17IEzIvBkiYVwfoKVhKZJbTfqCRdQdg=="
+      "version": "1.4.144",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.144.tgz",
+      "integrity": "sha512-R3RV3rU1xWwFJlSClVWDvARaOk6VUO/FubHLodIASDB3Mc2dzuWvNdfOgH9bwHUTqT79u92qw60NWfwUdzAqdg=="
     },
     "emittery": {
       "version": "0.8.1",
@@ -21557,7 +21576,7 @@
         "prelude-ls": {
           "version": "1.1.2",
           "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-          "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+          "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w=="
         },
         "source-map": {
           "version": "0.6.1",
@@ -21773,7 +21792,7 @@
         "p-locate": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-          "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+          "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==",
           "requires": {
             "p-limit": "^1.1.0"
           }
@@ -21781,12 +21800,12 @@
         "p-try": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-          "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
+          "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww=="
         },
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="
         }
       }
     },
@@ -22863,9 +22882,9 @@
       "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="
     },
     "i18next": {
-      "version": "21.8.5",
-      "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.8.5.tgz",
-      "integrity": "sha512-uI5LVG10SBHLVOclr6yY1aCimmrzeZ0dwD73Sio61E8gQEwRmKI7/M8RKM084mNNy7VscKtxzSwELrso8BKv1g==",
+      "version": "21.8.6",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.8.6.tgz",
+      "integrity": "sha512-tD0umB5lcYXJiD06m/XOEgdvDkFD17m13BP2tmSLralYhGPdmmPK6rErcmhc37t/6mubKdso30NLpPIomHaKnw==",
       "requires": {
         "@babel/runtime": "^7.17.2"
       }
@@ -25158,7 +25177,7 @@
     "node-int64": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
-      "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
+      "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="
     },
     "node-releases": {
       "version": "2.0.5",
@@ -25173,7 +25192,7 @@
     "normalize-range": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="
     },
     "normalize-url": {
       "version": "6.1.0",
@@ -25204,7 +25223,7 @@
     "object-assign": {
       "version": "4.1.1",
       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
     },
     "object-hash": {
       "version": "3.0.0",
@@ -25303,7 +25322,7 @@
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
       "requires": {
         "wrappy": "1"
       }
@@ -25424,7 +25443,7 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
     },
     "path-key": {
       "version": "3.1.1",
@@ -25439,7 +25458,7 @@
     "path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
     },
     "path-type": {
       "version": "4.0.0",
@@ -25449,7 +25468,7 @@
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+      "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
     },
     "picocolors": {
       "version": "1.0.0",
@@ -25553,7 +25572,7 @@
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+          "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="
         }
       }
     },
@@ -26053,11 +26072,11 @@
       }
     },
     "postcss-preset-env": {
-      "version": "7.6.0",
-      "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.6.0.tgz",
-      "integrity": "sha512-5cnzpSFZnQJOlBu85xn4Nnluy/WjIST/ugn+gOVcKnmFJ+GLtkfRhmJPo/TW9UDpG7oyA467kvDOO8mtcpOL4g==",
+      "version": "7.7.0",
+      "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.7.0.tgz",
+      "integrity": "sha512-2Q9YARQju+j2BVgAyDnW1pIWIMlaHZqbaGISPMmalznNlWcNFIZFQsJfRLXS+WHmHJDCmV7wIWpVf9JNKR4Elw==",
       "requires": {
-        "@csstools/postcss-cascade-layers": "^1.0.1",
+        "@csstools/postcss-cascade-layers": "^1.0.2",
         "@csstools/postcss-color-function": "^1.1.0",
         "@csstools/postcss-font-format-keywords": "^1.0.0",
         "@csstools/postcss-hwb-function": "^1.0.1",
@@ -26067,16 +26086,17 @@
         "@csstools/postcss-oklab-function": "^1.1.0",
         "@csstools/postcss-progressive-custom-properties": "^1.3.0",
         "@csstools/postcss-stepped-value-functions": "^1.0.0",
+        "@csstools/postcss-trigonometric-functions": "^1.0.0",
         "@csstools/postcss-unset-value": "^1.0.1",
         "autoprefixer": "^10.4.7",
         "browserslist": "^4.20.3",
         "css-blank-pseudo": "^3.0.3",
         "css-has-pseudo": "^3.0.4",
         "css-prefers-color-scheme": "^6.0.3",
-        "cssdb": "^6.6.1",
+        "cssdb": "^6.6.2",
         "postcss-attribute-case-insensitive": "^5.0.0",
         "postcss-clamp": "^4.1.0",
-        "postcss-color-functional-notation": "^4.2.2",
+        "postcss-color-functional-notation": "^4.2.3",
         "postcss-color-hex-alpha": "^8.0.3",
         "postcss-color-rebeccapurple": "^7.0.2",
         "postcss-custom-media": "^8.0.0",
@@ -26094,7 +26114,7 @@
         "postcss-lab-function": "^4.2.0",
         "postcss-logical": "^5.0.4",
         "postcss-media-minmax": "^5.0.0",
-        "postcss-nesting": "^10.1.6",
+        "postcss-nesting": "^10.1.7",
         "postcss-opacity-percentage": "^1.1.2",
         "postcss-overflow-shorthand": "^3.0.3",
         "postcss-page-break": "^3.0.4",
@@ -26319,7 +26339,7 @@
     "q": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
+      "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw=="
     },
     "qs": {
       "version": "6.10.3",
@@ -26857,9 +26877,9 @@
       }
     },
     "rollup": {
-      "version": "2.75.4",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.4.tgz",
-      "integrity": "sha512-JgZiJMJkKImMZJ8ZY1zU80Z2bA/TvrL/7D9qcBCrfl2bP+HUaIw0QHUroB4E3gBpFl6CRFM1YxGbuYGtdAswbQ==",
+      "version": "2.75.5",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.5.tgz",
+      "integrity": "sha512-JzNlJZDison3o2mOxVmb44Oz7t74EfSd1SQrplQk0wSaXV7uLQXtVdHbxlcT3w+8tZ1TL4r/eLfc7nAbz38BBA==",
       "requires": {
         "fsevents": "~2.3.2"
       }
@@ -27656,22 +27676,15 @@
       }
     },
     "terser-webpack-plugin": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz",
-      "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==",
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz",
+      "integrity": "sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==",
       "requires": {
+        "@jridgewell/trace-mapping": "^0.3.7",
         "jest-worker": "^27.4.5",
         "schema-utils": "^3.1.1",
         "serialize-javascript": "^6.0.0",
-        "source-map": "^0.6.1",
         "terser": "^5.7.2"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
-        }
       }
     },
     "test-exclude": {
@@ -28000,9 +28013,9 @@
       }
     },
     "watchpack": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
-      "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
       "requires": {
         "glob-to-regexp": "^0.4.1",
         "graceful-fs": "^4.1.2"
@@ -28022,9 +28035,9 @@
       "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
     },
     "webpack": {
-      "version": "5.72.1",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz",
-      "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==",
+      "version": "5.73.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz",
+      "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==",
       "requires": {
         "@types/eslint-scope": "^3.7.3",
         "@types/estree": "^0.0.51",
@@ -28118,9 +28131,9 @@
       }
     },
     "webpack-dev-server": {
-      "version": "4.9.0",
-      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz",
-      "integrity": "sha512-+Nlb39iQSOSsFv0lWUuUTim3jDQO8nhK3E68f//J2r5rIcp4lULHXz2oZ0UVdEeWXEh5lSzYUlzarZhDAeAVQw==",
+      "version": "4.9.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.1.tgz",
+      "integrity": "sha512-CTMfu2UMdR/4OOZVHRpdy84pNopOuigVIsRbGX3LVDMWNP8EUgC5mUBMErbwBlHTEX99ejZJpVqrir6EXAEajA==",
       "requires": {
         "@types/bonjour": "^3.5.9",
         "@types/connect-history-api-fallback": "^1.3.5",
@@ -28146,7 +28159,7 @@
         "schema-utils": "^4.0.0",
         "selfsigned": "^2.0.1",
         "serve-index": "^1.9.1",
-        "sockjs": "^0.3.21",
+        "sockjs": "^0.3.24",
         "spdy": "^4.0.2",
         "webpack-dev-middleware": "^5.3.1",
         "ws": "^8.4.2"
-- 
GitLab