diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 3bf2a12..0000000 --- a/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -dist -*/node_modules -Dockerfile* diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index 2300230..0000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1,11 +0,0 @@ -# https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view - -# Run prettier (https://github.com/binwiederhier/ntfy/pull/746) -6f6a2d1f693070bf72e89d86748080e4825c9164 -c87549e71a10bc789eac8036078228f06e515a8e -ca5d736a7169eb6b4b0d849e061d5bf9565dcc53 -2e27f58963feb9e4d1c573d4745d07770777fa7d - -# Run eslint (https://github.com/binwiederhier/ntfy/pull/748) -f558b4dbe9bb5b9e0e87fada1215de2558353173 -8319f1cf26113167fb29fe12edaff5db74caf35f diff --git a/.github/images/logo.png b/.github/images/logo.png deleted file mode 100644 index 351db4d..0000000 Binary files a/.github/images/logo.png and /dev/null differ diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 0076c0f..e5e989b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,21 +4,30 @@ jobs: build: runs-on: ubuntu-latest steps: - - - name: Checkout code - uses: actions/checkout@v3 - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v2 with: go-version: '1.19.x' - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v2 with: node-version: '18' - cache: 'npm' - cache-dependency-path: './web/package-lock.json' + - + name: Checkout code + uses: actions/checkout@v2 + - + name: Cache Go and npm modules + uses: actions/cache@v3 + with: + path: | + ~/go/pkg/mod + ~/go/bin + ~/.npm + web/node_modules + key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }} + restore-keys: ${{ runner.os }}-ntfy- - name: Install dependencies run: make build-deps-ubuntu diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 6991dea..2ba9b9c 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -30,7 +30,7 @@ jobs: run: | cd build/ntfy-docs.github.io git config user.name "GitHub Actions Bot" - git config user.email "" + git config user.email "<>" git add docs/ git commit -m "Updated docs" git push origin main diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f709332..7341add 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -7,21 +7,30 @@ jobs: release: runs-on: ubuntu-latest steps: - - - name: Checkout code - uses: actions/checkout@v3 - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v2 with: go-version: '1.19.x' - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v2 with: node-version: '18' - cache: 'npm' - cache-dependency-path: './web/package-lock.json' + - + name: Checkout code + uses: actions/checkout@v2 + - + name: Cache Go and npm modules + uses: actions/cache@v3 + with: + path: | + ~/go/pkg/mod + ~/go/bin + ~/.npm + web/node_modules + key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }} + restore-keys: ${{ runner.os }}-ntfy- - name: Docker login uses: docker/login-action@v2 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7473567..372a87c 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -4,21 +4,30 @@ jobs: test: runs-on: ubuntu-latest steps: - - - name: Checkout code - uses: actions/checkout@v3 - name: Install Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v2 with: go-version: '1.19.x' - name: Install node - uses: actions/setup-node@v3 + uses: actions/setup-node@v2 with: node-version: '18' - cache: 'npm' - cache-dependency-path: './web/package-lock.json' + - + name: Checkout code + uses: actions/checkout@v2 + - + name: Cache Go and npm modules + uses: actions/cache@v3 + with: + path: | + ~/go/pkg/mod + ~/go/bin + ~/.npm + web/node_modules + key: ${{ runner.os }}-ntfy-${{ hashFiles('**/go.sum', '**/package.lock') }} + restore-keys: ${{ runner.os }}-ntfy- - name: Install dependencies run: make build-deps-ubuntu diff --git a/.gitignore b/.gitignore index f695607..2b566b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ dist/ -dev-dist/ build/ .idea/ .vscode/ @@ -12,4 +11,3 @@ secrets/ *.iml node_modules/ .DS_Store -__pycache__ diff --git a/.goreleaser.yml b/.goreleaser.yml index 131a302..9ba8bb4 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -97,7 +97,7 @@ nfpms: - dst: /var/lib/ntfy type: dir - dst: /usr/share/ntfy/logo.png - src: web/public/static/images/ntfy.png + src: web/public/static/img/ntfy.png scripts: preinstall: "scripts/preinst.sh" postinstall: "scripts/postinst.sh" diff --git a/Dockerfile b/Dockerfile index feb813f..7c2052e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM r.batts.cloud/debian:testing +FROM alpine LABEL org.opencontainers.image.authors="philipp.heckel@gmail.com" LABEL org.opencontainers.image.url="https://ntfy.sh/" diff --git a/Dockerfile-build b/Dockerfile-build deleted file mode 100644 index 9c6d1bc..0000000 --- a/Dockerfile-build +++ /dev/null @@ -1,54 +0,0 @@ -FROM r.batts.cloud/golang:1.19 as builder - -ARG VERSION=dev -ARG COMMIT=unknown - -RUN apt-get update -RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash -RUN apt-get install -y \ - build-essential \ - nodejs \ - python3-pip \ - python3-venv - -WORKDIR /app -ADD Makefile . - -# docs -ADD ./requirements.txt . -RUN make docs-deps -ADD ./mkdocs.yml . -ADD ./docs ./docs -RUN make docs-build - -# web -ADD ./web/package.json ./web/package-lock.json ./web/ -RUN make web-deps -ADD ./web ./web -RUN make web-build - -# cli & server -ADD go.mod go.sum main.go ./ -ADD ./client ./client -ADD ./cmd ./cmd -ADD ./log ./log -ADD ./server ./server -ADD ./user ./user -ADD ./util ./util -RUN make VERSION=$VERSION COMMIT=$COMMIT cli-linux-server - -FROM r.batts.cloud/debian:testing - -LABEL org.opencontainers.image.authors="philipp.heckel@gmail.com" -LABEL org.opencontainers.image.url="https://ntfy.sh/" -LABEL org.opencontainers.image.documentation="https://docs.ntfy.sh/" -LABEL org.opencontainers.image.source="https://github.com/binwiederhier/ntfy" -LABEL org.opencontainers.image.vendor="Philipp C. Heckel" -LABEL org.opencontainers.image.licenses="Apache-2.0, GPL-2.0" -LABEL org.opencontainers.image.title="ntfy" -LABEL org.opencontainers.image.description="Send push notifications to your phone or desktop using PUT/POST" - -COPY --from=builder /app/dist/ntfy_linux_server/ntfy /usr/bin/ntfy - -EXPOSE 80/tcp -ENTRYPOINT ["ntfy"] diff --git a/Makefile b/Makefile index 440bfa6..8ca86da 100644 --- a/Makefile +++ b/Makefile @@ -31,16 +31,10 @@ help: @echo " make cli-darwin-server - Build client & server (no GoReleaser, current arch, macOS)" @echo " make cli-client - Build client only (no GoReleaser, current arch, Linux/macOS/Windows)" @echo - @echo "Build dev Docker:" - @echo " make docker-dev - Build client & server for current architecture using Docker only" - @echo @echo "Build web app:" @echo " make web - Build the web app" @echo " make web-deps - Install web app dependencies (npm install the universe)" @echo " make web-build - Actually build the web app" - @echo " make web-lint - Run eslint on the web app" - @echo " make web-format - Run prettier on the web app" - @echo " make web-format-check - Run prettier on the web app, but don't change anything" @echo @echo "Build documentation:" @echo " make docs - Build the documentation" @@ -86,33 +80,23 @@ build: web docs cli update: web-deps-update cli-deps-update docs-deps-update docker pull alpine -docker-dev: - docker build \ - --file ./Dockerfile-build \ - --tag binwiederhier/ntfy:$(VERSION) \ - --tag binwiederhier/ntfy:dev \ - --build-arg VERSION=$(VERSION) \ - --build-arg COMMIT=$(COMMIT) \ - ./ - # Ubuntu-specific build-deps-ubuntu: - sudo apt-get update - sudo apt-get install -y \ + sudo apt update + sudo apt install -y \ curl \ gcc-aarch64-linux-gnu \ gcc-arm-linux-gnueabi \ jq - which pip3 || sudo apt-get install -y python3-pip + which pip3 || sudo apt install -y python3-pip # Documentation docs: docs-deps docs-build -docs-build: venv .PHONY - @. venv/bin/activate && \ - if ! /bin/echo -e "import sys\nif sys.version_info < (3,8):\n exit(1)" | python3; then \ +docs-build: .PHONY + @if ! /bin/echo -e "import sys\nif sys.version_info < (3,8):\n exit(1)" | python3; then \ if which python3.8; then \ echo "python3.8 $(shell which mkdocs) build"; \ python3.8 $(shell which mkdocs) build; \ @@ -125,15 +109,10 @@ docs-build: venv .PHONY mkdocs build; \ fi -venv: - python3 -m venv ./venv - -docs-deps: venv .PHONY - . venv/bin/activate && \ +docs-deps: .PHONY pip3 install -r requirements.txt -docs-deps-update: venv .PHONY - . venv/bin/activate && \ +docs-deps-update: .PHONY pip3 install -r requirements.txt --upgrade @@ -148,7 +127,8 @@ web-build: && rm -rf ../server/site \ && mv build ../server/site \ && rm \ - ../server/site/config.js + ../server/site/config.js \ + ../server/site/asset-manifest.json web-deps: cd web && npm install @@ -157,37 +137,29 @@ web-deps: web-deps-update: cd web && npm update -web-format: - cd web && npm run format - -web-format-check: - cd web && npm run format:check - -web-lint: - cd web && npm run lint # Main server/client build cli: cli-deps - goreleaser build --snapshot --clean + goreleaser build --snapshot --rm-dist cli-linux-amd64: cli-deps-static-sites - goreleaser build --snapshot --clean --id ntfy_linux_amd64 + goreleaser build --snapshot --rm-dist --id ntfy_linux_amd64 cli-linux-armv6: cli-deps-static-sites cli-deps-gcc-armv6-armv7 - goreleaser build --snapshot --clean --id ntfy_linux_armv6 + goreleaser build --snapshot --rm-dist --id ntfy_linux_armv6 cli-linux-armv7: cli-deps-static-sites cli-deps-gcc-armv6-armv7 - goreleaser build --snapshot --clean --id ntfy_linux_armv7 + goreleaser build --snapshot --rm-dist --id ntfy_linux_armv7 cli-linux-arm64: cli-deps-static-sites cli-deps-gcc-arm64 - goreleaser build --snapshot --clean --id ntfy_linux_arm64 + goreleaser build --snapshot --rm-dist --id ntfy_linux_arm64 cli-windows-amd64: cli-deps-static-sites - goreleaser build --snapshot --clean --id ntfy_windows_amd64 + goreleaser build --snapshot --rm-dist --id ntfy_windows_amd64 cli-darwin-all: cli-deps-static-sites - goreleaser build --snapshot --clean --id ntfy_darwin_all + goreleaser build --snapshot --rm-dist --id ntfy_darwin_all cli-linux-server: cli-deps-static-sites # This is a target to build the CLI (including the server) manually. @@ -254,7 +226,7 @@ cli-build-results: # Test/check targets -check: test web-format-check fmt-check vet web-lint lint staticcheck +check: test fmt-check vet lint staticcheck test: .PHONY go test $(shell go list ./... | grep -vE 'ntfy/(test|examples|tools)') @@ -305,11 +277,11 @@ staticcheck: .PHONY # Releasing targets -release: clean cli-deps release-checks docs web check - goreleaser release --clean +release: clean update cli-deps release-checks docs web check + goreleaser release --rm-dist -release-snapshot: clean cli-deps docs web check - goreleaser release --snapshot --skip-publish --clean +release-snapshot: clean update cli-deps docs web check + goreleaser release --snapshot --skip-publish --rm-dist release-checks: $(eval LATEST_TAG := $(shell git describe --abbrev=0 --tags | cut -c2-)) diff --git a/README.md b/README.md index cebf55b..c42bfd1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![ntfy](web/public/static/images/ntfy.png) +![ntfy](web/public/static/img/ntfy.png) # ntfy.sh | Send push notifications to your phone or desktop via PUT/POST [![Release](https://img.shields.io/github/release/binwiederhier/ntfy.svg?color=success&style=flat-square)](https://github.com/binwiederhier/ntfy/releases/latest) @@ -23,16 +23,13 @@ available on [Google Play](https://play.google.com/store/apps/details?id=io.heck as well as an [open source iOS app](https://github.com/binwiederhier/ntfy-ios) available on the [App Store](https://apps.apple.com/us/app/ntfy/id1625396347).

- - - - - + + + + +

-## [ntfy Pro](https://ntfy.sh/app) ๐Ÿ’ธ ๐ŸŽ‰ -I now offer paid plans for [ntfy.sh](https://ntfy.sh/) if you don't want to self-host, or you want to support the development of ntfy (โ†’ [Purchase via web app](https://ntfy.sh/app)). You can **buy a plan for as low as $3.33/month** (if you use promo code `MYTOPIC`, limited time only). You can also donate via [GitHub Sponsors](https://github.com/sponsors/binwiederhier), and [Liberapay](https://liberapay.com/ntfy). I would be very humbled by your sponsorship. โค๏ธ - ## **[Documentation](https://ntfy.sh/docs/)** [Getting started](https://ntfy.sh/docs/) | @@ -129,18 +126,6 @@ account costs. Even small donations are very much appreciated. A big fat **Thank - - - - - - - - - - - - I'd also like to thank JetBrains for providing their awesome [IntelliJ IDEA](https://www.jetbrains.com/idea/) to me for free, and [DigitalOcean](https://m.do.co/c/442b929528db) (*referral link*) for supporting the project: diff --git a/client/client.go b/client/client.go index 93cf7da..b744fa1 100644 --- a/client/client.go +++ b/client/client.go @@ -11,25 +11,23 @@ import ( "heckel.io/ntfy/util" "io" "net/http" - "regexp" "strings" "sync" "time" ) +// Event type constants const ( - // MessageEvent identifies a message event - MessageEvent = "message" + MessageEvent = "message" + KeepaliveEvent = "keepalive" + OpenEvent = "open" + PollRequestEvent = "poll_request" ) const ( maxResponseBytes = 4096 ) -var ( - topicRegex = regexp.MustCompile(`^[-_A-Za-z0-9]{1,64}$`) // Same as in server/server.go -) - // Client is the ntfy client that can be used to publish and subscribe to ntfy topics type Client struct { Messages chan *Message @@ -98,14 +96,8 @@ func (c *Client) Publish(topic, message string, options ...PublishOption) (*Mess // To pass title, priority and tags, check out WithTitle, WithPriority, WithTagsList, WithDelay, WithNoCache, // WithNoFirebase, and the generic WithHeader. func (c *Client) PublishReader(topic string, body io.Reader, options ...PublishOption) (*Message, error) { - topicURL, err := c.expandTopicURL(topic) - if err != nil { - return nil, err - } - req, err := http.NewRequest("POST", topicURL, body) - if err != nil { - return nil, err - } + topicURL := c.expandTopicURL(topic) + req, _ := http.NewRequest("POST", topicURL, body) for _, option := range options { if err := option(req); err != nil { return nil, err @@ -141,14 +133,11 @@ func (c *Client) PublishReader(topic string, body io.Reader, options ...PublishO // By default, all messages will be returned, but you can change this behavior using a SubscribeOption. // See WithSince, WithSinceAll, WithSinceUnixTime, WithScheduled, and the generic WithQueryParam. func (c *Client) Poll(topic string, options ...SubscribeOption) ([]*Message, error) { - topicURL, err := c.expandTopicURL(topic) - if err != nil { - return nil, err - } ctx := context.Background() messages := make([]*Message, 0) msgChan := make(chan *Message) errChan := make(chan error) + topicURL := c.expandTopicURL(topic) log.Debug("%s Polling from topic", util.ShortTopicURL(topicURL)) options = append(options, WithPoll()) go func() { @@ -177,18 +166,15 @@ func (c *Client) Poll(topic string, options ...SubscribeOption) ([]*Message, err // Example: // // c := client.New(client.NewConfig()) -// subscriptionID, _ := c.Subscribe("mytopic") +// subscriptionID := c.Subscribe("mytopic") // for m := range c.Messages { // fmt.Printf("New message: %s", m.Message) // } -func (c *Client) Subscribe(topic string, options ...SubscribeOption) (string, error) { - topicURL, err := c.expandTopicURL(topic) - if err != nil { - return "", err - } +func (c *Client) Subscribe(topic string, options ...SubscribeOption) string { c.mu.Lock() defer c.mu.Unlock() subscriptionID := util.RandomString(10) + topicURL := c.expandTopicURL(topic) log.Debug("%s Subscribing to topic", util.ShortTopicURL(topicURL)) ctx, cancel := context.WithCancel(context.Background()) c.subscriptions[subscriptionID] = &subscription{ @@ -197,7 +183,7 @@ func (c *Client) Subscribe(topic string, options ...SubscribeOption) (string, er cancel: cancel, } go handleSubscribeConnLoop(ctx, c.Messages, topicURL, subscriptionID, options...) - return subscriptionID, nil + return subscriptionID } // Unsubscribe unsubscribes from a topic that has been previously subscribed to using the unique @@ -213,16 +199,31 @@ func (c *Client) Unsubscribe(subscriptionID string) { sub.cancel() } -func (c *Client) expandTopicURL(topic string) (string, error) { +// UnsubscribeAll unsubscribes from a topic that has been previously subscribed with Subscribe. +// If there are multiple subscriptions matching the topic, all of them are unsubscribed from. +// +// A topic can be either a full URL (e.g. https://myhost.lan/mytopic), a short URL which is then prepended https:// +// (e.g. myhost.lan -> https://myhost.lan), or a short name which is expanded using the default host in the +// config (e.g. mytopic -> https://ntfy.sh/mytopic). +func (c *Client) UnsubscribeAll(topic string) { + c.mu.Lock() + defer c.mu.Unlock() + topicURL := c.expandTopicURL(topic) + for _, sub := range c.subscriptions { + if sub.topicURL == topicURL { + delete(c.subscriptions, sub.ID) + sub.cancel() + } + } +} + +func (c *Client) expandTopicURL(topic string) string { if strings.HasPrefix(topic, "http://") || strings.HasPrefix(topic, "https://") { - return topic, nil + return topic } else if strings.Contains(topic, "/") { - return fmt.Sprintf("https://%s", topic), nil + return fmt.Sprintf("https://%s", topic) } - if !topicRegex.MatchString(topic) { - return "", fmt.Errorf("invalid topic name: %s", topic) - } - return fmt.Sprintf("%s/%s", c.config.DefaultHost, topic), nil + return fmt.Sprintf("%s/%s", c.config.DefaultHost, topic) } func handleSubscribeConnLoop(ctx context.Context, msgChan chan *Message, topicURL, subcriptionID string, options ...SubscribeOption) { diff --git a/client/client_test.go b/client/client_test.go index f0b15a3..a71ea5c 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -21,7 +21,7 @@ func TestClient_Publish_Subscribe(t *testing.T) { defer test.StopServer(t, s, port) c := client.New(newTestConfig(port)) - subscriptionID, _ := c.Subscribe("mytopic") + subscriptionID := c.Subscribe("mytopic") time.Sleep(time.Second) msg, err := c.Publish("mytopic", "some message") diff --git a/cmd/serve.go b/cmd/serve.go index 5d5381b..4e3ee39 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -37,8 +37,8 @@ var flagsServe = append( append([]cli.Flag{}, flagsDefault...), &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: defaultServerConfigFile, DefaultText: defaultServerConfigFile, Usage: "config file"}, altsrc.NewStringFlag(&cli.StringFlag{Name: "base-url", Aliases: []string{"base_url", "B"}, EnvVars: []string{"NTFY_BASE_URL"}, Usage: "externally visible base URL for this host (e.g. https://ntfy.sh)"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"listen_http", "l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: server.DefaultListenHTTP, Usage: "ip:port used as HTTP listen address"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-https", Aliases: []string{"listen_https", "L"}, EnvVars: []string{"NTFY_LISTEN_HTTPS"}, Usage: "ip:port used as HTTPS listen address"}), + altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"listen_http", "l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: server.DefaultListenHTTP, Usage: "ip:port used to as HTTP listen address"}), + altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-https", Aliases: []string{"listen_https", "L"}, EnvVars: []string{"NTFY_LISTEN_HTTPS"}, Usage: "ip:port used to as HTTPS listen address"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-unix", Aliases: []string{"listen_unix", "U"}, EnvVars: []string{"NTFY_LISTEN_UNIX"}, Usage: "listen on unix socket path"}), altsrc.NewIntFlag(&cli.IntFlag{Name: "listen-unix-mode", Aliases: []string{"listen_unix_mode"}, EnvVars: []string{"NTFY_LISTEN_UNIX_MODE"}, DefaultText: "system default", Usage: "file permissions of unix socket, e.g. 0700"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "key-file", Aliases: []string{"key_file", "K"}, EnvVars: []string{"NTFY_KEY_FILE"}, Usage: "private key file, if listen-https is set"}), @@ -59,12 +59,11 @@ var flagsServe = append( altsrc.NewDurationFlag(&cli.DurationFlag{Name: "keepalive-interval", Aliases: []string{"keepalive_interval", "k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: server.DefaultKeepaliveInterval, Usage: "interval of keepalive messages"}), altsrc.NewDurationFlag(&cli.DurationFlag{Name: "manager-interval", Aliases: []string{"manager_interval", "m"}, EnvVars: []string{"NTFY_MANAGER_INTERVAL"}, Value: server.DefaultManagerInterval, Usage: "interval of for message pruning and stats printing"}), altsrc.NewStringSliceFlag(&cli.StringSliceFlag{Name: "disallowed-topics", Aliases: []string{"disallowed_topics"}, EnvVars: []string{"NTFY_DISALLOWED_TOPICS"}, Usage: "topics that are not allowed to be used"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "web-root", Aliases: []string{"web_root"}, EnvVars: []string{"NTFY_WEB_ROOT"}, Value: "/", Usage: "sets root of the web app (e.g. /, or /app), or disables it (disable)"}), + altsrc.NewStringFlag(&cli.StringFlag{Name: "web-root", Aliases: []string{"web_root"}, EnvVars: []string{"NTFY_WEB_ROOT"}, Value: "app", Usage: "sets web root to landing page (home), web app (app) or disabled (disable)"}), altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-signup", Aliases: []string{"enable_signup"}, EnvVars: []string{"NTFY_ENABLE_SIGNUP"}, Value: false, Usage: "allows users to sign up via the web app, or API"}), altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-login", Aliases: []string{"enable_login"}, EnvVars: []string{"NTFY_ENABLE_LOGIN"}, Value: false, Usage: "allows users to log in via the web app, or API"}), altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-reservations", Aliases: []string{"enable_reservations"}, EnvVars: []string{"NTFY_ENABLE_RESERVATIONS"}, Value: false, Usage: "allows users to reserve topics (if their tier allows it)"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "upstream-base-url", Aliases: []string{"upstream_base_url"}, EnvVars: []string{"NTFY_UPSTREAM_BASE_URL"}, Value: "", Usage: "forward poll request to an upstream server, this is needed for iOS push notifications for self-hosted servers"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "upstream-access-token", Aliases: []string{"upstream_access_token"}, EnvVars: []string{"NTFY_UPSTREAM_ACCESS_TOKEN"}, Value: "", Usage: "access token to use for the upstream server; needed only if upstream rate limits are exceeded or upstream server requires auth"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-addr", Aliases: []string{"smtp_sender_addr"}, EnvVars: []string{"NTFY_SMTP_SENDER_ADDR"}, Usage: "SMTP server address (host:port) for outgoing emails"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-user", Aliases: []string{"smtp_sender_user"}, EnvVars: []string{"NTFY_SMTP_SENDER_USER"}, Usage: "SMTP user (if e-mail sending is enabled)"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-pass", Aliases: []string{"smtp_sender_pass"}, EnvVars: []string{"NTFY_SMTP_SENDER_PASS"}, Usage: "SMTP password (if e-mail sending is enabled)"}), @@ -72,10 +71,6 @@ var flagsServe = append( altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-listen", Aliases: []string{"smtp_server_listen"}, EnvVars: []string{"NTFY_SMTP_SERVER_LISTEN"}, Usage: "SMTP server address (ip:port) for incoming emails, e.g. :25"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-domain", Aliases: []string{"smtp_server_domain"}, EnvVars: []string{"NTFY_SMTP_SERVER_DOMAIN"}, Usage: "SMTP domain for incoming e-mail, e.g. ntfy.sh"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-addr-prefix", Aliases: []string{"smtp_server_addr_prefix"}, EnvVars: []string{"NTFY_SMTP_SERVER_ADDR_PREFIX"}, Usage: "SMTP email address prefix for topics to prevent spam (e.g. 'ntfy-')"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-account", Aliases: []string{"twilio_account"}, EnvVars: []string{"NTFY_TWILIO_ACCOUNT"}, Usage: "Twilio account SID, used for phone calls, e.g. AC123..."}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-auth-token", Aliases: []string{"twilio_auth_token"}, EnvVars: []string{"NTFY_TWILIO_AUTH_TOKEN"}, Usage: "Twilio auth token"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-phone-number", Aliases: []string{"twilio_phone_number"}, EnvVars: []string{"NTFY_TWILIO_PHONE_NUMBER"}, Usage: "Twilio number to use for outgoing calls"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "twilio-verify-service", Aliases: []string{"twilio_verify_service"}, EnvVars: []string{"NTFY_TWILIO_VERIFY_SERVICE"}, Usage: "Twilio Verify service ID, used for phone number verification"}), altsrc.NewIntFlag(&cli.IntFlag{Name: "global-topic-limit", Aliases: []string{"global_topic_limit", "T"}, EnvVars: []string{"NTFY_GLOBAL_TOPIC_LIMIT"}, Value: server.DefaultTotalTopicLimit, Usage: "total number of topics allowed"}), altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-subscription-limit", Aliases: []string{"visitor_subscription_limit"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIPTION_LIMIT"}, Value: server.DefaultVisitorSubscriptionLimit, Usage: "number of subscriptions per visitor"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-total-size-limit", Aliases: []string{"visitor_attachment_total_size_limit"}, EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT"}, Value: "100M", Usage: "total storage limit used for attachments per visitor"}), @@ -91,9 +86,6 @@ var flagsServe = append( altsrc.NewStringFlag(&cli.StringFlag{Name: "stripe-secret-key", Aliases: []string{"stripe_secret_key"}, EnvVars: []string{"NTFY_STRIPE_SECRET_KEY"}, Value: "", Usage: "key used for the Stripe API communication, this enables payments"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "stripe-webhook-key", Aliases: []string{"stripe_webhook_key"}, EnvVars: []string{"NTFY_STRIPE_WEBHOOK_KEY"}, Value: "", Usage: "key required to validate the authenticity of incoming webhooks from Stripe"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "billing-contact", Aliases: []string{"billing_contact"}, EnvVars: []string{"NTFY_BILLING_CONTACT"}, Value: "", Usage: "e-mail or website to display in upgrade dialog (only if payments are enabled)"}), - altsrc.NewBoolFlag(&cli.BoolFlag{Name: "enable-metrics", Aliases: []string{"enable_metrics"}, EnvVars: []string{"NTFY_ENABLE_METRICS"}, Value: false, Usage: "if set, Prometheus metrics are exposed via the /metrics endpoint"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "metrics-listen-http", Aliases: []string{"metrics_listen_http"}, EnvVars: []string{"NTFY_METRICS_LISTEN_HTTP"}, Usage: "ip:port used to expose the metrics endpoint (implicitly enables metrics)"}), - altsrc.NewStringFlag(&cli.StringFlag{Name: "profile-listen-http", Aliases: []string{"profile_listen_http"}, EnvVars: []string{"NTFY_PROFILE_LISTEN_HTTP"}, Usage: "ip:port used to expose the profiling endpoints (implicitly enables profiling)"}), ) var cmdServe = &cli.Command{ @@ -149,7 +141,6 @@ func execServe(c *cli.Context) error { enableLogin := c.Bool("enable-login") enableReservations := c.Bool("enable-reservations") upstreamBaseURL := c.String("upstream-base-url") - upstreamAccessToken := c.String("upstream-access-token") smtpSenderAddr := c.String("smtp-sender-addr") smtpSenderUser := c.String("smtp-sender-user") smtpSenderPass := c.String("smtp-sender-pass") @@ -157,10 +148,6 @@ func execServe(c *cli.Context) error { smtpServerListen := c.String("smtp-server-listen") smtpServerDomain := c.String("smtp-server-domain") smtpServerAddrPrefix := c.String("smtp-server-addr-prefix") - twilioAccount := c.String("twilio-account") - twilioAuthToken := c.String("twilio-auth-token") - twilioPhoneNumber := c.String("twilio-phone-number") - twilioVerifyService := c.String("twilio-verify-service") totalTopicLimit := c.Int("global-topic-limit") visitorSubscriptionLimit := c.Int("visitor-subscription-limit") visitorSubscriberRateLimiting := c.Bool("visitor-subscriber-rate-limiting") @@ -176,9 +163,6 @@ func execServe(c *cli.Context) error { stripeSecretKey := c.String("stripe-secret-key") stripeWebhookKey := c.String("stripe-webhook-key") billingContact := c.String("billing-contact") - metricsListenHTTP := c.String("metrics-listen-http") - enableMetrics := c.Bool("enable-metrics") || metricsListenHTTP != "" - profileListenHTTP := c.String("profile-listen-http") // Check values if firebaseKeyFile != "" && !util.FileExists(firebaseKeyFile) { @@ -205,6 +189,8 @@ func execServe(c *cli.Context) error { return errors.New("if set, base-url must start with http:// or https://") } else if baseURL != "" && strings.HasSuffix(baseURL, "/") { return errors.New("if set, base-url must not end with a slash (/)") + } else if !util.Contains([]string{"app", "home", "disable"}, webRoot) { + return errors.New("if set, web-root must be 'home' or 'app'") } else if upstreamBaseURL != "" && !strings.HasPrefix(upstreamBaseURL, "http://") && !strings.HasPrefix(upstreamBaseURL, "https://") { return errors.New("if set, upstream-base-url must start with http:// or https://") } else if upstreamBaseURL != "" && strings.HasSuffix(upstreamBaseURL, "/") { @@ -219,20 +205,10 @@ func execServe(c *cli.Context) error { return errors.New("cannot set enable-signup without also setting enable-login") } else if stripeSecretKey != "" && (stripeWebhookKey == "" || baseURL == "") { return errors.New("if stripe-secret-key is set, stripe-webhook-key and base-url must also be set") - } else if twilioAccount != "" && (twilioAuthToken == "" || twilioPhoneNumber == "" || twilioVerifyService == "" || baseURL == "" || authFile == "") { - return errors.New("if twilio-account is set, twilio-auth-token, twilio-phone-number, twilio-verify-service, base-url, and auth-file must also be set") } - // Backwards compatibility - if webRoot == "app" { - webRoot = "/" - } else if webRoot == "home" { - webRoot = "/app" - } else if webRoot == "disable" { - webRoot = "" - } else if !strings.HasPrefix(webRoot, "/") { - webRoot = "/" + webRoot - } + webRootIsApp := webRoot == "app" + enableWeb := webRoot != "disable" // Default auth permissions authDefault, err := user.ParsePermission(authDefaultAccess) @@ -311,9 +287,8 @@ func execServe(c *cli.Context) error { conf.KeepaliveInterval = keepaliveInterval conf.ManagerInterval = managerInterval conf.DisallowedTopics = disallowedTopics - conf.WebRoot = webRoot + conf.WebRootIsApp = webRootIsApp conf.UpstreamBaseURL = upstreamBaseURL - conf.UpstreamAccessToken = upstreamAccessToken conf.SMTPSenderAddr = smtpSenderAddr conf.SMTPSenderUser = smtpSenderUser conf.SMTPSenderPass = smtpSenderPass @@ -321,10 +296,6 @@ func execServe(c *cli.Context) error { conf.SMTPServerListen = smtpServerListen conf.SMTPServerDomain = smtpServerDomain conf.SMTPServerAddrPrefix = smtpServerAddrPrefix - conf.TwilioAccount = twilioAccount - conf.TwilioAuthToken = twilioAuthToken - conf.TwilioPhoneNumber = twilioPhoneNumber - conf.TwilioVerifyService = twilioVerifyService conf.TotalTopicLimit = totalTopicLimit conf.VisitorSubscriptionLimit = visitorSubscriptionLimit conf.VisitorAttachmentTotalSizeLimit = visitorAttachmentTotalSizeLimit @@ -340,12 +311,10 @@ func execServe(c *cli.Context) error { conf.StripeSecretKey = stripeSecretKey conf.StripeWebhookKey = stripeWebhookKey conf.BillingContact = billingContact + conf.EnableWeb = enableWeb conf.EnableSignup = enableSignup conf.EnableLogin = enableLogin conf.EnableReservations = enableReservations - conf.EnableMetrics = enableMetrics - conf.MetricsListenHTTP = metricsListenHTTP - conf.ProfileListenHTTP = profileListenHTTP conf.Version = c.App.Version // Set up hot-reloading of config diff --git a/cmd/subscribe.go b/cmd/subscribe.go index c85c468..3b4b447 100644 --- a/cmd/subscribe.go +++ b/cmd/subscribe.go @@ -72,7 +72,7 @@ ntfy subscribe TOPIC COMMAND $NTFY_TITLE $title, $t Message title $NTFY_PRIORITY $priority, $prio, $p Message priority (1=min, 5=max) $NTFY_TAGS $tags, $tag, $ta Message tags (comma separated list) - $NTFY_RAW $raw Raw JSON message + $NTFY_RAW $raw Raw JSON message Examples: ntfy sub mytopic 'notify-send "$m"' # Execute command for incoming messages @@ -119,7 +119,8 @@ func execSubscribe(c *cli.Context) error { } if token != "" { options = append(options, client.WithBearerAuth(token)) - } else if user != "" { + } + if user != "" { var pass string parts := strings.SplitN(user, ":", 2) if len(parts) == 2 { @@ -135,10 +136,6 @@ func execSubscribe(c *cli.Context) error { fmt.Fprintf(c.App.ErrWriter, "\r%s\r", strings.Repeat(" ", 20)) } options = append(options, client.WithBasicAuth(user, pass)) - } else if conf.DefaultToken != "" { - options = append(options, client.WithBearerAuth(conf.DefaultToken)) - } else if conf.DefaultUser != "" && conf.DefaultPassword != nil { - options = append(options, client.WithBasicAuth(conf.DefaultUser, *conf.DefaultPassword)) } if scheduled { options = append(options, client.WithScheduled()) @@ -194,10 +191,7 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic, topicOptions = append(topicOptions, auth) } - subscriptionID, err := cl.Subscribe(s.Topic, topicOptions...) - if err != nil { - return err - } + subscriptionID := cl.Subscribe(s.Topic, topicOptions...) if s.Command != "" { cmds[subscriptionID] = s.Command } else if conf.DefaultCommand != "" { @@ -207,10 +201,7 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic, } } if topic != "" { - subscriptionID, err := cl.Subscribe(topic, options...) - if err != nil { - return err - } + subscriptionID := cl.Subscribe(topic, options...) cmds[subscriptionID] = command } for m := range cl.Messages { diff --git a/cmd/subscribe_test.go b/cmd/subscribe_test.go index 0b3a0a4..a22b0c9 100644 --- a/cmd/subscribe_test.go +++ b/cmd/subscribe_test.go @@ -310,52 +310,3 @@ func TestCLI_Subscribe_Token_And_UserPass(t *testing.T) { require.Error(t, err) require.Equal(t, "cannot set both --user and --token", err.Error()) } - -func TestCLI_Subscribe_Default_Token(t *testing.T) { - message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}` - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/mytopic/json", r.URL.Path) - require.Equal(t, "Bearer tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2", r.Header.Get("Authorization")) - - w.WriteHeader(http.StatusOK) - w.Write([]byte(message)) - })) - defer server.Close() - - filename := filepath.Join(t.TempDir(), "client.yml") - require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(` -default-host: %s -default-token: tk_AgQdq7mVBoFD37zQVN29RhuMzNIz2 -`, server.URL)), 0600)) - - app, _, stdout, _ := newTestApp() - - require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--config=" + filename, "mytopic"})) - - require.Equal(t, message, strings.TrimSpace(stdout.String())) -} - -func TestCLI_Subscribe_Default_UserPass(t *testing.T) { - message := `{"id":"RXIQBFaieLVr","time":124,"expires":1124,"event":"message","topic":"mytopic","message":"triggered"}` - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/mytopic/json", r.URL.Path) - require.Equal(t, "Basic cGhpbGlwcDpteXBhc3M=", r.Header.Get("Authorization")) - - w.WriteHeader(http.StatusOK) - w.Write([]byte(message)) - })) - defer server.Close() - - filename := filepath.Join(t.TempDir(), "client.yml") - require.Nil(t, os.WriteFile(filename, []byte(fmt.Sprintf(` -default-host: %s -default-user: philipp -default-password: mypass -`, server.URL)), 0600)) - - app, _, stdout, _ := newTestApp() - - require.Nil(t, app.Run([]string{"ntfy", "subscribe", "--poll", "--config=" + filename, "mytopic"})) - - require.Equal(t, message, strings.TrimSpace(stdout.String())) -} diff --git a/cmd/tier.go b/cmd/tier.go index f1c8ddc..c0b83d7 100644 --- a/cmd/tier.go +++ b/cmd/tier.go @@ -18,7 +18,6 @@ const ( defaultMessageLimit = 5000 defaultMessageExpiryDuration = "12h" defaultEmailLimit = 20 - defaultCallLimit = 0 defaultReservationLimit = 3 defaultAttachmentFileSizeLimit = "15M" defaultAttachmentTotalSizeLimit = "100M" @@ -49,7 +48,6 @@ var cmdTier = &cli.Command{ &cli.Int64Flag{Name: "message-limit", Value: defaultMessageLimit, Usage: "daily message limit"}, &cli.StringFlag{Name: "message-expiry-duration", Value: defaultMessageExpiryDuration, Usage: "duration after which messages are deleted"}, &cli.Int64Flag{Name: "email-limit", Value: defaultEmailLimit, Usage: "daily email limit"}, - &cli.Int64Flag{Name: "call-limit", Value: defaultCallLimit, Usage: "daily phone call limit"}, &cli.Int64Flag{Name: "reservation-limit", Value: defaultReservationLimit, Usage: "topic reservation limit"}, &cli.StringFlag{Name: "attachment-file-size-limit", Value: defaultAttachmentFileSizeLimit, Usage: "per-attachment file size limit"}, &cli.StringFlag{Name: "attachment-total-size-limit", Value: defaultAttachmentTotalSizeLimit, Usage: "total size limit of attachments for the user"}, @@ -93,7 +91,6 @@ Examples: &cli.Int64Flag{Name: "message-limit", Usage: "daily message limit"}, &cli.StringFlag{Name: "message-expiry-duration", Usage: "duration after which messages are deleted"}, &cli.Int64Flag{Name: "email-limit", Usage: "daily email limit"}, - &cli.Int64Flag{Name: "call-limit", Usage: "daily phone call limit"}, &cli.Int64Flag{Name: "reservation-limit", Usage: "topic reservation limit"}, &cli.StringFlag{Name: "attachment-file-size-limit", Usage: "per-attachment file size limit"}, &cli.StringFlag{Name: "attachment-total-size-limit", Usage: "total size limit of attachments for the user"}, @@ -218,7 +215,6 @@ func execTierAdd(c *cli.Context) error { MessageLimit: c.Int64("message-limit"), MessageExpiryDuration: messageExpiryDuration, EmailLimit: c.Int64("email-limit"), - CallLimit: c.Int64("call-limit"), ReservationLimit: c.Int64("reservation-limit"), AttachmentFileSizeLimit: attachmentFileSizeLimit, AttachmentTotalSizeLimit: attachmentTotalSizeLimit, @@ -271,9 +267,6 @@ func execTierChange(c *cli.Context) error { if c.IsSet("email-limit") { tier.EmailLimit = c.Int64("email-limit") } - if c.IsSet("call-limit") { - tier.CallLimit = c.Int64("call-limit") - } if c.IsSet("reservation-limit") { tier.ReservationLimit = c.Int64("reservation-limit") } @@ -364,7 +357,6 @@ func printTier(c *cli.Context, tier *user.Tier) { fmt.Fprintf(c.App.ErrWriter, "- Message limit: %d\n", tier.MessageLimit) fmt.Fprintf(c.App.ErrWriter, "- Message expiry duration: %s (%d seconds)\n", tier.MessageExpiryDuration.String(), int64(tier.MessageExpiryDuration.Seconds())) fmt.Fprintf(c.App.ErrWriter, "- Email limit: %d\n", tier.EmailLimit) - fmt.Fprintf(c.App.ErrWriter, "- Phone call limit: %d\n", tier.CallLimit) fmt.Fprintf(c.App.ErrWriter, "- Reservation limit: %d\n", tier.ReservationLimit) fmt.Fprintf(c.App.ErrWriter, "- Attachment file size limit: %s\n", util.FormatSize(tier.AttachmentFileSizeLimit)) fmt.Fprintf(c.App.ErrWriter, "- Attachment total size limit: %s\n", util.FormatSize(tier.AttachmentTotalSizeLimit)) diff --git a/docs/_overrides/main.html b/docs/_overrides/main.html index 52483eb..53a26fc 100644 --- a/docs/_overrides/main.html +++ b/docs/_overrides/main.html @@ -32,11 +32,11 @@ -If you like ntfy, please consider sponsoring me via GitHub Sponsors +If you like ntfy, please consider sponsoring it via GitHub Sponsors or Liberapay -, or subscribing to ntfy Pro. + - - - diff --git a/web/package-lock.json b/web/package-lock.json index b5754d9..635f42a 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,8 +8,8 @@ "name": "ntfy", "version": "1.0.0", "dependencies": { - "@emotion/react": "^11.11.0", - "@emotion/styled": "^11.11.0", + "@emotion/react": "^11.8.2", + "@emotion/styled": "^11.8.1", "@mui/icons-material": "^5.4.2", "@mui/material": "latest", "dexie": "^3.2.1", @@ -24,29 +24,17 @@ "react-i18next": "^11.16.2", "react-infinite-scroll-component": "^6.1.0", "react-router-dom": "^6.2.2", + "react-scripts": "^5.0.0", "stacktrace-gps": "^3.0.4", "stacktrace-js": "^2.0.2" - }, - "devDependencies": { - "@vitejs/plugin-react": "^4.0.0", - "eslint": "^8.41.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "prettier": "^2.8.8", - "vite": "^4.3.8" } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { @@ -54,9 +42,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -65,30 +53,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.21.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.9.tgz", - "integrity": "sha512-FUGed8kfhyWvbYug/Un/VPJD41rDIgoVVcR+FuzhzOYyRz5uED+Gd3SLZml0Uw2l2aHFb7ZgdW5mGA3G2cCCnQ==", - "dev": true, + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", + "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", - "dev": true, + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz", + "integrity": "sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.21.0", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.0", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.0", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -103,13 +89,53 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/generator": { - "version": "7.21.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.9.tgz", - "integrity": "sha512-F3fZga2uv09wFdEjEQIJxXALXfz0+JaOb7SabvVMmjHxeVTuGW8wgE8Vp1Hd7O+zMTYtcfEISGRzPkeiaPPsvg==", - "dev": true, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "dependencies": { - "@babel/types": "^7.21.5", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.11.0", + "eslint": "^7.5.0 || ^8.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.1.tgz", + "integrity": "sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==", + "dependencies": { + "@babel/types": "^7.21.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -118,14 +144,49 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", - "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", - "dev": true, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dependencies": { - "@babel/compat-data": "^7.21.5", - "@babel/helper-validator-option": "^7.21.0", + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" @@ -137,11 +198,89 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.0.tgz", + "integrity": "sha512-Q8wNiMIdwsv5la5SPxNYzzkPnjgC0Sy0i7jLkVOCdllu/xcVNkr3TeZzbHBJrj+XXRqzX5uCyCoV9eu6xUG7KQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-member-expression-to-functions": "^7.21.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.0.tgz", + "integrity": "sha512-N+LaFW/auRSWdx7SHD/HiARwXQju1vXTW4fKr4u5SgBUTm51OKEjKgj+cs00ggW3kEvNqwErnlwuq7Y3xBe4eg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz", - "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==", - "dev": true, + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dependencies": { + "@babel/types": "^7.18.6" + }, "engines": { "node": ">=6.9.0" } @@ -150,7 +289,6 @@ "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, "dependencies": { "@babel/template": "^7.20.7", "@babel/types": "^7.21.0" @@ -163,7 +301,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, @@ -171,52 +308,115 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz", + "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==", "dependencies": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dependencies": { + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz", - "integrity": "sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==", - "dev": true, + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", + "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dependencies": { - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@babel/traverse": "^7.21.2", + "@babel/types": "^7.21.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dependencies": { + "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", - "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", - "dev": true, + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz", + "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.20.7", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", - "dev": true, + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", + "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dependencies": { - "@babel/types": "^7.21.5" + "@babel/types": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", + "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", + "dependencies": { + "@babel/types": "^7.20.0" }, "engines": { "node": ">=6.9.0" @@ -226,7 +426,6 @@ "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, @@ -235,9 +434,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", - "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "engines": { "node": ">=6.9.0" } @@ -254,20 +453,32 @@ "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", + "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.5", + "@babel/types": "^7.20.5" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", - "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", - "dev": true, + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", + "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dependencies": { "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" @@ -287,10 +498,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.9.tgz", - "integrity": "sha512-q5PNg/Bi1OpGgx5jYlvWZwAorZepEudDMCLtj967aeS7WMont7dUZI46M2XwcIQqvUlMxWfdLFu4S/qSxeUu5g==", - "dev": true, + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", + "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -298,11 +508,339 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-react-jsx-self": { + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz", + "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-proposal-optional-chaining": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.21.0.tgz", - "integrity": "sha512-f/Eq+79JEu+KUANFks9UZCcvydOOGMgF7jBrcwjHa5jTZD8JivnhCJYvmlhR/WTXBWonDExPoW0eO/CR4QJirA==", - "dev": true, + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", + "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.21.0.tgz", + "integrity": "sha512-MfgX49uRrFUTL/HvWtmx3zmpyzMMr4MTj3d527MLlr/4RTT9G/ytFFP7qet2uM2Ve03b+BkpWUpK+lRXnQ+v9w==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/plugin-syntax-decorators": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", + "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz", + "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz", + "integrity": "sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w==", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -313,11 +851,46 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.19.6.tgz", - "integrity": "sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==", - "dev": true, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", + "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", + "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" }, @@ -328,10 +901,913 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", + "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", + "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz", + "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz", + "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz", + "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.21.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-replace-supers": "^7.20.7", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz", + "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/template": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz", + "integrity": "sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-flow": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz", + "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz", + "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==", + "dependencies": { + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz", + "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==", + "dependencies": { + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-simple-access": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz", + "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-identifier": "^7.19.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", + "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.20.5", + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.20.2.tgz", + "integrity": "sha512-KS/G8YI8uwMGKErLFOHS/ekhqdHhpEloxs43NecQHVgo2QuQSyJhGIY1fL8UGl9wy5ItVwwoUL4YxVqsplGq2g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz", + "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz", + "integrity": "sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-jsx": "^7.18.6", + "@babel/types": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", + "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz", + "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", + "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "regenerator-transform": "^0.15.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.0.tgz", + "integrity": "sha512-ReY6pxwSzEU0b3r2/T/VhqMKg/AkceBT19X0UptA3/tYi5Pe2eXgEUH+NNMC5nok6c6XQz5tyVTUpuezRfSMSg==", + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz", + "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.0.tgz", + "integrity": "sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-typescript": "^7.20.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", + "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", + "dependencies": { + "@babel/compat-data": "^7.20.1", + "@babel/helper-compilation-targets": "^7.20.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.20.1", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.20.2", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.20.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.20.2", + "@babel/plugin-transform-classes": "^7.20.2", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.20.2", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.19.6", + "@babel/plugin-transform-modules-commonjs": "^7.19.6", + "@babel/plugin-transform-modules-systemjs": "^7.19.6", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.20.1", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.19.0", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.20.2", + "babel-plugin-polyfill-corejs2": "^0.3.3", + "babel-plugin-polyfill-corejs3": "^0.6.0", + "babel-plugin-polyfill-regenerator": "^0.4.1", + "core-js-compat": "^3.25.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz", + "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-react-display-name": "^7.18.6", + "@babel/plugin-transform-react-jsx": "^7.18.6", + "@babel/plugin-transform-react-jsx-development": "^7.18.6", + "@babel/plugin-transform-react-pure-annotations": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.0.tgz", + "integrity": "sha512-myc9mpoVA5m1rF8K8DgLEatOYFDpwC+RkMkjZ0Du6uI62YvDe8uxIEYVs/VCdSJ097nlALiU/yBC7//3nI+hNg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-validator-option": "^7.21.0", + "@babel/plugin-transform-typescript": "^7.21.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, "node_modules/@babel/runtime": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", - "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -340,33 +1816,31 @@ } }, "node_modules/@babel/template": { - "version": "7.21.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz", - "integrity": "sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==", - "dev": true, + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/parser": "^7.21.9", - "@babel/types": "^7.21.5" + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", - "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", - "dev": true, + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.2.tgz", + "integrity": "sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==", "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-environment-visitor": "^7.21.5", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.21.1", + "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.5", - "@babel/types": "^7.21.5", + "@babel/parser": "^7.21.2", + "@babel/types": "^7.21.2", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -375,11 +1849,11 @@ } }, "node_modules/@babel/types": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz", - "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", + "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", "dependencies": { - "@babel/helper-string-parser": "^7.21.5", + "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, @@ -387,66 +1861,342 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==" + }, + "node_modules/@csstools/normalize.css": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz", + "integrity": "sha512-M0qqxAcwCsIVfpFQSlGN5XjXWu8l5JDZN+fPt1LeW5SZexQTgnaEvgXAY+CeygRw0EeppWHi12JxESWiWrB0Sg==" + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.1.1.tgz", + "integrity": "sha512-jwx+WCqszn53YHOfvFMJJRd/B2GqkCBt+1MJSG6o5/s8+ytHMvDZXsJgUEWLk12UnLd7HYKac4BYU5i/Ron1Cw==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4", + "postcss-selector-parser": "^6.0.10" + } + }, "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", + "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/serialize": "^1.1.1", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", - "stylis": "4.2.0" + "stylis": "4.1.3" } }, "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "version": "11.10.5", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", + "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "stylis": "4.2.0" + "@emotion/memoize": "^0.8.0", + "@emotion/sheet": "^1.2.1", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", + "stylis": "4.1.3" } }, "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", + "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", - "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", + "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", "dependencies": { - "@emotion/memoize": "^0.8.1" + "@emotion/memoize": "^0.8.0" } }, "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", + "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" }, "node_modules/@emotion/react": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.0.tgz", - "integrity": "sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw==", + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", + "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.2", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/babel-plugin": "^11.10.6", + "@emotion/cache": "^11.10.5", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0", + "@emotion/weak-memoize": "^0.3.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -459,33 +2209,33 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", - "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", + "@emotion/hash": "^0.9.0", + "@emotion/memoize": "^0.8.0", + "@emotion/unitless": "^0.8.0", + "@emotion/utils": "^1.2.0", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", + "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" }, "node_modules/@emotion/styled": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", - "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", + "version": "11.10.6", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", + "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.1", - "@emotion/serialize": "^1.1.2", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" + "@emotion/babel-plugin": "^11.10.6", + "@emotion/is-prop-valid": "^1.2.0", + "@emotion/serialize": "^1.1.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", + "@emotion/utils": "^1.2.0" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -498,413 +2248,36 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", + "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", + "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", + "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", + "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.4.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -919,11 +2292,15 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -934,11 +2311,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", - "dev": true, + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", + "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -947,7 +2345,6 @@ "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", - "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -961,7 +2358,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, "engines": { "node": ">=12.22" }, @@ -973,18 +2369,686 @@ "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", + "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", + "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/reporters": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^27.5.1", + "jest-config": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-resolve-dependencies": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "jest-watcher": "^27.5.1", + "micromatch": "^4.0.4", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", + "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "dependencies": { + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", + "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "@sinonjs/fake-timers": "^8.0.1", + "@types/node": "*", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", + "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/types": "^27.5.1", + "expect": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", + "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-haste-map": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^8.1.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/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/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", + "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9", + "source-map": "^0.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/source-map/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/@jest/test-result": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", + "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", + "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "dependencies": { + "@jest/test-result": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-runtime": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", + "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^27.5.1", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-util": "^27.5.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/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/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", + "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^16.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { "node": ">=6.0.0" @@ -994,7 +3058,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1003,43 +3066,61 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dev": true, + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" }, "node_modules/@mui/base": { - "version": "5.0.0-beta.2", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.2.tgz", - "integrity": "sha512-R9R+aqrl1QhZJaO05rhvooqxOaf7SKpQ+EjW80sbP3ticTVmLmrn4YBLQS7/ML+WXdrkrPtqSmKFdSE5Ik3gBQ==", + "version": "5.0.0-alpha.119", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.119.tgz", + "integrity": "sha512-XA5zhlYfXi67u613eIF0xRmktkatx6ERy3h+PwrMN5IcWFbgiL1guz8VpdXON+GWb8+G7B8t5oqTFIaCqaSAeA==", "dependencies": { "@babel/runtime": "^7.21.0", - "@emotion/is-prop-valid": "^1.2.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", - "@popperjs/core": "^2.11.7", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "@popperjs/core": "^2.11.6", "clsx": "^1.2.1", "prop-types": "^15.8.1", "react-is": "^18.2.0" @@ -1063,18 +3144,18 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.2.tgz", - "integrity": "sha512-aOLCXMCySMFL2WmUhnz+DjF84AoFVu8rn35OsL759HXOZMz8zhEwVf5w/xxkWx7DycM2KXDTgAvYW48nTfqTLA==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.11.tgz", + "integrity": "sha512-0YK0K9GfW1ysw9z4ztWAjLW+bktf+nExMyn2+EQe1Ijb0kF2kz1kIOmb4+di0/PsXG70uCuw4DhEIdNd+JQkRA==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" } }, "node_modules/@mui/icons-material": { - "version": "5.11.16", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.16.tgz", - "integrity": "sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.11.11.tgz", + "integrity": "sha512-Eell3ADmQVE8HOpt/LZ3zIma8JSvPh3XgnhwZLT0k5HRqZcd6F/QDHc7xsWtgz09t+UEFvOYJXjtrwKmLdwwpw==", "dependencies": { "@babel/runtime": "^7.21.0" }, @@ -1097,19 +3178,19 @@ } }, "node_modules/@mui/material": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.13.2.tgz", - "integrity": "sha512-Pfke1l0GG2OJb/Nr10aVr8huoBFcBTdWKV5iFSTEHqf9c2C1ZlyYMISn7ui6X3Gix8vr+hP5kVqH1LAWwQSb6w==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.11.tgz", + "integrity": "sha512-sSe0dmKjB1IGOYt32Pcha+cXV3IIrX5L5mFAF9LDRssp/x53bluhgLLbkc8eTiJvueVvo6HAyze6EkFEYLQRXQ==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/base": "5.0.0-beta.2", - "@mui/core-downloads-tracker": "^5.13.2", - "@mui/system": "^5.13.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", - "@types/react-transition-group": "^4.4.6", + "@mui/base": "5.0.0-alpha.119", + "@mui/core-downloads-tracker": "^5.11.11", + "@mui/system": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", + "@types/react-transition-group": "^4.4.5", "clsx": "^1.2.1", - "csstype": "^3.1.2", + "csstype": "^3.1.1", "prop-types": "^15.8.1", "react-is": "^18.2.0", "react-transition-group": "^4.4.5" @@ -1141,12 +3222,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz", - "integrity": "sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.11.tgz", + "integrity": "sha512-yLgTkjNC1mpye2SOUkc+zQQczUpg8NvQAETvxwXTMzNgJK1pv4htL7IvBM5vmCKG7IHAB3hX26W2u6i7bxwF3A==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.13.1", + "@mui/utils": "^5.11.11", "prop-types": "^15.8.1" }, "engines": { @@ -1167,13 +3248,13 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz", - "integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz", + "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==", "dependencies": { "@babel/runtime": "^7.21.0", - "@emotion/cache": "^11.11.0", - "csstype": "^3.1.2", + "@emotion/cache": "^11.10.5", + "csstype": "^3.1.1", "prop-types": "^15.8.1" }, "engines": { @@ -1198,17 +3279,17 @@ } }, "node_modules/@mui/system": { - "version": "5.13.2", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.13.2.tgz", - "integrity": "sha512-TPyWmRJPt0JPVxacZISI4o070xEJ7ftxpVtu6LWuYVOUOINlhoGOclam4iV8PDT3EMQEHuUrwU49po34UdWLlw==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.11.tgz", + "integrity": "sha512-a9gaOAJBjpzypDfhbGZQ8HzdcxdxsKkFvbp1aAWZhFHBPdehEkARNh7mj851VfEhD/GdffYt85PFKFKdUta5Eg==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/private-theming": "^5.13.1", - "@mui/styled-engine": "^5.13.2", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", + "@mui/private-theming": "^5.11.11", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.11", "clsx": "^1.2.1", - "csstype": "^3.1.2", + "csstype": "^3.1.1", "prop-types": "^15.8.1" }, "engines": { @@ -1237,9 +3318,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz", + "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==", "peerDependencies": { "@types/react": "*" }, @@ -1250,13 +3331,13 @@ } }, "node_modules/@mui/utils": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz", - "integrity": "sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A==", + "version": "5.11.11", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.11.tgz", + "integrity": "sha512-neMM5rrEXYQrOrlxUfns/TGgX4viS8K2zb9pbQh11/oUUYFlGI32Tn+PHePQx7n6Fy/0zq6WxdBFC9VpnJ5JrQ==", "dependencies": { "@babel/runtime": "^7.21.0", "@types/prop-types": "^15.7.5", - "@types/react-is": "^18.2.0", + "@types/react-is": "^16.7.1 || ^17.0.0", "prop-types": "^15.8.1", "react-is": "^18.2.0" }, @@ -1271,11 +3352,38 @@ "react": "^17.0.0 || ^18.0.0" } }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1288,7 +3396,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -1297,7 +3404,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1306,43 +3412,625 @@ "node": ">= 8" } }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.10.tgz", + "integrity": "sha512-j0Ya0hCFZPd4x40qLzbhGsh9TMtdb+CJQiso+WxLOPNasohq9cc5SNUcwsZaRH6++Xh91Xkm/xHCkuIiIu0LUA==", + "dependencies": { + "ansi-html-community": "^0.0.8", + "common-path-prefix": "^3.0.0", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "find-up": "^5.0.0", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^3.0.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <4.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/@popperjs/core": { - "version": "2.11.7", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", - "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", + "version": "2.11.6", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", + "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, "node_modules/@remix-run/router": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.6.2.tgz", - "integrity": "sha512-LzqpSrMK/3JBAVBI9u3NWtOhWNw5AMQfrUFYB0+bDHTSw17z++WJLsPsxAuK+oSddsxk4d7F/JcdDPM1M5YAhA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.3.tgz", + "integrity": "sha512-YRHie1yQEj0kqqCTCJEfHqYSSNlZQ696QJG+MMiW4mxSl9I0ojz/eRhJS4fs88Z5i6D1SmoF9d3K99/QOhI8/w==", "engines": { "node": ">=14" } }, + "node_modules/@rollup/plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", + "integrity": "sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==", + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "@types/babel__core": "^7.1.9", + "rollup": "^1.20.0||^2.0.0" + }, + "peerDependenciesMeta": { + "@types/babel__core": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz", + "integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "@types/resolve": "1.17.1", + "builtin-modules": "^3.1.0", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz", + "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==", + "dependencies": { + "@rollup/pluginutils": "^3.1.0", + "magic-string": "^0.25.7" + }, + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", + "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==" + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@surma/rollup-plugin-off-main-thread": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", + "integrity": "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==", + "dependencies": { + "ejs": "^3.1.6", + "json5": "^2.2.0", + "magic-string": "^0.25.0", + "string.prototype.matchall": "^4.0.6" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz", + "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz", + "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz", + "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz", + "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz", + "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz", + "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz", + "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz", + "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==", + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1", + "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1", + "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0", + "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0", + "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0", + "@svgr/babel-plugin-transform-svg-component": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/core": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz", + "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==", + "dependencies": { + "@svgr/plugin-jsx": "^5.5.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", + "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==", + "dependencies": { + "@babel/types": "^7.12.6" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz", + "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==", + "dependencies": { + "@babel/core": "^7.12.3", + "@svgr/babel-preset": "^5.5.0", + "@svgr/hast-util-to-babel-ast": "^5.5.0", + "svg-parser": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz", + "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "deepmerge": "^4.2.2", + "svgo": "^1.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/webpack": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", + "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/plugin-transform-react-constant-elements": "^7.12.1", + "@babel/preset-env": "^7.12.1", + "@babel/preset-react": "^7.12.5", + "@svgr/core": "^5.5.0", + "@svgr/plugin-jsx": "^5.5.0", + "@svgr/plugin-svgo": "^5.5.0", + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.21.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz", + "integrity": "sha512-rc9K8ZpVjNcLs8Fp0dkozd5Pt2Apk1glO4Vgz8ix1u6yFByxfqo5Yavpy65o+93TAe24jr7v+eSBtFLvOQtCRQ==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==" + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.10", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz", + "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" + }, + "node_modules/@types/node": { + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" }, "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, + "node_modules/@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==" + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, + "node_modules/@types/q": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", + "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, "node_modules/@types/react": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.7.tgz", - "integrity": "sha512-ojrXpSH2XFCmHm7Jy3q44nXDyN54+EYKP2lBhJ2bqfyPj6cIUW/FZW/Csdia34NQgq7KYcAlHi5184m4X88+yw==", + "version": "18.0.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz", + "integrity": "sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1350,49 +4038,480 @@ } }, "node_modules/@types/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-1vz2yObaQkLL7YFe/pme2cpvDsCwI1WXIfL+5eLz0MI9gFG24Re16RzUsI8t9XZn9ZWvgLNDrJBmrqXJO7GNQQ==", + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz", + "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-transition-group": { - "version": "4.4.6", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz", - "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==", + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.0.0.tgz", - "integrity": "sha512-HX0XzMjL3hhOYm+0s95pb0Z7F8O81G7joUHgfDd/9J/ZZf5k4xX6QAMFkKsHFxaHlf6X7GD7+XuaZ66ULiJuhQ==", - "dev": true, + "node_modules/@types/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", "dependencies": { - "@babel/core": "^7.21.4", - "@babel/plugin-transform-react-jsx-self": "^7.21.0", - "@babel/plugin-transform-react-jsx-source": "^7.19.6", - "react-refresh": "^0.14.0" + "@types/node": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==" + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", + "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==" + }, + "node_modules/@types/ws": { + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "16.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", + "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz", + "integrity": "sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/type-utils": "5.54.0", + "@typescript-eslint/utils": "5.54.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "vite": "^4.2.0" + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.54.0.tgz", + "integrity": "sha512-rRYECOTh5V3iWsrOzXi7h1jp3Bi9OkJHrb3wECi3DVqMGTilo9wAYmCbT+6cGdrzUY3MWcAa2mESM6FMik6tVw==", + "dependencies": { + "@typescript-eslint/utils": "5.54.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz", + "integrity": "sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz", + "integrity": "sha512-VTPYNZ7vaWtYna9M4oD42zENOBrb+ZYyCNdFs949GcN8Miwn37b8b7eMj+EZaq7VK9fx0Jd+JhmkhjFhvnovhg==", + "dependencies": { + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/visitor-keys": "5.54.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz", + "integrity": "sha512-WI+WMJ8+oS+LyflqsD4nlXMsVdzTMYTxl16myXPaCXnSgc7LWwMsjxQFZCK/rVmTZ3FN71Ct78ehO9bRC7erYQ==", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.54.0", + "@typescript-eslint/utils": "5.54.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.0.tgz", + "integrity": "sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz", + "integrity": "sha512-X2rJG97Wj/VRo5YxJ8Qx26Zqf0RRKsVHd4sav8NElhbZzhpBI8jU54i6hfo9eheumj4oO4dcRN1B/zIVEqR/MQ==", + "dependencies": { + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/visitor-keys": "5.54.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.0.tgz", + "integrity": "sha512-cuwm8D/Z/7AuyAeJ+T0r4WZmlnlxQ8wt7C7fLpFlKMR+dY6QO79Cq1WpJhvZbMA4ZeZGHiRWnht7ZJ8qkdAunw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.54.0", + "@typescript-eslint/types": "5.54.0", + "@typescript-eslint/typescript-estree": "5.54.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.0.tgz", + "integrity": "sha512-xu4wT7aRCakGINTLGeyGqDn+78BwFlggwBjnHa1ar/KaGagnmwLYmlrXIrgAaQ3AE1Vd6nLfKASm7LrFHNbKGA==", + "dependencies": { + "@typescript-eslint/types": "5.54.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/acorn": { "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -1400,20 +4519,106 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1425,11 +4630,79 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1445,39 +4718,48 @@ "node": ">=4" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } }, "node_modules/aria-query": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, "dependencies": { "deep-equal": "^2.0.5" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, "node_modules/array-includes": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -1492,11 +4774,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, "node_modules/array.prototype.flat": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -1514,7 +4803,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -1528,11 +4816,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.tosorted": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -1541,17 +4846,70 @@ "get-intrinsic": "^1.1.3" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + }, "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", - "dev": true + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -1560,10 +4918,9 @@ } }, "node_modules/axe-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.1.tgz", - "integrity": "sha512-sCXXUhA+cljomZ3ZAwb8i1p3oOlkABzPy08ZDAoGcYuvtBPlQ1Ytde129ArXyHWDhfeewq7rlx9F+cUx2SSlkg==", - "dev": true, + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz", + "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==", "engines": { "node": ">=4" } @@ -1572,11 +4929,159 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dev": true, "dependencies": { "deep-equal": "^2.0.5" } }, + "node_modules/babel-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", + "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "dependencies": { + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz", + "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==", + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", + "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -1591,27 +5096,268 @@ "npm": ">=6" } }, + "node_modules/babel-plugin-named-asset-import": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz", + "integrity": "sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==", + "peerDependencies": { + "@babel/core": "^7.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", + "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3", + "core-js-compat": "^3.25.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-transform-react-remove-prop-types": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz", + "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==" + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", + "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "dependencies": { + "babel-plugin-jest-hoist": "^27.5.1", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-react-app": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz", + "integrity": "sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==", + "dependencies": { + "@babel/core": "^7.16.0", + "@babel/plugin-proposal-class-properties": "^7.16.0", + "@babel/plugin-proposal-decorators": "^7.16.4", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0", + "@babel/plugin-proposal-numeric-separator": "^7.16.0", + "@babel/plugin-proposal-optional-chaining": "^7.16.0", + "@babel/plugin-proposal-private-methods": "^7.16.0", + "@babel/plugin-transform-flow-strip-types": "^7.16.0", + "@babel/plugin-transform-react-display-name": "^7.16.0", + "@babel/plugin-transform-runtime": "^7.16.4", + "@babel/preset-env": "^7.16.4", + "@babel/preset-react": "^7.16.0", + "@babel/preset-typescript": "^7.16.0", + "@babel/runtime": "^7.16.3", + "babel-plugin-macros": "^3.1.0", + "babel-plugin-transform-react-remove-prop-types": "^0.4.24" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/bfj": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz", + "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==", + "dependencies": { + "bluebird": "^3.5.5", + "check-types": "^11.1.1", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/bonjour-service": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz", + "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==", + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, "funding": [ { "type": "opencollective", @@ -1635,11 +5381,42 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -1656,11 +5433,49 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, "node_modules/caniuse-lite": { - "version": "1.0.30001489", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz", - "integrity": "sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ==", - "dev": true, + "version": "1.0.30001460", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz", + "integrity": "sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==", "funding": [ { "type": "opencollective", @@ -1669,13 +5484,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" } ] }, + "node_modules/case-sensitive-paths-webpack-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz", + "integrity": "sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==", + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -1697,6 +5516,112 @@ "node": ">=0.8.0" } }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/check-types": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.2.tgz", + "integrity": "sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==" + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==" + }, + "node_modules/clean-css": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/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/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, "node_modules/clsx": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", @@ -1705,6 +5630,33 @@ "node": ">=6" } }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dependencies": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1718,23 +5670,191 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/confusing-browser-globals": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true + "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-js": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.0.tgz", + "integrity": "sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.29.0.tgz", + "integrity": "sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ==", + "dependencies": { + "browserslist": "^4.21.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.29.0.tgz", + "integrity": "sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -1762,7 +5882,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -1772,22 +5891,444 @@ "node": ">= 8" } }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-declaration-sorter": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz", + "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==", + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.19", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz", + "integrity": "sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==", + "dependencies": { + "cssnano": "^5.0.6", + "jest-worker": "^27.0.2", + "postcss": "^8.3.5", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/css-minimizer-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/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" + }, + "node_modules/css-tree": { + "version": "1.0.0-alpha.37", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", + "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==", + "dependencies": { + "mdn-data": "2.0.4", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-tree/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/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.4.1.tgz", + "integrity": "sha512-0Q8NOMpXJ3iTDDbUv9grcmQAfdDx4qz+fN/+Md2FGbevT+6+bJNQ2LjB2YIUlLbpBTM32idU1Sb+tb/uGt6/XQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "5.1.15", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz", + "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==", + "dependencies": { + "cssnano-preset-default": "^5.2.14", + "lilconfig": "^2.0.3", + "yaml": "^1.10.2" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-preset-default": { + "version": "5.2.14", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz", + "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==", + "dependencies": { + "css-declaration-sorter": "^6.3.1", + "cssnano-utils": "^3.1.0", + "postcss-calc": "^8.2.3", + "postcss-colormin": "^5.3.1", + "postcss-convert-values": "^5.1.3", + "postcss-discard-comments": "^5.1.2", + "postcss-discard-duplicates": "^5.1.0", + "postcss-discard-empty": "^5.1.1", + "postcss-discard-overridden": "^5.1.0", + "postcss-merge-longhand": "^5.1.7", + "postcss-merge-rules": "^5.1.4", + "postcss-minify-font-values": "^5.1.0", + "postcss-minify-gradients": "^5.1.1", + "postcss-minify-params": "^5.1.4", + "postcss-minify-selectors": "^5.2.1", + "postcss-normalize-charset": "^5.1.0", + "postcss-normalize-display-values": "^5.1.0", + "postcss-normalize-positions": "^5.1.1", + "postcss-normalize-repeat-style": "^5.1.1", + "postcss-normalize-string": "^5.1.0", + "postcss-normalize-timing-functions": "^5.1.0", + "postcss-normalize-unicode": "^5.1.1", + "postcss-normalize-url": "^5.1.0", + "postcss-normalize-whitespace": "^5.1.1", + "postcss-ordered-values": "^5.1.3", + "postcss-reduce-initial": "^5.1.2", + "postcss-reduce-transforms": "^5.1.0", + "postcss-svgo": "^5.1.0", + "postcss-unique-selectors": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/cssnano-utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz", + "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/csso/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/cssom": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==" + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" + }, "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1800,18 +6341,26 @@ } } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==" + }, "node_modules/deep-equal": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", - "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", - "dev": true, + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", + "integrity": "sha512-RdpzE0Hv4lhowpIUKKMJfeH6C1pXdtT1/it80ubgWqwI3qpuxUBpC1S4hnHg+zjnuOoDkzUtUCEEkG+XG5l3Mw==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.0", + "es-get-iterator": "^1.1.2", + "get-intrinsic": "^1.1.3", "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", + "is-array-buffer": "^3.0.1", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -1819,7 +6368,7 @@ "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", + "regexp.prototype.flags": "^1.4.3", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", @@ -1832,14 +6381,39 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/deepmerge": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", + "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", - "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -1851,6 +6425,97 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/detective": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", + "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", + "dependencies": { + "acorn-node": "^1.8.2", + "defined": "^1.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/dexie": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/dexie/-/dexie-3.2.3.tgz", @@ -1860,20 +6525,64 @@ } }, "node_modules/dexie-react-hooks": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dexie-react-hooks/-/dexie-react-hooks-1.1.3.tgz", - "integrity": "sha512-bXXE1gfYtfuVYTNiOlyam+YVaO8KaqacgRuxFuP37YtpS6o/jxT6KOl5h+hhqY36s0UavlHWbL+HWJFMcQumIg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/dexie-react-hooks/-/dexie-react-hooks-1.1.1.tgz", + "integrity": "sha512-Cam5JP6PxHN564RvWEoe8cqLhosW0O4CAZ9XEVYeGHJBa6KEJlOpd9CUpV3kmU9dm2MrW97/lk7qkf1xpij7gA==", "peerDependencies": { "@types/react": ">=16", "dexie": ">=3.1.0-alpha.1 <5.0.0", "react": ">=16" } }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff-sequences": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", + "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==" + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -1881,6 +6590,14 @@ "node": ">=6.0.0" } }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dependencies": { + "utila": "~0.4" + } + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -1890,17 +6607,178 @@ "csstype": "^3.0.2" } }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/ejs": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/electron-to-chromium": { - "version": "1.4.407", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.407.tgz", - "integrity": "sha512-5smEvFSFYMv90tICOzRVP7Opp98DAC4KW7RRipg3BuNpGbbV3N+x24Zh3sbLb1T5haGtOSy/hrBfXsWnIM9aCg==", - "dev": true + "version": "1.4.320", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.320.tgz", + "integrity": "sha512-h70iRscrNluMZPVICXYl5SSB+rBKo22XfuIS1ER0OQxQZpKTnFpuS6coj7wY9M/3trv7OR88rRMOlKmRvDty7Q==" + }, + "node_modules/emittery": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, "node_modules/error-ex": { "version": "1.3.2", @@ -1919,18 +6797,17 @@ } }, "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dev": true, + "version": "1.21.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz", + "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", "gopd": "^1.0.1", @@ -1938,8 +6815,8 @@ "has-property-descriptors": "^1.0.0", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "internal-slot": "^1.0.4", + "is-array-buffer": "^3.0.1", "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", @@ -1947,12 +6824,11 @@ "is-string": "^1.0.7", "is-typed-array": "^1.1.10", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", "string.prototype.trimend": "^1.0.6", "string.prototype.trimstart": "^1.0.6", "typed-array-length": "^1.0.4", @@ -1966,11 +6842,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==" + }, "node_modules/es-get-iterator": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -1986,11 +6866,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" + }, "node_modules/es-set-tostringtag": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.3", "has": "^1.0.3", @@ -2004,7 +6888,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, "dependencies": { "has": "^1.0.3" } @@ -2013,7 +6896,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -2026,52 +6908,19 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2083,16 +6932,90 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", - "dev": true, + "node_modules/escodegen": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/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==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", + "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", + "dependencies": { + "@eslint/eslintrc": "^2.0.0", + "@eslint/js": "8.35.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2102,9 +7025,10 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2112,12 +7036,13 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "graphemer": "^1.4.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -2125,6 +7050,7 @@ "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", + "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -2139,63 +7065,37 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, + "node_modules/eslint-config-react-app": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", + "integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==", "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", + "@babel/core": "^7.16.0", + "@babel/eslint-parser": "^7.16.3", + "@rushstack/eslint-patch": "^1.1.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "babel-preset-react-app": "^10.0.1", + "confusing-browser-globals": "^1.0.11", + "eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-import": "^2.25.3", + "eslint-plugin-jest": "^25.3.0", "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" + "eslint-plugin-react": "^7.27.1", + "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-testing-library": "^5.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", - "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "eslint": "^8.0.0" } }, "node_modules/eslint-import-resolver-node": { "version": "0.3.7", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", - "dev": true, "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.11.0", @@ -2206,16 +7106,14 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dependencies": { "debug": "^3.2.7" }, @@ -2232,16 +7130,31 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, "dependencies": { "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-flowtype": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz", + "integrity": "sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==", + "dependencies": { + "lodash": "^4.17.21", + "string-natural-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@babel/plugin-syntax-flow": "^7.14.5", + "@babel/plugin-transform-react-jsx": "^7.14.9", + "eslint": "^8.1.0" + } + }, "node_modules/eslint-plugin-import": { "version": "2.27.5", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", - "dev": true, "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -2270,7 +7183,6 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, "dependencies": { "ms": "^2.1.1" } @@ -2279,7 +7191,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -2287,11 +7198,41 @@ "node": ">=0.10.0" } }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "25.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz", + "integrity": "sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==", + "dependencies": { + "@typescript-eslint/experimental-utils": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^4.0.0 || ^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", - "dev": true, "dependencies": { "@babel/runtime": "^7.20.7", "aria-query": "^5.1.3", @@ -2317,11 +7258,18 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" } }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/eslint-plugin-react": { "version": "7.32.2", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", - "dev": true, "dependencies": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", @@ -2350,7 +7298,6 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, "engines": { "node": ">=10" }, @@ -2362,7 +7309,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -2374,7 +7320,6 @@ "version": "2.0.0-next.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", - "dev": true, "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -2387,39 +7332,185 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-testing-library": { + "version": "5.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.2.tgz", + "integrity": "sha512-f1DmDWcz5SDM+IpCkEX0lbFqrrTs8HRsEElzDEqN/EBI0hpRj8Cns5+IVANXswE8/LeybIJqPAOQIFu2j5Y5sw==", + "dependencies": { + "@typescript-eslint/utils": "^5.43.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0", + "npm": ">=6" + }, + "peerDependencies": { + "eslint": "^7.5.0 || ^8.0.0" + } + }, "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "engines": { + "node": ">=10" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2430,11 +7521,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2450,7 +7545,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2461,14 +7555,12 @@ "node_modules/eslint/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/eslint/node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -2483,16 +7575,25 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2500,15 +7601,25 @@ "node": ">=8" } }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", - "dev": true, + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2517,11 +7628,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -2533,7 +7655,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -2545,52 +7666,219 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==" + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", + "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dependencies": { + "bser": "2.1.1" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -2598,6 +7886,117 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", @@ -2607,7 +8006,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2623,7 +8021,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -2635,29 +8032,259 @@ "node_modules/flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, "dependencies": { "is-callable": "^1.1.3" } }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz", + "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==", + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==" + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -2676,7 +8303,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -2694,7 +8320,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2703,31 +8328,59 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-proto": "^1.0.1", "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-own-enumerable-property-symbols": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", + "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -2743,7 +8396,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -2763,7 +8415,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -2771,11 +8422,50 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -2784,7 +8474,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, "dependencies": { "define-properties": "^1.1.3" }, @@ -2795,11 +8484,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -2807,11 +8514,39 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/harmony-reflect": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz", + "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==" }, "node_modules/has": { "version": "1.0.3", @@ -2828,7 +8563,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2845,7 +8579,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -2857,7 +8590,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2869,7 +8601,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -2881,7 +8612,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -2892,6 +8622,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -2905,6 +8643,98 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/html-parse-stringify": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", @@ -2913,6 +8743,140 @@ "void-elements": "3.1.0" } }, + "node_modules/html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/humanize-duration": { "version": "3.28.0", "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.28.0.tgz", @@ -2956,15 +8920,61 @@ "cross-fetch": "3.1.5" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, + "node_modules/identity-obj-proxy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz", + "integrity": "sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==", + "dependencies": { + "harmony-reflect": "^1.4.6" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, "engines": { "node": ">= 4" } }, + "node_modules/immer": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", + "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -2980,11 +8990,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "engines": { "node": ">=0.8.19" } @@ -2993,7 +9020,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -3002,14 +9028,17 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/internal-slot": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", - "dev": true, "dependencies": { "get-intrinsic": "^1.2.0", "has": "^1.0.3", @@ -3019,11 +9048,18 @@ "node": ">= 0.4" } }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "engines": { + "node": ">= 10" + } + }, "node_modules/is-arguments": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -3039,7 +9075,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -3058,7 +9093,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -3066,11 +9100,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -3086,7 +9130,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3095,9 +9138,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dependencies": { "has": "^1.0.3" }, @@ -3109,7 +9152,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -3120,20 +9162,48 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -3145,16 +9215,19 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==" + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -3162,11 +9235,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-number-object": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -3177,20 +9257,42 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -3202,11 +9304,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "engines": { + "node": ">=6" + } + }, "node_modules/is-set": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3215,7 +9332,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -3223,11 +9339,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -3242,7 +9368,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -3257,7 +9382,6 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", - "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -3272,11 +9396,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, "node_modules/is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3285,7 +9413,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -3297,7 +9424,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -3306,45 +9432,2180 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/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/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jake": { + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jake/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", + "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "dependencies": { + "@jest/core": "^27.5.1", + "import-local": "^3.0.2", + "jest-cli": "^27.5.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", + "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "dependencies": { + "@jest/types": "^27.5.1", + "execa": "^5.0.0", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", + "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", + "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "dependencies": { + "@jest/core": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "prompts": "^2.0.1", + "yargs": "^16.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", + "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "dependencies": { + "@babel/core": "^7.8.0", + "@jest/test-sequencer": "^27.5.1", + "@jest/types": "^27.5.1", + "babel-jest": "^27.5.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.9", + "jest-circus": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-jasmine2": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runner": "^27.5.1", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", + "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", + "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", + "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1", + "jsdom": "^16.6.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", + "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^27.5.1", + "jest-serializer": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "micromatch": "^4.0.4", + "walker": "^1.0.7" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", + "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^27.5.1", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "pretty-format": "^27.5.1", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", + "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "dependencies": { + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", + "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", + "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.5.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^27.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", + "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", + "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", + "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "dependencies": { + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^27.5.1", + "jest-validate": "^27.5.1", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", + "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "dependencies": { + "@jest/types": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-snapshot": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", + "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "dependencies": { + "@jest/console": "^27.5.1", + "@jest/environment": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.8.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^27.5.1", + "jest-environment-jsdom": "^27.5.1", + "jest-environment-node": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-leak-detector": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-runtime": "^27.5.1", + "jest-util": "^27.5.1", + "jest-worker": "^27.5.1", + "source-map-support": "^0.5.6", + "throat": "^6.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", + "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/globals": "^27.5.1", + "@jest/source-map": "^27.5.1", + "@jest/test-result": "^27.5.1", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-mock": "^27.5.1", + "jest-regex-util": "^27.5.1", + "jest-resolve": "^27.5.1", + "jest-snapshot": "^27.5.1", + "jest-util": "^27.5.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-serializer": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", + "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", + "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "dependencies": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.0.0", + "@jest/transform": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^27.5.1", + "graceful-fs": "^4.2.9", + "jest-diff": "^27.5.1", + "jest-get-type": "^27.5.1", + "jest-haste-map": "^27.5.1", + "jest-matcher-utils": "^27.5.1", + "jest-message-util": "^27.5.1", + "jest-util": "^27.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^27.5.1", + "semver": "^7.3.2" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "dependencies": { + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", + "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "dependencies": { + "@jest/types": "^27.5.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^27.5.1", + "leven": "^3.1.0", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz", + "integrity": "sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==", + "dependencies": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "jest-regex-util": "^28.0.0", + "jest-watcher": "^28.0.0", + "slash": "^4.0.0", + "string-length": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "jest": "^27.0.0 || ^28.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/console/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/@types/yargs": { + "version": "17.0.22", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz", + "integrity": "sha512-pet5WJ9U8yPVRhkwuEIp5ktAeAqRZOq4UdAyWLWzxbtpyXnzbtLdKiXAjJzi/KLmPGS9wk86lUFWZFN6sISo4g==", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-watch-typeahead/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-watch-typeahead/node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-watch-typeahead/node_modules/jest-watcher/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watch-typeahead/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watch-typeahead/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", + "integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", + "dependencies": { + "char-regex": "^2.0.0", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watch-typeahead/node_modules/string-length/node_modules/char-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz", + "integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/jest-watch-typeahead/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", + "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "dependencies": { + "@jest/test-result": "^27.5.1", + "@jest/types": "^27.5.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^27.5.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } }, "node_modules/js-base64": { "version": "3.7.5", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz", "integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==" }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dependencies": { - "argparse": "^2.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "dependencies": { + "abab": "^2.0.5", + "acorn": "^8.2.4", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.3.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.1", + "domexception": "^2.0.1", + "escodegen": "^2.0.0", + "form-data": "^3.0.0", + "html-encoding-sniffer": "^2.0.1", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.0", + "parse5": "6.0.1", + "saxes": "^5.0.1", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.0.0", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.5.0", + "ws": "^7.4.6", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dependencies": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -3357,23 +11618,25 @@ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -3381,11 +11644,29 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", - "dev": true, "dependencies": { "array-includes": "^3.1.5", "object.assign": "^4.1.3" @@ -3394,26 +11675,55 @@ "node": ">=4.0" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" }, "node_modules/language-tags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dev": true, "dependencies": { "language-subtag-registry": "~0.3.2" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -3422,16 +11732,44 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -3442,11 +11780,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" }, "node_modules/loose-envify": { "version": "1.4.0", @@ -3459,20 +11821,236 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "dependencies": { "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "dependencies": { + "sourcemap-codec": "^1.4.8" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3484,28 +12062,42 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -3516,8 +12108,34 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } }, "node_modules/node-fetch": { "version": "2.6.7", @@ -3538,11 +12156,77 @@ } } }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" + }, "node_modules/node-releases": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", - "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", - "dev": true + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", + "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -3552,11 +12236,18 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -3565,7 +12256,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -3581,7 +12271,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -3590,7 +12279,6 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3608,7 +12296,6 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3622,7 +12309,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3635,11 +12321,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", + "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", + "dependencies": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object.hasown": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", - "dev": true, "dependencies": { "define-properties": "^1.1.4", "es-abstract": "^1.20.4" @@ -3652,7 +12354,6 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -3665,20 +12366,72 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -3695,7 +12448,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -3710,7 +12462,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -3721,6 +12472,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3749,11 +12529,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -3762,7 +12563,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3771,7 +12571,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -3781,6 +12580,11 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "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": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -3789,17 +12593,173 @@ "node": ">=8" } }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "engines": { + "node": ">=4" + } }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "dev": true, + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "funding": [ { "type": "opencollective", @@ -3808,14 +12768,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -3823,28 +12779,1230 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-browser-comments": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz", + "integrity": "sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==", + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "browserslist": ">=4", + "postcss": ">=8" + } + }, + "node_modules/postcss-calc": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", + "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", + "dependencies": { + "postcss-selector-parser": "^6.0.9", + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-colormin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz", + "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "colord": "^2.9.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-convert-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz", + "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", + "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-discard-comments": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz", + "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz", + "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-empty": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz", + "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz", + "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-flexbugs-fixes": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz", + "integrity": "sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==", + "peerDependencies": { + "postcss": "^8.1.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz", + "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^5.1.1" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-merge-rules": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz", + "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^3.1.0", + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz", + "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz", + "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==", + "dependencies": { + "colord": "^2.9.1", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-params": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz", + "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==", + "dependencies": { + "browserslist": "^4.21.4", + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz", + "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nested": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz", + "integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-normalize": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-10.0.1.tgz", + "integrity": "sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==", + "dependencies": { + "@csstools/normalize.css": "*", + "postcss-browser-comments": "^4", + "sanitize.css": "*" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "browserslist": ">= 4", + "postcss": ">= 8" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz", + "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==", + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz", + "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz", + "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz", + "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-string": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz", + "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz", + "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz", + "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz", + "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==", + "dependencies": { + "normalize-url": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz", + "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz", + "integrity": "sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==", + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-ordered-values": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz", + "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==", + "dependencies": { + "cssnano-utils": "^3.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz", + "integrity": "sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==", + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.1.1", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.13", + "browserslist": "^4.21.4", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.1.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.10", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "postcss-env-function": "^4.0.6", + "postcss-focus-visible": "^6.0.4", + "postcss-focus-within": "^5.0.4", + "postcss-font-variant": "^5.0.0", + "postcss-gap-properties": "^3.0.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.2.0", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz", + "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==", + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz", + "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", + "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz", + "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^2.7.0" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/postcss-svgo/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/postcss-svgo/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==" + }, + "node_modules/postcss-svgo/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/postcss-svgo/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz", + "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==", + "dependencies": { + "postcss-selector-parser": "^6.0.5" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "engines": { "node": ">= 0.8.0" } }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "engines": { - "node": ">=10.13.0" + "node": ">=6" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" } }, "node_modules/prop-types": { @@ -3862,20 +14020,71 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, "engines": { "node": ">=6" } }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -3891,6 +14100,74 @@ } ] }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -3902,6 +14179,128 @@ "node": ">=0.10.0" } }, + "node_modules/react-app-polyfill": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz", + "integrity": "sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==", + "dependencies": { + "core-js": "^3.19.2", + "object-assign": "^4.1.1", + "promise": "^8.1.0", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.9", + "whatwg-fetch": "^3.6.2" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-dev-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/react-dev-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/react-dev-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/react-dev-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/react-dev-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -3914,6 +14313,11 @@ "react": "^18.2.0" } }, + "node_modules/react-error-overlay": { + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" + }, "node_modules/react-i18next": { "version": "11.18.6", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", @@ -3952,20 +14356,19 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "dev": true, + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", + "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "engines": { "node": ">=0.10.0" } }, "node_modules/react-router": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.11.2.tgz", - "integrity": "sha512-74z9xUSaSX07t3LM+pS6Un0T55ibUE/79CzfZpy5wsPDZaea1F8QkrsiyRnA2YQ7LwE/umaydzXZV80iDCPkMg==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.2.tgz", + "integrity": "sha512-lF7S0UmXI5Pd8bmHvMdPKI4u4S5McxmHnzJhrYi9ZQ6wE+DA8JN5BzVC5EEBuduWWDaiJ8u6YhVOCmThBli+rw==", "dependencies": { - "@remix-run/router": "1.6.2" + "@remix-run/router": "1.3.3" }, "engines": { "node": ">=14" @@ -3975,12 +14378,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.11.2.tgz", - "integrity": "sha512-JNbKtAeh1VSJQnH6RvBDNhxNwemRj7KxCzc5jb7zvDSKRnPWIFj9pO+eXqjM69gQJ0r46hSz1x4l9y0651DKWw==", + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.2.tgz", + "integrity": "sha512-N/oAF1Shd7g4tWy+75IIufCGsHBqT74tnzHQhbiUTYILYF0Blk65cg+HPZqwC+6SqEyx033nKqU7by38v3lBZg==", "dependencies": { - "@remix-run/router": "1.6.2", - "react-router": "6.11.2" + "@remix-run/router": "1.3.3", + "react-router": "6.8.2" }, "engines": { "node": ">=14" @@ -3990,6 +14393,78 @@ "react-dom": ">=16.8" } }, + "node_modules/react-scripts": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", + "dependencies": { + "@babel/core": "^7.16.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", + "react-refresh": "^0.11.0", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "bin": { + "react-scripts": "bin/react-scripts.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + }, + "peerDependencies": { + "react": ">= 16", + "typescript": "^3.2.1 || ^4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -4005,20 +14480,91 @@ "react-dom": ">=16.6.0" } }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/regenerator-transform": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", + "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", - "dev": true, + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -4027,12 +14573,99 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.1.tgz", + "integrity": "sha512-nCOzW2V/X15XpLsK2rlgdwrysrBq+AauCn+omItIz4R1pIcmeot5zvjdmOBRLzEH/CkC6IxMJVmxDe3QcMuNVQ==", "dependencies": { - "is-core-module": "^2.11.0", + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4043,6 +14676,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -4051,11 +14703,82 @@ "node": ">=4" } }, + "node_modules/resolve-url-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz", + "integrity": "sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^7.0.35", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=8.9" + }, + "peerDependencies": { + "rework": "1.0.1", + "rework-visit": "1.0.0" + }, + "peerDependenciesMeta": { + "rework": { + "optional": true + }, + "rework-visit": { + "optional": true + } + } + }, + "node_modules/resolve-url-loader/node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" + }, + "node_modules/resolve-url-loader/node_modules/postcss": { + "version": "7.0.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", + "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", + "dependencies": { + "picocolors": "^0.2.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/resolve-url-loader/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/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4065,7 +14788,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -4077,26 +14799,78 @@ } }, "node_modules/rollup": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", - "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", - "dev": true, + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" + "node": ">=10.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/rollup-plugin-terser/node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/rollup-plugin-terser/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -4115,11 +14889,29 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -4129,6 +14921,69 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize.css": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", + "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" + }, + "node_modules/sass-loader": { + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/scheduler": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", @@ -4137,20 +14992,211 @@ "loose-envify": "^1.1.0" } }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -4162,16 +15208,22 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.0.tgz", + "integrity": "sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -4181,6 +15233,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -4193,11 +15278,92 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/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/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility" + }, "node_modules/stack-generator": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", @@ -4206,6 +15372,25 @@ "stackframe": "^1.3.4" } }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "engines": { + "node": ">=8" + } + }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -4238,11 +15423,18 @@ "stacktrace-gps": "^3.0.4" } }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, "dependencies": { "internal-slot": "^1.0.4" }, @@ -4250,11 +15442,53 @@ "node": ">= 0.4" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-natural-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", + "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/string.prototype.matchall": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -4269,28 +15503,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/string.prototype.trimend": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -4304,7 +15520,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -4314,11 +15529,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dependencies": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4327,19 +15554,33 @@ } }, "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "engines": { - "node": ">=4" + "node": ">=8" + } + }, + "node_modules/strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" } }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "engines": { "node": ">=8" }, @@ -4347,10 +15588,40 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylehacks": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz", + "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==", + "dependencies": { + "browserslist": "^4.21.4", + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >=14.0" + }, + "peerDependencies": { + "postcss": "^8.2.15" + } + }, "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", + "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" }, "node_modules/supports-color": { "version": "5.5.0", @@ -4363,6 +15634,37 @@ "node": ">=4" } }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -4374,11 +15676,277 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==" + }, + "node_modules/svgo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz", + "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==", + "deprecated": "This SVGO version is no longer supported. Upgrade to v2.x.x.", + "dependencies": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.37", + "csso": "^4.0.2", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz", + "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^3.2.1", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "node_modules/svgo/node_modules/css-what": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz", + "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/svgo/node_modules/domutils/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==" + }, + "node_modules/svgo/node_modules/nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dependencies": { + "boolbase": "~1.0.0" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, + "node_modules/tailwindcss": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz", + "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==", + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.0.9", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "6.0.0", + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/tailwindcss/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tempy": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz", + "integrity": "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==", + "dependencies": { + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.16.5", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.5.tgz", + "integrity": "sha512-qcwfg4+RZa3YvlFh0qjifnzBHjKGNbtDo9yivMqMFDy9Q6FSaQWSB/j1xKhsoUFJIqDOM3TsN6D5xbrMrFcHbg==", + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" + }, + "node_modules/throat": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", + "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==" }, "node_modules/throttle-debounce": { "version": "2.3.0", @@ -4388,6 +15956,16 @@ "node": ">=8" } }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -4396,16 +15974,61 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, + "node_modules/tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==" + }, "node_modules/tsconfig-paths": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dev": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -4417,7 +16040,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, "dependencies": { "minimist": "^1.2.0" }, @@ -4425,11 +16047,42 @@ "json5": "lib/cli.js" } }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -4437,11 +16090,18 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "engines": { "node": ">=10" }, @@ -4449,11 +16109,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typed-array-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -4463,11 +16134,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -4478,11 +16169,87 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==" + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", - "dev": true, + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -4491,10 +16258,6 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -4502,7 +16265,7 @@ "picocolors": "^1.0.0" }, "bin": { - "update-browserslist-db": "cli.js" + "browserslist-lint": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -4512,57 +16275,86 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } }, - "node_modules/vite": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.8.tgz", - "integrity": "sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ==", - "dev": true, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { - "vite": "bin/vite.js" + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", + "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" }, "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } + "node": ">=10.12.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" } }, "node_modules/void-elements": { @@ -4573,10 +16365,419 @@ "node": ">=0.10.0" } }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "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" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "engines": { + "node": ">=10.4" + } + }, + "node_modules/webpack": { + "version": "5.75.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", + "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz", + "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-manifest-plugin": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz", + "integrity": "sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==", + "dependencies": { + "tapable": "^2.0.0", + "webpack-sources": "^2.2.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "peerDependencies": { + "webpack": "^4.44.2 || ^5.47.0" + } + }, + "node_modules/webpack-manifest-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/webpack-manifest-plugin/node_modules/webpack-sources": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz", + "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==", + "dependencies": { + "source-list-map": "^2.0.1", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "node_modules/whatwg-url": { "version": "5.0.0", @@ -4587,11 +16788,15 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/whatwg-url/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -4606,7 +16811,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -4622,7 +16826,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -4637,7 +16840,6 @@ "version": "1.1.9", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", - "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -4657,22 +16859,416 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/workbox-background-sync": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.5.4.tgz", + "integrity": "sha512-0r4INQZMyPky/lj4Ou98qxcThrETucOde+7mRGJl13MPJugQNKeZQOdIJe/1AchOP23cTqHcN/YVpD6r8E6I8g==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-broadcast-update": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.5.4.tgz", + "integrity": "sha512-I/lBERoH1u3zyBosnpPEtcAVe5lwykx9Yg1k6f8/BGEPGaMMgZrwVrqL1uA9QZ1NGGFoyE6t9i7lBjOlDhFEEw==", + "dependencies": { + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-build": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-6.5.4.tgz", + "integrity": "sha512-kgRevLXEYvUW9WS4XoziYqZ8Q9j/2ziJYEtTrjdz5/L/cTUa2XfyMP2i7c3p34lgqJ03+mTiz13SdFef2POwbA==", + "dependencies": { + "@apideck/better-ajv-errors": "^0.3.1", + "@babel/core": "^7.11.1", + "@babel/preset-env": "^7.11.0", + "@babel/runtime": "^7.11.2", + "@rollup/plugin-babel": "^5.2.0", + "@rollup/plugin-node-resolve": "^11.2.1", + "@rollup/plugin-replace": "^2.4.1", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", + "ajv": "^8.6.0", + "common-tags": "^1.8.0", + "fast-json-stable-stringify": "^2.1.0", + "fs-extra": "^9.0.1", + "glob": "^7.1.6", + "lodash": "^4.17.20", + "pretty-bytes": "^5.3.0", + "rollup": "^2.43.1", + "rollup-plugin-terser": "^7.0.0", + "source-map": "^0.8.0-beta.0", + "stringify-object": "^3.3.0", + "strip-comments": "^2.0.1", + "tempy": "^0.6.0", + "upath": "^1.2.0", + "workbox-background-sync": "6.5.4", + "workbox-broadcast-update": "6.5.4", + "workbox-cacheable-response": "6.5.4", + "workbox-core": "6.5.4", + "workbox-expiration": "6.5.4", + "workbox-google-analytics": "6.5.4", + "workbox-navigation-preload": "6.5.4", + "workbox-precaching": "6.5.4", + "workbox-range-requests": "6.5.4", + "workbox-recipes": "6.5.4", + "workbox-routing": "6.5.4", + "workbox-strategies": "6.5.4", + "workbox-streams": "6.5.4", + "workbox-sw": "6.5.4", + "workbox-window": "6.5.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/workbox-build/node_modules/@apideck/better-ajv-errors": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz", + "integrity": "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==", + "dependencies": { + "json-schema": "^0.4.0", + "jsonpointer": "^5.0.0", + "leven": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "ajv": ">=8" + } + }, + "node_modules/workbox-build/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/workbox-build/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/workbox-build/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/workbox-build/node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workbox-build/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/workbox-build/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/workbox-build/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "node_modules/workbox-cacheable-response": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.5.4.tgz", + "integrity": "sha512-DCR9uD0Fqj8oB2TSWQEm1hbFs/85hXXoayVwFKLVuIuxwJaihBsLsp4y7J9bvZbqtPJ1KlCkmYVGQKrBU4KAug==", + "dependencies": { + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-core": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.4.tgz", + "integrity": "sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q==" + }, + "node_modules/workbox-expiration": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.5.4.tgz", + "integrity": "sha512-jUP5qPOpH1nXtjGGh1fRBa1wJL2QlIb5mGpct3NzepjGG2uFFBn4iiEBiI9GUmfAFR2ApuRhDydjcRmYXddiEQ==", + "dependencies": { + "idb": "^7.0.1", + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-google-analytics": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.5.4.tgz", + "integrity": "sha512-8AU1WuaXsD49249Wq0B2zn4a/vvFfHkpcFfqAFHNHwln3jK9QUYmzdkKXGIZl9wyKNP+RRX30vcgcyWMcZ9VAg==", + "dependencies": { + "workbox-background-sync": "6.5.4", + "workbox-core": "6.5.4", + "workbox-routing": "6.5.4", + "workbox-strategies": "6.5.4" + } + }, + "node_modules/workbox-navigation-preload": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.5.4.tgz", + "integrity": "sha512-IIwf80eO3cr8h6XSQJF+Hxj26rg2RPFVUmJLUlM0+A2GzB4HFbQyKkrgD5y2d84g2IbJzP4B4j5dPBRzamHrng==", + "dependencies": { + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-precaching": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.5.4.tgz", + "integrity": "sha512-hSMezMsW6btKnxHB4bFy2Qfwey/8SYdGWvVIKFaUm8vJ4E53JAY+U2JwLTRD8wbLWoP6OVUdFlXsTdKu9yoLTg==", + "dependencies": { + "workbox-core": "6.5.4", + "workbox-routing": "6.5.4", + "workbox-strategies": "6.5.4" + } + }, + "node_modules/workbox-range-requests": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.5.4.tgz", + "integrity": "sha512-Je2qR1NXCFC8xVJ/Lux6saH6IrQGhMpDrPXWZWWS8n/RD+WZfKa6dSZwU+/QksfEadJEr/NfY+aP/CXFFK5JFg==", + "dependencies": { + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-recipes": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.5.4.tgz", + "integrity": "sha512-QZNO8Ez708NNwzLNEXTG4QYSKQ1ochzEtRLGaq+mr2PyoEIC1xFW7MrWxrONUxBFOByksds9Z4//lKAX8tHyUA==", + "dependencies": { + "workbox-cacheable-response": "6.5.4", + "workbox-core": "6.5.4", + "workbox-expiration": "6.5.4", + "workbox-precaching": "6.5.4", + "workbox-routing": "6.5.4", + "workbox-strategies": "6.5.4" + } + }, + "node_modules/workbox-routing": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.4.tgz", + "integrity": "sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg==", + "dependencies": { + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-strategies": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.4.tgz", + "integrity": "sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw==", + "dependencies": { + "workbox-core": "6.5.4" + } + }, + "node_modules/workbox-streams": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.5.4.tgz", + "integrity": "sha512-FXKVh87d2RFXkliAIheBojBELIPnWbQdyDvsH3t74Cwhg0fDheL1T8BqSM86hZvC0ZESLsznSYWw+Va+KVbUzg==", + "dependencies": { + "workbox-core": "6.5.4", + "workbox-routing": "6.5.4" + } + }, + "node_modules/workbox-sw": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.5.4.tgz", + "integrity": "sha512-vo2RQo7DILVRoH5LjGqw3nphavEjK4Qk+FenXeUsknKn14eCNedHOXWbmnvP4ipKhlE35pvJ4yl4YYf6YsJArA==" + }, + "node_modules/workbox-webpack-plugin": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.5.4.tgz", + "integrity": "sha512-LmWm/zoaahe0EGmMTrSLUi+BjyR3cdGEfU3fS6PN1zKFYbqAKuQ+Oy/27e4VSXsyIwAw8+QDfk1XHNGtZu9nQg==", + "dependencies": { + "fast-json-stable-stringify": "^2.1.0", + "pretty-bytes": "^5.4.1", + "upath": "^1.2.0", + "webpack-sources": "^1.4.3", + "workbox-build": "6.5.4" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "webpack": "^4.4.0 || ^5.9.0" + } + }, + "node_modules/workbox-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/workbox-webpack-plugin/node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/workbox-window": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-6.5.4.tgz", + "integrity": "sha512-HnLZJDwYBE+hpG25AQBO8RUWBJRaCsI9ksQJEp3aCOFCaG5kqaToAYXFRAHxzRluM2cQbGzdQF5rjKPWPA1fug==", + "dependencies": { + "@types/trusted-types": "^2.0.2", + "workbox-core": "6.5.4" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "1.10.2", @@ -4682,11 +17278,35 @@ "node": ">= 6" } }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/web/package.json b/web/package.json index c00e8c6..9e919ef 100644 --- a/web/package.json +++ b/web/package.json @@ -3,16 +3,14 @@ "version": "1.0.0", "private": true, "scripts": { - "start": "NODE_OPTIONS=\"--enable-source-maps\" vite", - "build": "vite build", - "serve": "vite preview", - "format": "prettier . --write", - "format:check": "prettier . --check", - "lint": "eslint --report-unused-disable-directives --ext .js,.jsx ./src/" + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" }, "dependencies": { - "@emotion/react": "^11.11.0", - "@emotion/styled": "^11.11.0", + "@emotion/react": "^11.8.2", + "@emotion/styled": "^11.8.1", "@mui/icons-material": "^5.4.2", "@mui/material": "latest", "dexie": "^3.2.1", @@ -27,21 +25,10 @@ "react-i18next": "^11.16.2", "react-infinite-scroll-component": "^6.1.0", "react-router-dom": "^6.2.2", + "react-scripts": "^5.0.0", "stacktrace-gps": "^3.0.4", "stacktrace-js": "^2.0.2" }, - "devDependencies": { - "@vitejs/plugin-react": "^4.0.0", - "eslint": "^8.41.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "prettier": "^2.8.8", - "vite": "^4.3.8" - }, "browserslist": { "production": [ ">0.2%", @@ -53,8 +40,5 @@ "last 1 firefox version", "last 1 safari version" ] - }, - "prettier": { - "printWidth": 140 } } diff --git a/web/public/config.js b/web/public/config.js index 2f46d65..30da691 100644 --- a/web/public/config.js +++ b/web/public/config.js @@ -6,14 +6,12 @@ // During web development, you may change values here for rapid testing. var config = { - base_url: window.location.origin, // Change to test against a different server - app_root: "/app", - enable_login: true, - enable_signup: true, - enable_payments: false, - enable_reservations: true, - enable_emails: true, - enable_calls: true, - billing_contact: "", - disallowed_topics: ["docs", "static", "file", "app", "account", "settings", "signup", "login", "v1"], + base_url: window.location.origin, // Change to test against a different server + app_root: "/app", + enable_login: true, + enable_signup: true, + enable_payments: true, + enable_reservations: true, + billing_contact: "", + disallowed_topics: ["docs", "static", "file", "app", "account", "settings", "signup", "login", "v1"] }; diff --git a/web/public/home.html b/web/public/home.html new file mode 100644 index 0000000..43007ca --- /dev/null +++ b/web/public/home.html @@ -0,0 +1,182 @@ + + + + + + ntfy.sh | Send push notifications to your phone via PUT/POST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Send push notifications to your phone or desktop via PUT/POST

+

+ ntfy (pronounce: notify) is a simple HTTP-based pub-sub notification service. + It allows you to send notifications to your phone or desktop via scripts from any computer, + entirely without signup, cost or setup. It's also open source if you want to run your own. +

+
+ + + + + + + +
+ +

Publishing messages

+

+ Publishing messages can be done via PUT or POST. Topics are created on the fly by subscribing or publishing to them. + Because there is no sign-up, the topic is essentially a password, so pick something that's not easily guessable. +

+

+ Here's an example showing how to publish a message using a POST request (via curl -d): +

+ + curl -d "Backup successful ๐Ÿ˜€" ntfy.sh/mytopic + +

+ There are more features related to publishing messages: You can set a + notification priority, a title, + and tag messages. + Here's an example using some of them together: +

+ + curl \
+   -H "Title: Unauthorized access detected" \
+   -H "Priority: urgent" \
+   -H "Tags: warning,skull" \
+   -d "Remote access to $(hostname) detected. Act right away." \
+   ntfy.sh/mytopic +
+

+ Here's what that looks like in the Android app: +

+
+ +
Urgent notification with pop-over
+
+ +

Subscribe to a topic

+

+ You can create and subscribe to a topic either using your phone, + in this web UI, or in your own app by subscribing via the API. +

+ +

Subscribe from your phone

+

+ Simply get the app and start publishing messages. To learn more about the app, + check out the documentation. +

+

+ + + +

+

+ Here's a video showing the app in action: +

+
+ +
Sending push notifications to your Android phone
+
+ +

Subscribe via web app

+

+ Subscribe to topics in the web app and receive messages as desktop notification. + It is available at ntfy.sh/app. +

+
+ +
ntfy web app, available at ntfy.sh/app
+
+ +

Subscribe using the API

+

+ There's a super simple API that you can use to integrate your own app. You can consume + a JSON stream, + an SSE/EventSource stream, + a plain text stream, + or via WebSockets. +

+

+ Here's an example for JSON. The connection stays open, so you can retrieve messages as they come in: +

+ + $ curl -s ntfy.sh/mytopic/json
+ {"id":"SLiKI64DOt","time":1635528757,"event":"open","topic":"mytopic"}
+ {"id":"hwQ2YpKdmg","time":1635528741,"event":"message","topic":"mytopic","message":"Hi!"}
+ {"id":"DGUDShMCsc","time":1635528787,"event":"keepalive","topic":"mytopic"}
+ ... +
+

+ Here's a short video demonstrating it in action: +

+
+ +
Subscribing to the JSON stream with curl
+
+ +

Check out the docs!

+

+ ntfy has so many more features and you can learn about all of them in the documentation + (I tried my very best to make it the best docs ever ๐Ÿ˜‰, not sure if I succeeded, hehe). +

+
+ +
Check out the documentation
+
+ +

100% open source & forever free

+

+ I love free software, and I'm doing this because it's fun. I have no bad intentions, and I will + never monetize or sell your information. This service will always stay + free and open. + You can read more in the FAQs and in the privacy policy. +

+ +
Made with โค๏ธ by Philipp C. Heckel
+
+ + + + diff --git a/web/public/index.html b/web/public/index.html new file mode 100644 index 0000000..4dd8ef2 --- /dev/null +++ b/web/public/index.html @@ -0,0 +1,44 @@ + + + + + ntfy web + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/web/public/static/css/app.css b/web/public/static/css/app.css index 213859c..12b105a 100644 --- a/web/public/static/css/app.css +++ b/web/public/static/css/app.css @@ -1,11 +1,10 @@ /* web app styling overrides */ -a, -a:visited { - color: #338574; +a, a:visited { + color: #338574; } a:hover { - text-decoration: none; - color: #317f6f; + text-decoration: none; + color: #317f6f; } diff --git a/web/public/static/css/fonts.css b/web/public/static/css/fonts.css index 2cf00a3..4245d0f 100644 --- a/web/public/static/css/fonts.css +++ b/web/public/static/css/fonts.css @@ -2,32 +2,36 @@ /* roboto-300 - latin */ @font-face { - font-family: "Roboto"; - font-style: normal; - font-weight: 300; - src: local(""), url("../fonts/roboto-v29-latin-300.woff2") format("woff2"); + font-family: 'Roboto'; + font-style: normal; + font-weight: 300; + src: local(''), + url('../fonts/roboto-v29-latin-300.woff2') format('woff2'); } /* roboto-regular - latin */ @font-face { - font-family: "Roboto"; - font-style: normal; - font-weight: 400; - src: local(""), url("../fonts/roboto-v29-latin-regular.woff2") format("woff2"); + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: local(''), + url('../fonts/roboto-v29-latin-regular.woff2') format('woff2'); } /* roboto-500 - latin */ @font-face { - font-family: "Roboto"; - font-style: normal; - font-weight: 500; - src: local(""), url("../fonts/roboto-v29-latin-500.woff2") format("woff2"); + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + src: local(''), + url('../fonts/roboto-v29-latin-500.woff2') format('woff2'); } /* roboto-700 - latin */ @font-face { - font-family: "Roboto"; - font-style: normal; - font-weight: 700; - src: local(""), url("../fonts/roboto-v29-latin-700.woff2") format("woff2"); + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + src: local(''), + url('../fonts/roboto-v29-latin-700.woff2') format('woff2'); } diff --git a/web/public/static/css/home.css b/web/public/static/css/home.css new file mode 100644 index 0000000..feeaa7e --- /dev/null +++ b/web/public/static/css/home.css @@ -0,0 +1,280 @@ +/* general styling */ + +html, body { + font-family: 'Roboto', sans-serif; + font-weight: 400; + font-size: 1.1em; + color: #444; + margin: 0; + padding: 0; +} + +html { + /* prevent scrollbar from repositioning website: + * https://www.w3docs.com/snippets/css/how-to-prevent-scrollbar-from-repositioning-web-page.html */ + overflow-y: scroll; +} + +a, a:visited { + color: #338574; +} + +a:hover { + text-decoration: none; + color: #317f6f; +} + +h1 { + margin-top: 35px; + margin-bottom: 30px; + font-size: 2.5em; + word-wrap: break-word; /* For very long topics */ + padding-right: 40px; /* For the X on the detail page */ + font-weight: 300; + color: #666; +} + +h2 { + margin-top: 30px; + margin-bottom: 5px; + font-size: 1.8em; + font-weight: 300; + color: #333; +} + +h3 { + margin-top: 25px; + margin-bottom: 5px; + font-size: 1.3em; + font-weight: 300; + color: #333; +} + +p { + margin-top: 10px; + margin-bottom: 20px; + line-height: 160%; + font-weight: 400; +} + +p.smallMarginBottom { + margin-bottom: 10px; +} + +b { + font-weight: 500; +} + +tt { + background: #eee; + padding: 2px 7px; + border-radius: 3px; +} + +code { + display: block; + background: #eee; + font-family: monospace; + padding: 20px; + border-radius: 3px; + margin-top: 10px; + margin-bottom: 20px; + overflow-x: auto; + white-space: nowrap; +} + +/* Main page */ + +#main { + max-width: 900px; + margin: 0 auto 50px auto; + padding: 0 10px; +} + +#error { + color: darkred; + font-style: italic; +} + +#ironicCenterTagDontFreakOut { + color: #666; +} + +/* Anchors */ + +.anchor .anchorLink { + color: #ccc; + text-decoration: none; + padding: 0 5px; + visibility: hidden; +} + +.anchor:hover .anchorLink { + visibility: visible; +} + +.anchor .anchorLink:hover { + color: #338574; + visibility: visible; +} + +/* Figures */ + +figure { + text-align: center; +} + +figure img, figure video { + filter: drop-shadow(3px 3px 3px #ccc); + border-radius: 7px; + max-width: 100%; +} + +figure video { + width: 100%; + max-height: 450px; +} + +figcaption { + text-align: center; + font-style: italic; + padding-top: 10px; +} + +/* Screenshots */ + +#screenshots { + text-align: center; +} + +#screenshots img { + height: 190px; + margin: 3px; + border-radius: 5px; + filter: drop-shadow(2px 2px 2px #ddd); +} + +#screenshots .nowrap { + white-space: nowrap; +} + +/* Lightbox; thanks to https://yossiabramov.com/blog/vanilla-js-lightbox */ + +.lightbox { + opacity: 0; + visibility: hidden; + position: fixed; + left:0; + right: 0; + top: 0; + bottom: 0; + z-index: -1; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.15s ease-in; +} + +.lightbox.show { + background-color: rgba(0,0,0, 0.75); + opacity: 1; + visibility: visible; + z-index: 1000; +} + +.lightbox img { + max-width: 90%; + max-height: 90%; + filter: drop-shadow(5px 5px 10px #222); + border-radius: 5px; +} + +.lightbox .close-lightbox { + cursor: pointer; + position: absolute; + top: 30px; + right: 30px; + width: 20px; + height: 20px; +} + +.lightbox .close-lightbox::after, +.lightbox .close-lightbox::before { + content: ''; + width: 3px; + height: 20px; + background-color: #ddd; + position: absolute; + border-radius: 5px; + transform: rotate(45deg); +} + +.lightbox .close-lightbox::before { + transform: rotate(-45deg); +} + +.lightbox .close-lightbox:hover::after, +.lightbox .close-lightbox:hover::before { + background-color: #fff; +} + +/* Header */ + +#header { + background: #338574; + height: 130px; +} + +#header #headerBox { + max-width: 900px; + margin: 0 auto; + padding: 0 10px; +} + +#header #logo { + margin-top: 23px; + float: left; +} + +#header #name { + float: left; + color: white; + font-size: 2.6em; + font-weight: 300; + margin: 35px 0 0 20px; +} + +#header ol { + list-style-type: none; + float: right; + margin-top: 80px; +} + +#header ol li { + display: inline-block; + margin: 0 10px; + font-weight: 400; +} + +#header ol li a, nav ol li a:visited { + color: white; + text-decoration: none; +} + +#header ol li a:hover { + text-decoration: underline; +} + +li { + padding: 4px 0; + margin: 4px 0; + font-size: 0.9em; +} + + +/* Hide top menu SMALL SCREEN */ +@media only screen and (max-width: 780px) { + #header ol { + display: none; + } +} diff --git a/web/public/static/images/favicon.ico b/web/public/static/images/favicon.ico deleted file mode 100644 index 857fa54..0000000 Binary files a/web/public/static/images/favicon.ico and /dev/null differ diff --git a/web/public/static/img/android-video-overview.mp4 b/web/public/static/img/android-video-overview.mp4 new file mode 100644 index 0000000..cf29509 Binary files /dev/null and b/web/public/static/img/android-video-overview.mp4 differ diff --git a/web/public/static/img/android-video-subscribe-api.mp4 b/web/public/static/img/android-video-subscribe-api.mp4 new file mode 100644 index 0000000..d73e5c6 Binary files /dev/null and b/web/public/static/img/android-video-subscribe-api.mp4 differ diff --git a/web/public/static/img/badge-appstore.png b/web/public/static/img/badge-appstore.png new file mode 100644 index 0000000..0b4ce1c Binary files /dev/null and b/web/public/static/img/badge-appstore.png differ diff --git a/web/public/static/img/badge-fdroid.png b/web/public/static/img/badge-fdroid.png new file mode 100644 index 0000000..9464d38 Binary files /dev/null and b/web/public/static/img/badge-fdroid.png differ diff --git a/web/public/static/img/badge-googleplay.png b/web/public/static/img/badge-googleplay.png new file mode 100644 index 0000000..36036d8 Binary files /dev/null and b/web/public/static/img/badge-googleplay.png differ diff --git a/web/public/static/img/favicon.png b/web/public/static/img/favicon.png new file mode 100644 index 0000000..92312fe Binary files /dev/null and b/web/public/static/img/favicon.png differ diff --git a/web/public/static/images/ntfy.png b/web/public/static/img/ntfy.png similarity index 100% rename from web/public/static/images/ntfy.png rename to web/public/static/img/ntfy.png diff --git a/.github/images/screenshot-curl.png b/web/public/static/img/screenshot-curl.png similarity index 100% rename from .github/images/screenshot-curl.png rename to web/public/static/img/screenshot-curl.png diff --git a/web/public/static/img/screenshot-docs.png b/web/public/static/img/screenshot-docs.png new file mode 100644 index 0000000..4345ded Binary files /dev/null and b/web/public/static/img/screenshot-docs.png differ diff --git a/web/public/static/img/screenshot-phone-add.jpg b/web/public/static/img/screenshot-phone-add.jpg new file mode 100644 index 0000000..f728ec9 Binary files /dev/null and b/web/public/static/img/screenshot-phone-add.jpg differ diff --git a/.github/images/screenshot-phone-detail.jpg b/web/public/static/img/screenshot-phone-detail.jpg similarity index 100% rename from .github/images/screenshot-phone-detail.jpg rename to web/public/static/img/screenshot-phone-detail.jpg diff --git a/.github/images/screenshot-phone-main.jpg b/web/public/static/img/screenshot-phone-main.jpg similarity index 100% rename from .github/images/screenshot-phone-main.jpg rename to web/public/static/img/screenshot-phone-main.jpg diff --git a/.github/images/screenshot-phone-notification.jpg b/web/public/static/img/screenshot-phone-notification.jpg similarity index 100% rename from .github/images/screenshot-phone-notification.jpg rename to web/public/static/img/screenshot-phone-notification.jpg diff --git a/web/public/static/img/screenshot-phone-popover.png b/web/public/static/img/screenshot-phone-popover.png new file mode 100644 index 0000000..31d1515 Binary files /dev/null and b/web/public/static/img/screenshot-phone-popover.png differ diff --git a/.github/images/screenshot-web-detail.png b/web/public/static/img/screenshot-web-detail.png similarity index 100% rename from .github/images/screenshot-web-detail.png rename to web/public/static/img/screenshot-web-detail.png diff --git a/web/public/static/js/home.js b/web/public/static/js/home.js new file mode 100644 index 0000000..80b1405 --- /dev/null +++ b/web/public/static/js/home.js @@ -0,0 +1,84 @@ + +/* All the things */ + +let currentUrl = window.location.hostname; +if (window.location.port) { + currentUrl += ':' + window.location.port +} + +/* Screenshots */ +const lightbox = document.getElementById("lightbox"); + +const showScreenshotOverlay = (e, el, index) => { + lightbox.classList.add('show'); + document.addEventListener('keydown', nextScreenshotKeyboardListener); + return showScreenshot(e, index); +}; + +const showScreenshot = (e, index) => { + const actualIndex = resolveScreenshotIndex(index); + lightbox.innerHTML = '
' + screenshots[actualIndex].innerHTML; + lightbox.querySelector('img').onclick = (e) => { return showScreenshot(e,actualIndex+1); }; + currentScreenshotIndex = actualIndex; + e.stopPropagation(); + return false; +}; + +const nextScreenshot = (e) => { + return showScreenshot(e, currentScreenshotIndex+1); +}; + +const previousScreenshot = (e) => { + return showScreenshot(e, currentScreenshotIndex-1); +}; + +const resolveScreenshotIndex = (index) => { + if (index < 0) { + return screenshots.length - 1; + } else if (index > screenshots.length - 1) { + return 0; + } + return index; +}; + +const hideScreenshotOverlay = (e) => { + lightbox.classList.remove('show'); + document.removeEventListener('keydown', nextScreenshotKeyboardListener); +}; + +const nextScreenshotKeyboardListener = (e) => { + switch (e.keyCode) { + case 37: + previousScreenshot(e); + break; + case 39: + nextScreenshot(e); + break; + } +}; + +let currentScreenshotIndex = 0; +const screenshots = [...document.querySelectorAll("#screenshots a")]; +screenshots.forEach((el, index) => { + el.onclick = (e) => { return showScreenshotOverlay(e, el, index); }; +}); + +lightbox.onclick = hideScreenshotOverlay; + +// Add anchor links +document.querySelectorAll('.anchor').forEach((el) => { + if (el.hasAttribute('id')) { + const id = el.getAttribute('id'); + const anchor = document.createElement('a'); + anchor.innerHTML = `#`; + el.appendChild(anchor); + } +}); + +// Change ntfy.sh url and protocol to match self-hosted one +document.querySelectorAll('.ntfyUrl').forEach((el) => { + el.innerHTML = currentUrl; +}); +document.querySelectorAll('.ntfyProtocol').forEach((el) => { + el.innerHTML = window.location.protocol + "//"; +}); diff --git a/web/public/static/langs/ar.json b/web/public/static/langs/ar.json index 0c9fcc7..d663468 100644 --- a/web/public/static/langs/ar.json +++ b/web/public/static/langs/ar.json @@ -152,7 +152,7 @@ "publish_dialog_chip_delay_label": "ุชุฃุฎูŠุฑ ุงู„ุชุณู„ูŠู…", "subscribe_dialog_login_description": "ู‡ุฐุง ุงู„ู…ูˆุถูˆุน ู…ุญู…ูŠ ุจูƒู„ู…ุฉ ู…ุฑูˆุฑ. ุงู„ุฑุฌุงุก ุฅุฏุฎุงู„ ุงุณู… ุงู„ู…ุณุชุฎุฏู… ูˆูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ ู„ู„ุงุดุชุฑุงูƒ.", "subscribe_dialog_subscribe_button_cancel": "ุฅู„ุบุงุก", - "common_back": "ุงู„ุนูˆุฏุฉ", + "subscribe_dialog_login_button_back": "ุงู„ุนูˆุฏุฉ", "prefs_notifications_sound_play": "ุชุดุบูŠู„ ุงู„ุตูˆุช ุงู„ู…ุญุฏุฏ", "prefs_notifications_min_priority_title": "ุฃูˆู„ูˆูŠุฉ ุฏู†ูŠุง", "prefs_notifications_min_priority_max_only": "ุงู„ุฃูˆู„ูˆูŠุฉ ุงู„ู‚ุตูˆู‰ ูู‚ุท", @@ -214,8 +214,8 @@ "account_delete_description": "ุงุญุฐู ุญุณุงุจูƒ ู†ู‡ุงุฆูŠุง", "account_delete_dialog_label": "ูƒู„ู…ุฉ ุงู„ู…ุฑูˆุฑ", "account_upgrade_dialog_title": "ุชุบูŠูŠุฑ ูุฆุฉ ุงู„ุญุณุงุจ", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} ุฑุณุงุฆู„ ูŠูˆู…ูŠุฉ", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} ู…ู† ุฑุณุงุฆู„ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ูŠูˆู…ูŠุฉ", + "account_upgrade_dialog_tier_features_messages": "{{messages}} ุฑุณุงุฆู„ ูŠูˆู…ูŠุฉ", + "account_upgrade_dialog_tier_features_emails": "{{emails}} ู…ู† ุฑุณุงุฆู„ ุงู„ุจุฑูŠุฏ ุงู„ุฅู„ูƒุชุฑูˆู†ูŠ ุงู„ูŠูˆู…ูŠุฉ", "account_upgrade_dialog_button_cancel": "ุฅู„ุบุงุก", "account_upgrade_dialog_button_pay_now": "ุงุฏูุน ุงู„ุขู† ูˆุงุดุชุฑูƒ", "account_upgrade_dialog_button_cancel_subscription": "ุฅู„ุบุงุก ุงู„ุงุดุชุฑุงูƒ", @@ -225,7 +225,7 @@ "account_tokens_table_expires_header": "ุชู†ุชู‡ูŠ ู…ุฏุฉ ุตู„ุงุญูŠุชู‡ ููŠ", "account_tokens_table_never_expires": "ู„ุง ุชู†ุชู‡ูŠ ุตู„ุงุญูŠุชู‡ุง ุฃุจุฏุง", "account_tokens_table_current_session": "ุฌู„ุณุฉ ุงู„ู…ุชุตูุญ ุงู„ุญุงู„ูŠุฉ", - "common_copy_to_clipboard": "ุงู†ุณุฎ ุฅู„ู‰ ุงู„ุญุงูุธุฉ", + "account_tokens_table_copy_to_clipboard": "ุงู†ุณุฎ ุฅู„ู‰ ุงู„ุญุงูุธุฉ", "account_tokens_table_cannot_delete_or_edit": "ู„ุง ูŠู…ูƒู† ุชุญุฑูŠุฑ ุฃูˆ ุญุฐู ุงู„ุฑู…ุฒ ุงู„ู…ู…ูŠุฒ ู„ู„ุฌู„ุณุฉ ุงู„ุญุงู„ูŠุฉ", "account_tokens_table_create_token_button": "ุฅู†ุดุงุก ุฑู…ุฒ ู…ู…ูŠุฒ ู„ู„ูˆุตูˆู„", "account_tokens_table_last_origin_tooltip": "ู…ู† ุนู†ูˆุงู† IP {{ip}}ุŒ ุงู†ู‚ุฑ ู„ู„ุจุญุซ", @@ -314,7 +314,7 @@ "publish_dialog_progress_uploading_detail": "ุชุญู…ูŠู„ {{loaded}}/{{total}} ({{percent}}ูช) โ€ฆ", "account_basics_tier_interval_monthly": "ุดู‡ุฑูŠุง", "account_basics_tier_interval_yearly": "ุณู†ูˆูŠุง", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} ู…ูˆุงุถูŠุน ู…ุญุฌูˆุฒุฉ", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} ู…ูˆุงุถูŠุน ู…ุญุฌูˆุฒุฉ", "account_upgrade_dialog_billing_contact_website": "ู„ู„ุฃุณุฆู„ุฉ ุงู„ู…ุชุนู„ู‚ุฉ ุจุงู„ููˆุชุฑุฉุŒ ูŠุฑุฌู‰ ุงู„ุฑุฌูˆุน ุฅู„ู‰ ู…ูˆู‚ุนู†ุง ุนู„ู‰ ุงู„ูˆูŠุจ.", "prefs_notifications_min_priority_description_x_or_higher": "ุฅุธู‡ุงุฑ ุงู„ุฅุดุนุงุฑุงุช ุฅุฐุง ูƒุงู†ุช ุงู„ุฃูˆู„ูˆูŠุฉ {{number}} ({{name}}) ุฃูˆ ุฃุนู„ู‰", "account_upgrade_dialog_billing_contact_email": "ู„ู„ุฃุณุฆู„ุฉ ุงู„ู…ุชุนู„ู‚ุฉ ุจุงู„ููˆุชุฑุฉุŒ ุงู„ุฑุฌุงุก ุงู„ุงุชุตุงู„ ุจู†ุง ู…ุจุงุดุฑุฉ.", diff --git a/web/public/static/langs/bg.json b/web/public/static/langs/bg.json index a040b01..5f41735 100644 --- a/web/public/static/langs/bg.json +++ b/web/public/static/langs/bg.json @@ -104,7 +104,7 @@ "subscribe_dialog_subscribe_topic_placeholder": "ะ˜ะผะต ะฝะฐ ั‚ะตะผะฐั‚ะฐ, ะฝะฐะฟั€. phils_alerts", "subscribe_dialog_subscribe_use_another_label": "ะ˜ะทะฟะพะปะทะฒะฐะฝะต ะฝะฐ ะดั€ัƒะณ ััŠั€ะฒัŠั€", "subscribe_dialog_login_username_label": "ะŸะพั‚ั€ะตะฑะธั‚ะตะป, ะฝะฐะฟั€. phil", - "common_back": "ะะฐะทะฐะด", + "subscribe_dialog_login_button_back": "ะะฐะทะฐะด", "subscribe_dialog_subscribe_button_cancel": "ะžั‚ะบะฐะท", "subscribe_dialog_login_description": "ะขะตะผะฐั‚ะฐ ะต ะทะฐั‰ะธั‚ะตะฝะฐ. ะ—ะฐ ะดะฐ ัะต ะฐะฑะพะฝะธั€ะฐั‚ะต ะฒัŠะฒะตะดะตั‚ะต ะฟะพั‚ั€ะตะฑะธั‚ะตะป ะธ ะฟะฐั€ะพะปะฐ.", "subscribe_dialog_subscribe_button_subscribe": "ะะฑะพะฝะธั€ะฐะฝะต", @@ -248,44 +248,5 @@ "account_basics_tier_free": "ะฑะตะทะฟะปะฐั‚ะตะฝ", "account_basics_tier_basic": "ะฑะฐะทะพะฒ", "account_basics_tier_change_button": "ะŸั€ะพะผะตะฝัะฝะต", - "account_basics_tier_paid_until": "ะะฑะพะฝะฐะผะตะฝั‚ัŠั‚ ะต ะฟะปะฐั‚ะตะฝ ะดะพ {{date}} ะธ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ั‰ะต ัะต ะฟะพะดะฝะพะฒะธ", - "account_usage_attachment_storage_title": "ะฅั€ะฐะฝะธะปะธั‰ะต ะทะฐ ะฟั€ะธะบะฐั‡ะตะฝะธ ั„ะฐะนะปะพะฒะต", - "account_delete_dialog_button_cancel": "ะžั‚ะบะฐะท", - "account_upgrade_dialog_interval_monthly": "ะœะตัะตั‡ะฝะพ", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} ั€ะตะทะตั€ะฒะธั€ะฐะฝะธ ั‚ะตะผะธ", - "account_upgrade_dialog_tier_features_no_reservations": "ะัะผะฐ ั€ะตะทะตั€ะฒะธั€ะฐะฝะธ ั‚ะตะผะธ", - "account_tokens_dialog_button_cancel": "ะžั‚ะบะฐะท", - "account_delete_title": "ะŸั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฟั€ะพั„ะธะปะฐ", - "account_upgrade_dialog_title": "ะŸั€ะพะผัะฝะฐ ะฝะธะฒะพั‚ะพ ะฝะฐ ะฟั€ะพั„ะธะปะฐ", - "account_usage_emails_title": "ะ˜ะทะฟั€ะฐั‚ะตะฝะธ ััŠะพะฑั‰ะตะฝะธั", - "account_usage_reservations_title": "ะ ะตะทะตั€ะฒะธั€ะฐะฝะธ ั‚ะตะผะธ", - "account_usage_reservations_none": "ะัะผะฐ ั€ะตะทะตั€ะฒะธั€ะฐะฝะธ ั‚ะตะผะธ", - "account_usage_cannot_create_portal_session": "ะŸะพั€ั‚ะฐะปัŠั‚ ะทะฐ ั€ะฐะทะฟะปะฐั‰ะฐะฝะต ะฝะต ะผะพะถะต ะดะฐ ะฑัŠะดะต ะพั‚ะฒะพั€ะตะฝ", - "account_upgrade_dialog_interval_yearly": "ะ“ะพะดะธัˆะฝะพ", - "account_delete_description": "ะ‘ะตะทะฒัŠะทะฒั€ะฐั‚ะฝะพ ะฟั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฟั€ะพั„ะธะปะฐ", - "account_delete_dialog_button_submit": "ะ‘ะตะทะฒัŠะทะฒั€ะฐั‚ะฝะพ ะฟั€ะตะผะฐั…ะฒะฐะฝะต ะฝะฐ ะฟั€ะพั„ะธะปะฐ", - "account_upgrade_dialog_interval_yearly_discount_save": "ะพั‚ัั‚ัŠะฟะบะฐ {{discount}}%", - "account_upgrade_dialog_button_cancel": "ะžั‚ะบะฐะท", - "account_upgrade_dialog_button_redirect_signup": "ะ ะตะณะธัั‚ั€ะธั€ะฐะฝะต", - "account_tokens_table_label_header": "ะ•ั‚ะธะบะตั‚", - "prefs_reservations_edit_button": "ะะฐัั‚ั€ะพะนะบะธ ะฝะฐ ะดะพัั‚ัŠะฟะฐ", - "prefs_reservations_table_topic_header": "ะขะตะผะฐ", - "prefs_reservations_table_access_header": "ะ”ะพัั‚ัŠะฟ", - "prefs_reservations_dialog_topic_label": "ะขะตะผะฐ", - "prefs_reservations_dialog_access_label": "ะ”ะพัั‚ัŠะฟ", - "account_basics_password_dialog_current_password_incorrect": "ะ“ั€ะตัˆะฝะฐ ะฟะฐั€ะพะปะฐ", - "account_basics_tier_description": "ะะธะฒะพ ะฝะฐ ะฟั€ะพั„ะธะปะฐ", - "account_basics_tier_upgrade_button": "ะะฐะดะณั€ะฐะถะดะฐะฝะต ะดะพ Pro", - "account_usage_messages_title": "ะŸัƒะฑะปะธะบัƒะฒะฐะฝะธ ััŠะพะฑั‰ะตะฝะธั", - "account_tokens_table_last_access_header": "ะŸะพัะปะตะดะตะฝ ะดะพัั‚ัŠะฟ", - "account_basics_tier_payment_overdue": "ะ˜ะผะฐั‚ะต ะฟั€ะพัั€ะพั‡ะตะฝะพ ะทะฐะดัŠะปะถะตะฝะธะต. ะžะฑะฝะพะฒะตั‚ะต ะฝะฐั‡ะธะฝะฐ ะฝะฐ ะฟะปะฐั‰ะฐะฝะต, ะทะฐั‰ะพั‚ะพ ะฒ ะฟั€ะพั‚ะธะฒะตะฝ ัะปัƒั‡ะฐะน ัะบะพั€ะพ ะฟั€ะพั„ะธะปัŠั‚ ะฒะธ ั‰ะต ะทะฐะณัƒะฑะธ ะฟั€ะตะดะธะผัั‚ะฒะฐั‚ะฐ ะฝะฐ ะฐะฑะพะฝะฐะผะตะฝั‚ะฐ.", - "account_usage_basis_ip_description": "ะกั‚ะฐั‚ะธัั‚ะธะบะฐั‚ะฐ ะธ ะพะณั€ะฐะฝะธั‡ะตะฝะธัั‚ะฐ ะฝะฐ ะธะทะฟะพะปะทะฒะฐะฝะต ัะต ะพั‚ั‡ะธั‚ะฐั‚ ะฟะพ IP ะฐะดั€ะตั, ั‚ะฐะบะฐ ั‡ะต ะผะพะถะต ะดะฐ ะฑัŠะดะฐั‚ ัะฟะพะดะตะปะตะฝะธ ั ะดั€ัƒะณะธ ะฟะพั‚ั€ะตะฑะธั‚ะตะปะธ. ะŸะพะบะฐะทะฐะฝะธั‚ะต ะฟะพ-ะณะพั€ะต ะพะณั€ะฐะฝะธั‡ะตะฝะธั ัะฐ ะฟั€ะธะฑะปะธะทะธั‚ะตะปะฝะธ ะธ ัะต ะพัะฝะพะฒะฐะฒะฐั‚ ะฝะฐ ััŠั‰ะตัั‚ะฒัƒะฒะฐั‰ะธั‚ะต ะพะณั€ะฐะฝะธั‡ะตะฝะธั ะฝะฐ ะธะทะฟะพะปะทะฒะฐะฝะต.", - "account_delete_dialog_description": "ะขะพะฒะฐ ะดะตะนัั‚ะฒะธะต ั‰ะต ะดะพะฒะตะดะต ะดะพ ะฑะตะทะฒัŠะทะฒั€ะฐั‚ะฝะพั‚ะพ ะธะทั‚ั€ะธะฒะฐะฝะต ะฝะฐ ะฟั€ะพั„ะธะปะฐ ะฒะธ, ะฒะบะปัŽั‡ะธั‚ะตะปะฝะพ ะฝะฐ ะฒัะธั‡ะบะธ ะดะฐะฝะฝะธ, ะบะพะธั‚ะพ ัะต ััŠั…ั€ะฐะฝัะฒะฐั‚ ะฝะฐ ััŠั€ะฒัŠั€ะฐ. ะกะปะตะด ะธะทั‚ั€ะธะฒะฐะฝะตั‚ะพ ะฟะพั‚ั€ะตะฑะธั‚ะตะปัะบะพั‚ะพ ะฒะธ ะธะผะต ะฝัะผะฐ ะดะฐ ะฑัŠะดะต ะดะพัั‚ัŠะฟะฝะพ ะฒ ะฟั€ะพะดัŠะปะถะตะฝะธะต ะฝะฐ 7 ะดะฝะธ. ะะบะพ ะฝะฐะธัั‚ะธะฝะฐ ะธัะบะฐั‚ะต ะดะฐ ะฟั€ะพะดัŠะปะถะธั‚ะต, ะฟะพั‚ะฒัŠั€ะดะตั‚ะต ั ะฟะฐั€ะพะปะฐั‚ะฐ ัะธ ะฒ ะฟะพะปะตั‚ะพ ะฟะพ-ะดะพะปัƒ.", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} ั€ะตะทะตั€ะฒะธั€ะฐะฝะฐ ั‚ะตะผะฐ", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "ัะฟะตัั‚ะตั‚ะต ะดะพ {{discount}}%", - "account_delete_dialog_billing_warning": "ะ˜ะทั‚ั€ะธะฒะฐะฝะตั‚ะพ ะฝะฐ ะฟั€ะพั„ะธะปะฐ ะฝะตะทะฐะฑะฐะฒะฝะพ ะพั‚ะผะตะฝั ะธ ะฟะปะฐั‚ะตะฝะธั ะฐะฑะพะฝะฐะผะตะฝั‚. ะัะผะฐ ะดะฐ ะธะผะฐั‚ะต ะดะพัั‚ัŠะฟ ะดะพ ั‚ะฐะฑะปะพั‚ะพ ะทะฐ ะฟะปะฐั‰ะฐะฝะธั.", - "account_upgrade_dialog_cancel_warning": "ะขะพะฒะฐ ะดะตะนัั‚ะฒะธะต ั‰ะต ะฟั€ะตะบั€ะฐั‚ะธ ะฐะฑะพะฝะฐะผะตะฝั‚ะฐ ะธ ั‰ะต ะฟั€ะพะผะตะฝะธ ะฟั€ะพั„ะธะปะฐ ะฒะธ ะฝะฐ ะฝะตะฟะปะฐั‚ะตะฝ ะฝะฐ {{date}}. ะะฐ ั‚ะฐะทะธ ะดะฐั‚ะฐ ั€ะตะทะตั€ะฒะธั€ะฐะฝะธั‚ะต ั‚ะตะผะธ, ะบะฐะบั‚ะพ ะธ ะฟะฐะทะตะฝะธั‚ะต ะฝะฐ ััŠั€ะฒัŠั€ะฐ ััŠะพะฑั‰ะตะฝะธั, ั‰ะต ะฑัŠะดะฐั‚ ะฟั€ะตะผะฐั…ะฝะฐั‚ะธ.", - "account_upgrade_dialog_proration_info": "ะŸั€ะตะธะทั‡ะธัะปัะฒะฐะฝะต ะฝะฐ ะฟะปะฐั‰ะฐะฝะธั: ะŸั€ะธ ะฝะฐะดะณั€ะฐะถะดะฐะฝะต ะผะตะถะดัƒ ะฟะปะฐั‚ะตะฝะธ ะฟะปะฐะฝะพะฒะต ั€ะฐะทะปะธะบะฐั‚ะฐ ะฒ ั†ะตะฝะฐั‚ะฐ ั‰ะต ะฑัŠะดะต ะฝะฐั‡ะธัะปะตะฝะฐ ะฝะตะทะฐะฑะฐะฒะฝะพ. ะŸั€ะธ ะฟั€ะตะผะธะฝะฐะฒะฐะฝะต ะบัŠะผ ะฟะพ-ะตะฒั‚ะธะฝ ะฟะปะฐะฝ ะฝะฐะดะฟะปะฐั‚ะตะฝะฐั‚ะฐ ััƒะผะฐ ั‰ะต ะฑัŠะดะต ะธะทะฟะพะปะทะฒะฐะฝะฐ ะทะฐ ะฟะปะฐั‰ะฐะฝะต ะทะฐ ะฑัŠะดะตั‰ะธ ะฟะตั€ะธะพะดะธ.", - "account_basics_tier_manage_billing_button": "ะฃะฟั€ะฐะฒะปะตะฝะธะต ะฝะฐ ะฟะปะฐั‰ะฐะฝะธัั‚ะฐ", - "account_basics_tier_canceled_subscription": "ะะฑะพะฝะฐะผะตะฝั‚ัŠั‚ ะต ะฟั€ะตะบั€ะฐั‚ะตะฝ ะธ ะฟั€ะพั„ะธะปัŠั‚ ั‰ะต ะฑัŠะดะต ะฟั€ะพะผะตะฝะตะฝ ะฝะฐ ะฝะตะฟะปะฐั‚ะตะฝ ะฝะฐ {{date}}." + "account_basics_tier_paid_until": "ะะฑะพะฝะฐะผะตะฝั‚ัŠั‚ ะต ะฟะปะฐั‚ะตะฝ ะดะพ {{date}} ะธ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ั‰ะต ัะต ะฟะพะดะฝะพะฒะธ" } diff --git a/web/public/static/langs/cs.json b/web/public/static/langs/cs.json index 6b967c8..032e8b7 100644 --- a/web/public/static/langs/cs.json +++ b/web/public/static/langs/cs.json @@ -91,7 +91,7 @@ "subscribe_dialog_subscribe_button_subscribe": "Pล™ihlรกsit odbฤ›r", "subscribe_dialog_login_username_label": "Uลพivatelskรฉ jmรฉno, napล™. phil", "subscribe_dialog_login_password_label": "Heslo", - "common_back": "Zpฤ›t", + "subscribe_dialog_login_button_back": "Zpฤ›t", "subscribe_dialog_login_button_login": "Pล™ihlรกsit se", "subscribe_dialog_error_user_not_authorized": "Uลพivatel {{username}} nenรญ autorizovรกn", "subscribe_dialog_error_user_anonymous": "anonymnฤ›", @@ -287,9 +287,9 @@ "account_upgrade_dialog_title": "Zmฤ›na รบrovnฤ› รบฤtu", "account_upgrade_dialog_proration_info": "Prohlรกลกenรญ: Pล™i pล™echodu mezi placenรฝmi รบrovnฤ›mi bude rozdรญl v cenฤ› zaรบฤtovรกn okamลพitฤ›. Pล™i pล™echodu na niลพลกรญ รบroveลˆ se zลฏstatek pouลพije na platbu za budoucรญ zรบฤtovacรญ obdobรญ.", "account_upgrade_dialog_reservations_warning_one": "Vybranรก รบroveลˆ umoลพลˆuje mรฉnฤ› rezervovanรฝch tรฉmat neลพ vaลกe aktuรกlnรญ รบroveลˆ. Neลพ zmฤ›nรญte svou รบroveลˆ, odstraลˆte alespoลˆ jednu rezervaci. Rezervace mลฏลพete odstranit v Nastavenรญ.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} rezervovanรฝch tรฉmat", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} dennรญch zprรกv", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} dennรญch e-mailลฏ", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} rezervovanรฝch tรฉmat", + "account_upgrade_dialog_tier_features_messages": "{{messages}} dennรญch zprรกv", + "account_upgrade_dialog_tier_features_emails": "{{emails}} dennรญch e-mailลฏ", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} na soubor", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} celkovรฝ รบloลพnรฝ prostor", "account_upgrade_dialog_tier_selected_label": "Vybrรกno", @@ -305,7 +305,7 @@ "account_tokens_table_expires_header": "Vyprลกรญ", "account_tokens_table_never_expires": "Nikdy nevyprลกรญ", "account_tokens_table_current_session": "Souฤasnรก relace prohlรญลพeฤe", - "common_copy_to_clipboard": "Kopรญrovรกnรญ do schrรกnky", + "account_tokens_table_copy_to_clipboard": "Kopรญrovรกnรญ do schrรกnky", "account_tokens_table_label_header": "Popisek", "account_tokens_table_cannot_delete_or_edit": "Nelze upravit nebo odstranit aktuรกlnรญ token relace", "account_tokens_table_create_token_button": "Vytvoล™it pล™รญstupovรฝ token", @@ -352,18 +352,5 @@ "account_upgrade_dialog_interval_yearly": "Roฤnรญ", "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} za rok. รšฤtuje se mฤ›sรญฤnฤ›.", "account_upgrade_dialog_billing_contact_email": "V pล™รญpadฤ› dotazลฏ tรฝkajรญcรญch se fakturace nรกs prosรญm kontaktujte pล™รญmo.", - "account_upgrade_dialog_billing_contact_website": "Otรกzky tรฝkajรญcรญ se fakturace naleznete na naลกich webovรฝch strรกnkรกch.", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} rezervovanรฉ tรฉma", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} dennรญ zprรกva", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} dennรญ e-mail", - "publish_dialog_call_label": "Telefonรกt", - "publish_dialog_call_reset": "Odstranit telefonรกt", - "publish_dialog_chip_call_label": "Telefonรกt", - "account_basics_phone_numbers_title": "Telefonnรญ ฤรญsla", - "account_basics_phone_numbers_dialog_description": "Pro oznรกmenรญ prostล™ednictvรญm tel. hovoru, musรญte pล™idat a ovฤ›ล™it alespoลˆ jedno telefonnรญ ฤรญslo. Ovฤ›ล™enรญ lze provรฉst pomocรญ SMS nebo telefonรกtu.", - "account_basics_phone_numbers_description": "K oznรกmenรญ telefonรกtem", - "account_basics_phone_numbers_no_phone_numbers_yet": "Zatรญm ลพรกdnรก telefonnรญ ฤรญsla", - "account_basics_phone_numbers_copied_to_clipboard": "Telefonnรญ ฤรญslo zkopรญrovรกno do schrรกnky", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "ลฝรกdnรก ovฤ›ล™enรก telefonnรญ ฤรญsla", - "publish_dialog_call_item": "Vytoฤit ฤรญslo {{number}}" + "account_upgrade_dialog_billing_contact_website": "Otรกzky tรฝkajรญcรญ se fakturace naleznete na naลกich webovรฝch strรกnkรกch." } diff --git a/web/public/static/langs/cy.json b/web/public/static/langs/cy.json deleted file mode 100644 index 68846b8..0000000 --- a/web/public/static/langs/cy.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "notifications_delete": "Dileu", - "action_bar_sign_in": "Mewngofnodi", - "notifications_copied_to_clipboard": "Wedi'i gopio i'r clipfwrdd", - "common_cancel": "Canslo", - "nav_button_account": "Cyfrif", - "common_save": "Arbed", - "common_add": "Ychwanegu", - "signup_title": "Creu cyfrif ntfy", - "signup_form_username": "Enw defnyddiwr", - "signup_form_password": "Cyfrinair", - "action_bar_logo_alt": "logo ntfy", - "action_bar_settings": "Gosodiadau", - "action_bar_profile_title": "Proffil", - "action_bar_profile_logout": "Allgofnodi", - "message_bar_publish": "Cyhoeddi neges", - "notifications_attachment_copy_url_button": "Copio URL", - "notifications_attachment_open_title": "Ewch i {{url}}", - "publish_dialog_base_url_label": "URL y Gwasanaeth", - "publish_dialog_priority_high": "Blaenoriaeth uchel", - "publish_dialog_title_label": "Teitl", - "publish_dialog_message_label": "Neges", - "publish_dialog_attach_label": "URL Atodiad", - "publish_dialog_filename_label": "Enw ffeil", - "publish_dialog_filename_placeholder": "Enw ffeil yr atodiad", - "action_bar_account": "Cyfrif", - "action_bar_unsubscribe": "Dad-danysgrifio", - "login_title": "Mewngofnodi i'ch cyfrif ntfy", - "login_form_button_submit": "Mewngofnodi", - "action_bar_change_display_name": "Newid enw arddangos", - "action_bar_profile_settings": "Gosodiadau", - "nav_button_settings": "Gosodiadau", - "nav_button_documentation": "Dogfennaeth", - "alert_not_supported_context_description": "Dim ond dros HTTPS y gellir derbyn cyhoeddiadau. Mae hyn yn gyfyngiad ar yr API Notifications.", - "notifications_attachment_open_button": "Agor atodiad", - "notifications_attachment_file_document": "dogfen arall", - "notifications_click_open_button": "Agor linc", - "publish_dialog_base_url_placeholder": "URL y Gwasanaeth, e.e. https://example.com", - "publish_dialog_attach_placeholder": "Atodi ffeil drwy URL, e.e. https://f-droid.org/F-Droid.apk", - "notifications_click_copy_url_button": "Copio linc", - "notifications_actions_open_url_title": "Ewch i {{url}}", - "publish_dialog_email_label": "Ebost" -} diff --git a/web/public/static/langs/da.json b/web/public/static/langs/da.json index c7477df..276e442 100644 --- a/web/public/static/langs/da.json +++ b/web/public/static/langs/da.json @@ -91,7 +91,7 @@ "publish_dialog_delay_label": "Forsinkelse", "publish_dialog_button_send": "Send", "subscribe_dialog_subscribe_button_subscribe": "Tilmeld", - "common_back": "Tilbage", + "subscribe_dialog_login_button_back": "Tilbage", "subscribe_dialog_login_username_label": "Brugernavn, f.eks. phil", "account_basics_title": "Konto", "subscribe_dialog_error_topic_already_reserved": "Emnet er allerede reserveret", @@ -201,18 +201,18 @@ "account_basics_password_dialog_current_password_label": "Nuvรฆrende kodeord", "account_basics_password_dialog_new_password_label": "Nyt kodeord", "notifications_loading": "Indlรฆser notifikationerโ€ฆ", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} daglige e-mails", + "account_upgrade_dialog_tier_features_emails": "{{emails}} daglige e-mails", "account_tokens_table_create_token_button": "Opret adgangstoken", "account_tokens_dialog_title_delete": "Slet adgangstoken", "publish_dialog_chip_email_label": "Videresend til e-mail", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} samlet lagerplads", "subscribe_dialog_subscribe_use_another_label": "Brug en anden server", "account_basics_tier_upgrade_button": "Opgrader til Pro", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} daglige beskeder", - "common_copy_to_clipboard": "Kopier til udklipsholder", + "account_upgrade_dialog_tier_features_messages": "{{messages}} daglige beskeder", + "account_tokens_table_copy_to_clipboard": "Kopier til udklipsholder", "prefs_reservations_edit_button": "Rediger emneadgang", "account_upgrade_dialog_title": "Skift kontoniveau", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reserverede emner", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} reserverede emner", "account_tokens_dialog_expires_never": "Token udlรธber aldrig", "account_tokens_table_current_session": "Nuvรฆrende browsersession", "account_tokens_dialog_title_edit": "Rediger adgangstoken", diff --git a/web/public/static/langs/de.json b/web/public/static/langs/de.json index 6343dee..f6a7361 100644 --- a/web/public/static/langs/de.json +++ b/web/public/static/langs/de.json @@ -94,7 +94,7 @@ "publish_dialog_delay_placeholder": "Auslieferung verzรถgern, z.B. {{unixTimestamp}}, {{relativeTime}}, oder \"{{naturalLanguage}}\" (nur Englisch)", "prefs_appearance_title": "Darstellung", "subscribe_dialog_login_password_label": "Kennwort", - "common_back": "Zurรผck", + "subscribe_dialog_login_button_back": "Zurรผck", "publish_dialog_chip_attach_url_label": "Datei von URL anhรคngen", "publish_dialog_chip_delay_label": "Auslieferung verzรถgern", "publish_dialog_chip_topic_label": "Thema รคndern", @@ -264,9 +264,9 @@ "account_upgrade_dialog_proration_info": "Anrechnung: Wenn Du auf einen hรถheren kostenpflichtigen Level wechselst wird die Differenz sofort berechnet. Beim Wechsel auf ein kleineres Level verwenden wir Dein Guthaben fรผr zukรผnftige Abrechnungsperioden.", "account_upgrade_dialog_reservations_warning_one": "Das gewรคhlte Level erlaubt weniger reservierte Themen als Dein aktueller Level. Bitte lรถschen vor dem Wechsel Deines Levels mindestens eine Reservierung. Du kannst Reservierungen in den Einstellungen lรถschen.", "account_upgrade_dialog_reservations_warning_other": "Das gewรคhlte Level erlaubt weniger reservierte Themen als Dein aktueller Level. Bitte lรถschen vor dem Wechsel Deines Levels mindestens {{count}} Reservierungen. Du kannst Reservierungen in den Einstellungen lรถschen.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reservierte Themen", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} Nachrichten pro Tag", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} Emails pro Tag", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} reservierte Themen", + "account_upgrade_dialog_tier_features_messages": "{{messages}} Nachrichten pro Tag", + "account_upgrade_dialog_tier_features_emails": "{{emails}} Emails pro Tag", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} pro Datei", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} gesamter Speicherplatz", "account_upgrade_dialog_tier_selected_label": "Ausgewรคhlt", @@ -284,7 +284,7 @@ "account_tokens_table_expires_header": "Verfรคllt", "account_tokens_table_never_expires": "Verfรคllt nie", "account_tokens_table_current_session": "Aktuelle Browser-Sitzung", - "common_copy_to_clipboard": "In die Zwischenablage kopieren", + "account_tokens_table_copy_to_clipboard": "In die Zwischenablage kopieren", "account_tokens_table_copied_to_clipboard": "Access-Token kopiert", "account_tokens_table_cannot_delete_or_edit": "Aktuelles Token kann nicht bearbeitet oder gelรถscht werden", "account_tokens_table_create_token_button": "Access-Token erzeugen", @@ -352,33 +352,5 @@ "account_basics_tier_interval_monthly": "monatlich", "account_upgrade_dialog_interval_monthly": "Monatlich", "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} pro Jahr. Monatlich abgerechnet.", - "account_upgrade_dialog_interval_yearly": "Jรคhrlich", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} tรคgliche Nachricht", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} reserviertes Thema", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} tรคgliche E-Mail", - "publish_dialog_call_label": "Telefonanruf", - "publish_dialog_call_item": "Telefonnummer {{number}} anrufen", - "publish_dialog_chip_call_label": "Telefonanruf", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "Keine verifizierten Telefonnummern", - "account_basics_phone_numbers_title": "Telefonnummern", - "account_basics_phone_numbers_copied_to_clipboard": "Telefonnummer wurde in die Zwischenablage kopiert", - "account_basics_phone_numbers_dialog_title": "Telefonnummer hinzufรผgen", - "account_upgrade_dialog_tier_features_calls_other": "{{calls}} Telefonanrufe pro Tag", - "account_upgrade_dialog_tier_features_no_calls": "Keine Telefonanrufe", - "publish_dialog_call_reset": "Telefonanruf entfernen", - "account_basics_phone_numbers_dialog_description": "Um die Benachrichtigung per Telefonanruf zu nutzen musst Du mindestens eine Telefonnummer hinzufรผgen und verifizieren. Die Verifizierung kann per SMS oder รผber einen Anruf erfolgen.", - "account_basics_phone_numbers_description": "Fรผr Telefon-Benachrichtigungen", - "account_basics_phone_numbers_no_phone_numbers_yet": "Noch keine Telefonnummern", - "account_basics_phone_numbers_dialog_number_label": "Telefonnummer", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_basics_phone_numbers_dialog_channel_call": "Anruf", - "account_basics_phone_numbers_dialog_number_placeholder": "z.B. +49123456789", - "account_basics_phone_numbers_dialog_verify_button_call": "Ruf mich an", - "account_basics_phone_numbers_dialog_verify_button_sms": "SMS senden", - "account_basics_phone_numbers_dialog_code_label": "Verifizierungs-Code", - "account_basics_phone_numbers_dialog_code_placeholder": "z.B. 123456", - "account_basics_phone_numbers_dialog_check_verification_button": "Code bestรคtigen", - "account_usage_calls_title": "Getรคtigte Anrufe", - "account_usage_calls_none": "Noch keine Anrufe mit diesem Account getรคtigt", - "account_upgrade_dialog_tier_features_calls_one": "{{calls}} Telefonanrufe pro Tag" + "account_upgrade_dialog_interval_yearly": "Jรคhrlich" } diff --git a/web/public/static/langs/en.json b/web/public/static/langs/en.json index 5d8a3a3..babdd1d 100644 --- a/web/public/static/langs/en.json +++ b/web/public/static/langs/en.json @@ -2,8 +2,6 @@ "common_cancel": "Cancel", "common_save": "Save", "common_add": "Add", - "common_back": "Back", - "common_copy_to_clipboard": "Copy to clipboard", "signup_title": "Create a ntfy account", "signup_form_username": "Username", "signup_form_password": "Password", @@ -129,9 +127,6 @@ "publish_dialog_email_label": "Email", "publish_dialog_email_placeholder": "Address to forward the notification to, e.g. phil@example.com", "publish_dialog_email_reset": "Remove email forward", - "publish_dialog_call_label": "Phone call", - "publish_dialog_call_item": "Call phone number {{number}}", - "publish_dialog_call_reset": "Remove phone call", "publish_dialog_attach_label": "Attachment URL", "publish_dialog_attach_placeholder": "Attach file by URL, e.g. https://f-droid.org/F-Droid.apk", "publish_dialog_attach_reset": "Remove attachment URL", @@ -143,8 +138,6 @@ "publish_dialog_other_features": "Other features:", "publish_dialog_chip_click_label": "Click URL", "publish_dialog_chip_email_label": "Forward to email", - "publish_dialog_chip_call_label": "Phone call", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "No verified phone numbers", "publish_dialog_chip_attach_url_label": "Attach file by URL", "publish_dialog_chip_attach_file_label": "Attach local file", "publish_dialog_chip_delay_label": "Delay delivery", @@ -172,6 +165,7 @@ "subscribe_dialog_login_description": "This topic is password-protected. Please enter username and password to subscribe.", "subscribe_dialog_login_username_label": "Username, e.g. phil", "subscribe_dialog_login_password_label": "Password", + "subscribe_dialog_login_button_back": "Back", "subscribe_dialog_login_button_login": "Login", "subscribe_dialog_error_user_not_authorized": "User {{username}} not authorized", "subscribe_dialog_error_topic_already_reserved": "Topic already reserved", @@ -188,21 +182,6 @@ "account_basics_password_dialog_confirm_password_label": "Confirm password", "account_basics_password_dialog_button_submit": "Change password", "account_basics_password_dialog_current_password_incorrect": "Password incorrect", - "account_basics_phone_numbers_title": "Phone numbers", - "account_basics_phone_numbers_dialog_description": "To use the call notification feature, you need to add and verify at least one phone number. Verification can be done via SMS or a phone call.", - "account_basics_phone_numbers_description": "For phone call notifications", - "account_basics_phone_numbers_no_phone_numbers_yet": "No phone numbers yet", - "account_basics_phone_numbers_copied_to_clipboard": "Phone number copied to clipboard", - "account_basics_phone_numbers_dialog_title": "Add phone number", - "account_basics_phone_numbers_dialog_number_label": "Phone number", - "account_basics_phone_numbers_dialog_number_placeholder": "e.g. +1222333444", - "account_basics_phone_numbers_dialog_verify_button_sms": "Send SMS", - "account_basics_phone_numbers_dialog_verify_button_call": "Call me", - "account_basics_phone_numbers_dialog_code_label": "Verification code", - "account_basics_phone_numbers_dialog_code_placeholder": "e.g. 123456", - "account_basics_phone_numbers_dialog_check_verification_button": "Confirm code", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_basics_phone_numbers_dialog_channel_call": "Call", "account_usage_title": "Usage", "account_usage_of_limit": "of {{limit}}", "account_usage_unlimited": "Unlimited", @@ -224,8 +203,6 @@ "account_basics_tier_manage_billing_button": "Manage billing", "account_usage_messages_title": "Published messages", "account_usage_emails_title": "Emails sent", - "account_usage_calls_title": "Phone calls made", - "account_usage_calls_none": "No phone calls can be made with this account", "account_usage_reservations_title": "Reserved topics", "account_usage_reservations_none": "No reserved topics for this account", "account_usage_attachment_storage_title": "Attachment storage", @@ -248,16 +225,10 @@ "account_upgrade_dialog_proration_info": "Proration: When upgrading between paid plans, the price difference will be charged immediately. When downgrading to a lower tier, the balance will be used to pay for future billing periods.", "account_upgrade_dialog_reservations_warning_one": "The selected tier allows fewer reserved topics than your current tier. Before changing your tier, please delete at least one reservation. You can remove reservations in the Settings.", "account_upgrade_dialog_reservations_warning_other": "The selected tier allows fewer reserved topics than your current tier. Before changing your tier, please delete at least {{count}} reservations. You can remove reservations in the Settings.", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} reserved topic", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reserved topics", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} reserved topics", "account_upgrade_dialog_tier_features_no_reservations": "No reserved topics", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} daily message", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} daily messages", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} daily email", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} daily emails", - "account_upgrade_dialog_tier_features_calls_one": "{{calls}} daily phone calls", - "account_upgrade_dialog_tier_features_calls_other": "{{calls}} daily phone calls", - "account_upgrade_dialog_tier_features_no_calls": "No phone calls", + "account_upgrade_dialog_tier_features_messages": "{{messages}} daily messages", + "account_upgrade_dialog_tier_features_emails": "{{emails}} daily emails", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per file", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} total storage", "account_upgrade_dialog_tier_price_per_month": "month", @@ -280,6 +251,7 @@ "account_tokens_table_expires_header": "Expires", "account_tokens_table_never_expires": "Never expires", "account_tokens_table_current_session": "Current browser session", + "account_tokens_table_copy_to_clipboard": "Copy to clipboard", "account_tokens_table_copied_to_clipboard": "Access token copied", "account_tokens_table_cannot_delete_or_edit": "Cannot edit or delete current session token", "account_tokens_table_create_token_button": "Create access token", diff --git a/web/public/static/langs/es.json b/web/public/static/langs/es.json index 62ecdaf..b19df52 100644 --- a/web/public/static/langs/es.json +++ b/web/public/static/langs/es.json @@ -81,7 +81,7 @@ "subscribe_dialog_login_description": "Este tรณpico estรก protegido por contraseรฑa. Por favor, introduzca su nombre de usuario y contraseรฑa para suscribirse.", "subscribe_dialog_login_username_label": "Nombre de usuario, ej. phil", "subscribe_dialog_login_password_label": "Contraseรฑa", - "common_back": "Volver", + "subscribe_dialog_login_button_back": "Volver", "subscribe_dialog_login_button_login": "Iniciar sesiรณn", "subscribe_dialog_error_user_not_authorized": "Usuario {{username}} no autorizado", "subscribe_dialog_error_user_anonymous": "anรณnimo", @@ -107,7 +107,7 @@ "prefs_appearance_language_title": "Idioma", "error_boundary_title": "Oh no, ntfy tuvo un error", "error_boundary_button_copy_stack_trace": "Copiar el stack trace", - "error_boundary_stack_trace": "Rastreo de pila", + "error_boundary_stack_trace": "Stack trace", "error_boundary_gathering_info": "Reunir mรกs informaciรณn โ€ฆ", "notifications_example": "Ejemplo", "prefs_notifications_min_priority_title": "Prioridad mรญnima", @@ -257,7 +257,7 @@ "account_tokens_table_expires_header": "Expira", "account_tokens_table_never_expires": "Nunca expira", "account_tokens_table_current_session": "Sesiรณn del navegador actual", - "common_copy_to_clipboard": "Copiar al portapapeles", + "account_tokens_table_copy_to_clipboard": "Copiar al portapapeles", "account_tokens_table_copied_to_clipboard": "Token de acceso copiado", "account_tokens_table_cannot_delete_or_edit": "No se puede editar ni eliminar el token de sesiรณn actual", "account_tokens_table_create_token_button": "Crear token de acceso", @@ -291,12 +291,12 @@ "account_delete_dialog_description": "Esto borrarรก permanentemente su cuenta, incluyendo todos los datos almacenados en el servidor. Tras la eliminaciรณn, su nombre de usuario no estarรก disponible durante 7 dรญas. Si realmente desea continuar, por favor confirme su contraseรฑa en la casilla de abajo.", "account_delete_dialog_label": "Contraseรฑa", "account_delete_dialog_button_submit": "Eliminar permanentemente la cuenta", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} tรณpicos reservados", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} tรณpicos reservados", "account_upgrade_dialog_cancel_warning": "Esto cancelarรก su suscripciรณn y degradarรก su cuenta en {{date}}. En esa fecha, sus tรณpicos reservados y sus mensajes almacenados en cachรฉ en el servidor serรกn eliminados.", "account_upgrade_dialog_proration_info": "Prorrateo: al actualizar entre planes pagos, la diferencia de precio se cobrarรก de inmediato. Al cambiar a un nivel inferior, el saldo se utilizarรก para pagar futuros perรญodos de facturaciรณn.", "account_upgrade_dialog_reservations_warning_other": "El nivel seleccionado permite menos tรณpicos reservados que su nivel actual. Antes de cambiar de nivel, por favor elimine al menos {{count}} reservaciones. Puede eliminar reservaciones en Configuraciรณn.", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} mensajes diarios", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} correos diarios", + "account_upgrade_dialog_tier_features_messages": "{{messages}} mensajes diarios", + "account_upgrade_dialog_tier_features_emails": "{{emails}} correos diarios", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} por archivo", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} almacenamiento total", "account_upgrade_dialog_tier_current_label": "Actual", @@ -352,34 +352,5 @@ "account_upgrade_dialog_tier_price_billed_yearly": "{{price}} facturado anualmente. Guardar {{save}}.", "account_upgrade_dialog_billing_contact_website": "Si tiene preguntas sobre facturaciรณn, consulte nuestra pรกgina web.", "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} al aรฑo. Facturaciรณn mensual.", - "account_upgrade_dialog_billing_contact_email": "Para preguntas sobre facturaciรณn, por favor contรกctenos directamente.", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} mensaje diario", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} correo electrรณnico diario", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} tema reservado", - "publish_dialog_call_label": "Llamada telefรณnica", - "publish_dialog_call_placeholder": "Nรบmero de telรฉfono al cual llamar con el mensaje, por ejemplo +12223334444, o \"sรญ\"", - "publish_dialog_chip_call_label": "Llamada telefรณnica", - "account_basics_phone_numbers_title": "Nรบmeros de telรฉfono", - "account_basics_phone_numbers_description": "Para notificaciones por llamada telรฉfonica", - "account_basics_phone_numbers_no_phone_numbers_yet": "Aรบn no hay nรบmeros de telรฉfono", - "account_basics_phone_numbers_dialog_number_label": "Nรบmero de telรฉfono", - "account_basics_phone_numbers_dialog_number_placeholder": "p. ej. +1222333444", - "account_basics_phone_numbers_dialog_verify_button_sms": "Envรญa SMS", - "account_basics_phone_numbers_dialog_verify_button_call": "Llรกmame", - "account_basics_phone_numbers_dialog_code_label": "Cรณdigo de verificaciรณn", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_basics_phone_numbers_dialog_channel_call": "Llamar", - "account_usage_calls_title": "Llamadas telefรณnicas realizadas", - "account_usage_calls_none": "No se pueden hacer llamadas telefรณnicas con esta cuenta", - "account_upgrade_dialog_tier_features_calls_one": "{{llamadas}} llamadas telefรณnicas diarias", - "account_upgrade_dialog_tier_features_calls_other": "{{llamadas}} llamadas telefรณnicas diarias", - "account_upgrade_dialog_tier_features_no_calls": "No hay llamadas telefรณnicas", - "publish_dialog_call_reset": "Eliminar llamada telefรณnica", - "account_basics_phone_numbers_dialog_description": "Para utilizar la funciรณn de notificaciรณn de llamadas, tiene que aรฑadir y verificar al menos un nรบmero de telรฉfono. La verificaciรณn puede realizarse mediante un SMS o una llamada telefรณnica.", - "account_basics_phone_numbers_copied_to_clipboard": "Nรบmero de telรฉfono copiado al portapapeles", - "account_basics_phone_numbers_dialog_check_verification_button": "Confirmar cรณdigo", - "account_basics_phone_numbers_dialog_title": "Agregar nรบmero de telรฉfono", - "account_basics_phone_numbers_dialog_code_placeholder": "p.ej. 123456", - "publish_dialog_call_item": "Llamar al nรบmero de telรฉfono {{number}}", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "No hay nรบmeros de telรฉfono verificados" + "account_upgrade_dialog_billing_contact_email": "Para preguntas sobre facturaciรณn, por favor contรกctenos directamente." } diff --git a/web/public/static/langs/fr.json b/web/public/static/langs/fr.json index cf4bb72..c279d02 100644 --- a/web/public/static/langs/fr.json +++ b/web/public/static/langs/fr.json @@ -106,7 +106,7 @@ "prefs_notifications_title": "Notifications", "prefs_notifications_delete_after_title": "Supprimer les notifications", "prefs_users_add_button": "Ajouter un utilisateur", - "common_back": "Retour", + "subscribe_dialog_login_button_back": "Retour", "subscribe_dialog_error_user_anonymous": "anonyme", "prefs_notifications_sound_no_sound": "Aucun son", "prefs_notifications_min_priority_title": "Prioritรฉ minimum", @@ -273,10 +273,10 @@ "account_delete_dialog_billing_warning": "Supprimer votre compte annule aussi immรฉdiatement votre facturation. Vous n'aurez plus accรจs ร  votre tableau de bord de facturation.", "account_upgrade_dialog_title": "Changer le tarif du compte", "account_upgrade_dialog_proration_info": "Facturationย : Lors d'un changement entre un plan payant et un autre, la diffรฉrence de prix sera crรฉditรฉe ou remboursรฉe sur la prochaine facture. Vous ne recevrez pas d'autre facture avant la fin de la prochaine pรฉriode de facturation.", - "account_upgrade_dialog_reservations_warning_other": "Le tarif sรฉlectionnรฉ autorise moins de sujets rรฉservรฉs que votre tarif actuel. Avant de changer de tarif, veuillez supprimer au moins {{count}} sujets rรฉservรฉs. Vous pouvez supprimer des sujets rรฉservรฉs dans les Paramรจtres.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} sujets rรฉservรฉs", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} messages journaliers", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} emails journaliers", + "account_upgrade_dialog_reservations_warning_other": "Le tarif sรฉlectionnรฉ autorise moins de sujets rรฉservรฉs que votre tarif actuel. Avant de changer de tarif, veuillez supprimer au moins {{count}} sujets rรฉservรฉs. Vous pouvez supprimer des sujets rรฉservรฉs dans les Settings.", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} sujets rรฉservรฉs", + "account_upgrade_dialog_tier_features_messages": "{{messages}} messages journaliers", + "account_upgrade_dialog_tier_features_emails": "{{emails}} emails journaliers", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} par fichier", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} stockage total", "account_upgrade_dialog_tier_selected_label": "Sรฉlectionnรฉ", @@ -293,7 +293,7 @@ "account_tokens_table_expires_header": "Expire", "account_tokens_table_never_expires": "N'expire jamais", "account_tokens_table_current_session": "Session de navigation actuelle", - "common_copy_to_clipboard": "Copier dans le presse-papier", + "account_tokens_table_copy_to_clipboard": "Copier dans le presse-papier", "account_tokens_table_copied_to_clipboard": "Jeton d'accรจs copiรฉ", "account_tokens_table_create_token_button": "Crรฉer un jeton d'accรจs", "account_tokens_table_last_origin_tooltip": "Depuis l'adresse IP {{ip}}, cliquer pour rechercher", @@ -337,39 +337,8 @@ "alert_not_supported_context_description": "Les notifications ne sont supportรฉes qu'en HTTPS. C'est une limitation de la Notifications API.", "account_basics_tier_payment_overdue": "Votre paiement est en retard. Veuillez mettre ร  jour votre mรฉthode de paiement, ou votre compte va bientรดt รชtre rรฉtrogradรฉ.", "account_upgrade_dialog_cancel_warning": "Cela va annuler votre abonnement et rรฉtrograder votre compte le {{date}}. Ce jour lร , les sujets rรฉservรฉs ainsi que tous les messages dans le cache du serveur seront supprimรฉs.", - "account_upgrade_dialog_reservations_warning_one": "Le tarif sรฉlectionnรฉ autorise moins de sujets rรฉservรฉs que votre tarif actuel. Avant de changer de tarif, veuillez supprimer au moins un sujet rรฉservรฉ. Vous pouvez supprimer des sujets rรฉservรฉs dans les Paramรจtres.", + "account_upgrade_dialog_reservations_warning_one": "Le tarif sรฉlectionnรฉ autorise moins de sujets rรฉservรฉs que votre tarif actuel. Avant de changer de tarif, veuillez supprimer au moins un sujet rรฉservรฉ. Vous pouvez supprimer des sujets rรฉservรฉs dans les Settings.", "account_tokens_description": "Utilisez des jetons d'accรจs lors de la publication ou de l'abonnement via l'API de ntfy, afin d'รฉviter d'envoyer vos identifiants de compte. Regardez la documentation pour en savoir plus.", "account_tokens_delete_dialog_description": "Avant de supprimer un jeton d'accรจs, assurez-vous qu'aucune application ou script ne soit en train de l'utiliser. Cette action ne peut pas รชtre annulรฉe.", - "prefs_reservations_description": "Vous pouvez rรฉserver les noms de sujet ร  usage personnel ici. Rรฉserver un sujet vous donne la propriรฉtรฉ sur ce sujet et vous permet de dรฉfinir les permissions d'accรจs ร  ce sujet pour d'autres utilisateurs.", - "account_basics_tier_interval_yearly": "annuel", - "account_upgrade_dialog_interval_yearly": "Annuel", - "account_upgrade_dialog_interval_yearly_discount_save": "รฉconomisez {{discount}}%", - "account_upgrade_dialog_tier_features_no_reservations": "Aucun sujet(s) rรฉservรฉ(s)", - "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} par an. Prรฉlevรฉ mensuellement.", - "account_upgrade_dialog_billing_contact_website": "Pour des questions en rapport avec la facturation, se rรฉfรฉrer ร  notre site internet.", - "account_basics_tier_interval_monthly": "mensuel", - "account_upgrade_dialog_interval_monthly": "Mensuel", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "รฉconomisez jusqu'ร  {{discount}}%", - "account_upgrade_dialog_tier_price_per_month": "mois", - "account_upgrade_dialog_tier_price_billed_yearly": "{{price}} prรฉlevรฉ annuellement. ร‰conomisez {{save}}.", - "account_upgrade_dialog_billing_contact_email": "Pour des questions concernant la facturation, merci de nous contacter directement.", - "publish_dialog_call_label": "Appel tรฉlรฉphonique", - "account_basics_phone_numbers_title": "Numรฉros de tรฉlรฉphone", - "account_basics_phone_numbers_dialog_description": "Pour utiliser la fonctionnalitรฉ de notification par appels, vous devez ajouter et vรฉrifier au moins un numรฉro de tรฉlรฉphone. La vรฉrification peut se faire par SMS ou appel tรฉlรฉphonique.", - "account_basics_phone_numbers_description": "Pour des notifications par appel tรฉlรฉphoniques", - "account_basics_phone_numbers_no_phone_numbers_yet": "Pas encore de numรฉros de tรฉlรฉphone", - "account_basics_phone_numbers_copied_to_clipboard": "Numรฉro de tรฉlรฉphone copiรฉ dans le presse-papier", - "account_basics_phone_numbers_dialog_title": "Ajouter un numรฉro de tรฉlรฉphone", - "account_basics_phone_numbers_dialog_number_label": "Numรฉro de tรฉlรฉphone", - "account_basics_phone_numbers_dialog_number_placeholder": "Ex : +33701020304", - "account_basics_phone_numbers_dialog_verify_button_sms": "Envoyer un SMS", - "account_basics_phone_numbers_dialog_verify_button_call": "Appelez moi", - "account_basics_phone_numbers_dialog_code_label": "Code de vรฉrification", - "account_basics_phone_numbers_dialog_code_placeholder": "Ex : 123456", - "account_basics_phone_numbers_dialog_check_verification_button": "Code de confirmarion", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_basics_phone_numbers_dialog_channel_call": "Appel", - "account_usage_calls_none": "Aucun appels tรฉlรฉphoniques ne peut รชtre fait avec ce compte", - "publish_dialog_call_reset": "Supprimer les appels tรฉlรฉphoniques", - "publish_dialog_chip_call_label": "Appel tรฉlรฉphonique" + "prefs_reservations_description": "Vous pouvez rรฉserver les noms de sujet ร  usage personnel ici. Rรฉserver un sujet vous donne la propriรฉtรฉ sur ce sujet et vous permet de dรฉfinir les permissions d'accรจs ร  ce sujet pour d'autres utilisateurs." } diff --git a/web/public/static/langs/gl.json b/web/public/static/langs/gl.json deleted file mode 100644 index 0967ef4..0000000 --- a/web/public/static/langs/gl.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/web/public/static/langs/hu.json b/web/public/static/langs/hu.json index b52e3a4..975d8d9 100644 --- a/web/public/static/langs/hu.json +++ b/web/public/static/langs/hu.json @@ -84,7 +84,7 @@ "subscribe_dialog_login_description": "Ez a tรฉma jelszรณval vรฉdett. Jelentkezz be a feliratkozรกshoz.", "subscribe_dialog_login_username_label": "Felhasznรกlรณnรฉv, pl: jozsi", "subscribe_dialog_login_password_label": "Jelszรณ", - "common_back": "Vissza", + "subscribe_dialog_login_button_back": "Vissza", "subscribe_dialog_login_button_login": "Belรฉpรฉs", "subscribe_dialog_error_user_anonymous": "nรฉvtelen", "subscribe_dialog_error_user_not_authorized": "A(z) {{username}} felhasznรกlรณnak nincs hozzรกfรฉrรฉse", diff --git a/web/public/static/langs/id.json b/web/public/static/langs/id.json index 48fcda0..6be8c9f 100644 --- a/web/public/static/langs/id.json +++ b/web/public/static/langs/id.json @@ -116,7 +116,7 @@ "common_save": "Simpan", "prefs_appearance_title": "Tampilan", "subscribe_dialog_login_password_label": "Kata sandi", - "common_back": "Kembali", + "subscribe_dialog_login_button_back": "Kembali", "prefs_notifications_sound_title": "Suara notifikasi", "prefs_notifications_min_priority_low_and_higher": "Prioritas rendah dan lebih tinggi", "prefs_notifications_min_priority_default_and_higher": "Prioritas bawaan dan lebih tinggi", @@ -258,9 +258,9 @@ "account_upgrade_dialog_title": "Ubah peringkat akun", "account_upgrade_dialog_proration_info": "Prorasi: Saat melakukan upgrade antar paket berbayar, selisih harga akan langsung dibebankan ke. Saat menurunkan ke tingkat yang lebih rendah, saldo akan digunakan untuk membayar periode penagihan di masa mendatang.", "account_upgrade_dialog_reservations_warning_other": "Peringkat yang dipilih memperbolehkan lebih sedikit reservasi topik daripada peringkat Anda saat ini. Sebelum mengubah peringkat Anda, silakan menghapus setidaknya {{count}} reservasi. Anda dapat menghapus reservasi di Pengaturan.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} topik yang telah direservasi", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} pesan harian", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} surel harian", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} topik yang telah direservasi", + "account_upgrade_dialog_tier_features_messages": "{{messages}} pesan harian", + "account_upgrade_dialog_tier_features_emails": "{{emails}} surel harian", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per berkas", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} jumlah penyimpanan", "account_upgrade_dialog_tier_selected_label": "Dipilih", @@ -278,7 +278,7 @@ "account_tokens_table_expires_header": "Kedaluwarsa", "account_tokens_table_never_expires": "Tidak pernah kedaluwarsa", "account_tokens_table_current_session": "Sesi peramban saat ini", - "common_copy_to_clipboard": "Salin ke papan klip", + "account_tokens_table_copy_to_clipboard": "Salin ke papan klip", "account_tokens_table_copied_to_clipboard": "Token akses disalin", "account_tokens_table_cannot_delete_or_edit": "Tidak dapat menyunting atau menghapus token sesi saat ini", "account_tokens_table_create_token_button": "Buat token akses", @@ -352,34 +352,5 @@ "account_upgrade_dialog_tier_price_per_month": "bulan", "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} per bulan. Ditagih setiap bulan.", "account_upgrade_dialog_billing_contact_email": "Untuk pertanyaan penagihan, silakan hubungi kami secara langsung.", - "account_upgrade_dialog_billing_contact_website": "Untuk pertanyaan penagihan, silakan menuju ke situs web kami.", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} topik yang direservasi", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} surel harian", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} pesan harian", - "publish_dialog_call_label": "Panggilan telepon", - "publish_dialog_call_placeholder": "Nomor telepon untuk dipanggil dengan pesan, mis. +622223334444, atau 'yes'", - "account_basics_phone_numbers_title": "Nomor telepon", - "account_basics_phone_numbers_dialog_description": "Untuk menggunakan fitur notifikasi telepon, Anda perlu menambahkan dan memverifikasi setidaknya satu nomor telepon. Verifikasi dapat dilakukan melalui SMS atau panggilan telepon.", - "account_basics_phone_numbers_no_phone_numbers_yet": "Belum ada nomor telepon", - "account_basics_phone_numbers_dialog_title": "Tambahkan nomor telepon", - "account_basics_phone_numbers_dialog_number_label": "Nomor telepon", - "account_basics_phone_numbers_dialog_number_placeholder": "mis. +62222333444", - "account_basics_phone_numbers_dialog_verify_button_sms": "Kirim SMS", - "account_basics_phone_numbers_dialog_channel_call": "Panggil", - "account_usage_calls_title": "Panggilan telepon dilakukan", - "account_usage_calls_none": "Tidak ada panggilan telepon yang dapat dilakukan dengan akun ini", - "account_upgrade_dialog_tier_features_calls_other": "{{calls}} panggilan telepon harian", - "publish_dialog_call_reset": "Hapus panggilan telepon", - "account_basics_phone_numbers_description": "Untuk notifikasi panggilan telepon", - "account_basics_phone_numbers_copied_to_clipboard": "Nomor telepon disalin ke papan klip", - "publish_dialog_chip_call_label": "Panggilan telepon", - "account_basics_phone_numbers_dialog_verify_button_call": "Panggil saya", - "account_basics_phone_numbers_dialog_code_placeholder": "mis. 123456", - "account_basics_phone_numbers_dialog_check_verification_button": "Konfirmasi kode", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_upgrade_dialog_tier_features_calls_one": "{{calls}} panggilan telepon harian", - "account_upgrade_dialog_tier_features_no_calls": "Tidak ada panggilan telepon", - "account_basics_phone_numbers_dialog_code_label": "Kode verifikasi", - "publish_dialog_call_item": "Panggil nomor telepon {{number}}", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "Tidak ada nomor telepon terverifikasi" + "account_upgrade_dialog_billing_contact_website": "Untuk pertanyaan penagihan, silakan menuju ke situs web kami." } diff --git a/web/public/static/langs/it.json b/web/public/static/langs/it.json index 95c4b5b..3dc40d5 100644 --- a/web/public/static/langs/it.json +++ b/web/public/static/langs/it.json @@ -178,7 +178,7 @@ "prefs_notifications_sound_play": "Riproduci il suono selezionato", "prefs_notifications_min_priority_title": "Prioritร  minima", "subscribe_dialog_login_description": "Questo argomento รจ protetto da password. Per favore inserisci username e password per iscriverti.", - "common_back": "Indietro", + "subscribe_dialog_login_button_back": "Indietro", "subscribe_dialog_error_user_not_authorized": "Utente {{username}} non autorizzato", "prefs_notifications_title": "Notifiche", "prefs_notifications_delete_after_title": "Elimina le notifiche", @@ -187,77 +187,5 @@ "prefs_notifications_delete_after_one_week": "Dopo una settimana", "prefs_notifications_delete_after_one_month": "Dopo un mese", "prefs_notifications_delete_after_three_hours_description": "Le notifiche vengono eliminate automaticamente dopo tre ore", - "error_boundary_unsupported_indexeddb_description": "L'app web ntfy ha bisogno di IndexedDB per funzionare e il tuo browser non supporta IndexedDB in modalitร  di navigazione privata.

Anche se questo รจ un peccato, non ha molto senso usare il web ntfy app in modalitร  di navigazione privata comunque, perchรฉ tutto รจ archiviato nella memoria del browser. Puoi leggere di piรน a riguardo in questo numero di GitHub o parlarci su Discord o Matrix.", - "nav_upgrade_banner_label": "Passa alla versione Pro di ntfy", - "alert_not_supported_context_description": "Le Notificche sono supportate solo tramite HTTPS. Questa รจ una limitazione delle Notifications API.", - "account_basics_password_dialog_new_password_label": "Nuova password", - "action_bar_profile_logout": "Esci", - "account_basics_tier_interval_monthly": "mensile", - "account_basics_tier_interval_yearly": "annuale", - "account_basics_tier_upgrade_button": "Passa alla versione Pro", - "account_basics_tier_change_button": "Cambia", - "account_basics_tier_paid_until": "Abbonamento pagato fino a {{data}}, e si rinnoverร  automaticamente", - "account_basics_tier_payment_overdue": "Il pagamento รจ scaduto. La preghiamo di aggiornare il suo metodo di pagamento, altrimenti il suo account verrร  presto declassato.", - "account_basics_tier_canceled_subscription": "L'abbonamento รจ stato annullato e sarร  declassato ad account gratuito a partire dalla {{data}}.", - "account_basics_tier_manage_billing_button": "Gestire la fatturazione", - "account_usage_messages_title": "Messaggi pubblicati", - "account_usage_reservations_title": "Argomenti riservati", - "account_usage_reservations_none": "Non ci sono argomenti riservati per questo account", - "signup_form_toggle_password_visibility": "Imposta la visibilitร  della password", - "signup_already_have_account": "Hai giร  un account? Accedi!", - "signup_disabled": "Registrazione disabilitata", - "signup_title": "Crea un account ntfy", - "signup_form_username": "Nome utente", - "signup_form_password": "Password", - "signup_form_confirm_password": "Conferma password", - "signup_form_button_submit": "Registrazione", - "signup_error_username_taken": "Il nome utente {{username}} รจ giร  utilizzato", - "signup_error_creation_limit_reached": "Il limite per la creazione di account รจ stato raggiunto", - "login_title": "Accedi al tuo account ntfy", - "login_form_button_submit": "Accedi", - "login_link_signup": "Registrati", - "login_disabled": "L'accesso รจ disabilitato", - "action_bar_account": "Account", - "action_bar_change_display_name": "Cambia il nome da visualizzare", - "action_bar_reservation_limit_reached": "Limite raggiunto", - "action_bar_profile_title": "Profilo", - "action_bar_profile_settings": "Impostazioni", - "action_bar_reservation_add": "Riserva un argomento", - "action_bar_reservation_edit": "Modifica l'argomento riservato", - "action_bar_reservation_delete": "Rimuovi l'argomento riservato", - "action_bar_sign_in": "Accedi", - "action_bar_sign_up": "Registrati", - "nav_button_account": "Account", - "nav_upgrade_banner_description": "Riserva argomenti, piรน messaggi ed e-mail e allegati piรน grandi", - "display_name_dialog_description": "Imposta un nome alternativo per un argomento che viene visualizzato nell'elenco delle sottoscrizioni. Questo aiuta a identificare piรน facilmente gli argomenti con nomi complicati.", - "display_name_dialog_title": "Cambia il nome visualizzato", - "display_name_dialog_placeholder": "Nome visualizzato", - "reserve_dialog_checkbox_label": "Riserva un argomento e configura l'accesso", - "subscribe_dialog_subscribe_button_generate_topic_name": "Genera un nome", - "subscribe_dialog_error_topic_already_reserved": "Argomento giร  in uso", - "account_basics_title": "Account", - "account_basics_username_title": "Nome utente", - "account_basics_username_admin_tooltip": "Sei Amministratore", - "account_basics_password_title": "Password", - "account_basics_password_description": "Cambia la password del tuo account", - "account_basics_password_dialog_title": "Cambia la password", - "account_basics_password_dialog_current_password_label": "Password attuale", - "account_basics_password_dialog_confirm_password_label": "Conferma la password", - "account_basics_password_dialog_button_submit": "Cambia la password", - "account_basics_password_dialog_current_password_incorrect": "Password errata", - "account_usage_title": "Utilizzo", - "account_usage_of_limit": "di {{limit}}", - "account_usage_unlimited": "Illimitato", - "account_usage_limits_reset_daily": "I limiti di utilizzo vengono azzerati ogni giorno a mezzanotte (orario UTC)", - "account_basics_tier_title": "Tipo di account", - "account_basics_tier_description": "Permessi del tuo account", - "account_basics_tier_admin": "Amministratore", - "account_basics_tier_admin_suffix_with_tier": "(con livello {{tier}})", - "account_basics_tier_admin_suffix_no_tier": "(nessun livello)", - "account_basics_tier_basic": "Base", - "account_basics_tier_free": "Gratuito", - "account_usage_emails_title": "Email inviate", - "account_usage_cannot_create_portal_session": "Impossibile aprire il portale di pagamento", - "account_delete_title": "Elimina account", - "account_basics_username_description": "Hey, sei tu โค" + "error_boundary_unsupported_indexeddb_description": "L'app web ntfy ha bisogno di IndexedDB per funzionare e il tuo browser non supporta IndexedDB in modalitร  di navigazione privata.

Anche se questo รจ un peccato, non ha molto senso usare il web ntfy app in modalitร  di navigazione privata comunque, perchรฉ tutto รจ archiviato nella memoria del browser. Puoi leggere di piรน a riguardo in questo numero di GitHub o parlarci su Discord o Matrix." } diff --git a/web/public/static/langs/ja.json b/web/public/static/langs/ja.json index 9c68679..8594a6f 100644 --- a/web/public/static/langs/ja.json +++ b/web/public/static/langs/ja.json @@ -20,7 +20,7 @@ "subscribe_dialog_login_description": "ใ“ใฎใƒˆใƒ”ใƒƒใ‚ฏใฏใƒญใ‚ฐใ‚คใƒณใ™ใ‚‹ๅฟ…่ฆใŒใ‚ใ‚Šใพใ™ใ€‚ใƒฆใƒผใ‚ถใƒผๅใจใƒ‘ใ‚นใƒฏใƒผใƒ‰ใ‚’ๅ…ฅๅŠ›ใ—ใฆใใ ใ•ใ„ใ€‚", "subscribe_dialog_login_username_label": "ใƒฆใƒผใ‚ถใƒผๅ, ไพ‹) phil", "subscribe_dialog_login_password_label": "ใƒ‘ใ‚นใƒฏใƒผใƒ‰", - "common_back": "ๆˆปใ‚‹", + "subscribe_dialog_login_button_back": "ๆˆปใ‚‹", "subscribe_dialog_login_button_login": "ใƒญใ‚ฐใ‚คใƒณ", "prefs_notifications_min_priority_high_and_higher": "ๅ„ชๅ…ˆๅบฆ้ซ˜ ใŠใ‚ˆใณใใ‚ŒไปฅไธŠ", "prefs_notifications_min_priority_max_only": "ๅ„ชๅ…ˆๅบฆๆœ€้ซ˜ใฎใฟ", @@ -240,10 +240,10 @@ "account_delete_dialog_billing_warning": "ใ‚ขใ‚ซใ‚ฆใƒณใƒˆใ‚’ๅ‰Š้™คใ™ใ‚‹ใจใ‚ตใƒ–ใ‚นใ‚ฏใƒชใƒ—ใ‚ทใƒงใƒณๆ”ฏๆ‰•ใ„ใ‚‚ๅณๆ™‚ใ‚ญใƒฃใƒณใ‚ปใƒซใ•ใ‚Œใพใ™ใ€‚ๆ”ฏๆ‰•ใ„ใƒ€ใƒƒใ‚ทใƒฅใƒœใƒผใƒ‰ใซใ‚‚ใ‚ขใ‚ฏใ‚ปใ‚นใงใใชใใชใ‚Šใพใ™ใ€‚", "account_upgrade_dialog_title": "ใ‚ขใ‚ซใ‚ฆใƒณใƒˆใƒ†ใ‚ฃใ‚ขใ‚’ๅค‰ๆ›ด", "account_upgrade_dialog_cancel_warning": "ใ“ใ‚Œใซใ‚ˆใ‚Šใ‚ตใƒ–ใ‚นใ‚ฏใƒชใƒ—ใ‚ทใƒงใƒณใ‚’ใ‚ญใƒฃใƒณใ‚ปใƒซใ—{{date}}ใซใ‚ขใ‚ซใ‚ฆใƒณใƒˆใ‚’ใƒ€ใ‚ฆใƒณใ‚ฐใƒฌใƒผใƒ‰ใ—ใพใ™ใ€‚ๅŒๆ—ฅใ€ใƒˆใƒ”ใƒƒใ‚ฏไบˆ็ด„ใŠใ‚ˆใณใ‚ตใƒผใƒใƒผใซใ‚ญใƒฃใƒƒใ‚ทใƒฅใ•ใ‚ŒใŸใƒกใƒƒใ‚ปใƒผใ‚ธใฏๅ‰Š้™คใ•ใ‚Œใพใ™ใ€‚", - "account_upgrade_dialog_proration_info": "่ฟฝ่จ˜ใ€‚ๆœ‰ๆ–™ใƒ—ใƒฉใƒณใ‚’ใ‚ขใƒƒใƒ—ใ‚ฐใƒฌใƒผใƒ‰ใ™ใ‚‹ๅ ดๅˆใ€ไพกๆ ผๅทฎใฏๅณๅบงใซ่ซ‹ๆฑ‚ใ•ใ‚Œใพใ™ใ€‚ใƒ€ใ‚ฆใƒณใ‚ฐใƒฌใƒผใƒ‰ใ™ใ‚‹ๅ ดๅˆใ€ๅทฎ้กใฏๆฌกใฎ่ซ‹ๆฑ‚ๆœŸ้–“ใฎๆ”ฏๆ‰•ใ„ใซๅˆฉ็”จใ•ใ‚Œใพใ™ใ€‚", - "account_upgrade_dialog_tier_features_reservations_other": "ไบˆ็ด„ใฎใƒˆใƒ”ใƒƒใ‚ฏ{{reservations}}ไปถ", - "account_upgrade_dialog_tier_features_emails_other": "ๆ—ฅๆฌกใƒกใƒผใƒซ{{emails}}ไปถ", - "account_upgrade_dialog_tier_features_messages_other": "ๆ—ฅๆฌกใƒกใƒƒใ‚ปใƒผใ‚ธ{{messages}}ไปถ", + "account_upgrade_dialog_proration_info": "่ฟฝ่จ˜ใ€‚ๆœ‰ๆ–™ใƒ—ใƒฉใƒณใ‚’ๅˆ‡ใ‚Šๆ›ฟใˆใ‚‹ๅ ดๅˆใ€ไพกๆ ผๅทฎใฏๆฌกใฎ่ซ‹ๆฑ‚ๆ›ธใง่ซ‹ๆฑ‚ใพใŸใฏ่ฟ”้‡‘ใ•ใ‚Œใพใ™ใ€‚ๆฌกใฎ่ซ‹ๆฑ‚ๆœŸ้–“ใฎ็ต‚ใ‚ใ‚Šใพใงใ€ๅˆฅใฎ่ซ‹ๆฑ‚ๆ›ธใ‚’ๅ—ใ‘ๅ–ใ‚‹ใ“ใจใฏใ‚ใ‚Šใพใ›ใ‚“ใ€‚", + "account_upgrade_dialog_tier_features_reservations": "ไบˆ็ด„ใฎใƒˆใƒ”ใƒƒใ‚ฏ{{reservations}}ไปถ", + "account_upgrade_dialog_tier_features_emails": "ๆ—ฅๆฌกใƒกใƒผใƒซ{{emails}}ไปถ", + "account_upgrade_dialog_tier_features_messages": "ๆ—ฅๆฌกใƒกใƒƒใ‚ปใƒผใ‚ธ{{messages}}ไปถ", "account_upgrade_dialog_tier_selected_label": "้ธๆŠž", "account_upgrade_dialog_tier_current_label": "็พๅœจ", "account_upgrade_dialog_button_cancel": "ใ‚ญใƒฃใƒณใ‚ปใƒซ", @@ -258,7 +258,7 @@ "account_tokens_table_expires_header": "ๆœŸ้™", "account_tokens_table_never_expires": "็„กๆœŸ้™", "account_tokens_table_current_session": "็พๅœจใฎใƒ–ใƒฉใ‚ฆใ‚ถใ‚ปใƒƒใ‚ทใƒงใƒณ", - "common_copy_to_clipboard": "ใ‚ฏใƒชใƒƒใƒ—ใƒœใƒผใƒ‰ใซใ‚ณใƒ”ใƒผ", + "account_tokens_table_copy_to_clipboard": "ใ‚ฏใƒชใƒƒใƒ—ใƒœใƒผใƒ‰ใซใ‚ณใƒ”ใƒผ", "account_tokens_table_copied_to_clipboard": "ใ‚ขใ‚ฏใ‚ปใ‚นใƒˆใƒผใ‚ฏใƒณใ‚’ใ‚ณใƒ”ใƒผใ—ใพใ—ใŸ", "account_tokens_table_cannot_delete_or_edit": "็พๅœจใฎใ‚ปใƒƒใ‚ทใƒงใƒณใƒˆใƒผใ‚ฏใƒณใฏ็ทจ้›†ใพใŸใฏๅ‰Š้™คใงใใพใ›ใ‚“", "account_tokens_table_create_token_button": "ใ‚ขใ‚ฏใ‚ปใ‚นใƒˆใƒผใ‚ฏใƒณใ‚’็”Ÿๆˆ", @@ -340,21 +340,5 @@ "prefs_reservations_dialog_title_add": "ใƒˆใƒ”ใƒƒใ‚ฏใ‚’ไบˆ็ด„", "prefs_reservations_dialog_description": "ใƒˆใƒ”ใƒƒใ‚ฏใ‚’ไบˆ็ด„ใ™ใ‚‹ไบ‹ใงใใฎใƒˆใƒ”ใƒƒใ‚ฏใฎๆ‰€ๆœ‰ๆจฉใŒไป˜ไธŽใ•ใ‚Œใ€ไป–ใฎใƒฆใƒผใ‚ถใƒผใซใ‚ขใ‚ฏใ‚ปใ‚นๆจฉใ‚’ไป˜ไธŽใ™ใ‚‹ไบ‹ใŒใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ™ใ€‚", "reservation_delete_dialog_description": "ไบˆ็ด„ใ‚’ๅ‰Š้™คใ™ใ‚‹ใจใƒˆใƒ”ใƒƒใ‚ฏใฎๆ‰€ๆœ‰ๆจฉใ‚’ๅคฑใ„ใ€ไป–ใฎไบบใŒไบˆ็ด„ใงใใ‚‹ใ‚ˆใ†ใซใชใ‚Šใพใ™ใ€‚ๆ—ขๅญ˜ใฎใƒกใƒƒใ‚ปใƒผใ‚ธใ‚„ๆทปไป˜ใƒ•ใ‚กใ‚คใƒซใฏไฟๆŒใพใŸใฏๅ‰Š้™คใ™ใ‚‹ใ“ใจใŒใงใใพใ™ใ€‚", - "reservation_delete_dialog_submit_button": "ไบˆ็ด„ใ‚’ๅ‰Š้™ค", - "account_basics_tier_interval_monthly": "ๆฏŽๆœˆ", - "account_upgrade_dialog_interval_monthly": "ๆฏŽๆœˆ", - "account_upgrade_dialog_interval_yearly": "ๆฏŽๅนด", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "ๆœ€ๅคง{{discount}}%็ฏ€็ด„", - "account_upgrade_dialog_tier_features_no_reservations": "ไบˆ็ด„ใƒˆใƒ”ใƒƒใ‚ฏใชใ—", - "account_upgrade_dialog_billing_contact_email": "ๆ”ฏๆ‰•ใ„ใซใคใ„ใฆใฎๅ•ใ„ๅˆใ‚ใ›ใฏใ€็›ดๆŽฅใŠๅ•ใ„ๅˆใ‚ใ›ใใ ใ•ใ„ใ€‚", - "account_upgrade_dialog_interval_yearly_discount_save": "{{discount}}%็ฏ€็ด„", - "account_basics_tier_interval_yearly": "ๆฏŽๅนด", - "account_upgrade_dialog_tier_price_per_month": "ๆœˆ", - "account_upgrade_dialog_tier_price_billed_monthly": "ๅนด้–“{{price}}ใ€‚ๆœˆๆฏŽใฎๆ”ฏๆ‰•ใ„ใ€‚", - "account_upgrade_dialog_tier_price_billed_yearly": "ๅนด้–“{{price}}ใฎๆ”ฏๆ‰•ใ„ใ€‚{{save}}็ฏ€็ด„ใ€‚", - "account_upgrade_dialog_billing_contact_website": "ๆ”ฏๆ‰•ใ„ใซ้–ขใ™ใ‚‹่ณชๅ•ใฏใ€ใ‚ฆใ‚งใƒ–ใ‚ตใ‚คใƒˆใ‚’ๅ‚็…งใ—ใฆไธ‹ใ•ใ„ใ€‚", - "account_upgrade_dialog_tier_features_messages_one": "ๆฏŽๆ—ฅ {{messages}} ใƒกใƒƒใ‚ปใƒผใ‚ธ", - "account_upgrade_dialog_tier_features_reservations_one": "ไบˆ็ด„ๆธˆใฟใƒˆใƒ”ใƒƒใ‚ฏ {{reservations}} ไปถ", - "account_upgrade_dialog_tier_features_emails_one": "ๆฏŽๆ—ฅใƒกใƒผใƒซ {{emails}} ไปถ", - "publish_dialog_call_label": "้›ป่ฉฑ" + "reservation_delete_dialog_submit_button": "ไบˆ็ด„ใ‚’ๅ‰Š้™ค" } diff --git a/web/public/static/langs/ko.json b/web/public/static/langs/ko.json index 2e46c7a..67c3128 100644 --- a/web/public/static/langs/ko.json +++ b/web/public/static/langs/ko.json @@ -93,7 +93,7 @@ "subscribe_dialog_error_user_not_authorized": "์‚ฌ์šฉ์ž {{username}} ์€(๋Š”) ์ธ์ฆ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค", "subscribe_dialog_login_username_label": "์‚ฌ์šฉ์ž ์ด๋ฆ„, ์˜ˆ๋ฅผ ๋“ค๋ฉด phil", "subscribe_dialog_login_password_label": "๋น„๋ฐ€๋ฒˆํ˜ธ", - "common_back": "๋’ค๋กœ๊ฐ€๊ธฐ", + "subscribe_dialog_login_button_back": "๋’ค๋กœ๊ฐ€๊ธฐ", "subscribe_dialog_login_button_login": "๋กœ๊ทธ์ธ", "prefs_notifications_title": "์•Œ๋ฆผ", "prefs_notifications_sound_title": "์•Œ๋ฆผ ํšจ๊ณผ์Œ", diff --git a/web/public/static/langs/nb_NO.json b/web/public/static/langs/nb_NO.json index 0dd9571..312791d 100644 --- a/web/public/static/langs/nb_NO.json +++ b/web/public/static/langs/nb_NO.json @@ -113,7 +113,7 @@ "prefs_notifications_delete_after_one_week_description": "Merknader slettes automatisk etter รฉn uke", "prefs_notifications_delete_after_one_month_description": "Merknader slettes automatisk etter รฉn mรฅned", "priority_min": "min.", - "common_back": "Tilbake", + "subscribe_dialog_login_button_back": "Tilbake", "prefs_notifications_delete_after_three_hours": "Etter tre timer", "prefs_users_table_base_url_header": "Tjeneste-nettadresse", "common_cancel": "Avbryt", diff --git a/web/public/static/langs/nl.json b/web/public/static/langs/nl.json index 8ccb629..3c7adb4 100644 --- a/web/public/static/langs/nl.json +++ b/web/public/static/langs/nl.json @@ -44,7 +44,7 @@ "notifications_mark_read": "Markeer als gelezen", "notifications_delete": "Verwijder", "notifications_copied_to_clipboard": "Gekopieerd naar klembord", - "notifications_tags": "Labels", + "notifications_tags": "Tags", "notifications_priority_x": "Prioriteit {{priority}}", "notifications_new_indicator": "Nieuwe notificatie", "notifications_attachment_image": "Afbeelding bijlage", @@ -140,7 +140,7 @@ "subscribe_dialog_subscribe_title": "Onderwerp abonneren", "subscribe_dialog_subscribe_description": "Onderwerpen zijn mogelijk niet beschermd met een wachtwoord, kies daarom een moeilijk te raden naam. Na abonneren kun je notificaties via PUT/POST sturen.", "subscribe_dialog_login_password_label": "Wachtwoord", - "common_back": "Terug", + "subscribe_dialog_login_button_back": "Terug", "subscribe_dialog_login_button_login": "Aanmelden", "subscribe_dialog_error_user_not_authorized": "Gebruiker {{username}} heeft geen toegang", "subscribe_dialog_error_user_anonymous": "anoniem", @@ -226,7 +226,7 @@ "account_usage_unlimited": "Onbeperkt", "account_basics_tier_title": "Account type", "account_basics_tier_admin": "Beheerder", - "account_basics_tier_admin_suffix_with_tier": "(met {{tier}} niveau)", + "account_basics_tier_admin_suffix_with_tier": "", "account_basics_tier_basic": "Basis", "account_basics_tier_free": "Gratis", "account_basics_tier_change_button": "Wijzig", @@ -248,137 +248,5 @@ "subscribe_dialog_error_topic_already_reserved": "Onderwerp al gereserveerd", "account_basics_password_dialog_title": "Wijzig wachtwoord", "account_usage_limits_reset_daily": "Gebruikslimieten worden dagelijks om middernacht (UTC) gereset", - "account_basics_tier_upgrade_button": "Upgrade naar Pro", - "account_upgrade_dialog_title": "Accountniveau wijzigen", - "account_upgrade_dialog_interval_yearly_discount_save": "bespaar {{discount}}%", - "account_upgrade_dialog_tier_price_billed_yearly": "{{price}} jaarlijks gefactureerd. Bespaar {{save}}.", - "account_upgrade_dialog_cancel_warning": "Hiermee wordt uw abonnement opgezegd en wordt uw account gedowngraded op {{date}}. Op die datum worden onderwerpreserveringen en berichten in de cache op de server verwijderd .", - "account_tokens_dialog_button_update": "Token bijwerken", - "account_upgrade_dialog_proration_info": "Pro rata: Bij een upgrade tussen betaalde abonnementen wordt het prijsverschil onmiddellijk in rekening gebracht. Wanneer u downgradet naar een lager niveau, wordt het saldo gebruikt om toekomstige factureringsperioden te betalen.", - "account_upgrade_dialog_reservations_warning_one": "Het geselecteerde niveau staat minder gereserveerde onderwerpen toe dan uw huidige niveau. Voordat u uw niveau wijzigt, , moet u ten minste รฉรฉn reservering verwijderen . U kunt reserveringen verwijderen in de Instellingen.", - "account_upgrade_dialog_reservations_warning_other": "Het geselecteerde niveau staat minder gereserveerde onderwerpen toe dan uw huidige niveau. Voordat u uw niveau wijzigt, moet u ten minste {{count}} reserveringen verwijderen. U kunt reserveringen verwijderen in de Instellingen.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} gereserveerde onderwerpen", - "account_upgrade_dialog_billing_contact_email": "Neem voor vragen over facturering rechtstreeks contact met ons op.", - "account_tokens_table_token_header": "Token", - "account_tokens_table_never_expires": "Verloopt nooit", - "account_tokens_table_current_session": "Huidige browsersessie", - "prefs_reservations_table_everyone_read_only": "Ik kan publiceren en abonneren, iedereen kan zich abonneren", - "prefs_reservations_table_everyone_write_only": "Ik kan publiceren en abonneren, iedereen kan publiceren", - "account_usage_reservations_none": "Geen gereserveerde onderwerpen voor dit account", - "account_usage_attachment_storage_title": "Bijlage-opslag", - "account_usage_attachment_storage_description": "{{filesize}} per bestand, verwijderd na {{expiry}}", - "account_delete_dialog_description": "Hiermee wordt uw account definitief verwijderd, inclusief alle gegevens die op de server zijn opgeslagen. Na verwijdering is uw gebruikersnaam 7 dagen niet beschikbaar. Als u echt wilt doorgaan, bevestig dan met uw wachtwoord in het onderstaande vak.", - "account_delete_dialog_billing_warning": "Als u uw account verwijdert, wordt ook uw facturering onmiddellijk geannuleerd. U heeft dan geen toegang meer tot het factureringsdashboard.", - "account_tokens_dialog_button_cancel": "Annuleren", - "reservation_delete_dialog_submit_button": "Reservering verwijderen", - "prefs_reservations_table_everyone_deny_all": "Alleen ik kan publiceren en abonneren", - "reservation_delete_dialog_description": "Het verwijderen van een reservering geeft het eigendom van het onderwerp op en stelt anderen in staat het te reserveren. U kunt bestaande berichten en bijlagen behouden of verwijderen.", - "account_basics_tier_interval_monthly": "maandelijks", - "account_basics_tier_interval_yearly": "jaarlijks", - "account_usage_basis_ip_description": "Gebruiksstatistieken en -limieten voor dit account zijn gebaseerd op uw IP-adres en kunnen dus worden gedeeld met andere gebruikers. De hierboven weergegeven limieten zijn bij benadering gebaseerd op de bestaande limieten.", - "account_usage_cannot_create_portal_session": "Kan factureringsportaal niet openen", - "account_delete_title": "Account verwijderen", - "account_delete_description": "Verwijder uw account definitief", - "account_delete_dialog_label": "Wachtwoord", - "account_delete_dialog_button_cancel": "Annuleren", - "account_delete_dialog_button_submit": "Verwijder uw account definitief", - "account_upgrade_dialog_interval_monthly": "Maandelijks", - "account_upgrade_dialog_interval_yearly": "Jaarlijks", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "bespaar tot {{discount}}%", - "account_upgrade_dialog_tier_features_no_reservations": "Geen gereserveerde onderwerpen", - "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} totale opslag", - "account_upgrade_dialog_tier_current_label": "Huidig", - "account_upgrade_dialog_button_update_subscription": "Abonnement bijwerken", - "account_tokens_title": "Toegangstokens", - "account_tokens_description": "Gebruik toegangstokens bij het publiceren en abonneren via de ntfy API, zodat u uw accountgegevens niet hoeft op te sturen. Bekijk de documentatie voor meer informatie.", - "account_tokens_table_label_header": "Label", - "account_tokens_table_cannot_delete_or_edit": "Kan huidige sessietoken niet bewerken of verwijderen", - "account_tokens_dialog_expires_label": "Toegangstoken verloopt over", - "account_tokens_dialog_expires_unchanged": "Vervaldatum ongewijzigd laten", - "account_tokens_dialog_expires_x_hours": "Token verloopt over {{hours}} uur", - "account_tokens_dialog_expires_x_days": "Token verloopt over {{days}} dagen", - "account_tokens_dialog_expires_never": "Token verloopt nooit", - "account_tokens_delete_dialog_title": "Toegangstoken verwijderen", - "account_tokens_delete_dialog_description": "Voordat u een toegangstoken verwijdert, moet u ervoor zorgen dat er geen toepassingen of scripts actief gebruik van maken. Deze actie kan niet ongedaan worden gemaakt.", - "prefs_users_table_cannot_delete_or_edit": "Kan ingelogde gebruiker niet verwijderen of bewerken", - "prefs_reservations_title": "Gereserveerde onderwerpen", - "prefs_reservations_description": "U kunt hier onderwerpnamen reserveren voor persoonlijk gebruik. Door een onderwerp te reserveren, wordt u eigenaar van het onderwerp en kunt u toegangsmachtigingen voor andere gebruikers voor het onderwerp definiรซren.", - "prefs_reservations_limit_reached": "Je hebt je limiet voor gereserveerde onderwerpen bereikt.", - "prefs_reservations_add_button": "Gereserveerd onderwerp toevoegen", - "prefs_reservations_table_click_to_subscribe": "Klik om je te abonneren", - "prefs_reservations_dialog_title_add": "Onderwerp reserveren", - "prefs_reservations_dialog_title_edit": "Gereserveerd onderwerp bewerken", - "prefs_reservations_dialog_title_delete": "Onderwerpreservering verwijderen", - "prefs_reservations_dialog_description": "Door een onderwerp te reserveren, wordt u eigenaar van het onderwerp en kunt u toegangsmachtigingen voor andere gebruikers voor het onderwerp definiรซren.", - "prefs_reservations_dialog_topic_label": "Onderwerp", - "prefs_reservations_dialog_access_label": "Toegang", - "reservation_delete_dialog_action_keep_title": "Bewaar in de cache opgeslagen berichten en bijlagen", - "reservation_delete_dialog_action_keep_description": "Berichten en bijlagen die in de cache op de server zijn opgeslagen, worden publiekelijk zichtbaar voor mensen die de onderwerpnaam kennen.", - "reservation_delete_dialog_action_delete_description": "Berichten en bijlagen in de cache worden permanent verwijderd. Deze actie kan niet ongedaan gemaakt worden.", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} gereserveerd onderwerp", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} dagelijks bericht", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} dagelijkse berichten", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} dagelijkse e-mail", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} dagelijkse e-mails", - "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per bestand", - "account_upgrade_dialog_tier_price_per_month": "maand", - "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} per jaar. Maandelijks gefactureerd.", - "account_upgrade_dialog_tier_selected_label": "Geselecteerd", - "account_upgrade_dialog_billing_contact_website": "Raadpleeg voor vragen over facturering onze website.", - "account_upgrade_dialog_button_cancel": "Annuleren", - "account_upgrade_dialog_button_redirect_signup": "Nu aanmelden", - "account_upgrade_dialog_button_pay_now": "Nu betalen en inschrijven", - "account_upgrade_dialog_button_cancel_subscription": "Abonnement opzeggen", - "account_tokens_table_last_access_header": "Laatste toegang", - "account_tokens_table_expires_header": "Verloopt op", - "common_copy_to_clipboard": "Kopieer naar klembord", - "account_tokens_table_copied_to_clipboard": "Toegangstoken gekopieerd", - "account_tokens_delete_dialog_submit_button": "Token definitief verwijderen", - "prefs_users_description_no_sync": "Gebruikers en wachtwoorden worden niet gesynchroniseerd met uw account.", - "reservation_delete_dialog_action_delete_title": "Verwijder in de cache opgeslagen berichten en bijlagen", - "account_basics_tier_description": "Het niveau van uw account", - "account_basics_tier_admin_suffix_no_tier": "(geen niveau)", - "account_basics_tier_manage_billing_button": "Facturering beheren", - "account_usage_messages_title": "Gepubliceerde berichten", - "account_usage_emails_title": "E-mails verzonden", - "account_usage_reservations_title": "Gereserveerde onderwerpen", - "account_tokens_table_create_token_button": "Toegangstoken maken", - "account_tokens_table_last_origin_tooltip": "Vanaf IP-adres {{ip}}, klik om op te zoeken", - "account_tokens_dialog_title_create": "Toegangstoken maken", - "account_tokens_dialog_title_edit": "Toegangstoken bewerken", - "account_tokens_dialog_title_delete": "Toegangstoken verwijderen", - "account_tokens_dialog_label": "Label, bijv. Radarr-meldingen", - "account_tokens_dialog_button_create": "Token maken", - "prefs_reservations_edit_button": "Onderwerptoegang bewerken", - "prefs_reservations_delete_button": "Toegang tot onderwerp resetten", - "prefs_reservations_table": "Tabel met gereserveerde onderwerpen", - "prefs_reservations_table_topic_header": "Onderwerp", - "prefs_reservations_table_access_header": "Toegang", - "prefs_reservations_table_everyone_read_write": "Iedereen kan publiceren en abonneren", - "prefs_reservations_table_not_subscribed": "Niet geabonneerd", - "publish_dialog_call_label": "Telefoongesprek", - "publish_dialog_call_reset": "Telefoongesprek verwijderen", - "publish_dialog_chip_call_label": "Telefoongesprek", - "account_basics_phone_numbers_title": "Telefoonnummers", - "account_basics_phone_numbers_description": "Voor meldingen via telefoongesprekken", - "account_basics_phone_numbers_no_phone_numbers_yet": "Nog geen telefoonnummers", - "account_basics_phone_numbers_dialog_verify_button_call": "Bel me", - "account_upgrade_dialog_tier_features_calls_one": "{{calls}} dagelijkse telefoontjes", - "account_basics_phone_numbers_copied_to_clipboard": "Telefoonnummer gekopieerd naar klembord", - "publish_dialog_call_item": "Bel telefoonnummer {{nummer}}", - "account_basics_phone_numbers_dialog_check_verification_button": "Bevestig code", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "Geen geverifieerde telefoonnummers", - "account_basics_phone_numbers_dialog_channel_call": "Telefoongesprek", - "account_basics_phone_numbers_dialog_number_label": "Telefoonnummer", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_basics_phone_numbers_dialog_code_placeholder": "bijv. 123456", - "account_upgrade_dialog_tier_features_calls_other": "{{calls}} dagelijkse telefoontjes", - "account_upgrade_dialog_tier_features_no_calls": "Geen telefoontjes", - "account_basics_phone_numbers_dialog_description": "Als u de functie voor oproepmeldingen wilt gebruiken, moet u ten minste รฉรฉn telefoonnummer toevoegen en verifiรซren. Verificatie kan worden gedaan via sms of een telefoontje.", - "account_basics_phone_numbers_dialog_title": "Telefoonnummer toevoegen", - "account_basics_phone_numbers_dialog_number_placeholder": "bijv. +1222333444", - "account_basics_phone_numbers_dialog_verify_button_sms": "Stuur SMS", - "account_basics_phone_numbers_dialog_code_label": "Verificatiecode", - "account_usage_calls_title": "Aantal telefoontjes", - "account_usage_calls_none": "Met dit account kan niet worden gebeld" + "account_basics_tier_upgrade_button": "Upgrade naar Pro" } diff --git a/web/public/static/langs/pl.json b/web/public/static/langs/pl.json index 9dea2b8..deccad9 100644 --- a/web/public/static/langs/pl.json +++ b/web/public/static/langs/pl.json @@ -107,7 +107,7 @@ "subscribe_dialog_login_username_label": "Nazwa uลผytkownika, np. phil", "subscribe_dialog_login_password_label": "Hasล‚o", "publish_dialog_button_cancel": "Anuluj", - "common_back": "Powrรณt", + "subscribe_dialog_login_button_back": "Powrรณt", "subscribe_dialog_login_button_login": "Zaloguj siฤ™", "subscribe_dialog_error_user_not_authorized": "Uลผytkownik {{username}} nie ma uprawnieล„", "subscribe_dialog_error_user_anonymous": "anonim", @@ -253,7 +253,7 @@ "account_tokens_table_expires_header": "Termin waลผnoล›ci", "account_tokens_table_never_expires": "Bezterminowy", "account_tokens_table_current_session": "Aktualna sesja przeglฤ…darki", - "common_copy_to_clipboard": "Kopiuj do schowka", + "account_tokens_table_copy_to_clipboard": "Kopiuj do schowka", "account_tokens_table_copied_to_clipboard": "Token zostaล‚ skopiowany", "account_tokens_table_cannot_delete_or_edit": "Nie moลผna edytowaฤ‡ ani usunฤ…ฤ‡ tokenu aktualnej sesji", "account_tokens_table_create_token_button": "Utwรณrz token dostฤ™powy", @@ -308,14 +308,5 @@ "account_upgrade_dialog_button_pay_now": "Zapล‚aฤ‡ i aktywuj subskrypcjฤ™", "account_tokens_dialog_button_cancel": "Anuluj", "account_tokens_dialog_expires_label": "Token dostฤ™powy wygasa po", - "account_tokens_dialog_expires_unchanged": "Pozostaw termin waลผnoล›ci bez zmian", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} rezerwacja tematu", - "account_upgrade_dialog_tier_features_reservations_few": "{{reservations}} rezerwacje tematรณw", - "account_upgrade_dialog_tier_features_reservations_many": "{{reservations}} rezerwacji tematรณw", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} mail dziennie", - "account_upgrade_dialog_tier_features_emails_few": "{{emails}} maile dziennie", - "account_upgrade_dialog_tier_features_emails_many": "{{emails}} maili dziennie", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} wiadomoล›ฤ‡ dziennie", - "account_upgrade_dialog_tier_features_messages_few": "{{messages}} wiadomoล›ci dziennie", - "account_upgrade_dialog_tier_features_messages_many": "{{messages}} wiadomoล›ci dziennie" + "account_tokens_dialog_expires_unchanged": "Pozostaw termin waลผnoล›ci bez zmian" } diff --git a/web/public/static/langs/pt.json b/web/public/static/langs/pt.json index 57d5656..61338db 100644 --- a/web/public/static/langs/pt.json +++ b/web/public/static/langs/pt.json @@ -31,7 +31,7 @@ "notifications_attachment_copy_url_title": "Copiar URL do anexo para a รกrea de transferรชncia", "notifications_attachment_copy_url_button": "Copiar URL", "notifications_attachment_open_title": "Ir para {{url}}", - "notifications_attachment_link_expired": "a ligaรงรฃo de descarga expirou", + "notifications_attachment_link_expired": "a ligaรงรฃo de transferรชncia expirou", "notifications_attachment_open_button": "Abrir anexo", "notifications_attachment_link_expires": "a ligaรงรฃo expira em {{date}}", "notifications_attachment_file_image": "ficheiro de imagem", @@ -144,7 +144,7 @@ "subscribe_dialog_login_description": "Esse tรณpico รฉ protegido por palavra-passe. Por favor insira um nome de utilizador e palavra-passe para subscrever.", "subscribe_dialog_login_username_label": "Nome, por exemplo: \"filipe\"", "subscribe_dialog_login_password_label": "Palavra-passe", - "common_back": "Voltar", + "subscribe_dialog_login_button_back": "Voltar", "subscribe_dialog_login_button_login": "Autenticar", "subscribe_dialog_error_user_anonymous": "anรณnimo", "prefs_notifications_title": "Notificaรงรตes", @@ -214,17 +214,5 @@ "login_link_signup": "Registar", "action_bar_reservation_add": "Reservar tรณpico", "action_bar_sign_up": "Registar", - "nav_button_account": "Conta", - "common_copy_to_clipboard": "Copiar", - "nav_upgrade_banner_label": "Atualizar para ntfy Pro", - "alert_not_supported_context_description": "Notificaรงรตes sรฃo suportadas apenas sobre HTTPS. Essa รฉ uma limitaรงรฃo da API de Notificaรงรตes.", - "display_name_dialog_title": "Alterar nome mostrado", - "display_name_dialog_description": "Configura um nome alternativo ao tรณpico que รฉ mostrado na lista de assinaturas. Isto ajuda a identificar tรณpicos com nomes complicados mais facilmente.", - "display_name_dialog_placeholder": "Nome exibido", - "reserve_dialog_checkbox_label": "Reservar tรณpico e configurar acesso", - "publish_dialog_call_label": "Chamada telefรดnica", - "publish_dialog_call_placeholder": "Nรบmero de telefone para ligar com a mensagem, ex: +12223334444, ou 'Sim'", - "publish_dialog_call_reset": "Remover chamada telefรดnica", - "publish_dialog_chip_call_label": "Chamada telefรดnica", - "subscribe_dialog_subscribe_button_generate_topic_name": "Gerar nome" + "nav_button_account": "Conta" } diff --git a/web/public/static/langs/pt_BR.json b/web/public/static/langs/pt_BR.json index acf5bca..79622be 100644 --- a/web/public/static/langs/pt_BR.json +++ b/web/public/static/langs/pt_BR.json @@ -93,7 +93,7 @@ "prefs_notifications_min_priority_low_and_higher": "Baixa prioridade e acima", "prefs_notifications_min_priority_default_and_higher": "Prioridade padrรฃo e acima", "subscribe_dialog_login_password_label": "Senha", - "common_back": "Voltar", + "subscribe_dialog_login_button_back": "Voltar", "prefs_notifications_min_priority_high_and_higher": "Alta prioridade e acima", "prefs_notifications_min_priority_max_only": "Apenas prioridade mรกxima", "prefs_notifications_delete_after_title": "Apagar notificaรงรตes", diff --git a/web/public/static/langs/ru.json b/web/public/static/langs/ru.json index 9633d97..1a0435e 100644 --- a/web/public/static/langs/ru.json +++ b/web/public/static/langs/ru.json @@ -1,5 +1,5 @@ { - "publish_dialog_priority_min": "ะœะธะฝะธะผะฐะปัŒะฝั‹ะน ะฟั€ะธะพั€ะธั‚ะตั‚", + "publish_dialog_priority_min": "ะะฐะธะผะตะฝัŒัˆะธะน ะฟั€ะธะพั€ะธั‚ะตั‚", "action_bar_settings": "ะะฐัั‚ั€ะพะนะบะธ", "action_bar_send_test_notification": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ ั‚ะตัั‚ะพะฒะพะต ัƒะฒะตะดะพะผะปะตะฝะธะต", "action_bar_clear_notifications": "ะฃะดะฐะปะธั‚ัŒ ะฒัะต ัƒะฒะตะดะพะผะปะตะฝะธั", @@ -9,22 +9,22 @@ "notifications_none_for_any_description": "ะงั‚ะพะฑั‹ ะพั‚ะฟั€ะฐะฒะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธะต ะฝะฐ ั‚ะตะผัƒ, ะฟั€ะพัั‚ะพ ัะดะตะปะฐะตั‚ะต PUT ะธะปะธ POST-ะทะฐะฟั€ะพั ะฝะฐ ะตั‘ URL-ะฐะดั€ะตั. ะ’ะพั‚ ะฟั€ะธะผะตั€ ั ะธัะฟะพะปัŒะทะพะฒะฐะฝะธะตะผ ะพะดะฝะพะน ะธะท ะฒะฐัˆะธั… ั‚ะตะผ.", "notifications_no_subscriptions_title": "ะŸะพั…ะพะถะต, ั‡ั‚ะพ ัƒ ะฒะฐั ะตั‰ั‘ ะฝะตั‚ ะฟะพะดะฟะธัะพะบ.", "alert_grant_description": "ะ ะฐะทั€ะตัˆะธั‚ะต ะฑั€ะฐัƒะทะตั€ัƒ ะฟะพะบะฐะทั‹ะฒะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั.", - "notifications_no_subscriptions_description": "ะะฐะถะผะธั‚ะต ะฝะฐ ััั‹ะปะบัƒ \"{{linktext}}\", ั‡ั‚ะพะฑั‹ ัะพะทะดะฐั‚ัŒ ะธะปะธ ะฟะพะดะฟะธัะฐั‚ัŒัั ะฝะฐ ั‚ะตะผัƒ. ะŸะพัะปะต ัั‚ะพะณะพ ะ’ั‹ ัะผะพะถะตั‚ะต ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ ัะพะพะฑั‰ะตะฝะธั ะธัะฟะพะปัŒะทัƒั PUT ะธะปะธ POST-ะทะฐะฟั€ะพัั‹ ะธ ะฟะพะปัƒั‡ะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั ะทะดะตััŒ.", + "notifications_no_subscriptions_description": "ะะฐะถะผะธั‚ะต ััั‹ะปะบัƒ \"{{linktext}}\", ั‡ั‚ะพะฑั‹ ัะพะทะดะฐั‚ัŒ ะธะปะธ ะฟะพะดะฟะธัะฐั‚ัŒัั ะฝะฐ ั‚ะตะผัƒ. ะŸะพัะปะต ัั‚ะพะณะพ ะ’ั‹ ัะผะพะถะตั‚ะต ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั, ะธัะฟะพะปัŒะทัƒั PUT ะธะปะธ POST-ะทะฐะฟั€ะพัั‹, ะธ ะฟะพะปัƒั‡ะฐั‚ัŒ ะธั… ะทะดะตััŒ.", "notifications_example": "ะŸั€ะธะผะตั€", "notifications_more_details": "ะ”ะปั ะฑะพะปะตะต ะฟะพะดั€ะพะฑะฝะพะน ะธะฝั„ะพั€ะผะฐั†ะธะธ, ะฟะพัะตั‚ะธั‚ะต ะฝะฐัˆ ัะฐะนั‚ ะธะปะธ ะดะพะบัƒะผะตะฝั‚ะฐั†ะธัŽ.", "notifications_loading": "ะ˜ะดะตั‚ ะทะฐะณั€ัƒะทะบะฐ ัƒะฒะตะดะพะผะปะตะฝะธะน โ€ฆ", - "publish_dialog_title_topic": "ะžะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ะฒ {{topic}}", - "publish_dialog_title_no_topic": "ะžะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธะต", + "publish_dialog_title_topic": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ ะฒ {{topic}}", + "publish_dialog_title_no_topic": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธะต", "publish_dialog_progress_uploading": "ะ˜ะดะตั‚ ะทะฐะณั€ัƒะทะบะฐ โ€ฆ", "publish_dialog_progress_uploading_detail": "ะ—ะฐะณั€ัƒะถะฐะตั‚ัั {{loaded}}/{{total}} ({{percent}}%) โ€ฆ", - "publish_dialog_message_published": "ะฃะฒะตะดะพะผะปะตะฝะธะต ะพะฟัƒะฑะปะธะบะพะฒะฐะฝะพ", - "publish_dialog_attachment_limits_file_and_quota_reached": "ะฟั€ะตะฒั‹ัˆะฐะตั‚ ะผะฐะบัะธะผะฐะปัŒะฝั‹ะน ั€ะฐะทะผะตั€ ั„ะฐะนะปะฐ {{fileSizeLimit}} ะธ ะบะฒะพั‚ัƒ, ะพัั‚ะฐะปะพััŒ {{remainingBytes}}", + "publish_dialog_message_published": "ะฃะฒะตะดะพะผะปะตะฝะธะต ะพั‚ะฟั€ะฐะฒะปะตะฝะพ", + "publish_dialog_attachment_limits_file_and_quota_reached": "ะฟั€ะตะฒั‹ัˆะฐะตั‚ ะผะฐะบัะธะผะฐะปัŒะฝั‹ะน ั€ะฐะทะผะตั€ ั„ะฐะนะปะฐ {{fileSizeLimit}} ะธ ััƒะผะผะฐั€ะฝั‹ะน ะพะฑัŠะตะผ ะฒัะตั… ะทะฐะณั€ัƒะถะตะฝะฝั‹ั… ั„ะฐะนะปะพะฒ (ะพัั‚ะฐะปะพััŒ {{remainingBytes}})", "publish_dialog_attachment_limits_file_reached": "ะฟั€ะตะฒั‹ัˆะฐะตั‚ ะผะฐะบัะธะผะฐะปัŒะฝั‹ะน ั€ะฐะทะผะตั€ ั„ะฐะนะปะฐ {{fileSizeLimit}}", - "publish_dialog_attachment_limits_quota_reached": "ะฟั€ะตะฒั‹ัˆะฐะตั‚ ะบะฒะพั‚ัƒ, ะพัั‚ะฐะปะพััŒ {{remainingBytes}}", + "publish_dialog_attachment_limits_quota_reached": "ะฟั€ะตะฒั‹ัˆะฐะตั‚ ััƒะผะผะฐั€ะฝั‹ะน ะพะฑัŠะตะผ ะฒัะตั… ะทะฐะณั€ัƒะถะตะฝะฝั‹ั… ั„ะฐะนะปะพะฒ (ะพัั‚ะฐะปะพััŒ {{remainingBytes}})", "publish_dialog_priority_low": "ะะธะทะบะธะน ะฟั€ะธะพั€ะธั‚ะตั‚", "publish_dialog_priority_default": "ะกั‚ะฐะฝะดะฐั€ั‚ะฝั‹ะน ะฟั€ะธะพั€ะธั‚ะตั‚", "publish_dialog_priority_high": "ะ’ั‹ัะพะบะธะน ะฟั€ะธะพั€ะธั‚ะตั‚", - "publish_dialog_priority_max": "ะœะฐะบัะธะผะฐะปัŒะฝั‹ะน ะฟั€ะธะพั€ะธั‚ะตั‚", + "publish_dialog_priority_max": "ะะฐะธะฒั‹ััˆะธะน ะฟั€ะธะพั€ะธั‚ะตั‚", "publish_dialog_base_url_label": "URL-ะฐะดั€ะตั ัะตั€ะฒะธัะฐ", "publish_dialog_base_url_placeholder": "URL-ะฐะดั€ะตั ัะตั€ะฒะธัะฐ, ะฝะฐะฟั€ะธะผะตั€ https://example.com", "publish_dialog_topic_label": "ะะฐะทะฒะฐะฝะธะต ั‚ะตะผั‹", @@ -37,9 +37,9 @@ "publish_dialog_tags_placeholder": "ะกะฟะธัะพะบ ั‚ัะณะพะฒ, ั€ะฐะทะดะตะปั‘ะฝะฝั‹ะน ะทะฐะฟัั‚ะพะน, ะฝะฐะฟั€ะธะผะตั€: warning, srv1-backup", "publish_dialog_priority_label": "ะŸั€ะธะพั€ะธั‚ะตั‚", "publish_dialog_click_label": "ะกัั‹ะปะบะฐ ะฟั€ะธ ะพั‚ะบั€ั‹ั‚ะธะธ", - "publish_dialog_click_placeholder": "URL-ะฐะดั€ะตั, ะบะพั‚ะพั€ั‹ะน ะพั‚ะบั€ะพะตั‚ัั ะฟั€ะธ ะฝะฐะถะฐั‚ะธะธ ะฝะฐ ัƒะฒะตะดะพะผะปะตะฝะธะต", + "publish_dialog_click_placeholder": "URL-ะฐะดั€ะตั, ะบะพั‚ะพั€ั‹ะน ะพั‚ะบั€ะพะตั‚ัั ะฟั€ะธ ะฒะทะฐะธะผะพะดะตะนัั‚ะฒะธะธ ั ัƒะฒะตะดะพะผะปะตะฝะธะตะผ", "publish_dialog_email_label": "ะญะปะตะบั‚ั€ะพะฝะฝะฐั ะฟะพั‡ั‚ะฐ", - "message_bar_error_publishing": "ะžัˆะธะฑะบะฐ ะฟัƒะฑะปะธะบะฐั†ะธะธ ัƒะฒะตะดะพะผะปะตะฝะธั", + "message_bar_error_publishing": "ะžัˆะธะฑะบะฐ ะพั‚ะฟั€ะฐะฒะบะธ ัƒะฒะตะดะพะผะปะตะฝะธั", "alert_not_supported_title": "ะฃะฒะตะดะพะผะปะตะฝะธั ะฝะต ะฟะพะดะดะตั€ะถะธะฒะฐัŽั‚ัั", "alert_not_supported_description": "ะฃะฒะตะดะพะผะปะตะฝะธั ะฝะต ะฟะพะดะดะตั€ะถะธะฒะฐัŽั‚ัั ะฒะฐัˆะธะผ ะฑั€ะฐัƒะทะตั€ะพะผ.", "notifications_copied_to_clipboard": "ะกะบะพะฟะธั€ะพะฒะฐะฝะพ ะฒ ะฑัƒั„ะตั€ ะพะฑะผะตะฝะฐ", @@ -49,7 +49,7 @@ "nav_button_all_notifications": "ะ’ัะต ัƒะฒะตะดะพะผะปะตะฝะธั", "nav_button_settings": "ะะฐัั‚ั€ะพะนะบะธ", "nav_button_documentation": "ะ”ะพะบัƒะผะตะฝั‚ะฐั†ะธั", - "nav_button_publish_message": "ะžะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธะต", + "nav_button_publish_message": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธะต", "nav_button_subscribe": "ะŸะพะดะฟะธัะฐั‚ัŒัั ะฝะฐ ั‚ะตะผัƒ", "alert_grant_button": "ะ ะฐะทั€ะตัˆะธั‚ัŒ", "notifications_attachment_copy_url_button": "ะกะบะพะฟะธั€ะพะฒะฐั‚ัŒ URL-ะฐะดั€ะตั", @@ -78,7 +78,7 @@ "publish_dialog_chip_email_label": "ะŸะตั€ะตัะปะฐั‚ัŒ ะฝะฐ ัะปะตะบั‚ั€ะพะฝะฝัƒัŽ ะฟะพั‡ั‚ัƒ", "publish_dialog_chip_attach_url_label": "ะŸั€ะธะบั€ะตะฟะธั‚ัŒ ั„ะฐะนะป ะฟะพ URL", "publish_dialog_chip_attach_file_label": "ะŸั€ะธะบั€ะตะฟะธั‚ัŒ ะปะพะบะฐะปัŒะฝั‹ะน ั„ะฐะนะป", - "publish_dialog_chip_delay_label": "ะ—ะฐะดะตั€ะถะฐั‚ัŒ ะดะพัั‚ะฐะฒะบัƒ", + "publish_dialog_chip_delay_label": "ะ—ะฐะดะตั€ะถะบะฐ ะดะพัั‚ะฐะฒะบะธ", "publish_dialog_chip_topic_label": "ะ˜ะทะผะตะฝะธั‚ัŒ ั‚ะตะผัƒ", "publish_dialog_details_examples_description": "ะŸั€ะธะผะตั€ั‹ ะธ ะฟะพะดั€ะพะฑะฝะพะต ะพะฟะธัะฐะฝะธะต ะฒัะตั… ั„ัƒะฝะบั†ะธะน ัะผะพั‚ั€ะธั‚ะต ะฒ ะดะพะบัƒะผะตะฝั‚ะฐั†ะธะธ.", "publish_dialog_attach_label": "URL-ะฐะดั€ะตั ะฒะปะพะถะตะฝะธั", @@ -86,7 +86,7 @@ "publish_dialog_other_features": "ะ”ั€ัƒะณะธะต ะฒะพะทะผะพะถะฝะพัั‚ะธ:", "publish_dialog_button_cancel_sending": "ะžั‚ะผะตะฝะธั‚ัŒ ะพั‚ะฟั€ะฐะฒะบัƒ", "publish_dialog_button_send": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ", - "publish_dialog_checkbox_publish_another": "ะžะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ะตั‰ะต", + "publish_dialog_checkbox_publish_another": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ ะตั‰ะต", "publish_dialog_attached_file_title": "ะŸั€ะธะบั€ะตะฟะปั‘ะฝะฝั‹ะน ั„ะฐะนะป:", "publish_dialog_attached_file_filename_placeholder": "ะ˜ะผั ะฟั€ะธะบั€ะตะฟะปั‘ะฝะฝะพะณะพ ั„ะฐะนะปะฐ", "emoji_picker_search_placeholder": "ะŸะพะธัะบ ัะผะฐะนะปะธะบะพะฒ", @@ -98,7 +98,7 @@ "subscribe_dialog_login_description": "ะญั‚ะฐ ั‚ะตะผะฐ ะทะฐั‰ะธั‰ะตะฝะฐ ะฟะฐั€ะพะปะตะผ. ะŸะพะถะฐะปัƒะนัั‚ะฐ, ะฒะฒะตะดะธั‚ะต ะธะผั ะฟะพะปัŒะทะพะฒะฐั‚ะตะปั ะธ ะฟะฐั€ะพะปัŒ, ั‡ั‚ะพะฑั‹ ะฟะพะดะฟะธัะฐั‚ัŒัั.", "subscribe_dialog_login_username_label": "ะ˜ะผั ะฟะพะปัŒะทะพะฒะฐั‚ะตะปั. ะะฐะฟั€ะธะผะตั€, phil", "subscribe_dialog_login_password_label": "ะŸะฐั€ะพะปัŒ", - "common_back": "ะะฐะทะฐะด", + "subscribe_dialog_login_button_back": "ะะฐะทะฐะด", "subscribe_dialog_login_button_login": "ะ’ะพะนั‚ะธ", "subscribe_dialog_error_user_not_authorized": "ะŸะพะปัŒะทะพะฒะฐั‚ะตะปัŒ {{username}} ะฝะต ะฐะฒั‚ะพั€ะธะทะพะฒะฐะฝ", "subscribe_dialog_error_user_anonymous": "ะฐะฝะพะฝะธะผะฝั‹ะน ะฟะพะปัŒะทะพะฒะฐั‚ะตะปัŒ", @@ -106,13 +106,13 @@ "prefs_notifications_sound_title": "ะ—ะฒัƒะบ ัƒะฒะตะดะพะผะปะตะฝะธั", "prefs_notifications_sound_description_none": "ะฃะฒะตะดะพะผะปะตะฝะธั ะฝะต ะฒะพัะฟั€ะพะธะทะฒะพะดัั‚ ะฝะธะบะฐะบะธั… ะทะฒัƒะบะพะฒ ะฟั€ะธ ะฟะพะปัƒั‡ะตะฝะธะธ", "prefs_notifications_sound_no_sound": "ะ‘ะตะท ะทะฒัƒะบะฐ", - "prefs_notifications_min_priority_title": "ะœะธะฝะธะผะฐะปัŒะฝั‹ะน ะฟั€ะธะพั€ะธั‚ะตั‚", - "prefs_notifications_min_priority_description_any": "ะŸะพะบะฐะทั‹ะฒะฐั‚ัŒ ะฒัะต ัƒะฒะตะดะพะผะปะตะฝะธั, ะฝะตะทะฐะฒะธัะธะผะพ ะพั‚ ะฟั€ะธะพั€ะธั‚ะตั‚ะฐ", + "prefs_notifications_min_priority_title": "ะะฐะธะผะตะฝัŒัˆะธะน ะฟั€ะธะพั€ะธั‚ะตั‚", + "prefs_notifications_min_priority_description_any": "ะŸะพะบะฐะทะฐั‚ัŒ ะฒัะต ัƒะฒะตะดะพะผะปะตะฝะธั, ะฝะตะทะฐะฒะธัะธะผะพ ะพั‚ ะฟั€ะธะพั€ะธั‚ะตั‚ะฐ", "prefs_notifications_min_priority_description_x_or_higher": "ะŸะพะบะฐะทั‹ะฒะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั, ะตัะปะธ ะฟั€ะธะพั€ะธั‚ะตั‚ {{number}} ({{name}}) ะธะปะธ ะฒั‹ัˆะต", - "prefs_notifications_min_priority_description_max": "ะŸะพะบะฐะทั‹ะฒะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั, ะตัะปะธ ะฟั€ะธะพั€ะธั‚ะตั‚ ั€ะฐะฒะตะฝ 5 (ะผะฐะบัะธะผะฐะปัŒะฝั‹ะน)", + "prefs_notifications_min_priority_description_max": "ะŸะพะบะฐะทั‹ะฒะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั, ะตัะปะธ ะฟั€ะธะพั€ะธั‚ะตั‚ ั€ะฐะฒะตะฝ 5 (ะฝะฐะธะฒั‹ััˆะธะน)", "prefs_notifications_min_priority_any": "ะ›ัŽะฑะพะน ะฟั€ะธะพั€ะธั‚ะตั‚", "prefs_notifications_min_priority_low_and_higher": "ะะธะทะบะธะน ะฟั€ะธะพั€ะธั‚ะตั‚ ะธ ะฒั‹ัˆะต", - "prefs_notifications_min_priority_max_only": "ะขะพะปัŒะบะพ ะผะฐะบัะธะผะฐะปัŒะฝั‹ะน ะฟั€ะธะพั€ะธั‚ะตั‚", + "prefs_notifications_min_priority_max_only": "ะขะพะปัŒะบะพ ะฝะฐะธะฒั‹ััˆะธะน ะฟั€ะธะพั€ะธั‚ะตั‚", "prefs_notifications_delete_after_title": "ะฃะดะฐะปะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั", "prefs_notifications_delete_after_never": "ะะธะบะพะณะดะฐ", "prefs_notifications_delete_after_three_hours": "ะงะตั€ะตะท ั‚ั€ะธ ั‡ะฐัะฐ", @@ -140,11 +140,11 @@ "common_save": "ะกะพั…ั€ะฐะฝะธั‚ัŒ", "prefs_appearance_title": "ะ’ะฝะตัˆะฝะธะน ะฒะธะด", "prefs_appearance_language_title": "ะฏะทั‹ะบ", - "priority_min": "ะผะธะฝะธะผะฐะปัŒะฝั‹ะน", + "priority_min": "ะฝะฐะธะผะตะฝัŒัˆะธะน", "priority_low": "ะฝะธะทะบะธะน", "priority_default": "ัั‚ะฐะฝะดะฐั€ั‚ะฝั‹ะน", "priority_high": "ะฒั‹ัะพะบะธะน", - "priority_max": "ะผะฐะบัะธะผะฐะปัŒะฝั‹ะน", + "priority_max": "ะฝะฐะธะฒั‹ััˆะธะน", "error_boundary_title": "ะž ะฝะตั‚, ntfy ัะปะพะผะฐะปัั", "error_boundary_button_copy_stack_trace": "ะกะบะพะฟะธั€ะพะฒะฐั‚ัŒ ั‚ั€ะฐััะธั€ะพะฒะบัƒ ัั‚ะตะบะฐ", "error_boundary_stack_trace": "ะขั€ะฐััะธั€ะพะฒะบะฐ ัั‚ะตะบะฐ", @@ -155,7 +155,7 @@ "action_bar_show_menu": "ะŸะพะบะฐะทะฐั‚ัŒ ะผะตะฝัŽ", "action_bar_logo_alt": "ะ›ะพะณะพั‚ะธะฟ ntfy", "emoji_picker_search_clear": "ะกะฑั€ะพัะธั‚ัŒ ะฟะพะธัะบ", - "account_upgrade_dialog_cancel_warning": "ะญั‚ะพ ะดะตะนัั‚ะฒะธะต ะพั‚ะผะตะฝะธั‚ ะ’ะฐัˆัƒ ะฟะพะดะฟะธัะบัƒ ะธ ะฟะตั€ะตะฒะตะดะตั‚ ะ’ะฐัˆัƒัŽ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ ะฝะฐ ะฑะตัะฟะปะฐั‚ะฝะพะต ะพะฑัะปัƒะถะธะฒะฐะฝะธะต {{date}}. ะŸั€ะธ ะฝะฐัั‚ัƒะฟะปะตะฝะธะธ ัั‚ะพะน ะดะฐั‚ั‹, ะฒัะต ั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธั ะธ ัะพะพะฑั‰ะตะฝะธั ะฒ ะบััˆะต ะฑัƒะดัƒั‚ ัƒะดะฐะปะตะฝั‹.", + "account_upgrade_dialog_cancel_warning": "ะญั‚ะพ ะดะตะนัั‚ะฒะธะต ะพั‚ะผะตะฝะธั‚ ะ’ะฐัˆัƒ ะฟะพะดะฟะธัะบัƒ ะธ ะฟะตั€ะตะฒะตะดะตั‚ ะ’ะฐัˆัƒัŽ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ ะฝะฐ ะฑะตัะฟะปะฐั‚ะฝะพะต ะพะฑัะปัƒะถะธะฒะฐะฝะธะต {{date}}. ะŸั€ะธ ะฝะฐัั‚ัƒะฟะปะตะฝะธะธ ัั‚ะพะน ะดะฐั‚ั‹, ะฒัะต ั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธั ะธ ัƒะฒะตะดะพะผะปะตะฝะธั ะฒ ะบััˆะต ะฑัƒะดัƒั‚ ัƒะดะฐะปะตะฝั‹.", "account_tokens_table_create_token_button": "ะกะพะทะดะฐั‚ัŒ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟะฐ", "account_tokens_table_last_origin_tooltip": "ั IP-ะฐะดั€ะตัะฐ {{ip}}, ะฝะฐะถะผะธั‚ะต ะดะปั ะฟะพะดั€ะพะฑะฝะพัั‚ะตะน", "account_tokens_dialog_title_edit": "ะ˜ะทะผะตะฝะธั‚ัŒ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟะฐ", @@ -163,16 +163,16 @@ "account_delete_dialog_billing_warning": "ะฃะดะฐะปะตะฝะธะต ัƒั‡ะตั‚ะฝะพะน ะทะฐะฟะธัะธ ั‚ะฐะบะถะต ะพั‚ะผะตะฝัะตั‚ ะฒัะต ะฟะปะฐั‚ะฝั‹ะต ะฟะพะดะฟะธัะบะธ. ะฃ ะ’ะฐั ะฝะต ะฑัƒะดะตั‚ ะดะพัั‚ัƒะฟะฐ ะบ ะฟะพั€ั‚ะฐะปัƒ ะพะฟะปะฐั‚ั‹.", "account_delete_dialog_description": "ะญั‚ะพ ะดะตะนัั‚ะฒะธะต ะฑะตะทะฒะพะทะฒั€ะฐั‚ะฝะพ ัƒะดะฐะปะธั‚ ะ’ะฐัˆัƒ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ, ะฒะบะปัŽั‡ะฐั ะฒัะต ะ’ะฐัˆะธ ะดะฐะฝะฝั‹ะต ั…ั€ะฐะฝัั‰ะธะตัั ะฝะฐ ัะตั€ะฒะตั€ะต. ะŸะพัะปะต ัƒะดะฐะปะตะฝะธั, ะ’ะฐัˆะต ะธะผั ะฟะพะปัŒะทะพะฒะฐั‚ะตะปั ะฝะต ะฑัƒะดะตั‚ ะดะพัั‚ัƒะฟะฝะพ ะดะปั ั€ะตะณะธัั‚ั€ะฐั†ะธะธ ะฒ ั‚ะตั‡ะตะฝะธะธ 7 ะดะฝะตะน. ะ•ัะปะธ ะ’ั‹ ะดะตะนัั‚ะฒะธั‚ะตะปัŒะฝะพ ั…ะพั‚ะธั‚ะต ะฟั€ะพะดะพะปะถะธั‚ัŒ, ะฟะพะถะฐะปัƒะนัั‚ะฐ ะฒะฒะตะดะธั‚ะต ะ’ะฐัˆ ะฟะฐั€ะพะปัŒ ะฝะธะถะต.", "account_delete_dialog_label": "ะŸะฐั€ะพะปัŒ", - "reservation_delete_dialog_action_keep_description": "ะกะพะพะฑั‰ะตะฝะธั ะธ ะฒะปะพะถะตะฝะธั ะบะพั‚ะพั€ั‹ะต ะฝะฐั…ะพะดัั‚ัั ะฒ ะบััˆะต ัะตั€ะฒะตั€ะฐ ัั‚ะฐะฝัƒั‚ ะดะพัั‚ัƒะฟะฝั‹ ะฒัะตะผ, ะบั‚ะพ ะทะฝะฐะตั‚ ะธะผั ั‚ะตะผั‹.", + "reservation_delete_dialog_action_keep_description": "ะฃะฒะตะดะพะผะปะตะฝะธั ะธ ะฒะปะพะถะตะฝะธั ะบะพั‚ะพั€ั‹ะต ะฝะฐั…ะพะดัั‚ัั ะฒ ะบััˆะต ัะตั€ะฒะตั€ะฐ ัั‚ะฐะฝัƒั‚ ะดะพัั‚ัƒะฟะฝั‹ ะฒัะตะผ, ะบั‚ะพ ะทะฝะฐะตั‚ ะธะผั ั‚ะตะผั‹.", "prefs_reservations_table": "ะกะฟะธัะพะบ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ", "prefs_reservations_table_access_header": "ะ”ะพัั‚ัƒะฟ", - "prefs_reservations_table_everyone_write_only": "ะฏ ะผะพะณัƒ ะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั, ะฒัะต ะพัั‚ะฐะปัŒะฝั‹ะต ะผะพะณัƒั‚ ะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ", + "prefs_reservations_table_everyone_write_only": "ะฏ ะผะพะณัƒ ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั, ะฒัะต ะพัั‚ะฐะปัŒะฝั‹ะต ะผะพะณัƒั‚ ั‚ะพะปัŒะบะพ ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ", "prefs_reservations_dialog_description": "ะ ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธะต ะดะฐะตั‚ ะ’ะฐะผ ะฒะพะทะผะพะถะฝะพัั‚ัŒ ัƒะฟั€ะฐะฒะปัั‚ัŒ ั‚ะตะผะพะน ะธ ะฝะฐัั‚ั€ะฐะธะฒะฐั‚ัŒ ะฟั€ะฐะฒะธะปะฐ ะดะพัั‚ัƒะฟะฐ ะบ ะฝะตะน ะดะปั ะฟะพะปัŒะทะพะฒะฐั‚ะตะปะตะน.", - "reservation_delete_dialog_action_delete_title": "ะฃะดะฐะปะธั‚ัŒ ัะพะพะฑั‰ะตะฝะธั ะฒ ะบััˆะต ะธ ะฒะปะพะถะตะฝะธั", - "reservation_delete_dialog_action_delete_description": "ะกะพะพะฑั‰ะตะฝะธั ะฒ ะบััˆะต ะธ ะฒะปะพะถะตะฝะธั ะฑัƒะดัƒั‚ ะฑะตะทะฒะพะทะฒั€ะฐั‚ะฝะพ ัƒะดะฐะปะตะฝั‹. ะญั‚ะพ ะดะตะนัั‚ะฒะธะต ะฝะตะฒะพะทะผะพะถะฝะพ ะพั‚ะผะตะฝะธั‚ัŒ.", + "reservation_delete_dialog_action_delete_title": "ะฃะดะฐะปะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั ะฒ ะบััˆะต ะธ ะฒะปะพะถะตะฝะธั", + "reservation_delete_dialog_action_delete_description": "ะฃะฒะตะดะพะผะปะตะฝะธั ะฒ ะบััˆะต ะธ ะฒะปะพะถะตะฝะธั ะฑัƒะดัƒั‚ ะฑะตะทะฒะพะทะฒั€ะฐั‚ะฝะพ ัƒะดะฐะปะตะฝั‹. ะญั‚ะพ ะดะตะนัั‚ะฒะธะต ะฝะตะฒะพะทะผะพะถะฝะพ ะพั‚ะผะตะฝะธั‚ัŒ.", "prefs_reservations_table_not_subscribed": "ะะต ะฟะพะดะฟะธัะฐะฝ", - "prefs_reservations_table_everyone_deny_all": "ะขะพะปัŒะบะพ ั ะผะพะณัƒ ะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั", - "prefs_reservations_table_everyone_read_write": "ะ’ัะต ะผะพะณัƒั‚ ะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั", + "prefs_reservations_table_everyone_deny_all": "ะขะพะปัŒะบะพ ั ะผะพะณัƒ ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั", + "prefs_reservations_table_everyone_read_write": "ะ’ัะต ะผะพะณัƒั‚ ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั", "prefs_reservations_table_click_to_subscribe": "ะะฐะถะผะธั‚ะต ั‡ั‚ะพะฑั‹ ะฟะพะดะฟะธัะฐั‚ัŒัั", "prefs_reservations_dialog_title_add": "ะ—ะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐั‚ัŒ ั‚ะตะผัƒ", "prefs_reservations_dialog_title_delete": "ะฃะดะฐะปะธั‚ัŒ ั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธะต", @@ -182,7 +182,7 @@ "prefs_users_delete_button": "ะฃะดะฐะปะธั‚ัŒ ะฟะพะปัŒะทะพะฒะฐั‚ะตะปั", "prefs_users_table_cannot_delete_or_edit": "ะะตะฒะพะทะผะพะถะฝะพ ัƒะดะฐะปะธั‚ัŒ ะธะปะธ ั€ะตะดะฐะบั‚ะธั€ะพะฒะฐั‚ัŒ ะทะฐะปะพะณะธะฝะตะฝะฝะพะณะพ ะฟะพะปัŒะทะพะฒะฐั‚ะตะปั", "account_upgrade_dialog_reservations_warning_one": "ะ’ั‹ะฑั€ะฐะฝะฝะฐั ะฟะพะดะฟะธัะบะฐ ั€ะฐะทั€ะตัˆะฐะตั‚ ะผะตะฝัŒัˆะต ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ, ั‡ะตะผ ะตัั‚ัŒ ัƒ ะ’ะฐั ะฝะฐ ะดะฐะฝะฝั‹ะน ะผะพะผะตะฝั‚. ะŸะตั€ะตะด ัะผะตะฝะพะน ะฟะพะดะฟะธัะบะธ, ะฟะพะถะฐะปัƒะนัั‚ะฐ ัƒะดะฐะปะธั‚ะต ั…ะพั‚ั ะฑั‹ ะพะดะฝัƒ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝัƒัŽ ั‚ะตะผัƒ. ะ’ั‹ ะผะพะถะตั‚ะต ัั‚ะพ ัะดะตะปะฐั‚ัŒ ะฒ ะะฐัั‚ั€ะพะนะบะฐั….", - "account_upgrade_dialog_proration_info": "ะŸะตั€ะตัั‡ั‘ั‚ ะพะฟะปะฐั‚ั‹: ะฟั€ะธ ั€ะฐััˆะธั€ะตะฝะธะธ ะฟะพะดะฟะธัะบะธ, ั€ะฐะทะฝะธั†ะฐ ะฒ ั†ะตะฝะต ะพั‚ ั‚ะตะบัƒั‰ะตะน ัะฟะธัˆะตั‚ัั ัั€ะฐะทัƒ. ะŸั€ะธ ัƒะฟั€ะพั‰ะตะฝะธะธ ะฟะพะดะฟะธัะบะธ, ะฝะตะธัะฟะพะปัŒะทะพะฒะฐะฝะฝั‹ะต ัั€ะตะดัั‚ะฒะฐ ะฟะพะนะดัƒั‚ ะฒ ะพะฟะปะฐั‚ัƒ ะฑะฐะปะฐะฝัะฐ ะฟะพ ัะปะตะดัƒัŽั‰ะธะผ ัั‡ะตั‚ะฐะผ.", + "account_upgrade_dialog_proration_info": "ะŸะตั€ะตัั‡ั‘ั‚ ะพะฟะปะฐั‚ั‹: ะฟั€ะธ ะฟะตั€ะตั…ะพะดะต ะผะตะถะดัƒ ะฟะปะฐั‚ะฝั‹ะผะธ ะฟะพะดะฟะธัะบะฐะผะธ, ั€ะฐะทะฝะธั†ะฐ ะฒ ั†ะตะฝะต ะฑัƒะดะตั‚ ัะฟะธัะฐะฝะฐ ะธะปะธ ะฒะพะทะฒั€ะฐั‰ะตะฝะฐ ะฒ ะ’ะฐัˆะตะผ ัะปะตะดัƒัŽั‰ะตะผ ัั‡ะตั‚ะต. ะ’ั‹ ะฝะต ะฟะพะปัƒั‡ะธั‚ะต ะฝะพะฒั‹ะน ัั‡ะตั‚ ะดะพ ะบะพะฝั†ะฐ ัะปะตะดัƒัŽั‰ะตะณะพ ั†ะธะบะปะฐ ะพะฟะปะฐั‚ั‹.", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} ะฝะฐ ั„ะฐะนะป", "account_tokens_table_never_expires": "ะะธะบะพะณะดะฐ", "account_tokens_table_copied_to_clipboard": "ะขะพะบะตะฝ ะดะพัั‚ัƒะฟะฐ ัะบะพะฟะธั€ะพะฒะฐะฝ", @@ -192,7 +192,7 @@ "account_tokens_dialog_button_create": "ะกะพะทะดะฐั‚ัŒ ั‚ะพะบะตะฝ", "account_tokens_delete_dialog_submit_button": "ะ‘ะตะทะฒะพะทะฒั€ะฐั‚ะฝะพ ัƒะดะฐะปะธั‚ัŒ ั‚ะพะบะตะฝ", "account_upgrade_dialog_reservations_warning_other": "ะ’ั‹ะฑั€ะฐะฝะฝะฐั ะฟะพะดะฟะธัะบะฐ ั€ะฐะทั€ะตัˆะฐะตั‚ ะผะตะฝัŒัˆะต ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ, ั‡ะตะผ ะตัั‚ัŒ ัƒ ะ’ะฐั ะฝะฐ ะดะฐะฝะฝั‹ะน ะผะพะผะตะฝั‚. ะŸะตั€ะตะด ัะผะตะฝะพะน ะฟะพะดะฟะธัะบะธ, ะฟะพะถะฐะปัƒะนัั‚ะฐ ัƒะดะฐะปะธั‚ะต ั…ะพั‚ั ะฑั‹ {{count}} ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ. ะ’ั‹ ะผะพะถะตั‚ะต ัั‚ะพ ัะดะตะปะฐั‚ัŒ ะฒ ะะฐัั‚ั€ะพะนะบะฐั….", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} ัะพะพะฑั‰ะตะฝะธะน ะฒ ะดะตะฝัŒ", + "account_upgrade_dialog_tier_features_messages": "{{messages}} ัƒะฒะตะดะพะผะปะตะฝะธะน ะฒ ะดะตะฝัŒ", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} ััƒะผะผะฐั€ะฝั‹ะน ะพะฑัŠะตะผ", "account_upgrade_dialog_tier_selected_label": "ะ’ั‹ะฑั€ะฐะฝะฝะฐั", "account_tokens_table_current_session": "ะขะตะบัƒั‰ะธะน ัะตะฐะฝั ะฑั€ะฐัƒะทะตั€ะฐ", @@ -201,12 +201,12 @@ "account_tokens_dialog_expires_x_hours": "ะขะพะบะตะฝ ะธัั‚ะตะบะฐะตั‚ ั‡ะตั€ะตะท {{hours}} ั‡ะฐัะพะฒ", "account_tokens_dialog_expires_never": "ะขะพะบะตะฝ ะฝะธะบะพะณะดะฐ ะฝะต ะธัั‚ะตะบะฐะตั‚", "prefs_notifications_sound_play": "ะ’ะพัะฟั€ะพะธะทะฒะพะดะธั‚ัŒ ะฒั‹ะฑั€ะฐะฝะฝั‹ะน ะทะฒัƒะบ", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} ัะป. ัะพะพะฑั‰ะตะฝะธะน ะฒ ะดะตะฝัŒ", - "account_basics_tier_free": "ะ‘ะตัะฟะปะฐั‚ะฝั‹ะน", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ", + "account_upgrade_dialog_tier_features_emails": "{{emails}} ัะป. ัะพะพะฑั‰ะตะฝะธะน ะฒ ะดะตะฝัŒ", + "account_basics_tier_free": "ะฑะตัะฟะปะฐั‚ะฝะพะน", "account_tokens_dialog_title_create": "ะกะพะทะดะฐั‚ัŒ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟะฐ", "account_tokens_dialog_title_delete": "ะฃะดะฐะปะธั‚ัŒ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟะฐ", - "common_copy_to_clipboard": "ะกะบะพะฟะธั€ะพะฒะฐั‚ัŒ ะฒ ะฑัƒั„ะตั€ ะพะฑะผะตะฝะฐ", + "account_tokens_table_copy_to_clipboard": "ะกะบะพะฟะธั€ะพะฒะฐั‚ัŒ ะฒ ะฑัƒั„ะตั€ ะพะฑะผะตะฝะฐ", "account_tokens_dialog_button_cancel": "ะžั‚ะผะตะฝะฐ", "account_tokens_dialog_expires_unchanged": "ะžัั‚ะฐะฒะธั‚ัŒ ัั€ะพะบ ะธัั‚ะตั‡ะตะฝะธั ะฑะตะท ะธะทะผะตะฝะตะฝะธะน", "account_tokens_dialog_expires_x_days": "ะขะพะบะตะฝ ะธัั‚ะตะบะฐะตั‚ ั‡ะตั€ะตะท {{days}} ะดะฝะตะน", @@ -233,7 +233,7 @@ "signup_error_username_taken": "ะ˜ะผั ะฟะพะปัŒะทะพะฒะฐั‚ะตะปั {{username}} ัƒะถะต ะทะฐะฝัั‚ะพ", "signup_title": "ะกะพะทะดะฐั‚ัŒ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ ntfy", "signup_already_have_account": "ะฃะถะต ะตัั‚ัŒ ัƒั‡ะตั‚ะฝะฐั ะทะฐะฟะธััŒ? ะ’ะพะนะดะธั‚ะต!", - "signup_error_creation_limit_reached": "ะ›ะธะผะธั‚ ะฝะฐ ัะพะทะดะฐะฝะธะต ัƒั‡ะตั‚ะฝั‹ั… ะทะฐะฟะธัะตะน ะธัั‡ะตั€ะฟะฐะฝ", + "signup_error_creation_limit_reached": "ะŸั€ะตะฒั‹ัˆะตะฝ ะปะธะผะธั‚ ะฝะฐ ัะพะทะดะฐะฝะธะต ัƒั‡ะตั‚ะฝั‹ั… ะทะฐะฟะธัะตะน", "login_form_button_submit": "ะ’ั…ะพะด", "login_link_signup": "ะ ะตะณะธัั‚ั€ะฐั†ะธั", "login_disabled": "ะ’ั…ะพะด ะฝะตะดะพัั‚ัƒะฟะตะฝ", @@ -246,16 +246,16 @@ "action_bar_sign_in": "ะ’ั…ะพะด", "action_bar_sign_up": "ะ ะตะณะธัั‚ั€ะฐั†ะธั", "action_bar_change_display_name": "ะ˜ะทะผะตะฝะธั‚ัŒ ะฟัะตะฒะดะพะฝะธะผ", - "message_bar_publish": "ะžะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ัะพะพะฑั‰ะตะฝะธะต", - "nav_button_muted": "ะฃะฒะตะดะพะผะปะตะฝะธั ะทะฐะณะปัƒัˆะตะฝั‹", + "message_bar_publish": "ะžั‚ะฟั€ะฐะฒะธั‚ัŒ ัะพะพะฑั‰ะตะฝะธะต", + "nav_button_muted": "ะฃะฒะตะดะพะผะปะตะฝะธั ัะบั€ั‹ั‚ั‹", "nav_button_connecting": "ัƒัั‚ะฐะฝะพะฒะบะฐ ัะพะตะดะธะฝะตะฝะธั", "action_bar_account": "ะฃั‡ะตั‚ะฝะฐั ะทะฐะฟะธััŒ", "login_title": "ะ’ั…ะพะด ะฒ ะ’ะฐัˆัƒ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ ntfy", - "action_bar_reservation_limit_reached": "ะ›ะธะผะธั‚ ะธัั‡ะตั€ะฟะฐะฝ", - "action_bar_toggle_mute": "ะ—ะฐะณะปัƒัˆะธั‚ัŒ/ั€ะฐะทั€ะตัˆะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั", + "action_bar_reservation_limit_reached": "ะŸะตั€ะฒั‹ัˆะตะฝ ะปะธะผะธั‚", + "action_bar_toggle_mute": "ะกะบั€ั‹ั‚ัŒ/ะฟะพะบะฐะทะฐั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั", "nav_button_account": "ะฃั‡ะตั‚ะฝะฐั ะทะฐะฟะธััŒ", "nav_upgrade_banner_label": "ะŸะพะดะฟะธัˆะธั‚ะตััŒ ะฝะฐ ntfy Pro", - "message_bar_show_dialog": "ะžั‚ะบั€ั‹ั‚ัŒ ะดะธะฐะปะพะณ ะฟัƒะฑะปะธะบะฐั†ะธะธ", + "message_bar_show_dialog": "ะžั‚ะบั€ั‹ั‚ัŒ ะดะธะฐะปะพะณ ะพั‚ะฟั€ะฐะฒะบะธ", "notifications_list": "ะกะฟะธัะพะบ ัƒะฒะตะดะพะผะปะตะฝะธะน", "notifications_list_item": "ะฃะฒะตะดะพะผะปะตะฝะธะต", "notifications_mark_read": "ะŸะพะผะตั‚ะธั‚ัŒ ะบะฐะบ ะฟั€ะพั‡ั‚ะตะฝะฝะพะต", @@ -298,12 +298,12 @@ "account_basics_tier_payment_overdue": "ะฃ ะ’ะฐั ะทะฐะดะพะปะถะตะฝะฝะพัั‚ัŒ ะฟะพ ะพะฟะปะฐั‚ะต. ะŸะพะถะฐะปัƒะนัั‚ะฐ ะฟั€ะพะฒะตั€ัŒั‚ะต ะผะตั‚ะพะด ะพะฟะปะฐั‚ั‹, ะธะฝะฐั‡ะต ะ’ั‹ ัะบะพั€ะพ ะฟะพั‚ะตั€ัะตั‚ะต ะฟั€ะตะธะผัƒั‰ะตัั‚ะฒะฐ ะ’ะฐัˆะตะน ะฟะพะดะฟะธัะบะธ.", "account_basics_tier_canceled_subscription": "ะ’ะฐัˆะฐ ะฟะพะดะฟะธัะบะฐ ะฑั‹ะปะฐ ะพั‚ะผะตะฝะตะฝะฐ; ัƒั‡ะตั‚ะฝะฐั ะทะฐะฟะธััŒ ะฟะตั€ะตะนะดะตั‚ ะฝะฐ ะฑะตัะฟะปะฐั‚ะฝะพะต ะพะฑัะปัƒะถะธะฒะฐะฝะธะต {{date}}.", "account_basics_tier_manage_billing_button": "ะฃะฟั€ะฐะฒะปะตะฝะธะต ะพะฟะปะฐั‚ะพะน", - "account_usage_messages_title": "ะžะฟัƒะฑะปะธะบะพะฒะฐะฝะฝั‹ะต ัะพะพะฑั‰ะตะฝะธั", + "account_usage_messages_title": "ะžั‚ะฟั€ะฐะฒะปะตะฝะฝั‹ะต ัƒะฒะตะดะพะปะผะปะตะฝะธั", "account_usage_emails_title": "ะžั‚ะฟั€ะฐะฒะปะตะฝะฝั‹ะต ัะปะตะบั‚ั€ะพะฝะฝั‹ะต ัะพะพะฑั‰ะตะฝะธั", "account_usage_reservations_title": "ะ—ะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ะต ั‚ะตะผั‹", "account_usage_reservations_none": "ะะตั‚ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ", "account_usage_attachment_storage_title": "ะฅั€ะฐะฝะตะฝะธะต ะฒะปะพะถะตะฝะธะน", - "account_usage_attachment_storage_description": "{{filesize}} ะทะฐ ั„ะฐะนะป, ัƒะดะฐะปััŽั‚ัั ัะฟัƒัั‚ั {{expiry}}", + "account_usage_attachment_storage_description": "{{filesize}} ะทะฐ ั„ะฐะนะป, ัƒะดะฐะปััŽั‚ัั ะฟะพัะปะต {{expiry}}", "account_usage_cannot_create_portal_session": "ะะตะฒะพะทะผะพะถะฝะพ ะพั‚ะบั€ั‹ั‚ัŒ ะฟะพั€ั‚ะฐะป ะพะฟะปะฐั‚ั‹", "account_delete_title": "ะฃะดะฐะปะธั‚ัŒ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ", "account_delete_description": "ะ‘ะตะทะฒะพะทะฒั€ะฐั‚ะฝะพ ัƒะดะฐะปะธั‚ัŒ ะ’ะฐัˆัƒ ัƒั‡ะตั‚ะฝัƒัŽ ะทะฐะฟะธััŒ", @@ -312,7 +312,7 @@ "account_upgrade_dialog_button_cancel_subscription": "ะžั‚ะผะตะฝะธั‚ัŒ ะฟะพะดะฟะธัะบัƒ", "account_upgrade_dialog_button_update_subscription": "ะ˜ะทะผะตะฝะธั‚ัŒ ะฟะพะดะฟะธัะบัƒ", "account_tokens_title": "ะขะพะบะตะฝั‹ ะดะพัั‚ัƒะฟะฐ", - "account_tokens_description": "ะ˜ัะฟะพะปัŒะทัƒะนั‚ะต ั‚ะพะบะตะฝั‹ ะดะพัั‚ัƒะฟะฐ ะดะปั ะฟัƒะฑะปะธะบะฐั†ะธะธ ะธ ะฟะพะดะฟะธัะบะธ ั‡ะตั€ะตะท ntfy API ั‡ั‚ะพะฑั‹ ะฝะต ะฟะตั€ะตัั‹ะปะฐั‚ัŒ ะดะฐะฝะฝั‹ะต ะ’ะฐัˆะตะน ัƒั‡ะตั‚ะฝะพะน ะทะฐะฟะธัะธ. ะกะผะพั‚ั€ะธั‚ะต ะดะพะบัƒะผะตะฝั‚ะฐั†ะธัŽ ั‡ั‚ะพะฑั‹ ัƒะทะฝะฐั‚ัŒ ะฑะพะปัŒัˆะต.", + "account_tokens_description": "ะ˜ัะฟะพะปัŒะทัƒะนั‚ะต ั‚ะพะบะตะฝั‹ ะดะพัั‚ัƒะฟะฐ ะฟั€ะธ ะพั‚ะฟั€ะฐะฒะบะต ัƒะฒะตะดะพะผะปะตะฝะธะน ะธ ะฟะพะดะฟะธัะบะต ะฝะฐ ั‚ะตะผั‹ ั‡ะตั€ะตะท ntfy API ั‡ั‚ะพะฑั‹ ะฝะต ะฟะตั€ะตัั‹ะปะฐั‚ัŒ ะดะฐะฝะฝั‹ะต ะ’ะฐัˆะตะน ัƒั‡ะตั‚ะฝะพะน ะทะฐะฟะธัะธ. ะกะผะพั‚ั€ะธั‚ะต ะดะพะบัƒะผะตะฝั‚ะฐั†ะธัŽ ั‡ั‚ะพะฑั‹ ัƒะทะฝะฐั‚ัŒ ะฑะพะปัŒัˆะต.", "account_tokens_table_token_header": "ะขะพะบะตะฝ", "account_tokens_table_label_header": "ะะฐะทะฒะฐะฝะธะต", "account_tokens_table_last_access_header": "ะŸะพัะปะตะดะฝะธะน ะดะพัั‚ัƒะฟ", @@ -320,17 +320,17 @@ "account_tokens_dialog_label": "ะะฐะทะฒะฐะฝะธะต, ะฝะฐะฟั€ะธะผะตั€ Radarr notifications", "prefs_reservations_title": "ะ—ะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ะต ั‚ะตะผั‹", "prefs_reservations_description": "ะ—ะดะตััŒ ะ’ั‹ ะผะพะถะตั‚ะต ั€ะตะทะตั€ะฒะธั€ะพะฒะฐั‚ัŒ ั‚ะตะผั‹ ะดะปั ะปะธั‡ะฝะพะณะพ ะฟะพะปัŒะทะพะฒะฐะฝะธั. ะ ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธะต ะดะฐะตั‚ ะ’ะฐะผ ะฒะพะทะผะพะถะฝะพัั‚ัŒ ัƒะฟั€ะฐะฒะปัั‚ัŒ ั‚ะตะผะพะน ะธ ะฝะฐัั‚ั€ะฐะธะฒะฐั‚ัŒ ะฟั€ะฐะฒะธะปะฐ ะดะพัั‚ัƒะฟะฐ ะบ ะฝะตะน ะดะปั ะฟะพะปัŒะทะพะฒะฐั‚ะตะปะตะน.", - "prefs_reservations_limit_reached": "ะ’ั‹ ะธัั‡ะตั€ะฟะฐะปะธ ะ’ะฐัˆ ะปะธะผะธั‚ ะฝะฐ ะบะพะปะธั‡ะตัั‚ะฒะพ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ.", + "prefs_reservations_limit_reached": "ะ’ั‹ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะปะธ ะผะฐัะบะธะผะฐะปัŒะฝะพ ะฒะพะทะผะพะถะฝะพะต ะบะพะปะธั‡ะตัั‚ะฒะพ ั‚ะตะผ.", "prefs_reservations_add_button": "ะ”ะพะฑะฐะฒะธั‚ัŒ ั‚ะตะผัƒ", "prefs_reservations_edit_button": "ะะฐัั‚ั€ะพะนะบะฐ ะดะพัั‚ัƒะฟะฐ", "prefs_reservations_delete_button": "ะกะฑั€ะพัะธั‚ัŒ ะฟั€ะฐะฒะธะปะฐ ะดะพัั‚ัƒะฟะฐ", - "prefs_reservations_table_everyone_read_only": "ะฏ ะผะพะณัƒ ะฟัƒะฑะปะธะบะพะฒะฐั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั, ะฒัะต ะพัั‚ะฐะปัŒะฝั‹ะต ะผะพะณัƒั‚ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั", + "prefs_reservations_table_everyone_read_only": "ะฏ ะผะพะณัƒ ะพั‚ะฟั€ะฐะฒะปัั‚ัŒ ะธ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัŒัั, ะฒัะต ะพัั‚ะฐะปัŒะฝั‹ะต ะผะพะณัƒั‚ ั‚ะพะปัŒะบะพ ะฟะพะดะฟะธัั‹ะฒะฐั‚ัั", "prefs_reservations_dialog_access_label": "ะ”ะพัั‚ัƒะฟ", - "reservation_delete_dialog_description": "ะฃะดะฐะปะตะฝะธะต ั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธั ะดะฐะตั‚ ะฒะพะทะผะพะถะฝะพัั‚ัŒ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐั‚ัŒ ัั‚ัƒ ั‚ะตะผัƒ ะดั€ัƒะณะธะผ. ะ’ั‹ ะผะพะถะตั‚ะต ะพัั‚ะฐะฒะธั‚ัŒ ะธะปะธ ัƒะดะฐะปะธั‚ัŒ ััƒั‰ะตัั‚ะฒัƒัŽั‰ะธะต ัะพะพะฑั‰ะตะฝะธั ะธ ะฒะปะพะถะตะฝะธั.", - "reservation_delete_dialog_action_keep_title": "ะกะพั…ั€ะฐะฝะธั‚ัŒ ัะพะพะฑั‰ะตะฝะธั ะฒ ะบััˆะต ะธ ะฒะปะพะถะตะฝะธั", + "reservation_delete_dialog_description": "ะฃะดะฐะปะตะฝะธะต ั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธั ะดะฐะตั‚ ะฒะพะทะผะพะถะฝะพัั‚ัŒ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐั‚ัŒ ัั‚ัƒ ั‚ะตะผัƒ ะดั€ัƒะณะธะผ. ะ’ั‹ ะผะพะถะตั‚ะต ะพัั‚ะฐะฒะธั‚ัŒ ะธะปะธ ัƒะดะฐะปะธั‚ัŒ ััƒั‰ะตัั‚ะฒัƒัŽั‰ะธะต ัƒะฒะตะดะพะผะปะตะฝะธั ะธ ะฒะปะพะถะตะฝะธั.", + "reservation_delete_dialog_action_keep_title": "ะกะพั…ั€ะฐะฝะธั‚ัŒ ัƒะฒะตะดะพะผะปะตะฝะธั ะฒ ะบััˆะต ะธ ะฒะปะพะถะตะฝะธั", "reservation_delete_dialog_submit_button": "ะฃะดะฐะปะธั‚ัŒ ั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะธะต", - "account_basics_tier_basic": "ะ‘ะฐะทะพะฒั‹ะน", - "nav_upgrade_banner_description": "ะ—ะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ะต ั‚ะตะผั‹, ะฑะพะปัŒัˆะต ัะพะพะฑั‰ะตะฝะธะน ะธ ัะปะตะบั‚ั€ะพะฝะฝั‹ั… ะฟะธัะตะผ, ะฐ ั‚ะฐะบะถะต ะฒะปะพะถะตะฝะธั ะฑะพะปัŒัˆะตะณะพ ั€ะฐะทะผะตั€ะฐ", + "account_basics_tier_basic": "ะฑะฐะทะพะฒะพะน", + "nav_upgrade_banner_description": "ะ—ะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ะต ั‚ะตะผั‹, ะฑะพะปัŒัˆะต ัƒะฒะตะดะพะผะปะตะฝะธะน ะธ ัะปะตะบั‚ั€ะพะฝะฝั‹ั… ัะพะพะฑั‰ะตะฝะธะน, ะฐ ั‚ะฐะบะถะต ะฒะปะพะถะตะฝะธั ะฑะพะปัŒัˆะตะณะพ ั€ะฐะทะผะตั€ะฐ", "alert_not_supported_context_description": "ะฃะฒะตะดะพะผะปะตะฝะธั ะฟะพะดะดะตั€ะถะธะฒะฐัŽั‚ัั ั‚ะพะปัŒะบะพ ะฟะพ ะฟั€ะพั‚ะพะบะพะปัƒ HTTPS. ะญั‚ะพ ะพะณั€ะฐะฝะธั‡ะตะฝะธะต Notifications API.", "notifications_delete": "ะฃะดะฐะปะธั‚ัŒ", "notifications_new_indicator": "ะะพะฒะพะต ัƒะฒะตะดะพะผะปะตะฝะธะต", @@ -340,17 +340,5 @@ "account_basics_password_dialog_confirm_password_label": "ะŸะพะดั‚ะฒะตั€ะดะธั‚ะต ะฟะฐั€ะพะปัŒ", "account_basics_password_dialog_button_submit": "ะกะผะตะฝะธั‚ัŒ ะฟะฐั€ะพะปัŒ", "account_basics_tier_title": "ะขะธะฟ ัƒั‡ะตั‚ะฝะพะน ะทะฐะฟะธัะธ", - "error_boundary_unsupported_indexeddb_description": "ะ’ะตะฑ-ะฟั€ะธะปะพะถะตะฝะธะต ntfy ะธัะฟะพะปัŒะทัƒะตั‚ IndexedDB, ะบะพั‚ะพั€ั‹ะน ะฝะต ะฟะพะดะดะตั€ะถะธะฒะฐะตั‚ัั ะ’ะฐัˆะธะผ ะฑั€ะฐัƒะทะตั€ะพะผ ะฒ ะฟั€ะธะฒะฐั‚ะฝะพะผ ั€ะตะถะธะผะต.

ะฅะพั‚ั ัั‚ะพ ะธ ะฝะต ะปัƒั‡ัˆะธะน ะฒะฐั€ะธะฐะฝั‚, ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตะฑ-ะฟั€ะธะปะพะถะตะฝะธะต ntfy ะฒ ะฟั€ะธะฒะฐั‚ะฝะพะผ ั€ะตะถะธะผะต ะฝะต ะธะผะตะตั‚ ะพัะพะฑะพะณะพ ัะผั‹ัะปะฐ, ั‚ะฐะบ ะบะฐะบ ะฒัะต ะดะฐะฝะฝั‹ะต ั…ั€ะฐะฝัั‚ัŒัั ะฒ ะปะพะบะฐะปัŒะฝะพะผ ั…ั€ะฐะฝะธะปะธั‰ะต ะฑั€ะฐัƒะทะตั€ะฐ. ะ’ั‹ ะผะพะถะตั‚ะต ัƒะทะฝะฐั‚ัŒ ะฑะพะปัŒัˆะต ะฒ ัั‚ะพะผ ะพั‚ั‡ะตั‚ะต ะฝะฐ GitHub ะธะปะธ ัะฒัะทะฐะฒัˆะธััŒ ั ะฝะฐะผะธ ั‡ะตั€ะตะท Discord ะธะปะธ Matrix.", - "account_basics_tier_interval_monthly": "ะตะถะตะผะตััั‡ะฝะพ", - "account_basics_tier_interval_yearly": "ะตะถะตะณะพะดะฝะพ", - "account_upgrade_dialog_interval_yearly": "ะ•ะถะตะณะพะดะฝะพ", - "account_upgrade_dialog_interval_yearly_discount_save": "ัะบะธะดะบะฐ {{discount}}%", - "account_upgrade_dialog_interval_monthly": "ะ•ะถะตะผะตััั‡ะฝะพ", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "ัะบะธะดะบะฐ ะดะพ {{discount}}%", - "account_upgrade_dialog_tier_features_no_reservations": "ะะตั‚ ะทะฐั€ะตะทะตั€ะฒะธั€ะพะฒะฐะฝะฝั‹ั… ั‚ะตะผ", - "account_upgrade_dialog_tier_price_per_month": "ะฒ ะผะตััั†", - "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} ะฒ ะณะพะด. ะžะฟะปะฐั‚ะฐ ะฟะพะผะตััั‡ะฝะพ.", - "account_upgrade_dialog_tier_price_billed_yearly": "{{price}} ะตะถะตะณะพะดะฝะพ. ะกัะบะพะฝะพะผัŒั‚ะต {{save}}.", - "account_upgrade_dialog_billing_contact_email": "ะŸะพ ะฒะพะฟั€ะพัะฐะผ ะพะฟะปะฐั‚ั‹, ะฟะพะถะฐะปัƒะนัั‚ะฐ ัะฒัะถะธั‚ะตััŒ ั ะฝะฐะผะธ.", - "account_upgrade_dialog_billing_contact_website": "ะŸะพ ะฒะพะฟั€ะพัะฐะผ ะพะฟะปะฐั‚ั‹, ะฟะพะถะฐะปัƒะนัั‚ะฐ ะพะฑั€ะฐั‚ะธั‚ะตััŒ ะบ ะฝะฐัˆะตะผัƒ ัะฐะนั‚ัƒ." + "error_boundary_unsupported_indexeddb_description": "ะ’ะตะฑ-ะฟั€ะธะปะพะถะตะฝะธะต ntfy ะธัะฟะพะปัŒะทัƒะตั‚ IndexedDB, ะบะพั‚ะพั€ั‹ะน ะฝะต ะฟะพะดะดะตั€ะถะธะฒะฐะตั‚ัั ะ’ะฐัˆะธะผ ะฑั€ะฐัƒะทะตั€ะพะผ ะฒ ะฟั€ะธะฒะฐั‚ะฝะพะผ ั€ะตะถะธะผะต.

ะฅะพั‚ั ัั‚ะพ ะธ ะฝะต ะปัƒั‡ัˆะธะน ะฒะฐั€ะธะฐะฝั‚, ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฒะตะฑ-ะฟั€ะธะปะพะถะตะฝะธะต ntfy ะฒ ะฟั€ะธะฒะฐั‚ะฝะพะผ ั€ะตะถะธะผะต ะฝะต ะธะผะตะตั‚ ะพัะพะฑะพะณะพ ัะผั‹ัะปะฐ, ั‚ะฐะบ ะบะฐะบ ะฒัะต ะดะฐะฝะฝั‹ะต ั…ั€ะฐะฝัั‚ัŒัั ะฒ ะปะพะบะฐะปัŒะฝะพะผ ั…ั€ะฐะฝะธะปะธั‰ะต ะฑั€ะฐัƒะทะตั€ะฐ. ะ’ั‹ ะผะพะถะตั‚ะต ัƒะทะฝะฐั‚ัŒ ะฑะพะปัŒัˆะต ะฒ ัั‚ะพะผ ะพั‚ั‡ะตั‚ะต ะฝะฐ GitHub ะธะปะธ ัะฒัะทะฐะฒัˆะธััŒ ั ะฝะฐะผะธ ั‡ะตั€ะตะท Discord ะธะปะธ Matrix." } diff --git a/web/public/static/langs/sv.json b/web/public/static/langs/sv.json index bc4a540..4896c8c 100644 --- a/web/public/static/langs/sv.json +++ b/web/public/static/langs/sv.json @@ -76,309 +76,5 @@ "signup_form_username": "Anvรคndarnamn", "signup_already_have_account": "Har du redan ett konto? Logga in!", "signup_disabled": "Registrering รคr inaktiverad", - "signup_error_username_taken": "Anvรคndarnamn [[username]] anvรคnds redan", - "notifications_attachment_file_document": "annat dokument", - "notifications_attachment_file_app": "Android app fil", - "notifications_click_copy_url_title": "Kopiera lรคnk till urklipp", - "notifications_none_for_topic_title": "Du har inte fรฅtt nรฅgra notiser fรถr detta รคmnet รคnnu.", - "notifications_none_for_topic_description": "Fรถr att kunna skicka notiser till detta รคmnet, anvรคnd PUT eller POST till รคmnets URL.", - "notifications_actions_http_request_title": "Skicka HTTP {{method}} till {{url}}", - "publish_dialog_progress_uploading": "Laddar upp โ€ฆ", - "nav_upgrade_banner_description": "Reservera รคmnen, fler meddelanden och e-postmeddelanden och stรถrre bilagor", - "publish_dialog_attachment_limits_file_and_quota_reached": "รถverskrider {{fileSizeLimit}} filgrรคns och kvot, {{remainingBytes}} รฅterstรฅende", - "publish_dialog_attachment_limits_file_reached": "รถverskrider {{fileSizeLimit}} filgrรคns", - "publish_dialog_attachment_limits_quota_reached": "รถverskrider kvoten, {{remainingBytes}} รฅterstรฅr", - "publish_dialog_message_placeholder": "Skriv ett meddelande hรคr", - "publish_dialog_checkbox_publish_another": "Publicera en till", - "subscribe_dialog_error_user_anonymous": "anonym", - "account_basics_password_dialog_confirm_password_label": "Bekrรคfta lรถsenord", - "publish_dialog_email_placeholder": "Adress att vidarebefordra meddelandet till, t.ex. phil@example.com", - "publish_dialog_details_examples_description": "Exempel och en detaljerad beskrivning av alla sรคndningsfunktioner finns i dokumentationen .", - "publish_dialog_button_send": "Skicka", - "common_back": "Tillbaka", - "account_basics_tier_free": "Gratis", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} reserverat รคmne", - "account_delete_title": "Ta bort konto", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} dagliga meddelanden", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} dagligt e-postmeddelande", - "account_upgrade_dialog_button_cancel": "Avbryt", - "common_copy_to_clipboard": "Kopiera till urklipp", - "account_tokens_table_copied_to_clipboard": "ร…tkomsttoken kopierat", - "account_tokens_description": "Anvรคnd รฅtkomsttoken nรคr du publicerar och prenumererar via ntfy API, sรฅ att du inte behรถver skicka dina kontouppgifter. Lรคs mer i dokumentationen.", - "account_tokens_table_create_token_button": "Skapa รฅtkomsttoken", - "prefs_users_description_no_sync": "Anvรคndare och lรถsenord synkroniseras inte till ditt konto.", - "error_boundary_unsupported_indexeddb_description": "ntfy-webbappen behรถver IndexedDB fรถr att fungera och din webblรคsare har inte stรถd fรถr IndexedDB i privat surflรคge.

Detta รคr beklagligt, men det รคr inte heller sรคrskilt meningsfullt att anvรคnda ntfy-webbappen i privat surflรคge, eftersom allt lagras i webblรคsarens lagringsutrymme. Du kan lรคsa mer om det i detta GitHub-รคrende, eller prata med oss pรฅ Discord eller Matrix.", - "account_basics_tier_interval_monthly": "mรฅnadsvis", - "account_basics_tier_interval_yearly": "รฅrligen", - "account_basics_tier_canceled_subscription": "Din prenumeration avbrรถts och kommer att nedgraderas till ett gratis konto den {{date}}.", - "account_basics_tier_manage_billing_button": "Hantera fakturering", - "account_usage_messages_title": "Publicerade meddelande", - "account_usage_emails_title": "Skickade e-postmeddelanden", - "account_usage_reservations_title": "Reserverade รคmnen", - "account_usage_reservations_none": "Inga reserverade รคmnen fรถr det hรคr kontot", - "account_usage_attachment_storage_title": "Lagring av bilagor", - "account_usage_attachment_storage_description": "{{filesize}} per fil, raderas efter {{expiry}}", - "account_delete_description": "Ta bort ditt konto permanent", - "account_delete_dialog_description": "Detta kommer att radera ditt konto permanent, inklusive all data som lagras pรฅ servern. Efter raderingen kommer ditt anvรคndarnamn att vara otillgรคngligt i 7 dagar. Om du verkligen vill fortsรคtta, bekrรคfta med ditt lรถsenord i rutan nedan.", - "account_delete_dialog_label": "Lรถsenord", - "account_delete_dialog_button_cancel": "Avbryt", - "account_delete_dialog_button_submit": "Ta bort kontot permanent", - "account_delete_dialog_billing_warning": "Om du raderar ditt konto annulleras ocksรฅ din faktureringsprenumeration omedelbart. Du kommer inte lรคngre att ha tillgรฅng till instrumentpanelen fรถr fakturering.", - "account_upgrade_dialog_title": "ร„ndra kontonivรฅ", - "account_upgrade_dialog_interval_monthly": "Mรฅnadsvis", - "account_upgrade_dialog_interval_yearly": "ร…rligen", - "account_upgrade_dialog_interval_yearly_discount_save": "spara {{discount}}%", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "spara upp till {{discount}}%", - "account_upgrade_dialog_cancel_warning": "Detta kommer att sรคga upp din prenumeration och nedgradera ditt konto pรฅ {{date}}. Pรฅ det datumet kommer รคmnesreservationer och meddelanden som ligger i cacheminnet pรฅ servern att raderas.", - "account_upgrade_dialog_proration_info": "Deklaration: Nรคr du uppgraderar mellan betalda planer kommer prisskillnaden att debiteras omedelbart. Vid nedgradering till en lรคgre nivรฅ kommer saldot att anvรคndas fรถr att betala fรถr framtida faktureringsperioder.", - "account_upgrade_dialog_reservations_warning_one": "Den valda nivรฅn tillรฅter fรคrre reserverade รคmnen รคn din nuvarande nivรฅ. Innan du รคndrar nivรฅ, bรถr du ta bort minst en reservation. Du kan ta bort reservationer i Instรคllningar.", - "account_upgrade_dialog_reservations_warning_other": "Den valda nivรฅn tillรฅter fรคrre reserverade รคmnen รคn din nuvarande nivรฅ. Innan du รคndrar nivรฅ, ta bort minst {{count}} reservationer. Du kan ta bort reservationer i Instรคllningar.", - "account_upgrade_dialog_tier_features_no_reservations": "Inga reserverade รคmnen", - "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} per fil", - "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} total lagring", - "account_upgrade_dialog_tier_price_per_month": "mรฅnad", - "account_upgrade_dialog_tier_selected_label": "Vald", - "account_tokens_table_token_header": "Token", - "account_tokens_dialog_title_create": "Skapa รฅtkomsttoken", - "account_tokens_dialog_title_delete": "Ta bort รฅtkomsttoken", - "account_tokens_dialog_label": "Etikett, t.ex. Radarr-meddelanden", - "account_tokens_dialog_title_edit": "Redigera รฅtkomsttoken", - "account_tokens_dialog_button_create": "Skapa token", - "account_tokens_dialog_button_update": "Uppdatera token", - "account_tokens_delete_dialog_submit_button": "Ta bort token permanent", - "prefs_notifications_delete_after_one_day": "Efter en dag", - "reservation_delete_dialog_action_delete_description": "Cachade meddelanden och bilagor raderas permanent. Denna รฅtgรคrd kan inte รฅngras.", - "error_boundary_gathering_info": "Samla mer information โ€ฆ", - "error_boundary_unsupported_indexeddb_title": "Privat surfning stรถds inte", - "reservation_delete_dialog_submit_button": "Ta bort reservationen", - "priority_low": "lรฅg", - "error_boundary_title": "ร…h nej, ntfy kraschade", - "error_boundary_description": "Detta fรฅr naturligtvis inte ske. Vi beklagar verkligen detta.
Om du har tid, vรคnligen rapportera detta pรฅ GitHub, eller meddela oss via Discord eller Matrix.", - "notifications_no_subscriptions_title": "Det ser ut som om du inte har nรฅgra prenumerationer รคnnu.", - "notifications_more_details": "Mer information finns pรฅ webbplatsen eller i dokumentationen .", - "publish_dialog_title_topic": "Publicera till {{topic}}", - "publish_dialog_message_published": "Meddelande publicerat", - "publish_dialog_emoji_picker_show": "Vรคlj emoji", - "publish_dialog_base_url_placeholder": "Service-URL, t.ex. https://example.com", - "publish_dialog_topic_label": "ร„mnesnamn", - "publish_dialog_topic_placeholder": "ร„mnesnamn, t.ex. phils_alerts", - "publish_dialog_topic_reset": "ร…terstรคll รคmne", - "publish_dialog_title_label": "Titel", - "publish_dialog_title_placeholder": "Meddelandets rubrik, t.ex. Varning fรถr diskutrymme", - "publish_dialog_tags_label": "Taggar", - "publish_dialog_message_label": "Meddelande", - "publish_dialog_tags_placeholder": "Kommaseparerad lista med taggar, t.ex. warning, srv1-backup", - "publish_dialog_priority_label": "Prioritet", - "publish_dialog_click_label": "Klicka pรฅ URL", - "publish_dialog_click_placeholder": "URL som รถppnas nรคr man klickar pรฅ anmรคlan", - "publish_dialog_click_reset": "Ta bort klickbar URL", - "publish_dialog_email_reset": "Ta bort vidarebefordran av e-post", - "publish_dialog_attach_label": "URL fรถr bifogade filer", - "publish_dialog_attach_placeholder": "Bifoga fil via URL, t.ex. https://f-droid.org/F-Droid.apk", - "publish_dialog_filename_label": "Filnamn", - "publish_dialog_delay_label": "Fรถrdrรถjning", - "publish_dialog_filename_placeholder": "Filnamn fรถr bifogad fil", - "publish_dialog_delay_placeholder": "Fรถrdrรถj leverans, t.ex. {{unixTimestamp}}, {{relativeTime}} eller \"{{naturalLanguage}}\" (endast engelska)", - "publish_dialog_delay_reset": "Ta bort fรถrsenad leverans", - "publish_dialog_other_features": "Andra funktioner:", - "publish_dialog_chip_click_label": "Klicka pรฅ URL", - "publish_dialog_attached_file_title": "Bifogad fil:", - "publish_dialog_attached_file_filename_placeholder": "Filnamn fรถr bifogad fil", - "emoji_picker_search_placeholder": "Sรถk emoji", - "subscribe_dialog_subscribe_button_cancel": "Avbryt", - "prefs_notifications_sound_description_some": "Meddelanden spelar upp ljudet {{sound}} nรคr de anlรคnder", - "prefs_notifications_sound_no_sound": "Inget ljud", - "prefs_notifications_min_priority_any": "Alla prioriteringar", - "prefs_notifications_min_priority_low_and_higher": "Lรฅg prioritet och hรถgre", - "prefs_notifications_delete_after_three_hours": "Efter tre timmar", - "prefs_notifications_delete_after_never": "Aldrig", - "prefs_users_table": "Anvรคndartabell", - "prefs_users_add_button": "Lรคgg till anvรคndare", - "prefs_users_edit_button": "Redigera anvรคndare", - "prefs_users_dialog_title_add": "Lรคgg till anvรคndare", - "prefs_users_dialog_title_edit": "Redigera anvรคndare", - "prefs_users_dialog_base_url_label": "Tjรคnstens URL, t.ex. https://ntfy.sh", - "prefs_users_dialog_password_label": "Lรถsenord", - "prefs_appearance_title": "Utseende", - "prefs_appearance_language_title": "Sprรฅk", - "priority_min": "min", - "priority_default": "standard", - "priority_high": "hรถg", - "priority_max": "max", - "error_boundary_button_copy_stack_trace": "Kopiera stackspรฅrning", - "error_boundary_stack_trace": "Stackspรฅrning", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} reserverade รคmnen", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} dagligt meddelande", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} dagliga e-postmeddelanden", - "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} per รฅr. Faktureras mรฅnadsvis.", - "account_upgrade_dialog_tier_price_billed_yearly": "{{price}} faktureras รฅrligen. Spara {{save}}.", - "account_upgrade_dialog_tier_current_label": "Aktuell", - "account_upgrade_dialog_billing_contact_email": "Fรถr faktureringsfrรฅgor, vรคnligen kontakta oss direkt.", - "account_upgrade_dialog_billing_contact_website": "Fรถr frรฅgor om fakturering hรคnvisar vi till vรฅr webbplats.", - "account_upgrade_dialog_button_redirect_signup": "Registrera dig nu", - "account_upgrade_dialog_button_pay_now": "Betala nu och prenumerera", - "account_upgrade_dialog_button_cancel_subscription": "Avbryt prenumeration", - "account_upgrade_dialog_button_update_subscription": "Uppdatera prenumeration", - "account_tokens_table_label_header": "Etikett", - "account_tokens_table_last_access_header": "Sista รฅtkomst", - "account_tokens_table_expires_header": "Upphรถr", - "account_tokens_table_never_expires": "Upphรถr aldrig", - "account_tokens_table_current_session": "Nuvarande webblรคsarsession", - "account_tokens_table_cannot_delete_or_edit": "Det gรฅr inte att redigera eller ta bort aktuell sessionstoken", - "account_tokens_table_last_origin_tooltip": "Frรฅn IP-adress {{ip}}, klicka fรถr att sรถka upp", - "account_tokens_dialog_button_cancel": "Avbryt", - "account_tokens_dialog_expires_label": "ร…tkomsttoken lรถper ut om", - "account_tokens_dialog_expires_unchanged": "Lรคmna utgรฅngsdatumet ofรถrรคndrat", - "account_tokens_dialog_expires_x_hours": "Token gรฅr ut om {{hours}} timmar", - "account_tokens_dialog_expires_x_days": "Token lรถper ut om {{days}} dagar", - "account_tokens_dialog_expires_never": "Token upphรถr aldrig att gรคlla", - "account_tokens_delete_dialog_title": "Ta bort รฅtkomsttoken", - "account_tokens_delete_dialog_description": "Innan du tar bort en รฅtkomsttoken bรถr du se till att inga program eller skript anvรคnder den aktivt. Den hรคr รฅtgรคrden kan inte รฅngras.", - "prefs_notifications_title": "Notifieringar", - "prefs_notifications_sound_title": "Ljud fรถr meddelanden", - "prefs_notifications_sound_description_none": "Meddelanden spelar inte upp nรฅgot ljud nรคr de kommer", - "prefs_notifications_sound_play": "Spela upp valt ljud", - "prefs_notifications_min_priority_title": "Lรคgsta prioritet", - "prefs_notifications_min_priority_description_any": "Visa alla meddelanden, oavsett prioritet", - "prefs_notifications_min_priority_description_x_or_higher": "Visa meddelanden om prioritet รคr {{number}} ({{name}}) eller hรถgre", - "prefs_notifications_min_priority_description_max": "Visa notifieringar om prioritet รคr 5 (max)", - "prefs_notifications_min_priority_default_and_higher": "Standardprioritet och hรถgre", - "prefs_notifications_min_priority_high_and_higher": "Hรถg prioritet och hรถgre", - "prefs_notifications_min_priority_max_only": "Bara hรถgsta prioritet", - "prefs_notifications_delete_after_title": "Radera meddelanden", - "prefs_notifications_delete_after_one_week": "Efter en vecka", - "prefs_notifications_delete_after_one_month": "Efter en mรฅnad", - "prefs_notifications_delete_after_never_description": "Meddelanden raderas aldrig automatiskt", - "prefs_notifications_delete_after_three_hours_description": "Meddelanden raderas automatiskt efter tre timmar", - "prefs_users_description": "Lรคgg till/ta bort anvรคndare fรถr dina skyddade รคmnen hรคr. Observera att anvรคndarnamn och lรถsenord lagras i webblรคsarens lokala lagring.", - "prefs_users_delete_button": "Ta bort anvรคndare", - "prefs_users_table_cannot_delete_or_edit": "Kan inte ta bort eller redigera inloggad anvรคndare", - "prefs_users_table_user_header": "Anvรคndare", - "prefs_users_table_base_url_header": "Service-URL", - "prefs_users_dialog_username_label": "Anvรคndarnamn, t.ex. phil", - "prefs_reservations_title": "Reserverade รคmnen", - "prefs_reservations_description": "Du kan reservera รคmnesnamn fรถr personligt bruk hรคr. Genom att reservera ett รคmne fรฅr du รคganderรคtt till รคmnet och kan definiera รฅtkomstbehรถrigheter fรถr andra anvรคndare till รคmnet.", - "prefs_reservations_limit_reached": "Du har nรฅtt grรคnsen fรถr reserverade รคmnen.", - "prefs_reservations_add_button": "Lรคgg till reserverat รคmne", - "prefs_reservations_dialog_title_edit": "Redigera reserverat รคmne", - "prefs_reservations_dialog_title_delete": "Ta bort รคmnesreservation", - "signup_error_creation_limit_reached": "Grรคnsen fรถr skapande av konton har uppnรฅtts", - "alert_not_supported_context_description": "Meddelanden stรถds endast via HTTPS. Detta รคr en begrรคnsning av Notifications API.", - "notifications_actions_not_supported": "ร…tgรคrd stรถds inte i webbapplikationen", - "notifications_none_for_any_description": "Fรถr att skicka meddelanden till ett รคmne รคr det bara att PUT eller POST till รคmnets URL. Hรคr รคr ett exempel med ett av dina รคmnen.", - "notifications_no_subscriptions_description": "Klicka pรฅ lรคnken \"{{linktext}}\" fรถr att skapa eller prenumerera pรฅ ett รคmne. Dรคrefter kan du skicka meddelanden via PUT eller POST och du fรฅr meddelanden hรคr.", - "display_name_dialog_title": "ร„ndra visningsnamn", - "display_name_dialog_description": "Ange ett alternativt namn fรถr ett รคmne som visas i prenumerationslistan. Pรฅ sรฅ sรคtt kan du lรคttare identifiera รคmnen med komplicerade namn.", - "display_name_dialog_placeholder": "Visningsnamn", - "reserve_dialog_checkbox_label": "Reservera รคmne och konfigurera รฅtkomst", - "publish_dialog_title_no_topic": "Publicera meddelande", - "publish_dialog_progress_uploading_detail": "Laddar upp {{loaded}}/{{{total}} ({{procent}}}%) โ€ฆ", - "publish_dialog_priority_min": "Lรคgsta prioritet", - "publish_dialog_priority_low": "Lรฅg prioritet", - "publish_dialog_priority_default": "Standard prioritet", - "publish_dialog_priority_high": "Hรถg prioritet", - "publish_dialog_priority_max": "Hรถgsta prioritet", - "publish_dialog_base_url_label": "Service-URL", - "publish_dialog_email_label": "E-post", - "publish_dialog_attach_reset": "Ta bort URL fรถr bifogade filer", - "publish_dialog_chip_email_label": "Vidarebefordra till e-post", - "publish_dialog_chip_attach_url_label": "Bifoga fil via URL", - "publish_dialog_chip_attach_file_label": "Bifoga lokal fil", - "publish_dialog_chip_delay_label": "Fรถrdrรถj leveransen", - "publish_dialog_chip_topic_label": "ร„ndra รคmne", - "publish_dialog_button_cancel_sending": "Avbryt sรคndning", - "publish_dialog_button_cancel": "Avbryt", - "publish_dialog_attached_file_remove": "Ta bort bifogad fil", - "publish_dialog_drop_file_here": "Slรคpp filen hรคr", - "emoji_picker_search_clear": "Rensa sรถkning", - "subscribe_dialog_subscribe_title": "Prenumerera pรฅ รคmnet", - "subscribe_dialog_subscribe_description": "ร„mnen kanske inte รคr lรถsenordsskyddade, sรฅ vรคlj ett namn som inte รคr lรคtt att gissa. Nรคr du har prenumererat kan du lรคgga in/lรคgga in meddelanden.", - "subscribe_dialog_subscribe_topic_placeholder": "ร„mnesnamn, t.ex. phils_alerts", - "subscribe_dialog_subscribe_use_another_label": "Anvรคnd en annan server", - "subscribe_dialog_subscribe_base_url_label": "Service-URL", - "subscribe_dialog_subscribe_button_generate_topic_name": "Generera namn", - "subscribe_dialog_subscribe_button_subscribe": "Prenumerera", - "subscribe_dialog_login_title": "Inloggning krรคvs", - "subscribe_dialog_login_description": "Det hรคr รคmnet รคr lรถsenordsskyddat. Ange anvรคndarnamn och lรถsenord fรถr att prenumerera.", - "subscribe_dialog_login_username_label": "Anvรคndarnamn, t.ex. phil", - "subscribe_dialog_login_password_label": "Lรถsenord", - "subscribe_dialog_login_button_login": "Logga in", - "subscribe_dialog_error_user_not_authorized": "Anvรคndaren {{anvรคndarnamn}} inte auktoriserad", - "subscribe_dialog_error_topic_already_reserved": "ร„mnet รคr redan reserverat", - "account_basics_title": "Konto", - "account_basics_tier_paid_until": "Prenumerationen รคr betald fram till {{datum}}, och kommer att fรถrnyas automatiskt", - "account_basics_username_title": "Anvรคndarnamn", - "account_basics_username_description": "Hej, det รคr du โค", - "account_basics_username_admin_tooltip": "Du รคr admin", - "account_basics_password_title": "Lรถsenord", - "account_basics_password_description": "ร„ndra lรถsenordet till ditt konto", - "account_basics_tier_payment_overdue": "Din betalning รคr fรถrsenad. Vรคnligen uppdatera din betalningsmetod, annars kommer ditt konto att nedgraderas inom kort.", - "account_basics_password_dialog_title": "Byt lรถsenord", - "account_basics_password_dialog_current_password_label": "Aktuellt lรถsenord", - "account_basics_password_dialog_new_password_label": "Nytt lรถsenord", - "account_basics_password_dialog_button_submit": "Byt lรถsenord", - "account_basics_password_dialog_current_password_incorrect": "Felaktigt lรถsenord", - "account_usage_title": "Anvรคndning", - "account_usage_of_limit": "av {{limit}}", - "account_usage_unlimited": "Obegrรคnsad", - "account_usage_limits_reset_daily": "Anvรคndningsgrรคnserna รฅterstรคlls dagligen vid midnatt (UTC)", - "account_basics_tier_title": "Kontotyp", - "account_basics_tier_description": "Ditt kontos nivรฅ", - "account_basics_tier_admin": "Admin", - "account_basics_tier_admin_suffix_with_tier": "(med {{tier}}} nivรฅ)", - "account_basics_tier_admin_suffix_no_tier": "(ingen nivรฅ)", - "account_basics_tier_basic": "Grundlรคggande", - "account_basics_tier_upgrade_button": "Uppgradera till Pro", - "account_basics_tier_change_button": "ร„ndra", - "account_usage_cannot_create_portal_session": "Det gรฅr inte att รถppna faktureringsportalen", - "account_usage_basis_ip_description": "Anvรคndningsstatistik och begrรคnsningar fรถr det hรคr kontot baseras pรฅ din IP-adress, sรฅ de kan delas med andra anvรคndare. De grรคnser som visas ovan รคr ungefรคrliga och baseras pรฅ befintliga grรคnser.", - "account_tokens_title": "ร…tkomsttoken", - "prefs_notifications_delete_after_one_day_description": "Meddelanden raderas automatiskt efter en dag", - "prefs_notifications_delete_after_one_week_description": "Meddelanden raderas automatiskt efter en vecka", - "prefs_notifications_delete_after_one_month_description": "Meddelanden raderas automatiskt efter en mรฅnad", - "prefs_users_title": "Hantera anvรคndare", - "prefs_reservations_table_not_subscribed": "Prenumererar inte", - "prefs_reservations_table_click_to_subscribe": "Klicka fรถr att prenumerera", - "prefs_reservations_edit_button": "Redigera รคmnesรฅtkomst", - "prefs_reservations_delete_button": "ร…terstรคll รคmnesรฅtkomst", - "prefs_reservations_table": "Tabell รถver reserverade รคmnen", - "prefs_reservations_table_topic_header": "ร„mne", - "prefs_reservations_table_access_header": "Tillgรฅng", - "prefs_reservations_table_everyone_deny_all": "Endast jag kan publicera och prenumerera", - "prefs_reservations_table_everyone_read_only": "Jag kan publicera och prenumerera, alla kan prenumerera", - "prefs_reservations_table_everyone_write_only": "Jag kan publicera och prenumerera, alla kan publicera", - "prefs_reservations_table_everyone_read_write": "Alla kan publicera och prenumerera", - "prefs_reservations_dialog_title_add": "Reserverade รคmnen", - "prefs_reservations_dialog_description": "Genom att reservera ett รคmne fรฅr du รคganderรคtt till รคmnet och kan definiera รฅtkomstbehรถrigheter fรถr andra anvรคndare till รคmnet.", - "prefs_reservations_dialog_topic_label": "ร„mne", - "prefs_reservations_dialog_access_label": "Tillgรฅng", - "reservation_delete_dialog_action_keep_title": "Behรฅll cachade meddelanden och bilagor", - "reservation_delete_dialog_action_keep_description": "Meddelanden och bilagor som lagras pรฅ servern blir offentligt synliga fรถr personer som kรคnner till รคmnesnamnet.", - "reservation_delete_dialog_action_delete_title": "Ta bort meddelanden och bilagor som sparats i cacheminnet", - "reservation_delete_dialog_description": "Om du tar bort en reservation ger du upp รคganderรคtten till รคmnet och lรฅter andra reservera det. Du kan behรฅlla eller radera befintliga meddelanden och bilagor.", - "publish_dialog_call_label": "Telefonsamtal", - "publish_dialog_call_reset": "Ta bort telefonsamtal", - "publish_dialog_chip_call_label": "Telefonsamtal", - "account_basics_phone_numbers_title": "Telefonnummer", - "account_basics_phone_numbers_description": "Fรถr notifieringar via telefonsamtal", - "account_basics_phone_numbers_no_phone_numbers_yet": "Inga telefonnummer รคnnu", - "account_basics_phone_numbers_copied_to_clipboard": "Telefonnummer kopierat till urklipp", - "account_basics_phone_numbers_dialog_title": "Lรคgga till telefonnummer", - "account_basics_phone_numbers_dialog_number_label": "Telefonnummer", - "account_basics_phone_numbers_dialog_number_placeholder": "t.ex. +1222333444", - "account_basics_phone_numbers_dialog_verify_button_sms": "Skicka SMS", - "account_basics_phone_numbers_dialog_verify_button_call": "Ring mig", - "account_basics_phone_numbers_dialog_code_label": "Verifieringskod", - "account_basics_phone_numbers_dialog_channel_call": "Ring", - "account_usage_calls_title": "Telefonsamtal som gjorts", - "account_usage_calls_none": "Inga telefonsamtal kan gรถras med detta konto", - "publish_dialog_call_item": "Ring telefonnummer {{number}}", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "Inga verifierade telefonnummer", - "account_basics_phone_numbers_dialog_description": "Fรถr att anvรคnda funktionen fรถr samtalsavisering mรฅste du lรคgga till och verifiera minst ett telefonnummer. Verifieringen kan gรถras via SMS eller ett telefonsamtal.", - "account_basics_phone_numbers_dialog_code_placeholder": "t.ex. 123456", - "account_basics_phone_numbers_dialog_check_verification_button": "Bekrรคfta kod", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_upgrade_dialog_tier_features_calls_other": "{{calls}} dagliga telefonsamtal", - "account_upgrade_dialog_tier_features_no_calls": "Inga telefonsamtal", - "account_upgrade_dialog_tier_features_calls_one": "{{calls}} dagliga telefonsamtal" + "signup_error_username_taken": "Anvรคndarnamn [[username]] anvรคnds redan" } diff --git a/web/public/static/langs/tr.json b/web/public/static/langs/tr.json index 3eccda8..66136cf 100644 --- a/web/public/static/langs/tr.json +++ b/web/public/static/langs/tr.json @@ -34,7 +34,7 @@ "subscribe_dialog_login_description": "Bu konu parola korumalฤฑ. Abone olmak iรงin lรผtfen kullanฤฑcฤฑ adฤฑ ve parola girin.", "subscribe_dialog_login_username_label": "Kullanฤฑcฤฑ adฤฑ, รถrn. phil", "subscribe_dialog_login_password_label": "Parola", - "common_back": "Geri", + "subscribe_dialog_login_button_back": "Geri", "subscribe_dialog_login_button_login": "Oturum aรง", "subscribe_dialog_error_user_not_authorized": "{{username}} kullanฤฑcฤฑsฤฑ yetkili deฤŸil", "subscribe_dialog_error_user_anonymous": "anonim", @@ -253,9 +253,9 @@ "account_upgrade_dialog_title": "Hesap seviyesini deฤŸiลŸtir", "account_upgrade_dialog_proration_info": "Fiyatlandฤฑrma: รœcretli planlar arasฤฑnda yรผkseltme yaparken, fiyat farkฤฑ hemen tahsil edilecektir. Daha dรผลŸรผk bir seviyeye inildiฤŸinde, bakiye gelecek faturalandฤฑrma dรถnemleri iรงin รถdeme yapmak รผzere kullanฤฑlacaktฤฑr.", "account_upgrade_dialog_reservations_warning_other": "Seรงilen seviye, geรงerli seviyenizden daha az konu ayฤฑrtmaya izin veriyor. Seviyenizi deฤŸiลŸtirmeden รถnce lรผtfen en az {{count}} ayฤฑrtmayฤฑ silin. Ayฤฑrtmalarฤฑ Ayarlar sayfasฤฑndan kaldฤฑrabilirsiniz.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} konu ayฤฑrtฤฑldฤฑ", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} gรผnlรผk mesaj", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} gรผnlรผk e-posta", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} konu ayฤฑrtฤฑldฤฑ", + "account_upgrade_dialog_tier_features_messages": "{{messages}} gรผnlรผk mesaj", + "account_upgrade_dialog_tier_features_emails": "{{emails}} gรผnlรผk e-posta", "account_upgrade_dialog_tier_features_attachment_file_size": "dosya baลŸฤฑna {{filesize}}", "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} toplam depolama", "account_upgrade_dialog_tier_selected_label": "Seรงilen", @@ -268,7 +268,7 @@ "account_tokens_table_token_header": "Belirteรง", "account_tokens_table_label_header": "Etiket", "account_tokens_table_current_session": "Geรงerli tarayฤฑcฤฑ oturumu", - "common_copy_to_clipboard": "Panoya kopyala", + "account_tokens_table_copy_to_clipboard": "Panoya kopyala", "account_tokens_table_copied_to_clipboard": "EriลŸim belirteci kopyalandฤฑ", "account_tokens_table_cannot_delete_or_edit": "Geรงerli oturum belirteci dรผzenlenemez veya silinemez", "account_tokens_table_create_token_button": "EriลŸim belirteci oluลŸtur", @@ -352,8 +352,5 @@ "account_upgrade_dialog_interval_yearly_discount_save_up_to": "%{{discount}} kadar tasarruf edin", "account_upgrade_dialog_interval_monthly": "Aylฤฑk", "account_basics_tier_interval_monthly": "aylฤฑk", - "account_upgrade_dialog_billing_contact_website": "Faturalama ile ilgili sorularฤฑnฤฑz iรงin lรผtfen web sitemizi ziyaret edin.", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} ayฤฑrtฤฑlan konu", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} gรผnlรผk e-posta", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} gรผnlรผk mesaj" + "account_upgrade_dialog_billing_contact_website": "Faturalama ile ilgili sorularฤฑnฤฑz iรงin lรผtfen web sitemizi ziyaret edin." } diff --git a/web/public/static/langs/uk.json b/web/public/static/langs/uk.json index 32a3079..686a3d3 100644 --- a/web/public/static/langs/uk.json +++ b/web/public/static/langs/uk.json @@ -53,7 +53,7 @@ "subscribe_dialog_subscribe_use_another_label": "ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะฒะฐั‚ะธ ั–ะฝัˆะธะน ัะตั€ะฒะตั€", "subscribe_dialog_subscribe_base_url_label": "URL ัะปัƒะถะฑะธ", "subscribe_dialog_login_password_label": "ะŸะฐั€ะพะปัŒ", - "common_back": "ะะฐะทะฐะด", + "subscribe_dialog_login_button_back": "ะะฐะทะฐะด", "subscribe_dialog_error_user_not_authorized": "{{username}} ะบะพั€ะธัั‚ัƒะฒะฐั‡ ะฝะต ะฐะฒั‚ะพั€ะธะทะพะฒะฐะฝะธะน", "prefs_notifications_sound_description_none": "ะกะฟะพะฒั–ั‰ะตะฝะฝั ะฝะต ะฒั–ะดั‚ะฒะพั€ัŽัŽั‚ัŒ ะถะพะดะฝะพะณะพ ะทะฒัƒะบัƒ ะฟั€ะธ ะฝะฐะดั…ะพะดะถะตะฝะฝั–", "prefs_notifications_sound_description_some": "ะกะฟะพะฒั–ั‰ะตะฝะฝั ะฒั–ะดั‚ะฒะพั€ัŽัŽั‚ัŒ ะทะฒัƒะบ {{sound}}", @@ -237,149 +237,5 @@ "display_name_dialog_description": "ะ—ะฐะดะฐะนั‚ะต ะฐะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฝัƒ ะฝะฐะทะฒัƒ ะดะปั ั‚ะตะผะธ, ัะบะฐ ะฒั–ะดะพะฑั€ะฐะถะฐั‚ะธะผะตั‚ัŒัั ัƒ ัะฟะธัะบัƒ ะฟั–ะดะฟะธัะพะบ. ะฆะต ะดะพะฟะพะผะพะถะต ะปะตะณัˆะต ั–ะดะตะฝั‚ะธั„ั–ะบัƒะฒะฐั‚ะธ ั‚ะตะผะธ ะทั– ัะบะปะฐะดะฝะธะผะธ ะฝะฐะทะฒะฐะผะธ.", "display_name_dialog_placeholder": "ะ’ั–ะดะพะฑั€ะฐะถัƒะฒะฐะฝะต ั–ะผ'ั", "account_basics_password_title": "ะŸะฐั€ะพะปัŒ", - "account_basics_username_admin_tooltip": "ะ’ะธ ะฐะดะผั–ะฝั–ัั‚ั€ะฐั‚ะพั€", - "account_basics_tier_interval_monthly": "ั‰ะพะผั–ััั†ั", - "common_copy_to_clipboard": "ะกะบะพะฟั–ัŽะฒะฐั‚ะธ ะฒ ะฑัƒั„ะตั€ ะพะฑะผั–ะฝัƒ", - "account_basics_phone_numbers_title": "ะะพะผะตั€ะธ ั‚ะตะปะตั„ะพะฝั–ะฒ", - "account_basics_phone_numbers_description": "ะ”ะปั ัะฟะพะฒั–ั‰ะตะฝัŒ ั‡ะตั€ะตะท ั‚ะตะปะตั„ะพะฝะฝั– ะดะทะฒั–ะฝะบะธ", - "account_basics_phone_numbers_no_phone_numbers_yet": "ะŸะพะบะธ ั‰ะพ ะฝะตะผะฐั” ะฝะพะผะตั€ั–ะฒ ั‚ะตะปะตั„ะพะฝั–ะฒ", - "account_basics_phone_numbers_copied_to_clipboard": "ะะพะผะตั€ ั‚ะตะปะตั„ะพะฝัƒ ัะบะพะฟั–ะนะพะฒะฐะฝะพ ะฒ ะฑัƒั„ะตั€ ะพะฑะผั–ะฝัƒ", - "account_basics_phone_numbers_dialog_title": "ะ”ะพะดะฐั‚ะธ ะฝะพะผะตั€ ั‚ะตะปะตั„ะพะฝัƒ", - "account_basics_phone_numbers_dialog_number_label": "ะะพะผะตั€ ั‚ะตะปะตั„ะพะฝัƒ", - "account_basics_phone_numbers_dialog_number_placeholder": "ะฝะฐะฟั€ะธะบะปะฐะด, +1222333444", - "account_basics_phone_numbers_dialog_verify_button_sms": "ะะฐะดั–ัะปะฐั‚ะธ SMS", - "account_basics_phone_numbers_dialog_verify_button_call": "ะ—ะฐั‚ะตะปะตั„ะพะฝัƒะนั‚ะต ะผะตะฝั–", - "account_basics_phone_numbers_dialog_code_label": "ะšะพะด ะฟั–ะดั‚ะฒะตั€ะดะถะตะฝะฝั", - "account_basics_phone_numbers_dialog_code_placeholder": "ะฝะฐะฟั€ะธะบะปะฐะด, 123456", - "account_basics_phone_numbers_dialog_check_verification_button": "ะŸั–ะดั‚ะฒะตั€ะดะธั‚ะธ ะบะพะด", - "account_basics_phone_numbers_dialog_channel_sms": "SMS", - "account_basics_phone_numbers_dialog_channel_call": "ะ”ะทะฒั–ะฝะพะบ", - "account_basics_tier_interval_yearly": "ั‰ะพั€ะพะบัƒ", - "account_usage_calls_title": "ะ—ะดั–ะนัะฝะตะฝั– ั‚ะตะปะตั„ะพะฝะฝั– ะดะทะฒั–ะฝะบะธ", - "account_usage_calls_none": "ะ— ั†ัŒะพะณะพ ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ ะฝะต ะผะพะถะฝะฐ ะทะดั–ะนัะฝัŽะฒะฐั‚ะธ ั‚ะตะปะตั„ะพะฝะฝั– ะดะทะฒั–ะฝะบะธ", - "account_usage_attachment_storage_title": "ะ—ะฑะตั€ั–ะณะฐะฝะฝั ะฒะบะปะฐะดะตะฝัŒ", - "account_usage_attachment_storage_description": "{{filesize}} ะฝะฐ ั„ะฐะนะป, ะฒะธะดะฐะปัั”ั‚ัŒัั ะฟั–ัะปั {{expiry}}", - "account_usage_basis_ip_description": "ะกั‚ะฐั‚ะธัั‚ะธะบะฐ ะฒะธะบะพั€ะธัั‚ะฐะฝะฝั ั‚ะฐ ะปั–ะผั–ั‚ะธ ะดะปั ั†ัŒะพะณะพ ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ ะฑะฐะทัƒัŽั‚ัŒัั ะฝะฐ ะฒะฐัˆั–ะน IP-ะฐะดั€ะตัั–, ั‚ะพะผัƒ ะฒะพะฝะธ ะผะพะถัƒั‚ัŒ ะฑัƒั‚ะธ ะดะพัั‚ัƒะฟะฝั– ั–ะฝัˆะธะผ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐะผ. ะ›ั–ะผั–ั‚ะธ, ะฟะพะบะฐะทะฐะฝั– ะฒะธั‰ะต, ั” ะฟั€ะธะฑะปะธะทะฝะธะผะธ ั– ะฑะฐะทัƒัŽั‚ัŒัั ะฝะฐ ั–ัะฝัƒัŽั‡ะธั… ะปั–ะผั–ั‚ะฐั… ั‚ะฐั€ะธั„ั–ะฒ.", - "account_usage_cannot_create_portal_session": "ะะต ะฒะดะฐั”ั‚ัŒัั ะฒั–ะดะบั€ะธั‚ะธ ะฑั–ะปั–ะฝะณะพะฒะธะน ะฟะพั€ั‚ะฐะป", - "account_delete_title": "ะ’ะธะดะฐะปะตะฝะฝั ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ", - "account_delete_description": "ะะฐะทะฐะฒะถะดะธ ะฒะธะดะฐะปะธั‚ะธ ัะฒั–ะน ะพะฑะปั–ะบะพะฒะธะน ะทะฐะฟะธั", - "account_delete_dialog_label": "ะŸะฐั€ะพะปัŒ", - "account_delete_dialog_button_cancel": "ะกะบะฐััƒะฒะฐั‚ะธ", - "account_delete_dialog_button_submit": "ะ’ะธะดะฐะปะธั‚ะธ ะพะฑะปั–ะบะพะฒะธะน ะทะฐะฟะธั ะฝะฐะทะฐะฒะถะดะธ", - "account_delete_dialog_billing_warning": "ะ’ะธะดะฐะปะตะฝะฝั ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ ั‚ะฐะบะพะถ ะฝะตะณะฐะนะฝะพ ัะบะฐัะพะฒัƒั” ะฒะฐัˆัƒ ะฟั–ะดะฟะธัะบัƒ. ะ’ะธ ะฑั–ะปัŒัˆะต ะฝะต ะผะฐั‚ะธะผะตั‚ะต ะดะพัั‚ัƒะฟัƒ ะดะพ ะฑั–ะปั–ะฝะณะพะฒะพั— ะฟะฐะฝะตะปั–.", - "account_upgrade_dialog_title": "ะ—ะผั–ะฝะฐ ั€ั–ะฒะฝั ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ", - "account_upgrade_dialog_interval_monthly": "ะฉะพะผั–ััั†ั", - "account_upgrade_dialog_interval_yearly": "ะฉะพั€ั–ั‡ะฝะพ", - "account_upgrade_dialog_interval_yearly_discount_save": "ะตะบะพะฝะพะผั–ั {{discount}}%", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "ะตะบะพะฝะพะผั–ั ะดะพ {{discount}}%", - "publish_dialog_call_label": "ะขะตะปะตั„ะพะฝะฝะธะน ะดะทะฒั–ะฝะพะบ", - "publish_dialog_call_placeholder": "ะะพะผะตั€ ั‚ะตะปะตั„ะพะฝัƒ, ะฝะฐ ัะบะธะน ะฟะพั‚ั€ั–ะฑะฝะพ ะทะฐั‚ะตะปะตั„ะพะฝัƒะฒะฐั‚ะธ ะท ะฟะพะฒั–ะดะพะผะปะตะฝะฝัะผ, ะฝะฐะฟั€ะธะบะปะฐะด, +12223334444 ะฐะฑะพ \"yes\"", - "publish_dialog_chip_call_label": "ะขะตะปะตั„ะพะฝะฝะธะน ะดะทะฒั–ะฝะพะบ", - "publish_dialog_call_reset": "ะ’ะธะดะฐะปะธั‚ะธ ั‚ะตะปะตั„ะพะฝะฝะธะน ะดะทะฒั–ะฝะพะบ", - "account_basics_phone_numbers_dialog_description": "ะฉะพะฑ ะบะพั€ะธัั‚ัƒะฒะฐั‚ะธัั ั„ัƒะฝะบั†ั–ั”ัŽ ัะฟะพะฒั–ั‰ะตะฝะฝั ะฟั€ะพ ะดะทะฒั–ะฝะบะธ, ะฟะพั‚ั€ั–ะฑะฝะพ ะดะพะดะฐั‚ะธ ั‚ะฐ ะฒะตั€ะธั„ั–ะบัƒะฒะฐั‚ะธ ะฟั€ะธะฝะฐะนะผะฝั– ะพะดะธะฝ ั‚ะตะปะตั„ะพะฝะฝะธะน ะฝะพะผะตั€. ะ’ะตั€ะธั„ั–ะบะฐั†ั–ัŽ ะผะพะถะฝะฐ ะทะดั–ะนัะฝะธั‚ะธ ะทะฐ ะดะพะฟะพะผะพะณะพัŽ SMS ะฐะฑะพ ั‚ะตะปะตั„ะพะฝะฝะพะณะพ ะดะทะฒั–ะฝะบะฐ.", - "account_delete_dialog_description": "ะฆะต ะฟั€ะธะทะฒะตะดะต ะดะพ ะพัั‚ะฐั‚ะพั‡ะฝะพะณะพ ะฒะธะดะฐะปะตะฝะฝั ะฒะฐัˆะพะณะพ ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ, ะฒะบะปัŽั‡ะฐัŽั‡ะธ ะฒัั– ะดะฐะฝั–, ัะบั– ะทะฑะตั€ั–ะณะฐัŽั‚ัŒัั ะฝะฐ ัะตั€ะฒะตั€ั–. ะŸั–ัะปั ะฒะธะดะฐะปะตะฝะฝั ะฒะฐัˆะต ั–ะผ'ั ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ ะฑัƒะดะต ะฝะตะดะพัั‚ัƒะฟะฝะต ะฟั€ะพั‚ัะณะพะผ 7 ะดะฝั–ะฒ. ะฏะบั‰ะพ ะฒะธ ะดั–ะนัะฝะพ ั…ะพั‡ะตั‚ะต ะฟั€ะพะดะพะฒะถะธั‚ะธ, ะฑัƒะดัŒ ะปะฐัะบะฐ, ะฟั–ะดั‚ะฒะตั€ะดัŒั‚ะต ัะฒั–ะน ะฟะฐั€ะพะปัŒ ัƒ ะฟะพะปั– ะฝะธะถั‡ะต.", - "account_basics_tier_upgrade_button": "ะžะฝะพะฒะปะตะฝะฝั ะดะพ Pro", - "account_basics_password_description": "ะ—ะผั–ะฝะฐ ะฟะฐั€ะพะปั ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ", - "account_usage_of_limit": "ะท {{limit}}", - "account_usage_unlimited": "ะ‘ะตะท ะพะฑะผะตะถะตะฝัŒ", - "account_basics_tier_description": "ะ ั–ะฒะตะฝัŒ ะฟะพั‚ัƒะถะฝะพัั‚ั– ะฒะฐัˆะพะณะพ ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ", - "account_basics_tier_admin_suffix_with_tier": "(ะท ั€ั–ะฒะฝะตะผ {{tier}})", - "account_basics_tier_admin_suffix_no_tier": "(ะฑะตะท ั€ั–ะฒะฝั)", - "account_basics_tier_basic": "ะ‘ะฐะทะพะฒะธะน", - "account_basics_tier_free": "ะ‘ะตะทะบะพัˆั‚ะพะฒะฝะธะน", - "account_basics_tier_change_button": "ะ—ะผั–ะฝะธั‚ะธ", - "account_basics_tier_paid_until": "ะŸั–ะดะฟะธัะบะฐ ะพะฟะปะฐั‡ะตะฝะฐ ะดะพ {{date}} ั– ะฑัƒะดะต ะฐะฒั‚ะพะผะฐั‚ะธั‡ะฝะพ ะฟะพะฝะพะฒะปัŽะฒะฐั‚ะธัั", - "account_basics_tier_payment_overdue": "ะ’ะฐัˆ ะฟะปะฐั‚ั–ะถ ะฟั€ะพัั‚ั€ะพั‡ะตะฝะพ. ะ‘ัƒะดัŒ ะปะฐัะบะฐ, ะพะฝะพะฒั–ั‚ัŒ ัะฟะพัั–ะฑ ะพะฟะปะฐั‚ะธ, ั–ะฝะฐะบัˆะต ะฒะฐัˆ ะพะฑะปั–ะบะพะฒะธะน ะทะฐะฟะธั ะฑัƒะดะต ะทะฝะธะถะตะฝะพ ะดะพ ะฝะธะถั‡ะพะณะพ ั€ั–ะฒะฝั.", - "account_basics_tier_canceled_subscription": "ะ’ะฐัˆัƒ ะฟั–ะดะฟะธัะบัƒ ะฑัƒะปะพ ัะบะฐัะพะฒะฐะฝะพ, ั– ะท {{date}} ะฒะพะฝะฐ ะฑัƒะดะต ะทะฝะธะถะตะฝะฐ ะดะพ ะฑะตะทะบะพัˆั‚ะพะฒะฝะพะณะพ ะฐะบะฐัƒะฝั‚ะฐ.", - "account_basics_tier_manage_billing_button": "ะšะตั€ัƒะฒะฐั‚ะธ ั€ะฐั…ัƒะฝะบะฐะผะธ", - "account_usage_messages_title": "ะžะฟัƒะฑะปั–ะบะพะฒะฐะฝั– ะฟะพะฒั–ะดะพะผะปะตะฝะฝั", - "account_usage_emails_title": "ะะฐะดั–ัะปะฐะฝั– ะตะปะตะบั‚ั€ะพะฝะฝั– ะปะธัั‚ะธ", - "account_usage_reservations_title": "ะ—ะฐั€ะตะทะตั€ะฒะพะฒะฐะฝั– ั‚ะตะผะธ", - "account_usage_reservations_none": "ะ”ะปั ั†ัŒะพะณะพ ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ ะฝะตะผะฐั” ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะธั… ั‚ะตะผ", - "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} ะฝะฐ ั„ะฐะนะป", - "account_upgrade_dialog_tier_features_attachment_total_size": "{{totalsize}} ะทะฐะณะฐะปัŒะฝะต ัั…ะพะฒะธั‰ะต", - "account_upgrade_dialog_tier_current_label": "ะŸะพั‚ะพั‡ะฝะธะน", - "account_upgrade_dialog_tier_selected_label": "ะ’ะธะฑั€ะฐะฝะต", - "account_upgrade_dialog_cancel_warning": "ะฆะต ัะบะฐััƒั” ะฒะฐัˆัƒ ะฟั–ะดะฟะธัะบัƒ ั– ะทะฝะธะทะธั‚ัŒ ะฒะตั€ัั–ัŽ ะฒะฐัˆะพะณะพ ะพะฑะปั–ะบะพะฒะพะณะพ ะทะฐะฟะธััƒ {{date}}. ะฃ ั†ัŽ ะดะฐั‚ัƒ ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ั‚ะตะผ, ะฐ ั‚ะฐะบะพะถ ะฟะพะฒั–ะดะพะผะปะตะฝะฝั, ะบะตัˆะพะฒะฐะฝั– ะฝะฐ ัะตั€ะฒะตั€ั– , ะฑัƒะดะต ะฒะธะดะฐะปะตะฝะพ.", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝั– ั‚ะตะผะธ", - "account_upgrade_dialog_tier_features_no_reservations": "ะะตะผะฐั” ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะธั… ั‚ะตะผ", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} ะฟะพะฒั–ะดะพะผะปะตะฝัŒ ะฒ ะดะตะฝัŒ", - "account_upgrade_dialog_tier_features_emails_one": "{{emails}} ะตะปะตะบั‚ั€ะพะฝะฝะธะน ะปะธัั‚ ะฒ ะดะตะฝัŒ", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} ะตะปะตะบั‚ั€ะพะฝะฝะธั… ะปะธัั‚ั–ะฒ ะฒ ะดะตะฝัŒ", - "account_upgrade_dialog_tier_features_calls_one": "{{calls}} ั‚ะตะปะตั„ะพะฝะฝะธะน ะดะทะฒั–ะฝะพะบ ะฒ ะดะตะฝัŒ", - "account_upgrade_dialog_tier_features_calls_other": "{{ะดะทะฒั–ะฝะบะธ}} ั‚ะตะปะตั„ะพะฝะฝะธั… ะดะทะฒั–ะฝะบั–ะฒ ะฒ ะดะตะฝัŒ", - "account_upgrade_dialog_tier_features_no_calls": "ะ‘ะตะท ั‚ะตะปะตั„ะพะฝะฝะธั… ะดะทะฒั–ะฝะบั–ะฒ", - "account_upgrade_dialog_tier_price_per_month": "ะผั–ััั†ัŒ", - "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} ะฝะฐ ั€ั–ะบ. ะ ะฐั…ัƒะฝะพะบ ะฒะธัั‚ะฐะฒะปัั”ั‚ัŒัั ั‰ะพะผั–ััั†ั.", - "account_upgrade_dialog_tier_price_billed_yearly": "{{price}} ะฒะธัั‚ะฐะฒะปัั”ั‚ัŒัั ั‰ะพั€ั–ั‡ะฝะพ. ะ—ะฑะตั€ะตะถั–ั‚ัŒ {{save}}.", - "account_upgrade_dialog_billing_contact_email": "ะฏะบั‰ะพ ัƒ ะฒะฐั ะฒะธะฝะธะบะปะธ ะทะฐะฟะธั‚ะฐะฝะฝั ั‰ะพะดะพ ะพะฟะปะฐั‚ะธ, ะทะฒโ€™ัะถั–ั‚ัŒัั ะท ะฝะฐะผะธ ะฑะตะทะฟะพัะตั€ะตะดะฝัŒะพ.", - "account_upgrade_dialog_billing_contact_website": "ะฏะบั‰ะพ ัƒ ะฒะฐั ะฒะธะฝะธะบะปะธ ะทะฐะฟะธั‚ะฐะฝะฝั ั‰ะพะดะพ ะพะฟะปะฐั‚ะธ, ะฒั–ะดะฒั–ะดะฐะนั‚ะต ะฝะฐัˆ ะฒะตะฑ-ัะฐะนั‚.", - "account_upgrade_dialog_button_cancel_subscription": "ะกะบะฐััƒะฒะฐั‚ะธ ะฟั–ะดะฟะธัะบัƒ", - "account_upgrade_dialog_button_update_subscription": "ะžะฝะพะฒะธั‚ะธ ะฟั–ะดะฟะธัะบัƒ", - "account_tokens_title": "ะขะพะบะตะฝะธ ะดะพัั‚ัƒะฟัƒ", - "account_tokens_table_expires_header": "ะขะตั€ะผั–ะฝ ะดั–ั— ะทะฐะบั–ะฝั‡ัƒั”ั‚ัŒัั", - "account_tokens_description": "ะ’ะธะบะพั€ะธัั‚ะพะฒัƒะนั‚ะต ั‚ะพะบะตะฝะธ ะดะพัั‚ัƒะฟัƒ ะฟั€ะธ ะฟัƒะฑะปั–ะบะฐั†ั–ั— ั‚ะฐ ะฟั–ะดะฟะธัั†ั– ั‡ะตั€ะตะท ntfy API, ั‰ะพะฑ ะฝะต ะฝะฐะดัะธะปะฐั‚ะธ ัะฒะพั— ะพะฑะปั–ะบะพะฒั– ะดะฐะฝั–. ะžะทะฝะฐะนะพะผั‚ะตัั ะท ะดะพะบัƒะผะตะฝั‚ะฐั†ั–ั”ัŽ, ั‰ะพะฑ ะดั–ะทะฝะฐั‚ะธัั ะฑั–ะปัŒัˆะต.", - "account_tokens_table_token_header": "ะขะพะบะตะฝ", - "account_tokens_table_never_expires": "ะั–ะบะพะปะธ ะฝะต ะทะฐะบั–ะฝั‡ัƒั”ั‚ัŒัั", - "account_tokens_table_label_header": "ะœั–ั‚ะบะฐ", - "account_tokens_table_current_session": "ะŸะพั‚ะพั‡ะฝะธะน ัะตะฐะฝั ะฑั€ะฐัƒะทะตั€ะฐ", - "account_tokens_table_last_access_header": "ะžัั‚ะฐะฝะฝั–ะน ะดะพัั‚ัƒะฟ", - "account_tokens_table_copied_to_clipboard": "ะขะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ ัะบะพะฟั–ะนะพะฒะฐะฝะพ", - "account_tokens_table_cannot_delete_or_edit": "ะะตะผะพะถะปะธะฒะพ ั€ะตะดะฐะณัƒะฒะฐั‚ะธ ะฐะฑะพ ะฒะธะดะฐะปะธั‚ะธ ั‚ะพะบะตะฝ ะฟะพั‚ะพั‡ะฝะพะณะพ ัะตะฐะฝััƒ", - "account_tokens_table_create_token_button": "ะกั‚ะฒะพั€ะธั‚ะธ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ", - "account_tokens_table_last_origin_tooltip": "ะ— IP-ะฐะดั€ะตัะธ {{ip}} ะฝะฐั‚ะธัะฝั–ั‚ัŒ ะดะปั ะฟะพัˆัƒะบัƒ", - "account_tokens_dialog_title_create": "ะกั‚ะฒะพั€ะธั‚ะธ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ", - "account_tokens_dialog_button_cancel": "ะกะบะฐััƒะฒะฐั‚ะธ", - "account_tokens_dialog_title_edit": "ะ ะตะดะฐะณัƒะฒะฐั‚ะธ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ", - "account_tokens_dialog_title_delete": "ะ’ะธะดะฐะปะธั‚ะธ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ", - "account_tokens_dialog_label": "ะœั–ั‚ะบะฐ, ะฝะฐะฟั€ะธะบะปะฐะด, ัะฟะพะฒั–ั‰ะตะฝะฝั Radarr", - "account_tokens_dialog_button_create": "ะกั‚ะฒะพั€ะธั‚ะธ ั‚ะพะบะตะฝ", - "account_tokens_dialog_button_update": "ะžะฝะพะฒะธั‚ะธ ั‚ะพะบะตะฝ", - "account_tokens_dialog_expires_label": "ะขะตั€ะผั–ะฝ ะดั–ั— ั‚ะพะบะตะฝัƒ ะดะพัั‚ัƒะฟัƒ ะทะฐะบั–ะฝั‡ัƒั”ั‚ัŒัั ั‡ะตั€ะตะท", - "account_tokens_dialog_expires_x_hours": "ะขะตั€ะผั–ะฝ ะดั–ั— ั‚ะพะบะตะฝะฐ ะทะฐะบั–ะฝั‡ัƒั”ั‚ัŒัั ั‡ะตั€ะตะท {{hours}} ะณะพะดะธะฝ", - "account_tokens_dialog_expires_x_days": "ะขะตั€ะผั–ะฝ ะดั–ั— ั‚ะพะบะตะฝะฐ ะทะฐะบั–ะฝั‡ัƒั”ั‚ัŒัั ั‡ะตั€ะตะท {{days}} ะดะฝั–ะฒ", - "account_tokens_delete_dialog_description": "ะŸะตั€ัˆ ะฝั–ะถ ะฒะธะดะฐะปะธั‚ะธ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ, ะฟะตั€ะตะบะพะฝะฐะนั‚ะตัั, ั‰ะพ ะถะพะดะฝะฐ ะฟั€ะพะณั€ะฐะผะฐ ะฐะฑะพ ัะบั€ะธะฟั‚ ะฝะต ะฒะธะบะพั€ะธัั‚ะพะฒัƒั” ะนะพะณะพ. ะฆั ะดั–ั ะฝะต ะผะพะถะต ะฑัƒั‚ะธ ัะบะฐัะพะฒะฐะฝะฐ.", - "prefs_users_description_no_sync": "ะšะพั€ะธัั‚ัƒะฒะฐั‡ั– ั‚ะฐ ะฟะฐั€ะพะปั– ะฝะต ัะธะฝั…ั€ะพะฝั–ะทัƒัŽั‚ัŒัั ะท ะฒะฐัˆะธะผ ะฐะบะฐัƒะฝั‚ะพะผ.", - "prefs_users_table_cannot_delete_or_edit": "ะะตะผะพะถะปะธะฒะพ ะฒะธะดะฐะปะธั‚ะธ ะฐะฑะพ ะฒั–ะดั€ะตะดะฐะณัƒะฒะฐั‚ะธ ะบะพั€ะธัั‚ัƒะฒะฐั‡ะฐ, ัะบะธะน ัƒะฒั–ะนัˆะพะฒ ัƒ ัะธัั‚ะตะผัƒ", - "account_upgrade_dialog_tier_features_reservations_one": "{{reservations}} ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะฐ ั‚ะตะผะฐ", - "account_upgrade_dialog_tier_features_messages_one": "{{messages}} ะฟะพะฒั–ะดะพะผะปะตะฝะฝั ะฒ ะดะตะฝัŒ", - "account_tokens_dialog_expires_unchanged": "ะ—ะฐะปะธัˆะธั‚ะธ ั‚ะตั€ะผั–ะฝ ะฟั€ะธะดะฐั‚ะฝะพัั‚ั– ะฑะตะท ะทะผั–ะฝ", - "account_tokens_dialog_expires_never": "ะขะตั€ะผั–ะฝ ะดั–ั— ั‚ะพะบะตะฝะฐ ะฝั–ะบะพะปะธ ะฝะต ะทะฐะบั–ะฝั‡ัƒั”ั‚ัŒัั", - "account_tokens_delete_dialog_title": "ะ’ะธะดะฐะปะธั‚ะธ ั‚ะพะบะตะฝ ะดะพัั‚ัƒะฟัƒ", - "account_tokens_delete_dialog_submit_button": "ะ’ะธะดะฐะปะธั‚ะธ ั‚ะพะบะตะฝ ะฝะฐะทะฐะฒะถะดะธ", - "account_upgrade_dialog_proration_info": "ะŸั€ะพะฟะพั€ั†ั–ั: ะŸั€ะธ ะฟะตั€ะตั…ะพะดั– ะท ะพะดะฝะพะณะพ ั‚ะฐั€ะธั„ะฝะพะณะพ ะฟะปะฐะฝัƒ ะฝะฐ ั–ะฝัˆะธะน ั€ั–ะทะฝะธั†ั ะฒ ั†ั–ะฝั– ะฑัƒะดะต ัะฟะธัะฐะฝะฐ ะฝะตะณะฐะนะฝะพ. ะŸั€ะธ ะฟะตั€ะตั…ะพะดั– ะฝะฐ ะฝะธะถั‡ะธะน ั€ั–ะฒะตะฝัŒ ะทะฐะปะธัˆะพะบ ะบะพัˆั‚ั–ะฒ ะฑัƒะดะต ะฒะธะบะพั€ะธัั‚ะฐะฝะพ ะดะปั ะพะฟะปะฐั‚ะธ ะผะฐะนะฑัƒั‚ะฝั–ั… ั€ะพะทั€ะฐั…ัƒะฝะบะพะฒะธั… ะฟะตั€ั–ะพะดั–ะฒ.", - "account_upgrade_dialog_reservations_warning_one": "ะžะฑั€ะฐะฝะธะน ั€ั–ะฒะตะฝัŒ ะดะพะทะฒะพะปัั” ะผะตะฝัˆะต ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะธั… ั‚ะตะผ, ะฝั–ะถ ะฒะฐัˆ ะฟะพั‚ะพั‡ะฝะธะน ั€ั–ะฒะตะฝัŒ. ะŸะตั€ัˆ ะฝั–ะถ ะทะผั–ะฝะธั‚ะธ ัะฒั–ะน ั€ั–ะฒะตะฝัŒ, ะฑัƒะดัŒ ะปะฐัะบะฐ, ะฒะธะดะฐะปั–ั‚ัŒ ะฟั€ะธะฝะฐะนะผะฝั– ะพะดะฝะต ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั. ะ’ะธ ะผะพะถะตั‚ะต ะฒะธะดะฐะปะธั‚ะธ ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ะฒ ะะฐะปะฐัˆั‚ัƒะฒะฐะฝะฝัั….", - "account_upgrade_dialog_reservations_warning_other": "ะžะฑั€ะฐะฝะธะน ั€ั–ะฒะตะฝัŒ ะดะพะทะฒะพะปัั” ะผะตะฝัˆะต ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะธั… ั‚ะตะผ, ะฝั–ะถ ะฒะฐัˆ ะฟะพั‚ะพั‡ะฝะธะน ั€ั–ะฒะตะฝัŒ. ะŸะตั€ัˆ ะฝั–ะถ ะทะผั–ะฝะธั‚ะธ ัะฒั–ะน ั€ั–ะฒะตะฝัŒ, ะฑัƒะดัŒ ะปะฐัะบะฐ, ะฒะธะดะฐะปั–ั‚ัŒ ะฟั€ะธะฝะฐะนะผะฝั– {{count}} ั€ะตะทะตั€ะฒัƒะฒะฐะฝัŒ. ะ’ะธ ะผะพะถะตั‚ะต ะฒะธะดะฐะปะธั‚ะธ ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ะฒ ะะฐะปะฐัˆั‚ัƒะฒะฐะฝะฝัั….", - "account_upgrade_dialog_button_cancel": "ะกะบะฐััƒะฒะฐั‚ะธ", - "account_upgrade_dialog_button_redirect_signup": "ะ—ะฐั€ะตั”ัั‚ั€ัƒะฒะฐั‚ะธัั ะทะฐั€ะฐะท", - "account_upgrade_dialog_button_pay_now": "ะžะฟะปะฐั‚ะธั‚ะธ ะทะฐั€ะฐะท ั– ะฟั–ะดะฟะธัะฐั‚ะธัั", - "prefs_reservations_add_button": "ะ”ะพะดะฐั‚ะธ ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝัƒ ั‚ะตะผัƒ", - "prefs_reservations_edit_button": "ะ ะตะดะฐะณัƒะฒะฐั‚ะธ ะดะพัั‚ัƒะฟ ะดะพ ั‚ะตะผะธ", - "prefs_reservations_limit_reached": "ะ’ะธ ะดะพััะณะปะธ ะปั–ะผั–ั‚ัƒ ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะธั… ั‚ะตะผ.", - "prefs_reservations_table_click_to_subscribe": "ะะฐั‚ะธัะฝั–ั‚ัŒ, ั‰ะพะฑ ะฟั–ะดะฟะธัะฐั‚ะธัั", - "prefs_reservations_table_topic_header": "ะขะตะผะฐ", - "prefs_reservations_description": "ะขัƒั‚ ะฒะธ ะผะพะถะตั‚ะต ะทะฐั€ะตะทะตั€ะฒัƒะฒะฐั‚ะธ ะฝะฐะทะฒะธ ั‚ะตะผ ะดะปั ะพัะพะฑะธัั‚ะพะณะพ ะบะพั€ะธัั‚ัƒะฒะฐะฝะฝั. ะ ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ั‚ะตะผะธ ะดะฐั” ะฒะฐะผ ะฟั€ะฐะฒะพ ะฒะปะฐัะฝะพัั‚ั– ะฝะฐ ั‚ะตะผัƒ ั– ะดะพะทะฒะพะปัั” ะฒะธะทะฝะฐั‡ะฐั‚ะธ ะฟั€ะฐะฒะฐ ะดะพัั‚ัƒะฟัƒ ะดะพ ะฝะตั— ั–ะฝัˆะธั… ะบะพั€ะธัั‚ัƒะฒะฐั‡ั–ะฒ.", - "prefs_reservations_table": "ะขะฐะฑะปะธั†ั ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝะธั… ั‚ะตะผ", - "prefs_reservations_table_access_header": "ะ”ะพัั‚ัƒะฟ", - "prefs_reservations_table_everyone_deny_all": "ะขั–ะปัŒะบะธ ั ะผะพะถัƒ ะฟัƒะฑะปั–ะบัƒะฒะฐั‚ะธ ั‚ะฐ ะฟั–ะดะฟะธััƒะฒะฐั‚ะธััŒ", - "prefs_reservations_table_everyone_read_only": "ะฏ ะผะพะถัƒ ะฟัƒะฑะปั–ะบัƒะฒะฐั‚ะธ ั‚ะฐ ะฟั–ะดะฟะธััƒะฒะฐั‚ะธััŒ, ะบะพะถะตะฝ ะผะพะถะต ะฟั–ะดะฟะธัะฐั‚ะธัั", - "prefs_reservations_table_everyone_write_only": "ะฏ ะผะพะถัƒ ะฟัƒะฑะปั–ะบัƒะฒะฐั‚ะธ ั– ะฟั–ะดะฟะธััƒะฒะฐั‚ะธัั, ะบะพะถะตะฝ ะผะพะถะต ะฟัƒะฑะปั–ะบัƒะฒะฐั‚ะธ", - "prefs_reservations_table_everyone_read_write": "ะšะพะถะตะฝ ะผะพะถะต ะฟัƒะฑะปั–ะบัƒะฒะฐั‚ะธ ั‚ะฐ ะฟั–ะดะฟะธััƒะฒะฐั‚ะธัั", - "prefs_reservations_table_not_subscribed": "ะะต ะฟั–ะดะฟะธัะฐะฝะธะน", - "prefs_reservations_dialog_title_add": "ะ—ะฐั€ะตะทะตั€ะฒัƒะฒะฐั‚ะธ ั‚ะตะผัƒ", - "prefs_reservations_dialog_title_edit": "ะ ะตะดะฐะณัƒะฒะฐั‚ะธ ะทะฐั€ะตะทะตั€ะฒะพะฒะฐะฝัƒ ั‚ะตะผัƒ", - "prefs_reservations_title": "ะ—ะฐั€ะตะทะตั€ะฒะพะฒะฐะฝั– ั‚ะตะผะธ", - "prefs_reservations_delete_button": "ะกะบะธะฝัƒั‚ะธ ะดะพัั‚ัƒะฟ ะดะพ ั‚ะตะผะธ", - "prefs_reservations_dialog_description": "ะ ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ั‚ะตะผะธ ะดะฐั” ะฒะฐะผ ะฟั€ะฐะฒะพ ะฒะปะฐัะฝะพัั‚ั– ะฝะฐ ั†ัŽ ั‚ะตะผัƒ ั– ะดะพะทะฒะพะปัั” ะฒะธะทะฝะฐั‡ะฐั‚ะธ ะฟั€ะฐะฒะฐ ะดะพัั‚ัƒะฟัƒ ะดะพ ะฝะตั— ั–ะฝัˆะธั… ะบะพั€ะธัั‚ัƒะฒะฐั‡ั–ะฒ.", - "prefs_reservations_dialog_topic_label": "ะขะตะผะฐ", - "prefs_reservations_dialog_access_label": "ะ”ะพัั‚ัƒะฟ", - "reservation_delete_dialog_description": "ะ’ะธะดะฐะปะตะฝะฝั ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ะฟะพะทะฑะฐะฒะปัั” ะฒะฐั ะฟั€ะฐะฒะฐ ะฒะปะฐัะฝะพัั‚ั– ะฝะฐ ั‚ะตะผัƒ ั– ะดะพะทะฒะพะปัั” ั–ะฝัˆะธะผ ะทะฐั€ะตะทะตั€ะฒัƒะฒะฐั‚ะธ ั—ั—. ะ’ะธ ะผะพะถะตั‚ะต ะทะฑะตั€ะตะณั‚ะธ ะฐะฑะพ ะฒะธะดะฐะปะธั‚ะธ ั–ัะฝัƒัŽั‡ั– ะฟะพะฒั–ะดะพะผะปะตะฝะฝั ั– ะฒะบะปะฐะดะตะฝะฝั.", - "reservation_delete_dialog_submit_button": "ะ’ะธะดะฐะปะธั‚ะธ ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั", - "publish_dialog_call_item": "ะขะตะปะตั„ะพะฝัƒะฒะฐั‚ะธ ะทะฐ ะฝะพะผะตั€ะพะผ {{ะฝะพะผะตั€}}", - "publish_dialog_chip_call_no_verified_numbers_tooltip": "ะะตะผะฐั” ะฟั–ะดั‚ะฒะตั€ะดะถะตะฝะธั… ะฝะพะผะตั€ั–ะฒ ั‚ะตะปะตั„ะพะฝั–ะฒ", - "prefs_reservations_dialog_title_delete": "ะ’ะธะดะฐะปะธั‚ะธ ั€ะตะทะตั€ะฒัƒะฒะฐะฝะฝั ั‚ะตะผะธ", - "reservation_delete_dialog_action_delete_title": "ะ’ะธะดะฐะปะตะฝะฝั ะบะตัˆะพะฒะฐะฝะธั… ะฟะพะฒั–ะดะพะผะปะตะฝัŒ ั– ะฒะบะปะฐะดะตะฝัŒ", - "reservation_delete_dialog_action_keep_title": "ะ—ะฑะตั€ะตะถะตะฝะฝั ะบะตัˆะพะฒะฐะฝะธั… ะฟะพะฒั–ะดะพะผะปะตะฝัŒ ั– ะฒะบะปะฐะดะตะฝัŒ", - "reservation_delete_dialog_action_keep_description": "ะŸะพะฒั–ะดะพะผะปะตะฝะฝั ั– ะฒะบะปะฐะดะตะฝะฝั, ัะบั– ะบะตัˆัƒัŽั‚ัŒัั ะฝะฐ ัะตั€ะฒะตั€ั–, ัั‚ะฐัŽั‚ัŒ ะทะฐะณะฐะปัŒะฝะพะดะพัั‚ัƒะฟะฝะธะผะธ ะดะปั ะปัŽะดะตะน, ัะบั– ะทะฝะฐัŽั‚ัŒ ะฝะฐะทะฒัƒ ั‚ะตะผะธ.", - "reservation_delete_dialog_action_delete_description": "ะšะตัˆะพะฒะฐะฝั– ะฟะพะฒั–ะดะพะผะปะตะฝะฝั ั‚ะฐ ะฒะบะปะฐะดะตะฝะฝั ะฑัƒะดัƒั‚ัŒ ะฒะธะดะฐะปะตะฝั– ะฝะฐะทะฐะฒะถะดะธ. ะฆั ะดั–ั ะฝะต ะผะพะถะต ะฑัƒั‚ะธ ัะบะฐัะพะฒะฐะฝะฐ." + "account_basics_username_admin_tooltip": "ะ’ะธ ะฐะดะผั–ะฝั–ัั‚ั€ะฐั‚ะพั€" } diff --git a/web/public/static/langs/zh_Hans.json b/web/public/static/langs/zh_Hans.json index 2db95f5..818aec0 100644 --- a/web/public/static/langs/zh_Hans.json +++ b/web/public/static/langs/zh_Hans.json @@ -103,7 +103,7 @@ "subscribe_dialog_login_description": "ๆœฌไธป้ข˜ๅ—ๅฏ†็ ไฟๆŠค๏ผŒ่ฏท่พ“ๅ…ฅ็”จๆˆทๅๅ’Œๅฏ†็ ่ฟ›่กŒ่ฎข้˜…ใ€‚", "subscribe_dialog_login_username_label": "็”จๆˆทๅ๏ผŒไพ‹ๅฆ‚ phil", "subscribe_dialog_login_password_label": "ๅฏ†็ ", - "common_back": "่ฟ”ๅ›ž", + "subscribe_dialog_login_button_back": "่ฟ”ๅ›ž", "subscribe_dialog_login_button_login": "็™ปๅฝ•", "subscribe_dialog_error_user_not_authorized": "ๆœชๆŽˆๆƒ {{username}} ็”จๆˆท", "subscribe_dialog_error_user_anonymous": "ๅŒฟๅ", @@ -293,12 +293,12 @@ "account_delete_dialog_billing_warning": "ๅˆ ้™คๆ‚จ็š„ๅธๆˆทไนŸไผš็ซ‹ๅณๅ–ๆถˆๆ‚จ็š„่ฎก่ดน่ฎข้˜…ใ€‚ๆ‚จๅฐ†ๆ— ๆณ•ๅ†่ฎฟ้—ฎ่ฎก่ดนไปช่กจๆฟใ€‚", "account_upgrade_dialog_title": "ๆ›ดๆ”นๅธๆˆท็ญ‰็บง", "account_upgrade_dialog_cancel_warning": "่ฟ™ๅฐ†ๅ–ๆถˆๆ‚จ็š„่ฎข้˜…๏ผŒๅนถๅœจ {{date}} ้™็บงๆ‚จ็š„ๅธๆˆทใ€‚ๅœจ้‚ฃไธ€ๅคฉ๏ผŒไธป้ข˜ไฟ็•™ไปฅๅŠ็ผ“ๅญ˜ๅœจๆœๅŠกๅ™จไธŠ็š„ๆถˆๆฏๅฐ†่ขซๅˆ ้™คใ€‚", - "account_upgrade_dialog_proration_info": "ๆŒ‰ๆฏ”ไพ‹ๅˆ†้…๏ผšๅœจไป˜่ดน่ฎกๅˆ’ไน‹้—ดๅ‡็บงๆ—ถ๏ผŒๅทฎไปทๅฐ†่ขซ็ซ‹ๅˆปๆ”ถๅ–ใ€‚ๅœจ้™็บงๅˆฐ่พƒไฝŽ็บงๅˆซๆ—ถ๏ผŒไฝ™้ขๅฐ†่ขซ็”จไบŽๆ”ฏไป˜ๆœชๆฅ็š„่ดฆๅ•ๅ‘จๆœŸใ€‚", + "account_upgrade_dialog_proration_info": "ๆŒ‰ๆฏ”ไพ‹ๅˆ†้…๏ผšๅœจไป˜่ดน่ฎกๅˆ’ไน‹้—ดๅˆ‡ๆขๆ—ถ๏ผŒๅทฎไปทๅฐ†ๅœจไธ‹ไธ€ๆฌก่ฎก่ดนๆ—ถๆ”ถๅ–ๆˆ–้€€่ฟ˜ใ€‚ๅœจไธ‹ไธ€ไธช่ฎก่ดนๅ‘จๆœŸ็ป“ๆŸไน‹ๅ‰๏ผŒๆ‚จไธไผšๆ”ถๅˆฐๅฆไธ€ๅผ ๆ”ถๆฎใ€‚", "account_upgrade_dialog_reservations_warning_one": "ๆ‰€้€‰็ญ‰็บงๅ…่ฎธ็š„ไฟ็•™ไธป้ข˜ๅฐ‘ไบŽๅฝ“ๅ‰็ญ‰็บงใ€‚ๅœจๆ›ดๆ”นๆ‚จ็š„็ญ‰็บงไน‹ๅ‰๏ผŒ่ฏท่‡ณๅฐ‘ๅˆ ้™ค 1 ้กนไฟ็•™ใ€‚ๆ‚จๅฏไปฅๅœจ่ฎพ็ฝฎไธญๅˆ ้™คไฟ็•™ใ€‚", "account_upgrade_dialog_reservations_warning_other": "ๆ‰€้€‰็ญ‰็บงๅ…่ฎธ็š„ไฟ็•™ไธป้ข˜ๅฐ‘ไบŽๅฝ“ๅ‰็ญ‰็บงใ€‚ๅœจๆ›ดๆ”นๆ‚จ็š„็ญ‰็บงไน‹ๅ‰๏ผŒ่ฏท่‡ณๅฐ‘ๅˆ ้™ค {{count}} ้กนไฟ็•™ใ€‚ๆ‚จๅฏไปฅๅœจ่ฎพ็ฝฎไธญๅˆ ้™คไฟ็•™ใ€‚", - "account_upgrade_dialog_tier_features_reservations_other": "{{reservations}} ๆกไฟ็•™ไธป้ข˜", - "account_upgrade_dialog_tier_features_messages_other": "{{messages}} ๆกๆฏๆ—ฅๆถˆๆฏ", - "account_upgrade_dialog_tier_features_emails_other": "{{emails}} ๆกๆฏๆ—ฅ้‚ฎไปถ", + "account_upgrade_dialog_tier_features_reservations": "{{reservations}} ๆกไฟ็•™ไธป้ข˜", + "account_upgrade_dialog_tier_features_messages": "{{messages}} ๆกๆฏๆ—ฅๆถˆๆฏ", + "account_upgrade_dialog_tier_features_emails": "{{emails}} ๆกๆฏๆ—ฅ้‚ฎไปถ", "account_upgrade_dialog_tier_features_attachment_file_size": "{{filesize}} ๆฏไธชๆ–‡ไปถ", "signup_form_confirm_password": "็กฎ่ฎคๅฏ†็ ", "signup_form_button_submit": "ๆณจๅ†Œ", @@ -333,24 +333,12 @@ "account_tokens_table_expires_header": "่ฟ‡ๆœŸ", "account_tokens_table_never_expires": "ๆฐธไธ่ฟ‡ๆœŸ", "account_tokens_table_current_session": "ๅฝ“ๅ‰ๆต่งˆๅ™จไผš่ฏ", - "common_copy_to_clipboard": "ๅคๅˆถๅˆฐๅ‰ช่ดดๆฟ", + "account_tokens_table_copy_to_clipboard": "ๅคๅˆถๅˆฐๅ‰ช่ดดๆฟ", "account_tokens_table_copied_to_clipboard": "ๅทฒๅคๅˆถ่ฎฟ้—ฎไปค็‰Œ", "account_tokens_table_cannot_delete_or_edit": "ๆ— ๆณ•็ผ–่พ‘ๆˆ–ๅˆ ้™คๅฝ“ๅ‰ไผš่ฏไปค็‰Œ", "account_tokens_table_create_token_button": "ๅˆ›ๅปบ่ฎฟ้—ฎไปค็‰Œ", "account_tokens_table_last_origin_tooltip": "ไบŽIPๅœฐๅ€ {{ip}}๏ผŒ็‚นๅ‡ปๆŸฅๆ‰พ", "account_tokens_dialog_label": "ๆ ‡็ญพ๏ผŒไพ‹ๅฆ‚๏ผšRadarr ้€š็Ÿฅ", "account_tokens_dialog_button_create": "ๅˆ›ๅปบไปค็‰Œ", - "account_tokens_dialog_button_update": "ๆ›ดๆ–ฐไปค็‰Œ", - "account_basics_tier_interval_monthly": "ๆฏๆœˆ", - "account_basics_tier_interval_yearly": "ๆฏๅนด", - "account_upgrade_dialog_interval_monthly": "ๆฏๆœˆ", - "account_upgrade_dialog_interval_yearly": "ๆฏๅนด", - "account_upgrade_dialog_interval_yearly_discount_save": "่Š‚็œ {{discount}}%", - "account_upgrade_dialog_interval_yearly_discount_save_up_to": "่Š‚็œ้ซ˜่พพ {{discount}}%", - "account_upgrade_dialog_tier_features_no_reservations": "ๆ— ไฟ็•™ไธป้ข˜", - "account_upgrade_dialog_tier_price_per_month": "ๆœˆ", - "account_upgrade_dialog_tier_price_billed_monthly": "{{price}} ๆฏๅนดใ€‚ๆŒ‰ๆœˆ่ฎก่ดนใ€‚", - "account_upgrade_dialog_tier_price_billed_yearly": "{{ไปทๆ ผ}} ๆŒ‰ๅนด่ฎก่ดนใ€‚่Š‚็œ {{save}}ใ€‚", - "account_upgrade_dialog_billing_contact_email": "ๆœ‰ๅ…ณ่ดฆๅ•้—ฎ้ข˜๏ผŒ่ฏท็›ดๆŽฅ่”็ณปๆˆ‘ไปฌ ใ€‚", - "account_upgrade_dialog_billing_contact_website": "ๆœ‰ๅ…ณ่ดฆๅ•้—ฎ้ข˜๏ผŒ่ฏทๅ‚่€ƒๆˆ‘ไปฌ็š„็ฝ‘็ซ™ ใ€‚" + "account_tokens_dialog_button_update": "ๆ›ดๆ–ฐไปค็‰Œ" } diff --git a/web/public/static/langs/zh_Hant.json b/web/public/static/langs/zh_Hant.json index aafc28e..c1b4de8 100644 --- a/web/public/static/langs/zh_Hant.json +++ b/web/public/static/langs/zh_Hant.json @@ -70,7 +70,7 @@ "subscribe_dialog_subscribe_button_subscribe": "่จ‚้–ฑ", "emoji_picker_search_clear": "ๆธ…้™ค", "subscribe_dialog_login_password_label": "ๅฏ†็ขผ", - "common_back": "่ฟ”ๅ›ž", + "subscribe_dialog_login_button_back": "่ฟ”ๅ›ž", "subscribe_dialog_login_button_login": "็™ปๅ…ฅ", "prefs_notifications_delete_after_never": "ๅพžไธ", "prefs_users_add_button": "ๆ–ฐๅขžไฝฟ็”จ่€…", diff --git a/web/src/app/AccountApi.js b/web/src/app/AccountApi.js index 9576c4e..243286b 100644 --- a/web/src/app/AccountApi.js +++ b/web/src/app/AccountApi.js @@ -1,430 +1,389 @@ -import i18n from "i18next"; import { - accountBillingPortalUrl, - accountBillingSubscriptionUrl, - accountPasswordUrl, - accountPhoneUrl, - accountPhoneVerifyUrl, - accountReservationSingleUrl, - accountReservationUrl, - accountSettingsUrl, - accountSubscriptionUrl, - accountTokenUrl, - accountUrl, - maybeWithBearerAuth, - tiersUrl, - withBasicAuth, - withBearerAuth, + accountBillingPortalUrl, + accountBillingSubscriptionUrl, + accountPasswordUrl, + accountReservationSingleUrl, + accountReservationUrl, + accountSettingsUrl, + accountSubscriptionSingleUrl, + accountSubscriptionUrl, + accountTokenUrl, + accountUrl, maybeWithBearerAuth, + tiersUrl, + withBasicAuth, + withBearerAuth } from "./utils"; import session from "./Session"; import subscriptionManager from "./SubscriptionManager"; +import i18n from "i18next"; import prefs from "./Prefs"; import routes from "../components/routes"; -import { fetchOrThrow, UnauthorizedError } from "./errors"; +import {fetchOrThrow, throwAppError, UnauthorizedError} from "./errors"; const delayMillis = 45000; // 45 seconds const intervalMillis = 900000; // 15 minutes class AccountApi { - constructor() { - this.timer = null; - this.listener = null; // Fired when account is fetched from remote - this.tiers = null; // Cached - } - - registerListener(listener) { - this.listener = listener; - } - - resetListener() { - this.listener = null; - } - - async login(user) { - const url = accountTokenUrl(config.base_url); - console.log(`[AccountApi] Checking auth for ${url}`); - const response = await fetchOrThrow(url, { - method: "POST", - headers: withBasicAuth({}, user.username, user.password), - }); - const json = await response.json(); // May throw SyntaxError - if (!json.token) { - throw new Error(`Unexpected server response: Cannot find token`); + constructor() { + this.timer = null; + this.listener = null; // Fired when account is fetched from remote + this.tiers = null; // Cached } - return json.token; - } - async logout() { - const url = accountTokenUrl(config.base_url); - console.log(`[AccountApi] Logging out from ${url} using token ${session.token()}`); - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth({}, session.token()), - }); - } - - async create(username, password) { - const url = accountUrl(config.base_url); - const body = JSON.stringify({ - username, - password, - }); - console.log(`[AccountApi] Creating user account ${url}`); - await fetchOrThrow(url, { - method: "POST", - body, - }); - } - - async get() { - const url = accountUrl(config.base_url); - console.log(`[AccountApi] Fetching user account ${url}`); - const response = await fetchOrThrow(url, { - headers: maybeWithBearerAuth({}, session.token()), // GET /v1/account endpoint can be called by anonymous - }); - const account = await response.json(); // May throw SyntaxError - console.log(`[AccountApi] Account`, account); - if (this.listener) { - this.listener(account); + registerListener(listener) { + this.listener = listener; } - return account; - } - async delete(password) { - const url = accountUrl(config.base_url); - console.log(`[AccountApi] Deleting user account ${url}`); - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - password, - }), - }); - } - - async changePassword(currentPassword, newPassword) { - const url = accountPasswordUrl(config.base_url); - console.log(`[AccountApi] Changing account password ${url}`); - await fetchOrThrow(url, { - method: "POST", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - password: currentPassword, - new_password: newPassword, - }), - }); - } - - async createToken(label, expires) { - const url = accountTokenUrl(config.base_url); - const body = { - label, - expires: expires > 0 ? Math.floor(Date.now() / 1000) + expires : 0, - }; - console.log(`[AccountApi] Creating user access token ${url}`); - await fetchOrThrow(url, { - method: "POST", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify(body), - }); - } - - async updateToken(token, label, expires) { - const url = accountTokenUrl(config.base_url); - const body = { - token, - label, - }; - if (expires > 0) { - body.expires = Math.floor(Date.now() / 1000) + expires; + resetListener() { + this.listener = null; } - console.log(`[AccountApi] Creating user access token ${url}`); - await fetchOrThrow(url, { - method: "PATCH", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify(body), - }); - } - async extendToken() { - const url = accountTokenUrl(config.base_url); - console.log(`[AccountApi] Extending user access token ${url}`); - await fetchOrThrow(url, { - method: "PATCH", - headers: withBearerAuth({}, session.token()), - }); - } - - async deleteToken(token) { - const url = accountTokenUrl(config.base_url); - console.log(`[AccountApi] Deleting user access token ${url}`); - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth({ "X-Token": token }, session.token()), - }); - } - - async updateSettings(payload) { - const url = accountSettingsUrl(config.base_url); - const body = JSON.stringify(payload); - console.log(`[AccountApi] Updating user account ${url}: ${body}`); - await fetchOrThrow(url, { - method: "PATCH", - headers: withBearerAuth({}, session.token()), - body, - }); - } - - async addSubscription(baseUrl, topic) { - const url = accountSubscriptionUrl(config.base_url); - const body = JSON.stringify({ - base_url: baseUrl, - topic, - }); - console.log(`[AccountApi] Adding user subscription ${url}: ${body}`); - const response = await fetchOrThrow(url, { - method: "POST", - headers: withBearerAuth({}, session.token()), - body, - }); - const subscription = await response.json(); // May throw SyntaxError - console.log(`[AccountApi] Subscription`, subscription); - return subscription; - } - - async updateSubscription(baseUrl, topic, payload) { - const url = accountSubscriptionUrl(config.base_url); - const body = JSON.stringify({ - base_url: baseUrl, - topic, - ...payload, - }); - console.log(`[AccountApi] Updating user subscription ${url}: ${body}`); - const response = await fetchOrThrow(url, { - method: "PATCH", - headers: withBearerAuth({}, session.token()), - body, - }); - const subscription = await response.json(); // May throw SyntaxError - console.log(`[AccountApi] Subscription`, subscription); - return subscription; - } - - async deleteSubscription(baseUrl, topic) { - const url = accountSubscriptionUrl(config.base_url); - console.log(`[AccountApi] Removing user subscription ${url}`); - const headers = { - "X-BaseURL": baseUrl, - "X-Topic": topic, - }; - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth(headers, session.token()), - }); - } - - async upsertReservation(topic, everyone) { - const url = accountReservationUrl(config.base_url); - console.log(`[AccountApi] Upserting user access to topic ${topic}, everyone=${everyone}`); - await fetchOrThrow(url, { - method: "POST", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - topic, - everyone, - }), - }); - } - - async deleteReservation(topic, deleteMessages) { - const url = accountReservationSingleUrl(config.base_url, topic); - console.log(`[AccountApi] Removing topic reservation ${url}`); - const headers = { - "X-Delete-Messages": deleteMessages ? "true" : "false", - }; - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth(headers, session.token()), - }); - } - - async billingTiers() { - if (this.tiers) { - return this.tiers; - } - const url = tiersUrl(config.base_url); - console.log(`[AccountApi] Fetching billing tiers`); - const response = await fetchOrThrow(url); // No auth needed! - this.tiers = await response.json(); // May throw SyntaxError - return this.tiers; - } - - async createBillingSubscription(tier, interval) { - console.log(`[AccountApi] Creating billing subscription with ${tier} and interval ${interval}`); - return this.upsertBillingSubscription("POST", tier, interval); - } - - async updateBillingSubscription(tier, interval) { - console.log(`[AccountApi] Updating billing subscription with ${tier} and interval ${interval}`); - return this.upsertBillingSubscription("PUT", tier, interval); - } - - async upsertBillingSubscription(method, tier, interval) { - const url = accountBillingSubscriptionUrl(config.base_url); - const response = await fetchOrThrow(url, { - method, - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - tier, - interval, - }), - }); - return response.json(); // May throw SyntaxError - } - - async deleteBillingSubscription() { - const url = accountBillingSubscriptionUrl(config.base_url); - console.log(`[AccountApi] Cancelling billing subscription`); - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth({}, session.token()), - }); - } - - async createBillingPortalSession() { - const url = accountBillingPortalUrl(config.base_url); - console.log(`[AccountApi] Creating billing portal session`); - const response = await fetchOrThrow(url, { - method: "POST", - headers: withBearerAuth({}, session.token()), - }); - return response.json(); // May throw SyntaxError - } - - async verifyPhoneNumber(phoneNumber, channel) { - const url = accountPhoneVerifyUrl(config.base_url); - console.log(`[AccountApi] Sending phone verification ${url}`); - await fetchOrThrow(url, { - method: "PUT", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - number: phoneNumber, - channel, - }), - }); - } - - async addPhoneNumber(phoneNumber, code) { - const url = accountPhoneUrl(config.base_url); - console.log(`[AccountApi] Adding phone number with verification code ${url}`); - await fetchOrThrow(url, { - method: "PUT", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - number: phoneNumber, - code, - }), - }); - } - - async deletePhoneNumber(phoneNumber) { - const url = accountPhoneUrl(config.base_url); - console.log(`[AccountApi] Deleting phone number ${url}`); - await fetchOrThrow(url, { - method: "DELETE", - headers: withBearerAuth({}, session.token()), - body: JSON.stringify({ - number: phoneNumber, - }), - }); - } - - async sync() { - try { - if (!session.token()) { - return null; - } - console.log(`[AccountApi] Syncing account`); - const account = await this.get(); - if (account.language) { - await i18n.changeLanguage(account.language); - } - if (account.notification) { - if (account.notification.sound) { - await prefs.setSound(account.notification.sound); + async login(user) { + const url = accountTokenUrl(config.base_url); + console.log(`[AccountApi] Checking auth for ${url}`); + const response = await fetchOrThrow(url, { + method: "POST", + headers: withBasicAuth({}, user.username, user.password) + }); + const json = await response.json(); // May throw SyntaxError + if (!json.token) { + throw new Error(`Unexpected server response: Cannot find token`); } - if (account.notification.delete_after) { - await prefs.setDeleteAfter(account.notification.delete_after); - } - if (account.notification.min_priority) { - await prefs.setMinPriority(account.notification.min_priority); - } - } - if (account.subscriptions) { - await subscriptionManager.syncFromRemote(account.subscriptions, account.reservations); - } - return account; - } catch (e) { - console.log(`[AccountApi] Error fetching account`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } - return undefined; + return json.token; } - } - startWorker() { - if (this.timer !== null) { - return; + async logout() { + const url = accountTokenUrl(config.base_url); + console.log(`[AccountApi] Logging out from ${url} using token ${session.token()}`); + await fetchOrThrow(url, { + method: "DELETE", + headers: withBearerAuth({}, session.token()) + }); } - console.log(`[AccountApi] Starting worker`); - this.timer = setInterval(() => this.runWorker(), intervalMillis); - setTimeout(() => this.runWorker(), delayMillis); - } - async runWorker() { - if (!session.token()) { - return; + async create(username, password) { + const url = accountUrl(config.base_url); + const body = JSON.stringify({ + username: username, + password: password + }); + console.log(`[AccountApi] Creating user account ${url}`); + await fetchOrThrow(url, { + method: "POST", + body: body + }); } - console.log(`[AccountApi] Extending user access token`); - try { - await this.extendToken(); - } catch (e) { - console.log(`[AccountApi] Error extending user access token`, e); + + async get() { + const url = accountUrl(config.base_url); + console.log(`[AccountApi] Fetching user account ${url}`); + const response = await fetchOrThrow(url, { + headers: maybeWithBearerAuth({}, session.token()) // GET /v1/account endpoint can be called by anonymous + }); + const account = await response.json(); // May throw SyntaxError + console.log(`[AccountApi] Account`, account); + if (this.listener) { + this.listener(account); + } + return account; + } + + async delete(password) { + const url = accountUrl(config.base_url); + console.log(`[AccountApi] Deleting user account ${url}`); + await fetchOrThrow(url, { + method: "DELETE", + headers: withBearerAuth({}, session.token()), + body: JSON.stringify({ + password: password + }) + }); + } + + async changePassword(currentPassword, newPassword) { + const url = accountPasswordUrl(config.base_url); + console.log(`[AccountApi] Changing account password ${url}`); + await fetchOrThrow(url, { + method: "POST", + headers: withBearerAuth({}, session.token()), + body: JSON.stringify({ + password: currentPassword, + new_password: newPassword + }) + }); + } + + async createToken(label, expires) { + const url = accountTokenUrl(config.base_url); + const body = { + label: label, + expires: (expires > 0) ? Math.floor(Date.now() / 1000) + expires : 0 + }; + console.log(`[AccountApi] Creating user access token ${url}`); + await fetchOrThrow(url, { + method: "POST", + headers: withBearerAuth({}, session.token()), + body: JSON.stringify(body) + }); + } + + async updateToken(token, label, expires) { + const url = accountTokenUrl(config.base_url); + const body = { + token: token, + label: label + }; + if (expires > 0) { + body.expires = Math.floor(Date.now() / 1000) + expires; + } + console.log(`[AccountApi] Creating user access token ${url}`); + await fetchOrThrow(url, { + method: "PATCH", + headers: withBearerAuth({}, session.token()), + body: JSON.stringify(body) + }); + } + + async extendToken() { + const url = accountTokenUrl(config.base_url); + console.log(`[AccountApi] Extending user access token ${url}`); + await fetchOrThrow(url, { + method: "PATCH", + headers: withBearerAuth({}, session.token()) + }); + } + + async deleteToken(token) { + const url = accountTokenUrl(config.base_url); + console.log(`[AccountApi] Deleting user access token ${url}`); + await fetchOrThrow(url, { + method: "DELETE", + headers: withBearerAuth({"X-Token": token}, session.token()) + }); + } + + async updateSettings(payload) { + const url = accountSettingsUrl(config.base_url); + const body = JSON.stringify(payload); + console.log(`[AccountApi] Updating user account ${url}: ${body}`); + await fetchOrThrow(url, { + method: "PATCH", + headers: withBearerAuth({}, session.token()), + body: body + }); + } + + async addSubscription(baseUrl, topic) { + const url = accountSubscriptionUrl(config.base_url); + const body = JSON.stringify({ + base_url: baseUrl, + topic: topic + }); + console.log(`[AccountApi] Adding user subscription ${url}: ${body}`); + const response = await fetchOrThrow(url, { + method: "POST", + headers: withBearerAuth({}, session.token()), + body: body + }); + const subscription = await response.json(); // May throw SyntaxError + console.log(`[AccountApi] Subscription`, subscription); + return subscription; + } + + async updateSubscription(baseUrl, topic, payload) { + const url = accountSubscriptionUrl(config.base_url); + const body = JSON.stringify({ + base_url: baseUrl, + topic: topic, + ...payload + }); + console.log(`[AccountApi] Updating user subscription ${url}: ${body}`); + const response = await fetchOrThrow(url, { + method: "PATCH", + headers: withBearerAuth({}, session.token()), + body: body + }); + const subscription = await response.json(); // May throw SyntaxError + console.log(`[AccountApi] Subscription`, subscription); + return subscription; + } + + async deleteSubscription(baseUrl, topic) { + const url = accountSubscriptionUrl(config.base_url); + console.log(`[AccountApi] Removing user subscription ${url}`); + const headers = { + "X-BaseURL": baseUrl, + "X-Topic": topic, + } + await fetchOrThrow(url, { + method: "DELETE", + headers: withBearerAuth(headers, session.token()), + }); + } + + async upsertReservation(topic, everyone) { + const url = accountReservationUrl(config.base_url); + console.log(`[AccountApi] Upserting user access to topic ${topic}, everyone=${everyone}`); + await fetchOrThrow(url, { + method: "POST", + headers: withBearerAuth({}, session.token()), + body: JSON.stringify({ + topic: topic, + everyone: everyone + }) + }); + } + + async deleteReservation(topic, deleteMessages) { + const url = accountReservationSingleUrl(config.base_url, topic); + console.log(`[AccountApi] Removing topic reservation ${url}`); + const headers = { + "X-Delete-Messages": deleteMessages ? "true" : "false" + } + await fetchOrThrow(url, { + method: "DELETE", + headers: withBearerAuth(headers, session.token()) + }); + } + + async billingTiers() { + if (this.tiers) { + return this.tiers; + } + const url = tiersUrl(config.base_url); + console.log(`[AccountApi] Fetching billing tiers`); + const response = await fetchOrThrow(url); // No auth needed! + this.tiers = await response.json(); // May throw SyntaxError + return this.tiers; + } + + async createBillingSubscription(tier, interval) { + console.log(`[AccountApi] Creating billing subscription with ${tier} and interval ${interval}`); + return await this.upsertBillingSubscription("POST", tier, interval) + } + + async updateBillingSubscription(tier, interval) { + console.log(`[AccountApi] Updating billing subscription with ${tier} and interval ${interval}`); + return await this.upsertBillingSubscription("PUT", tier, interval) + } + + async upsertBillingSubscription(method, tier, interval) { + const url = accountBillingSubscriptionUrl(config.base_url); + const response = await fetchOrThrow(url, { + method: method, + headers: withBearerAuth({}, session.token()), + body: JSON.stringify({ + tier: tier, + interval: interval + }) + }); + return await response.json(); // May throw SyntaxError + } + + async deleteBillingSubscription() { + const url = accountBillingSubscriptionUrl(config.base_url); + console.log(`[AccountApi] Cancelling billing subscription`); + await fetchOrThrow(url, { + method: "DELETE", + headers: withBearerAuth({}, session.token()) + }); + } + + async createBillingPortalSession() { + const url = accountBillingPortalUrl(config.base_url); + console.log(`[AccountApi] Creating billing portal session`); + const response = await fetchOrThrow(url, { + method: "POST", + headers: withBearerAuth({}, session.token()) + }); + return await response.json(); // May throw SyntaxError + } + + async sync() { + try { + if (!session.token()) { + return null; + } + console.log(`[AccountApi] Syncing account`); + const account = await this.get(); + if (account.language) { + await i18n.changeLanguage(account.language); + } + if (account.notification) { + if (account.notification.sound) { + await prefs.setSound(account.notification.sound); + } + if (account.notification.delete_after) { + await prefs.setDeleteAfter(account.notification.delete_after); + } + if (account.notification.min_priority) { + await prefs.setMinPriority(account.notification.min_priority); + } + } + if (account.subscriptions) { + await subscriptionManager.syncFromRemote(account.subscriptions, account.reservations); + } + return account; + } catch (e) { + console.log(`[AccountApi] Error fetching account`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } + } + } + + startWorker() { + if (this.timer !== null) { + return; + } + console.log(`[AccountApi] Starting worker`); + this.timer = setInterval(() => this.runWorker(), intervalMillis); + setTimeout(() => this.runWorker(), delayMillis); + } + + async runWorker() { + if (!session.token()) { + return; + } + console.log(`[AccountApi] Extending user access token`); + try { + await this.extendToken(); + } catch (e) { + console.log(`[AccountApi] Error extending user access token`, e); + } } - } } // Maps to user.Role in user/types.go export const Role = { - ADMIN: "admin", - USER: "user", + ADMIN: "admin", + USER: "user" }; // Maps to server.visitorLimitBasis in server/visitor.go export const LimitBasis = { - IP: "ip", - TIER: "tier", + IP: "ip", + TIER: "tier" }; // Maps to stripe.SubscriptionStatus export const SubscriptionStatus = { - ACTIVE: "active", - PAST_DUE: "past_due", + ACTIVE: "active", + PAST_DUE: "past_due" }; // Maps to stripe.PriceRecurringInterval export const SubscriptionInterval = { - MONTH: "month", - YEAR: "year", + MONTH: "month", + YEAR: "year" }; // Maps to user.Permission in user/types.go export const Permission = { - READ_WRITE: "read-write", - READ_ONLY: "read-only", - WRITE_ONLY: "write-only", - DENY_ALL: "deny-all", + READ_WRITE: "read-write", + READ_ONLY: "read-only", + WRITE_ONLY: "write-only", + DENY_ALL: "deny-all" }; const accountApi = new AccountApi(); diff --git a/web/src/app/Api.js b/web/src/app/Api.js index ba1cbe6..3d20d92 100644 --- a/web/src/app/Api.js +++ b/web/src/app/Api.js @@ -1,118 +1,115 @@ import { - fetchLinesIterator, - maybeWithAuth, - topicShortUrl, - topicUrl, - topicUrlAuth, - topicUrlJsonPoll, - topicUrlJsonPollWithSince, + fetchLinesIterator, + maybeWithAuth, + topicShortUrl, + topicUrl, + topicUrlAuth, + topicUrlJsonPoll, + topicUrlJsonPollWithSince } from "./utils"; import userManager from "./UserManager"; -import { fetchOrThrow } from "./errors"; +import {fetchOrThrow} from "./errors"; class Api { - async poll(baseUrl, topic, since) { - const user = await userManager.get(baseUrl); - const shortUrl = topicShortUrl(baseUrl, topic); - const url = since ? topicUrlJsonPollWithSince(baseUrl, topic, since) : topicUrlJsonPoll(baseUrl, topic); - const messages = []; - const headers = maybeWithAuth({}, user); - console.log(`[Api] Polling ${url}`); - for await (const line of fetchLinesIterator(url, headers)) { - const message = JSON.parse(line); - if (message.id) { - console.log(`[Api, ${shortUrl}] Received message ${line}`); - messages.push(message); - } - } - return messages; - } - - async publish(baseUrl, topic, message, options) { - const user = await userManager.get(baseUrl); - console.log(`[Api] Publishing message to ${topicUrl(baseUrl, topic)}`); - const headers = {}; - const body = { - topic, - message, - ...options, - }; - await fetchOrThrow(baseUrl, { - method: "PUT", - body: JSON.stringify(body), - headers: maybeWithAuth(headers, user), - }); - } - - /** - * Publishes to a topic using XMLHttpRequest (XHR), and returns a Promise with the active request. - * Unfortunately, fetch() does not support a progress hook, which is why XHR has to be used. - * - * Firefox XHR bug: - * Firefox has a bug(?), which returns 0 and "" for all fields of the XHR response in the case of an error, - * so we cannot determine the exact error. It also sometimes complains about CORS violations, even when the - * correct headers are clearly set. It's quite the odd behavior. - * - * There is an example, and the bug report here: - * - https://bugzilla.mozilla.org/show_bug.cgi?id=1733755 - * - https://gist.github.com/binwiederhier/627f146d1959799be207ad8c17a8f345 - */ - publishXHR(url, body, headers, onProgress) { - console.log(`[Api] Publishing message to ${url}`); - const xhr = new XMLHttpRequest(); - const send = new Promise((resolve, reject) => { - xhr.open("PUT", url); - if (body.type) { - xhr.overrideMimeType(body.type); - } - for (const [key, value] of Object.entries(headers)) { - xhr.setRequestHeader(key, value); - } - xhr.upload.addEventListener("progress", onProgress); - xhr.addEventListener("readystatechange", () => { - if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 299) { - console.log(`[Api] Publish successful (HTTP ${xhr.status})`, xhr.response); - resolve(xhr.response); - } else if (xhr.readyState === 4) { - // Firefox bug; see description above! - console.log(`[Api] Publish failed (HTTP ${xhr.status})`, xhr.responseText); - let errorText; - try { - const error = JSON.parse(xhr.responseText); - if (error.code && error.error) { - errorText = `Error ${error.code}: ${error.error}`; - } - } catch (e) { - // Nothing - } - xhr.abort(); - reject(errorText ?? "An error occurred"); + async poll(baseUrl, topic, since) { + const user = await userManager.get(baseUrl); + const shortUrl = topicShortUrl(baseUrl, topic); + const url = (since) + ? topicUrlJsonPollWithSince(baseUrl, topic, since) + : topicUrlJsonPoll(baseUrl, topic); + const messages = []; + const headers = maybeWithAuth({}, user); + console.log(`[Api] Polling ${url}`); + for await (let line of fetchLinesIterator(url, headers)) { + console.log(`[Api, ${shortUrl}] Received message ${line}`); + messages.push(JSON.parse(line)); } - }); - xhr.send(body); - }); - send.abort = () => { - console.log(`[Api] Publish aborted by user`); - xhr.abort(); - }; - return send; - } + return messages; + } - async topicAuth(baseUrl, topic, user) { - const url = topicUrlAuth(baseUrl, topic); - console.log(`[Api] Checking auth for ${url}`); - const response = await fetch(url, { - headers: maybeWithAuth({}, user), - }); - if (response.status >= 200 && response.status <= 299) { - return true; + async publish(baseUrl, topic, message, options) { + const user = await userManager.get(baseUrl); + console.log(`[Api] Publishing message to ${topicUrl(baseUrl, topic)}`); + const headers = {}; + const body = { + topic: topic, + message: message, + ...options + }; + await fetchOrThrow(baseUrl, { + method: 'PUT', + body: JSON.stringify(body), + headers: maybeWithAuth(headers, user) + }); } - if (response.status === 401 || response.status === 403) { - // See server/server.go - return false; + + /** + * Publishes to a topic using XMLHttpRequest (XHR), and returns a Promise with the active request. + * Unfortunately, fetch() does not support a progress hook, which is why XHR has to be used. + * + * Firefox XHR bug: + * Firefox has a bug(?), which returns 0 and "" for all fields of the XHR response in the case of an error, + * so we cannot determine the exact error. It also sometimes complains about CORS violations, even when the + * correct headers are clearly set. It's quite the odd behavior. + * + * There is an example, and the bug report here: + * - https://bugzilla.mozilla.org/show_bug.cgi?id=1733755 + * - https://gist.github.com/binwiederhier/627f146d1959799be207ad8c17a8f345 + */ + publishXHR(url, body, headers, onProgress) { + console.log(`[Api] Publishing message to ${url}`); + const xhr = new XMLHttpRequest(); + const send = new Promise(function (resolve, reject) { + xhr.open("PUT", url); + if (body.type) { + xhr.overrideMimeType(body.type); + } + for (const [key, value] of Object.entries(headers)) { + xhr.setRequestHeader(key, value); + } + xhr.upload.addEventListener("progress", onProgress); + xhr.addEventListener('readystatechange', () => { + if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status <= 299) { + console.log(`[Api] Publish successful (HTTP ${xhr.status})`, xhr.response); + resolve(xhr.response); + } else if (xhr.readyState === 4) { + // Firefox bug; see description above! + console.log(`[Api] Publish failed (HTTP ${xhr.status})`, xhr.responseText); + let errorText; + try { + const error = JSON.parse(xhr.responseText); + if (error.code && error.error) { + errorText = `Error ${error.code}: ${error.error}`; + } + } catch (e) { + // Nothing + } + xhr.abort(); + reject(errorText ?? "An error occurred"); + } + }) + xhr.send(body); + }); + send.abort = () => { + console.log(`[Api] Publish aborted by user`); + xhr.abort(); + } + return send; + } + + async topicAuth(baseUrl, topic, user) { + const url = topicUrlAuth(baseUrl, topic); + console.log(`[Api] Checking auth for ${url}`); + const response = await fetch(url, { + headers: maybeWithAuth({}, user) + }); + if (response.status >= 200 && response.status <= 299) { + return true; + } else if (response.status === 401 || response.status === 403) { // See server/server.go + return false; + } + throw new Error(`Unexpected server response ${response.status}`); } - throw new Error(`Unexpected server response ${response.status}`); - } } const api = new Api(); diff --git a/web/src/app/Connection.js b/web/src/app/Connection.js index 5358cdd..e86af78 100644 --- a/web/src/app/Connection.js +++ b/web/src/app/Connection.js @@ -1,14 +1,7 @@ -/* eslint-disable max-classes-per-file */ -import { basicAuth, bearerAuth, encodeBase64Url, topicShortUrl, topicUrlWs } from "./utils"; +import {basicAuth, bearerAuth, encodeBase64Url, topicShortUrl, topicUrlWs} from "./utils"; const retryBackoffSeconds = [5, 10, 20, 30, 60, 120]; -export class ConnectionState { - static Connected = "connected"; - - static Connecting = "connecting"; -} - /** * A connection contains a single WebSocket connection for one topic. It handles its connection * status itself, including reconnect attempts and backoff. @@ -16,103 +9,110 @@ export class ConnectionState { * Incoming messages and state changes are forwarded via listeners. */ class Connection { - constructor(connectionId, subscriptionId, baseUrl, topic, user, since, onNotification, onStateChanged) { - this.connectionId = connectionId; - this.subscriptionId = subscriptionId; - this.baseUrl = baseUrl; - this.topic = topic; - this.user = user; - this.since = since; - this.shortUrl = topicShortUrl(baseUrl, topic); - this.onNotification = onNotification; - this.onStateChanged = onStateChanged; - this.ws = null; - this.retryCount = 0; - this.retryTimeout = null; - } - - start() { - // Don't fetch old messages; we do that as a poll() when adding a subscription; - // we don't want to re-trigger the main view re-render potentially hundreds of times. - - const wsUrl = this.wsUrl(); - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Opening connection to ${wsUrl}`); - - this.ws = new WebSocket(wsUrl); - this.ws.onopen = (event) => { - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Connection established`, event); - this.retryCount = 0; - this.onStateChanged(this.subscriptionId, ConnectionState.Connected); - }; - this.ws.onmessage = (event) => { - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Message received from server: ${event.data}`); - try { - const data = JSON.parse(event.data); - if (data.event === "open") { - return; - } - const relevantAndValid = data.event === "message" && "id" in data && "time" in data && "message" in data; - if (!relevantAndValid) { - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Unexpected message. Ignoring.`); - return; - } - this.since = data.id; - this.onNotification(this.subscriptionId, data); - } catch (e) { - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Error handling message: ${e}`); - } - }; - this.ws.onclose = (event) => { - if (event.wasClean) { - console.log( - `[Connection, ${this.shortUrl}, ${this.connectionId}] Connection closed cleanly, code=${event.code} reason=${event.reason}` - ); + constructor(connectionId, subscriptionId, baseUrl, topic, user, since, onNotification, onStateChanged) { + this.connectionId = connectionId; + this.subscriptionId = subscriptionId; + this.baseUrl = baseUrl; + this.topic = topic; + this.user = user; + this.since = since; + this.shortUrl = topicShortUrl(baseUrl, topic); + this.onNotification = onNotification; + this.onStateChanged = onStateChanged; this.ws = null; - } else { - const retrySeconds = retryBackoffSeconds[Math.min(this.retryCount, retryBackoffSeconds.length - 1)]; - this.retryCount += 1; - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Connection died, retrying in ${retrySeconds} seconds`); - this.retryTimeout = setTimeout(() => this.start(), retrySeconds * 1000); - this.onStateChanged(this.subscriptionId, ConnectionState.Connecting); - } - }; - this.ws.onerror = (event) => { - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Error occurred: ${event}`, event); - }; - } + this.retryCount = 0; + this.retryTimeout = null; + } - close() { - console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Closing connection`); - const socket = this.ws; - const { retryTimeout } = this; - if (socket !== null) { - socket.close(); - } - if (retryTimeout !== null) { - clearTimeout(retryTimeout); - } - this.retryTimeout = null; - this.ws = null; - } + start() { + // Don't fetch old messages; we do that as a poll() when adding a subscription; + // we don't want to re-trigger the main view re-render potentially hundreds of times. - wsUrl() { - const params = []; - if (this.since) { - params.push(`since=${this.since}`); - } - if (this.user) { - params.push(`auth=${this.authParam()}`); - } - const wsUrl = topicUrlWs(this.baseUrl, this.topic); - return params.length === 0 ? wsUrl : `${wsUrl}?${params.join("&")}`; - } + const wsUrl = this.wsUrl(); + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Opening connection to ${wsUrl}`); - authParam() { - if (this.user.password) { - return encodeBase64Url(basicAuth(this.user.username, this.user.password)); + this.ws = new WebSocket(wsUrl); + this.ws.onopen = (event) => { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Connection established`, event); + this.retryCount = 0; + this.onStateChanged(this.subscriptionId, ConnectionState.Connected); + } + this.ws.onmessage = (event) => { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Message received from server: ${event.data}`); + try { + const data = JSON.parse(event.data); + if (data.event === 'open') { + return; + } + const relevantAndValid = + data.event === 'message' && + 'id' in data && + 'time' in data && + 'message' in data; + if (!relevantAndValid) { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Unexpected message. Ignoring.`); + return; + } + this.since = data.id; + this.onNotification(this.subscriptionId, data); + } catch (e) { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Error handling message: ${e}`); + } + }; + this.ws.onclose = (event) => { + if (event.wasClean) { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Connection closed cleanly, code=${event.code} reason=${event.reason}`); + this.ws = null; + } else { + const retrySeconds = retryBackoffSeconds[Math.min(this.retryCount, retryBackoffSeconds.length-1)]; + this.retryCount++; + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Connection died, retrying in ${retrySeconds} seconds`); + this.retryTimeout = setTimeout(() => this.start(), retrySeconds * 1000); + this.onStateChanged(this.subscriptionId, ConnectionState.Connecting); + } + }; + this.ws.onerror = (event) => { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Error occurred: ${event}`, event); + }; } - return encodeBase64Url(bearerAuth(this.user.token)); - } + + close() { + console.log(`[Connection, ${this.shortUrl}, ${this.connectionId}] Closing connection`); + const socket = this.ws; + const retryTimeout = this.retryTimeout; + if (socket !== null) { + socket.close(); + } + if (retryTimeout !== null) { + clearTimeout(retryTimeout); + } + this.retryTimeout = null; + this.ws = null; + } + + wsUrl() { + const params = []; + if (this.since) { + params.push(`since=${this.since}`); + } + if (this.user) { + params.push(`auth=${this.authParam()}`); + } + const wsUrl = topicUrlWs(this.baseUrl, this.topic); + return (params.length === 0) ? wsUrl : `${wsUrl}?${params.join('&')}`; + } + + authParam() { + if (this.user.password) { + return encodeBase64Url(basicAuth(this.user.username, this.user.password)); + } + return encodeBase64Url(bearerAuth(this.user.token)); + } +} + +export class ConnectionState { + static Connected = "connected"; + static Connecting = "connecting"; } export default Connection; diff --git a/web/src/app/ConnectionManager.js b/web/src/app/ConnectionManager.js index 2033cbe..1e805eb 100644 --- a/web/src/app/ConnectionManager.js +++ b/web/src/app/ConnectionManager.js @@ -1,8 +1,5 @@ import Connection from "./Connection"; -import { hashCode } from "./utils"; - -const makeConnectionId = async (subscription, user) => - user ? hashCode(`${subscription.id}|${user.username}|${user.password ?? ""}|${user.token ?? ""}`) : hashCode(`${subscription.id}`); +import {hashCode} from "./utils"; /** * The connection manager keeps track of active connections (WebSocket connections, see Connection). @@ -11,106 +8,109 @@ const makeConnectionId = async (subscription, user) => * as required. This is done pretty much exactly the same way as in the Android app. */ class ConnectionManager { - constructor() { - this.connections = new Map(); // ConnectionId -> Connection (hash, see below) - this.stateListener = null; // Fired when connection state changes - this.messageListener = null; // Fired when new notifications arrive - } - - registerStateListener(listener) { - this.stateListener = listener; - } - - resetStateListener() { - this.stateListener = null; - } - - registerMessageListener(listener) { - this.messageListener = listener; - } - - resetMessageListener() { - this.messageListener = null; - } - - /** - * This function figures out which websocket connections should be running by comparing the - * current state of the world (connections) with the target state (targetIds). - * - * It uses a "connectionId", which is sha256($subscriptionId|$username|$password) to identify - * connections. If any of them change, the connection is closed/replaced. - */ - async refresh(subscriptions, users) { - if (!subscriptions || !users) { - return; + constructor() { + this.connections = new Map(); // ConnectionId -> Connection (hash, see below) + this.stateListener = null; // Fired when connection state changes + this.messageListener = null; // Fired when new notifications arrive } - console.log(`[ConnectionManager] Refreshing connections`); - const subscriptionsWithUsersAndConnectionId = await Promise.all( - subscriptions.map(async (s) => { - const [user] = users.filter((u) => u.baseUrl === s.baseUrl); - const connectionId = await makeConnectionId(s, user); - return { ...s, user, connectionId }; - }) - ); - const targetIds = subscriptionsWithUsersAndConnectionId.map((s) => s.connectionId); - const deletedIds = Array.from(this.connections.keys()).filter((id) => !targetIds.includes(id)); - // Create and add new connections - subscriptionsWithUsersAndConnectionId.forEach((subscription) => { - const subscriptionId = subscription.id; - const { connectionId } = subscription; - const added = !this.connections.get(connectionId); - if (added) { - const { baseUrl, topic, user } = subscription; - const since = subscription.last; - const connection = new Connection( - connectionId, - subscriptionId, - baseUrl, - topic, - user, - since, - (subId, notification) => this.notificationReceived(subId, notification), - (subId, state) => this.stateChanged(subId, state) - ); - this.connections.set(connectionId, connection); - console.log( - `[ConnectionManager] Starting new connection ${connectionId} (subscription ${subscriptionId} with user ${ - user ? user.username : "anonymous" - })` - ); - connection.start(); - } - }); - - // Delete old connections - deletedIds.forEach((id) => { - console.log(`[ConnectionManager] Closing connection ${id}`); - const connection = this.connections.get(id); - this.connections.delete(id); - connection.close(); - }); - } - - stateChanged(subscriptionId, state) { - if (this.stateListener) { - try { - this.stateListener(subscriptionId, state); - } catch (e) { - console.error(`[ConnectionManager] Error updating state of ${subscriptionId} to ${state}`, e); - } + registerStateListener(listener) { + this.stateListener = listener; } - } - notificationReceived(subscriptionId, notification) { - if (this.messageListener) { - try { - this.messageListener(subscriptionId, notification); - } catch (e) { - console.error(`[ConnectionManager] Error handling notification for ${subscriptionId}`, e); - } + resetStateListener() { + this.stateListener = null; } - } + + registerMessageListener(listener) { + this.messageListener = listener; + } + + resetMessageListener() { + this.messageListener = null; + } + + /** + * This function figures out which websocket connections should be running by comparing the + * current state of the world (connections) with the target state (targetIds). + * + * It uses a "connectionId", which is sha256($subscriptionId|$username|$password) to identify + * connections. If any of them change, the connection is closed/replaced. + */ + async refresh(subscriptions, users) { + if (!subscriptions || !users) { + return; + } + console.log(`[ConnectionManager] Refreshing connections`); + const subscriptionsWithUsersAndConnectionId = await Promise.all(subscriptions + .map(async s => { + const [user] = users.filter(u => u.baseUrl === s.baseUrl); + const connectionId = await makeConnectionId(s, user); + return {...s, user, connectionId}; + })); + const targetIds = subscriptionsWithUsersAndConnectionId.map(s => s.connectionId); + const deletedIds = Array.from(this.connections.keys()).filter(id => !targetIds.includes(id)); + + // Create and add new connections + subscriptionsWithUsersAndConnectionId.forEach(subscription => { + const subscriptionId = subscription.id; + const connectionId = subscription.connectionId; + const added = !this.connections.get(connectionId) + if (added) { + const baseUrl = subscription.baseUrl; + const topic = subscription.topic; + const user = subscription.user; + const since = subscription.last; + const connection = new Connection( + connectionId, + subscriptionId, + baseUrl, + topic, + user, + since, + (subscriptionId, notification) => this.notificationReceived(subscriptionId, notification), + (subscriptionId, state) => this.stateChanged(subscriptionId, state) + ); + this.connections.set(connectionId, connection); + console.log(`[ConnectionManager] Starting new connection ${connectionId} (subscription ${subscriptionId} with user ${user ? user.username : "anonymous"})`); + connection.start(); + } + }); + + // Delete old connections + deletedIds.forEach(id => { + console.log(`[ConnectionManager] Closing connection ${id}`); + const connection = this.connections.get(id); + this.connections.delete(id); + connection.close(); + }); + } + + stateChanged(subscriptionId, state) { + if (this.stateListener) { + try { + this.stateListener(subscriptionId, state); + } catch (e) { + console.error(`[ConnectionManager] Error updating state of ${subscriptionId} to ${state}`, e); + } + } + } + + notificationReceived(subscriptionId, notification) { + if (this.messageListener) { + try { + this.messageListener(subscriptionId, notification); + } catch (e) { + console.error(`[ConnectionManager] Error handling notification for ${subscriptionId}`, e); + } + } + } +} + +const makeConnectionId = async (subscription, user) => { + return (user) + ? hashCode(`${subscription.id}|${user.username}|${user.password ?? ""}|${user.token ?? ""}`) + : hashCode(`${subscription.id}`); } const connectionManager = new ConnectionManager(); diff --git a/web/src/app/Notifier.js b/web/src/app/Notifier.js index 45792dc..613340c 100644 --- a/web/src/app/Notifier.js +++ b/web/src/app/Notifier.js @@ -1,4 +1,4 @@ -import { formatMessage, formatTitleWithDefault, openUrl, playSound, topicDisplayName, topicShortUrl } from "./utils"; +import {formatMessage, formatTitleWithDefault, openUrl, playSound, topicDisplayName, topicShortUrl} from "./utils"; import prefs from "./Prefs"; import subscriptionManager from "./SubscriptionManager"; import logo from "../img/ntfy.png"; @@ -8,87 +8,89 @@ import logo from "../img/ntfy.png"; * support this; most importantly, all iOS browsers do not support window.Notification. */ class Notifier { - async notify(subscriptionId, notification, onClickFallback) { - if (!this.supported()) { - return; - } - const subscription = await subscriptionManager.get(subscriptionId); - const shouldNotify = await this.shouldNotify(subscription, notification); - if (!shouldNotify) { - return; - } - const shortUrl = topicShortUrl(subscription.baseUrl, subscription.topic); - const displayName = topicDisplayName(subscription); - const message = formatMessage(notification); - const title = formatTitleWithDefault(notification, displayName); + async notify(subscriptionId, notification, onClickFallback) { + if (!this.supported()) { + return; + } + const subscription = await subscriptionManager.get(subscriptionId); + const shouldNotify = await this.shouldNotify(subscription, notification); + if (!shouldNotify) { + return; + } + const shortUrl = topicShortUrl(subscription.baseUrl, subscription.topic); + const displayName = topicDisplayName(subscription); + const message = formatMessage(notification); + const title = formatTitleWithDefault(notification, displayName); - // Show notification - console.log(`[Notifier, ${shortUrl}] Displaying notification ${notification.id}: ${message}`); - const n = new Notification(title, { - body: message, - icon: logo, - }); - if (notification.click) { - n.onclick = () => openUrl(notification.click); - } else { - n.onclick = () => onClickFallback(subscription); + // Show notification + console.log(`[Notifier, ${shortUrl}] Displaying notification ${notification.id}: ${message}`); + const n = new Notification(title, { + body: message, + icon: logo + }); + if (notification.click) { + n.onclick = (e) => openUrl(notification.click); + } else { + n.onclick = () => onClickFallback(subscription); + } + + // Play sound + const sound = await prefs.sound(); + if (sound && sound !== "none") { + try { + await playSound(sound); + } catch (e) { + console.log(`[Notifier, ${shortUrl}] Error playing audio`, e); + } + } } - // Play sound - const sound = await prefs.sound(); - if (sound && sound !== "none") { - try { - await playSound(sound); - } catch (e) { - console.log(`[Notifier, ${shortUrl}] Error playing audio`, e); - } + granted() { + return this.supported() && Notification.permission === 'granted'; } - } - granted() { - return this.supported() && Notification.permission === "granted"; - } - - maybeRequestPermission(cb) { - if (!this.supported()) { - cb(false); - return; + maybeRequestPermission(cb) { + if (!this.supported()) { + cb(false); + return; + } + if (!this.granted()) { + Notification.requestPermission().then((permission) => { + const granted = permission === 'granted'; + cb(granted); + }); + } } - if (!this.granted()) { - Notification.requestPermission().then((permission) => { - const granted = permission === "granted"; - cb(granted); - }); + + async shouldNotify(subscription, notification) { + if (subscription.mutedUntil === 1) { + return false; + } + const priority = (notification.priority) ? notification.priority : 3; + const minPriority = await prefs.minPriority(); + if (priority < minPriority) { + return false; + } + return true; } - } - async shouldNotify(subscription, notification) { - if (subscription.mutedUntil === 1) { - return false; + supported() { + return this.browserSupported() && this.contextSupported(); } - const priority = notification.priority ? notification.priority : 3; - const minPriority = await prefs.minPriority(); - if (priority < minPriority) { - return false; + + browserSupported() { + return 'Notification' in window; } - return true; - } - supported() { - return this.browserSupported() && this.contextSupported(); - } - - browserSupported() { - return "Notification" in window; - } - - /** - * Returns true if this is a HTTPS site, or served over localhost. Otherwise the Notification API - * is not supported, see https://developer.mozilla.org/en-US/docs/Web/API/notification - */ - contextSupported() { - return window.location.protocol === "https:" || window.location.hostname.match("^127.") || window.location.hostname === "localhost"; - } + /** + * Returns true if this is a HTTPS site, or served over localhost. Otherwise the Notification API + * is not supported, see https://developer.mozilla.org/en-US/docs/Web/API/notification + */ + contextSupported() { + return location.protocol === 'https:' + || location.hostname.match('^127.') + || location.hostname === 'localhost'; + } } const notifier = new Notifier(); diff --git a/web/src/app/Poller.js b/web/src/app/Poller.js index 372e46e..a7eed03 100644 --- a/web/src/app/Poller.js +++ b/web/src/app/Poller.js @@ -5,57 +5,54 @@ const delayMillis = 2000; // 2 seconds const intervalMillis = 300000; // 5 minutes class Poller { - constructor() { - this.timer = null; - } - - startWorker() { - if (this.timer !== null) { - return; + constructor() { + this.timer = null; } - console.log(`[Poller] Starting worker`); - this.timer = setInterval(() => this.pollAll(), intervalMillis); - setTimeout(() => this.pollAll(), delayMillis); - } - async pollAll() { - console.log(`[Poller] Polling all subscriptions`); - const subscriptions = await subscriptionManager.all(); - - await Promise.all( - subscriptions.map(async (s) => { - try { - await this.poll(s); - } catch (e) { - console.log(`[Poller] Error polling ${s.id}`, e); + startWorker() { + if (this.timer !== null) { + return; } - }) - ); - } - - async poll(subscription) { - console.log(`[Poller] Polling ${subscription.id}`); - - const since = subscription.last; - const notifications = await api.poll(subscription.baseUrl, subscription.topic, since); - if (!notifications || notifications.length === 0) { - console.log(`[Poller] No new notifications found for ${subscription.id}`); - return; + console.log(`[Poller] Starting worker`); + this.timer = setInterval(() => this.pollAll(), intervalMillis); + setTimeout(() => this.pollAll(), delayMillis); } - console.log(`[Poller] Adding ${notifications.length} notification(s) for ${subscription.id}`); - await subscriptionManager.addNotifications(subscription.id, notifications); - } - pollInBackground(subscription) { - const fn = async () => { - try { - await this.poll(subscription); - } catch (e) { - console.error(`[App] Error polling subscription ${subscription.id}`, e); - } - }; - setTimeout(() => fn(), 0); - } + async pollAll() { + console.log(`[Poller] Polling all subscriptions`); + const subscriptions = await subscriptionManager.all(); + for (const s of subscriptions) { + try { + await this.poll(s); + } catch (e) { + console.log(`[Poller] Error polling ${s.id}`, e); + } + } + } + + async poll(subscription) { + console.log(`[Poller] Polling ${subscription.id}`); + + const since = subscription.last; + const notifications = await api.poll(subscription.baseUrl, subscription.topic, since); + if (!notifications || notifications.length === 0) { + console.log(`[Poller] No new notifications found for ${subscription.id}`); + return; + } + console.log(`[Poller] Adding ${notifications.length} notification(s) for ${subscription.id}`); + await subscriptionManager.addNotifications(subscription.id, notifications); + } + + pollInBackground(subscription) { + const fn = async () => { + try { + await this.poll(subscription); + } catch (e) { + console.error(`[App] Error polling subscription ${subscription.id}`, e); + } + }; + setTimeout(() => fn(), 0); + } } const poller = new Poller(); diff --git a/web/src/app/Prefs.js b/web/src/app/Prefs.js index 8adc508..b444c6f 100644 --- a/web/src/app/Prefs.js +++ b/web/src/app/Prefs.js @@ -1,32 +1,32 @@ import db from "./db"; class Prefs { - async setSound(sound) { - db.prefs.put({ key: "sound", value: sound.toString() }); - } + async setSound(sound) { + db.prefs.put({key: 'sound', value: sound.toString()}); + } - async sound() { - const sound = await db.prefs.get("sound"); - return sound ? sound.value : "ding"; - } + async sound() { + const sound = await db.prefs.get('sound'); + return (sound) ? sound.value : "ding"; + } - async setMinPriority(minPriority) { - db.prefs.put({ key: "minPriority", value: minPriority.toString() }); - } + async setMinPriority(minPriority) { + db.prefs.put({key: 'minPriority', value: minPriority.toString()}); + } - async minPriority() { - const minPriority = await db.prefs.get("minPriority"); - return minPriority ? Number(minPriority.value) : 1; - } + async minPriority() { + const minPriority = await db.prefs.get('minPriority'); + return (minPriority) ? Number(minPriority.value) : 1; + } - async setDeleteAfter(deleteAfter) { - db.prefs.put({ key: "deleteAfter", value: deleteAfter.toString() }); - } + async setDeleteAfter(deleteAfter) { + db.prefs.put({key:'deleteAfter', value: deleteAfter.toString()}); + } - async deleteAfter() { - const deleteAfter = await db.prefs.get("deleteAfter"); - return deleteAfter ? Number(deleteAfter.value) : 604800; // Default is one week - } + async deleteAfter() { + const deleteAfter = await db.prefs.get('deleteAfter'); + return (deleteAfter) ? Number(deleteAfter.value) : 604800; // Default is one week + } } const prefs = new Prefs(); diff --git a/web/src/app/Pruner.js b/web/src/app/Pruner.js index 498c156..4594805 100644 --- a/web/src/app/Pruner.js +++ b/web/src/app/Pruner.js @@ -5,33 +5,33 @@ const delayMillis = 25000; // 25 seconds const intervalMillis = 1800000; // 30 minutes class Pruner { - constructor() { - this.timer = null; - } + constructor() { + this.timer = null; + } - startWorker() { - if (this.timer !== null) { - return; + startWorker() { + if (this.timer !== null) { + return; + } + console.log(`[Pruner] Starting worker`); + this.timer = setInterval(() => this.prune(), intervalMillis); + setTimeout(() => this.prune(), delayMillis); } - console.log(`[Pruner] Starting worker`); - this.timer = setInterval(() => this.prune(), intervalMillis); - setTimeout(() => this.prune(), delayMillis); - } - async prune() { - const deleteAfterSeconds = await prefs.deleteAfter(); - const pruneThresholdTimestamp = Math.round(Date.now() / 1000) - deleteAfterSeconds; - if (deleteAfterSeconds === 0) { - console.log(`[Pruner] Pruning is disabled. Skipping.`); - return; + async prune() { + const deleteAfterSeconds = await prefs.deleteAfter(); + const pruneThresholdTimestamp = Math.round(Date.now()/1000) - deleteAfterSeconds; + if (deleteAfterSeconds === 0) { + console.log(`[Pruner] Pruning is disabled. Skipping.`); + return; + } + console.log(`[Pruner] Pruning notifications older than ${deleteAfterSeconds}s (timestamp ${pruneThresholdTimestamp})`); + try { + await subscriptionManager.pruneNotifications(pruneThresholdTimestamp); + } catch (e) { + console.log(`[Pruner] Error pruning old subscriptions`, e); + } } - console.log(`[Pruner] Pruning notifications older than ${deleteAfterSeconds}s (timestamp ${pruneThresholdTimestamp})`); - try { - await subscriptionManager.pruneNotifications(pruneThresholdTimestamp); - } catch (e) { - console.log(`[Pruner] Error pruning old subscriptions`, e); - } - } } const pruner = new Pruner(); diff --git a/web/src/app/Session.js b/web/src/app/Session.js index 0b47f93..45f4842 100644 --- a/web/src/app/Session.js +++ b/web/src/app/Session.js @@ -1,30 +1,30 @@ class Session { - store(username, token) { - localStorage.setItem("user", username); - localStorage.setItem("token", token); - } + store(username, token) { + localStorage.setItem("user", username); + localStorage.setItem("token", token); + } - reset() { - localStorage.removeItem("user"); - localStorage.removeItem("token"); - } + reset() { + localStorage.removeItem("user"); + localStorage.removeItem("token"); + } - resetAndRedirect(url) { - this.reset(); - window.location.href = url; - } + resetAndRedirect(url) { + this.reset(); + window.location.href = url; + } - exists() { - return this.username() && this.token(); - } + exists() { + return this.username() && this.token(); + } - username() { - return localStorage.getItem("user"); - } + username() { + return localStorage.getItem("user"); + } - token() { - return localStorage.getItem("token"); - } + token() { + return localStorage.getItem("token"); + } } const session = new Session(); diff --git a/web/src/app/SubscriptionManager.js b/web/src/app/SubscriptionManager.js index ecbe4da..cdfe50e 100644 --- a/web/src/app/SubscriptionManager.js +++ b/web/src/app/SubscriptionManager.js @@ -1,189 +1,192 @@ import db from "./db"; -import { topicUrl } from "./utils"; +import {topicUrl} from "./utils"; class SubscriptionManager { - /** All subscriptions, including "new count"; this is a JOIN, see https://dexie.org/docs/API-Reference#joining */ - async all() { - const subscriptions = await db.subscriptions.toArray(); - return Promise.all( - subscriptions.map(async (s) => ({ - ...s, - new: await db.notifications.where({ subscriptionId: s.id, new: 1 }).count(), - })) - ); - } - - async get(subscriptionId) { - return db.subscriptions.get(subscriptionId); - } - - async add(baseUrl, topic, internal) { - const id = topicUrl(baseUrl, topic); - const existingSubscription = await this.get(id); - if (existingSubscription) { - return existingSubscription; + /** All subscriptions, including "new count"; this is a JOIN, see https://dexie.org/docs/API-Reference#joining */ + async all() { + const subscriptions = await db.subscriptions.toArray(); + await Promise.all(subscriptions.map(async s => { + s.new = await db.notifications + .where({ subscriptionId: s.id, new: 1 }) + .count(); + })); + return subscriptions; } - const subscription = { - id: topicUrl(baseUrl, topic), - baseUrl, - topic, - mutedUntil: 0, - last: null, - internal: internal || false, - }; - await db.subscriptions.put(subscription); - return subscription; - } - async syncFromRemote(remoteSubscriptions, remoteReservations) { - console.log(`[SubscriptionManager] Syncing subscriptions from remote`, remoteSubscriptions); + async get(subscriptionId) { + return await db.subscriptions.get(subscriptionId) + } - // Add remote subscriptions - const remoteIds = await Promise.all( - remoteSubscriptions.map(async (remote) => { - const local = await this.add(remote.base_url, remote.topic, false); - const reservation = remoteReservations?.find((r) => remote.base_url === config.base_url && remote.topic === r.topic) || null; - - await this.update(local.id, { - displayName: remote.display_name, // May be undefined - reservation, // May be null! - }); - - return local.id; - }) - ); - - // Remove local subscriptions that do not exist remotely - const localSubscriptions = await db.subscriptions.toArray(); - - await Promise.all( - localSubscriptions.map(async (local) => { - const remoteExists = remoteIds.includes(local.id); - if (!local.internal && !remoteExists) { - await this.remove(local.id); + async add(baseUrl, topic, internal) { + const id = topicUrl(baseUrl, topic); + const existingSubscription = await this.get(id); + if (existingSubscription) { + return existingSubscription; } - }) - ); - } - - async updateState(subscriptionId, state) { - db.subscriptions.update(subscriptionId, { state }); - } - - async remove(subscriptionId) { - await db.subscriptions.delete(subscriptionId); - await db.notifications.where({ subscriptionId }).delete(); - } - - async first() { - return db.subscriptions.toCollection().first(); // May be undefined - } - - async getNotifications(subscriptionId) { - // This is quite awkward, but it is the recommended approach as per the Dexie docs. - // It's actually fine, because the reading and filtering is quite fast. The rendering is what's - // killing performance. See https://dexie.org/docs/Collection/Collection.offset()#a-better-paging-approach - - return db.notifications - .orderBy("time") // Sort by time first - .filter((n) => n.subscriptionId === subscriptionId) - .reverse() - .toArray(); - } - - async getAllNotifications() { - return db.notifications - .orderBy("time") // Efficient, see docs - .reverse() - .toArray(); - } - - /** Adds notification, or returns false if it already exists */ - async addNotification(subscriptionId, notification) { - const exists = await db.notifications.get(notification.id); - if (exists) { - return false; + const subscription = { + id: topicUrl(baseUrl, topic), + baseUrl: baseUrl, + topic: topic, + mutedUntil: 0, + last: null, + internal: internal || false + }; + await db.subscriptions.put(subscription); + return subscription; } - try { - await db.notifications.add({ - ...notification, - subscriptionId, - // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation - new: 1, - }); // FIXME consider put() for double tab - await db.subscriptions.update(subscriptionId, { - last: notification.id, - }); - } catch (e) { - console.error(`[SubscriptionManager] Error adding notification`, e); + + async syncFromRemote(remoteSubscriptions, remoteReservations) { + console.log(`[SubscriptionManager] Syncing subscriptions from remote`, remoteSubscriptions); + + // Add remote subscriptions + let remoteIds = []; // = topicUrl(baseUrl, topic) + for (let i = 0; i < remoteSubscriptions.length; i++) { + const remote = remoteSubscriptions[i]; + const local = await this.add(remote.base_url, remote.topic, false); + const reservation = remoteReservations?.find(r => remote.base_url === config.base_url && remote.topic === r.topic) || null; + await this.update(local.id, { + displayName: remote.display_name, // May be undefined + reservation: reservation // May be null! + }); + remoteIds.push(local.id); + } + + // Remove local subscriptions that do not exist remotely + const localSubscriptions = await db.subscriptions.toArray(); + for (let i = 0; i < localSubscriptions.length; i++) { + const local = localSubscriptions[i]; + const remoteExists = remoteIds.includes(local.id); + if (!local.internal && !remoteExists) { + await this.remove(local.id); + } + } } - return true; - } - /** Adds/replaces notifications, will not throw if they exist */ - async addNotifications(subscriptionId, notifications) { - const notificationsWithSubscriptionId = notifications.map((notification) => ({ ...notification, subscriptionId })); - const lastNotificationId = notifications.at(-1).id; - await db.notifications.bulkPut(notificationsWithSubscriptionId); - await db.subscriptions.update(subscriptionId, { - last: lastNotificationId, - }); - } - - async updateNotification(notification) { - const exists = await db.notifications.get(notification.id); - if (!exists) { - return false; + async updateState(subscriptionId, state) { + db.subscriptions.update(subscriptionId, { state: state }); } - try { - await db.notifications.put({ ...notification }); - } catch (e) { - console.error(`[SubscriptionManager] Error updating notification`, e); + + async remove(subscriptionId) { + await db.subscriptions.delete(subscriptionId); + await db.notifications + .where({subscriptionId: subscriptionId}) + .delete(); } - return true; - } - async deleteNotification(notificationId) { - await db.notifications.delete(notificationId); - } + async first() { + return db.subscriptions.toCollection().first(); // May be undefined + } - async deleteNotifications(subscriptionId) { - await db.notifications.where({ subscriptionId }).delete(); - } + async getNotifications(subscriptionId) { + // This is quite awkward, but it is the recommended approach as per the Dexie docs. + // It's actually fine, because the reading and filtering is quite fast. The rendering is what's + // killing performance. See https://dexie.org/docs/Collection/Collection.offset()#a-better-paging-approach - async markNotificationRead(notificationId) { - await db.notifications.where({ id: notificationId }).modify({ new: 0 }); - } + return db.notifications + .orderBy("time") // Sort by time first + .filter(n => n.subscriptionId === subscriptionId) + .reverse() + .toArray(); + } - async markNotificationsRead(subscriptionId) { - await db.notifications.where({ subscriptionId, new: 1 }).modify({ new: 0 }); - } + async getAllNotifications() { + return db.notifications + .orderBy("time") // Efficient, see docs + .reverse() + .toArray(); + } - async setMutedUntil(subscriptionId, mutedUntil) { - await db.subscriptions.update(subscriptionId, { - mutedUntil, - }); - } + /** Adds notification, or returns false if it already exists */ + async addNotification(subscriptionId, notification) { + const exists = await db.notifications.get(notification.id); + if (exists) { + return false; + } + try { + notification.new = 1; // New marker (used for bubble indicator); cannot be boolean; Dexie index limitation + await db.notifications.add({ ...notification, subscriptionId }); // FIXME consider put() for double tab + await db.subscriptions.update(subscriptionId, { + last: notification.id + }); + } catch (e) { + console.error(`[SubscriptionManager] Error adding notification`, e); + } + return true; + } - async setDisplayName(subscriptionId, displayName) { - await db.subscriptions.update(subscriptionId, { - displayName, - }); - } + /** Adds/replaces notifications, will not throw if they exist */ + async addNotifications(subscriptionId, notifications) { + const notificationsWithSubscriptionId = notifications + .map(notification => ({ ...notification, subscriptionId })); + const lastNotificationId = notifications.at(-1).id; + await db.notifications.bulkPut(notificationsWithSubscriptionId); + await db.subscriptions.update(subscriptionId, { + last: lastNotificationId + }); + } - async setReservation(subscriptionId, reservation) { - await db.subscriptions.update(subscriptionId, { - reservation, - }); - } + async updateNotification(notification) { + const exists = await db.notifications.get(notification.id); + if (!exists) { + return false; + } + try { + await db.notifications.put({ ...notification }); + } catch (e) { + console.error(`[SubscriptionManager] Error updating notification`, e); + } + return true; + } - async update(subscriptionId, params) { - await db.subscriptions.update(subscriptionId, params); - } + async deleteNotification(notificationId) { + await db.notifications.delete(notificationId); + } - async pruneNotifications(thresholdTimestamp) { - await db.notifications.where("time").below(thresholdTimestamp).delete(); - } + async deleteNotifications(subscriptionId) { + await db.notifications + .where({subscriptionId: subscriptionId}) + .delete(); + } + + async markNotificationRead(notificationId) { + await db.notifications + .where({id: notificationId}) + .modify({new: 0}); + } + + async markNotificationsRead(subscriptionId) { + await db.notifications + .where({subscriptionId: subscriptionId, new: 1}) + .modify({new: 0}); + } + + async setMutedUntil(subscriptionId, mutedUntil) { + await db.subscriptions.update(subscriptionId, { + mutedUntil: mutedUntil + }); + } + + async setDisplayName(subscriptionId, displayName) { + await db.subscriptions.update(subscriptionId, { + displayName: displayName + }); + } + + async setReservation(subscriptionId, reservation) { + await db.subscriptions.update(subscriptionId, { + reservation: reservation + }); + } + + async update(subscriptionId, params) { + await db.subscriptions.update(subscriptionId, params); + } + + async pruneNotifications(thresholdTimestamp) { + await db.notifications + .where("time").below(thresholdTimestamp) + .delete(); + } } const subscriptionManager = new SubscriptionManager(); diff --git a/web/src/app/UserManager.js b/web/src/app/UserManager.js index 2cdd544..1e54eb0 100644 --- a/web/src/app/UserManager.js +++ b/web/src/app/UserManager.js @@ -2,45 +2,45 @@ import db from "./db"; import session from "./Session"; class UserManager { - async all() { - const users = await db.users.toArray(); - if (session.exists()) { - users.unshift(this.localUser()); + async all() { + const users = await db.users.toArray(); + if (session.exists()) { + users.unshift(this.localUser()); + } + return users; } - return users; - } - async get(baseUrl) { - if (session.exists() && baseUrl === config.base_url) { - return this.localUser(); + async get(baseUrl) { + if (session.exists() && baseUrl === config.base_url) { + return this.localUser(); + } + return db.users.get(baseUrl); } - return db.users.get(baseUrl); - } - async save(user) { - if (session.exists() && user.baseUrl === config.base_url) { - return; + async save(user) { + if (session.exists() && user.baseUrl === config.base_url) { + return; + } + await db.users.put(user); } - await db.users.put(user); - } - async delete(baseUrl) { - if (session.exists() && baseUrl === config.base_url) { - return; + async delete(baseUrl) { + if (session.exists() && baseUrl === config.base_url) { + return; + } + await db.users.delete(baseUrl); } - await db.users.delete(baseUrl); - } - localUser() { - if (!session.exists()) { - return null; + localUser() { + if (!session.exists()) { + return null; + } + return { + baseUrl: config.base_url, + username: session.username(), + token: session.token() // Not "password"! + }; } - return { - baseUrl: config.base_url, - username: session.username(), - token: session.token(), // Not "password"! - }; - } } const userManager = new UserManager(); diff --git a/web/src/app/config.js b/web/src/app/config.js index 24e86f3..bdec53e 100644 --- a/web/src/app/config.js +++ b/web/src/app/config.js @@ -1,9 +1,9 @@ -const { config } = window; +const config = window.config; // The backend returns an empty base_url for the config struct, // so the frontend (hey, that's us!) can use the current location. if (!config.base_url || config.base_url === "") { - config.base_url = window.location.origin; + config.base_url = window.location.origin; } export default config; diff --git a/web/src/app/db.js b/web/src/app/db.js index 0e1a5e7..564ee1c 100644 --- a/web/src/app/db.js +++ b/web/src/app/db.js @@ -1,4 +1,4 @@ -import Dexie from "dexie"; +import Dexie from 'dexie'; import session from "./Session"; // Uses Dexie.js @@ -8,14 +8,14 @@ import session from "./Session"; // - As per docs, we only declare the indexable columns, not all columns // The IndexedDB database name is based on the logged-in user -const dbName = session.username() ? `ntfy-${session.username()}` : "ntfy"; +const dbName = (session.username()) ? `ntfy-${session.username()}` : "ntfy"; const db = new Dexie(dbName); db.version(1).stores({ - subscriptions: "&id,baseUrl", - notifications: "&id,subscriptionId,time,new,[subscriptionId+new]", // compound key for query performance - users: "&baseUrl,username", - prefs: "&key", + subscriptions: '&id,baseUrl', + notifications: '&id,subscriptionId,time,new,[subscriptionId+new]', // compound key for query performance + users: '&baseUrl,username', + prefs: '&key' }); export default db; diff --git a/web/src/app/emojis.js b/web/src/app/emojis.js index b7912c3..f6dac7b 100644 --- a/web/src/app/emojis.js +++ b/web/src/app/emojis.js @@ -1,14500 +1,3 @@ // This file is generated by scripts/emoji-convert.sh to reduce the size // Original data source: https://github.com/github/gemoji/blob/master/db/emoji.json -export const rawEmojis = [ - { - emoji: "๐Ÿ˜€", - aliases: ["grinning"], - tags: ["smile", "happy"], - category: "Smileys & Emotion", - description: "grinning face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ƒ", - aliases: ["smiley"], - tags: ["happy", "joy", "haha"], - category: "Smileys & Emotion", - description: "grinning face with big eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜„", - aliases: ["smile"], - tags: ["happy", "joy", "laugh", "pleased"], - category: "Smileys & Emotion", - description: "grinning face with smiling eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜", - aliases: ["grin"], - tags: [], - category: "Smileys & Emotion", - description: "beaming face with smiling eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜†", - aliases: ["laughing", "satisfied"], - tags: ["happy", "haha"], - category: "Smileys & Emotion", - description: "grinning squinting face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜…", - aliases: ["sweat_smile"], - tags: ["hot"], - category: "Smileys & Emotion", - description: "grinning face with sweat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคฃ", - aliases: ["rofl"], - tags: ["lol", "laughing"], - category: "Smileys & Emotion", - description: "rolling on the floor laughing", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ˜‚", - aliases: ["joy"], - tags: ["tears"], - category: "Smileys & Emotion", - description: "face with tears of joy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™‚", - aliases: ["slightly_smiling_face"], - tags: [], - category: "Smileys & Emotion", - description: "slightly smiling face", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ™ƒ", - aliases: ["upside_down_face"], - tags: [], - category: "Smileys & Emotion", - description: "upside-down face", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ˜‰", - aliases: ["wink"], - tags: ["flirt"], - category: "Smileys & Emotion", - description: "winking face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜Š", - aliases: ["blush"], - tags: ["proud"], - category: "Smileys & Emotion", - description: "smiling face with smiling eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜‡", - aliases: ["innocent"], - tags: ["angel"], - category: "Smileys & Emotion", - description: "smiling face with halo", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅฐ", - aliases: ["smiling_face_with_three_hearts"], - tags: ["love"], - category: "Smileys & Emotion", - description: "smiling face with hearts", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜", - aliases: ["heart_eyes"], - tags: ["love", "crush"], - category: "Smileys & Emotion", - description: "smiling face with heart-eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคฉ", - aliases: ["star_struck"], - tags: ["eyes"], - category: "Smileys & Emotion", - description: "star-struck", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜˜", - aliases: ["kissing_heart"], - tags: ["flirt"], - category: "Smileys & Emotion", - description: "face blowing a kiss", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜—", - aliases: ["kissing"], - tags: [], - category: "Smileys & Emotion", - description: "kissing face", - unicode_version: "6.1", - }, - { - emoji: "โ˜บ๏ธ", - aliases: ["relaxed"], - tags: ["blush", "pleased"], - category: "Smileys & Emotion", - description: "smiling face", - unicode_version: "", - }, - { - emoji: "๐Ÿ˜š", - aliases: ["kissing_closed_eyes"], - tags: [], - category: "Smileys & Emotion", - description: "kissing face with closed eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜™", - aliases: ["kissing_smiling_eyes"], - tags: [], - category: "Smileys & Emotion", - description: "kissing face with smiling eyes", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿฅฒ", - aliases: ["smiling_face_with_tear"], - tags: [], - category: "Smileys & Emotion", - description: "smiling face with tear", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ˜‹", - aliases: ["yum"], - tags: ["tongue", "lick"], - category: "Smileys & Emotion", - description: "face savoring food", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜›", - aliases: ["stuck_out_tongue"], - tags: [], - category: "Smileys & Emotion", - description: "face with tongue", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜œ", - aliases: ["stuck_out_tongue_winking_eye"], - tags: ["prank", "silly"], - category: "Smileys & Emotion", - description: "winking face with tongue", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคช", - aliases: ["zany_face"], - tags: ["goofy", "wacky"], - category: "Smileys & Emotion", - description: "zany face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜", - aliases: ["stuck_out_tongue_closed_eyes"], - tags: ["prank"], - category: "Smileys & Emotion", - description: "squinting face with tongue", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค‘", - aliases: ["money_mouth_face"], - tags: ["rich"], - category: "Smileys & Emotion", - description: "money-mouth face", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿค—", - aliases: ["hugs"], - tags: [], - category: "Smileys & Emotion", - description: "hugging face", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿคญ", - aliases: ["hand_over_mouth"], - tags: ["quiet", "whoops"], - category: "Smileys & Emotion", - description: "face with hand over mouth", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคซ", - aliases: ["shushing_face"], - tags: ["silence", "quiet"], - category: "Smileys & Emotion", - description: "shushing face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿค”", - aliases: ["thinking"], - tags: [], - category: "Smileys & Emotion", - description: "thinking face", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿค", - aliases: ["zipper_mouth_face"], - tags: ["silence", "hush"], - category: "Smileys & Emotion", - description: "zipper-mouth face", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿคจ", - aliases: ["raised_eyebrow"], - tags: ["suspicious"], - category: "Smileys & Emotion", - description: "face with raised eyebrow", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜", - aliases: ["neutral_face"], - tags: ["meh"], - category: "Smileys & Emotion", - description: "neutral face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜‘", - aliases: ["expressionless"], - tags: [], - category: "Smileys & Emotion", - description: "expressionless face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ถ", - aliases: ["no_mouth"], - tags: ["mute", "silence"], - category: "Smileys & Emotion", - description: "face without mouth", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ถโ€๐ŸŒซ๏ธ", - aliases: ["face_in_clouds"], - tags: [], - category: "Smileys & Emotion", - description: "face in clouds", - unicode_version: "13.1", - }, - { - emoji: "๐Ÿ˜", - aliases: ["smirk"], - tags: ["smug"], - category: "Smileys & Emotion", - description: "smirking face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜’", - aliases: ["unamused"], - tags: ["meh"], - category: "Smileys & Emotion", - description: "unamused face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™„", - aliases: ["roll_eyes"], - tags: [], - category: "Smileys & Emotion", - description: "face with rolling eyes", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ˜ฌ", - aliases: ["grimacing"], - tags: [], - category: "Smileys & Emotion", - description: "grimacing face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ฎโ€๐Ÿ’จ", - aliases: ["face_exhaling"], - tags: [], - category: "Smileys & Emotion", - description: "face exhaling", - unicode_version: "13.1", - }, - { - emoji: "๐Ÿคฅ", - aliases: ["lying_face"], - tags: ["liar"], - category: "Smileys & Emotion", - description: "lying face", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ˜Œ", - aliases: ["relieved"], - tags: ["whew"], - category: "Smileys & Emotion", - description: "relieved face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜”", - aliases: ["pensive"], - tags: [], - category: "Smileys & Emotion", - description: "pensive face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ช", - aliases: ["sleepy"], - tags: ["tired"], - category: "Smileys & Emotion", - description: "sleepy face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคค", - aliases: ["drooling_face"], - tags: [], - category: "Smileys & Emotion", - description: "drooling face", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ˜ด", - aliases: ["sleeping"], - tags: ["zzz"], - category: "Smileys & Emotion", - description: "sleeping face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ท", - aliases: ["mask"], - tags: ["sick", "ill"], - category: "Smileys & Emotion", - description: "face with medical mask", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค’", - aliases: ["face_with_thermometer"], - tags: ["sick"], - category: "Smileys & Emotion", - description: "face with thermometer", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿค•", - aliases: ["face_with_head_bandage"], - tags: ["hurt"], - category: "Smileys & Emotion", - description: "face with head-bandage", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿคข", - aliases: ["nauseated_face"], - tags: ["sick", "barf", "disgusted"], - category: "Smileys & Emotion", - description: "nauseated face", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคฎ", - aliases: ["vomiting_face"], - tags: ["barf", "sick"], - category: "Smileys & Emotion", - description: "face vomiting", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคง", - aliases: ["sneezing_face"], - tags: ["achoo", "sick"], - category: "Smileys & Emotion", - description: "sneezing face", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅต", - aliases: ["hot_face"], - tags: ["heat", "sweating"], - category: "Smileys & Emotion", - description: "hot face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅถ", - aliases: ["cold_face"], - tags: ["freezing", "ice"], - category: "Smileys & Emotion", - description: "cold face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅด", - aliases: ["woozy_face"], - tags: ["groggy"], - category: "Smileys & Emotion", - description: "woozy face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜ต", - aliases: ["dizzy_face"], - tags: [], - category: "Smileys & Emotion", - description: "knocked-out face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ตโ€๐Ÿ’ซ", - aliases: ["face_with_spiral_eyes"], - tags: [], - category: "Smileys & Emotion", - description: "face with spiral eyes", - unicode_version: "13.1", - }, - { - emoji: "๐Ÿคฏ", - aliases: ["exploding_head"], - tags: ["mind", "blown"], - category: "Smileys & Emotion", - description: "exploding head", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿค ", - aliases: ["cowboy_hat_face"], - tags: [], - category: "Smileys & Emotion", - description: "cowboy hat face", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅณ", - aliases: ["partying_face"], - tags: ["celebration", "birthday"], - category: "Smileys & Emotion", - description: "partying face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅธ", - aliases: ["disguised_face"], - tags: [], - category: "Smileys & Emotion", - description: "disguised face", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ˜Ž", - aliases: ["sunglasses"], - tags: ["cool"], - category: "Smileys & Emotion", - description: "smiling face with sunglasses", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค“", - aliases: ["nerd_face"], - tags: ["geek", "glasses"], - category: "Smileys & Emotion", - description: "nerd face", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿง", - aliases: ["monocle_face"], - tags: [], - category: "Smileys & Emotion", - description: "face with monocle", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜•", - aliases: ["confused"], - tags: [], - category: "Smileys & Emotion", - description: "confused face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜Ÿ", - aliases: ["worried"], - tags: ["nervous"], - category: "Smileys & Emotion", - description: "worried face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ™", - aliases: ["slightly_frowning_face"], - tags: [], - category: "Smileys & Emotion", - description: "slightly frowning face", - unicode_version: "7.0", - }, - { - emoji: "โ˜น๏ธ", - aliases: ["frowning_face"], - tags: [], - category: "Smileys & Emotion", - description: "frowning face", - unicode_version: "", - }, - { - emoji: "๐Ÿ˜ฎ", - aliases: ["open_mouth"], - tags: ["surprise", "impressed", "wow"], - category: "Smileys & Emotion", - description: "face with open mouth", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ฏ", - aliases: ["hushed"], - tags: ["silence", "speechless"], - category: "Smileys & Emotion", - description: "hushed face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ฒ", - aliases: ["astonished"], - tags: ["amazed", "gasp"], - category: "Smileys & Emotion", - description: "astonished face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ณ", - aliases: ["flushed"], - tags: [], - category: "Smileys & Emotion", - description: "flushed face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅบ", - aliases: ["pleading_face"], - tags: ["puppy", "eyes"], - category: "Smileys & Emotion", - description: "pleading face", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜ฆ", - aliases: ["frowning"], - tags: [], - category: "Smileys & Emotion", - description: "frowning face with open mouth", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜ง", - aliases: ["anguished"], - tags: ["stunned"], - category: "Smileys & Emotion", - description: "anguished face", - unicode_version: "6.1", - }, - { - emoji: "๐Ÿ˜จ", - aliases: ["fearful"], - tags: ["scared", "shocked", "oops"], - category: "Smileys & Emotion", - description: "fearful face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฐ", - aliases: ["cold_sweat"], - tags: ["nervous"], - category: "Smileys & Emotion", - description: "anxious face with sweat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฅ", - aliases: ["disappointed_relieved"], - tags: ["phew", "sweat", "nervous"], - category: "Smileys & Emotion", - description: "sad but relieved face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ข", - aliases: ["cry"], - tags: ["sad", "tear"], - category: "Smileys & Emotion", - description: "crying face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ญ", - aliases: ["sob"], - tags: ["sad", "cry", "bawling"], - category: "Smileys & Emotion", - description: "loudly crying face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฑ", - aliases: ["scream"], - tags: ["horror", "shocked"], - category: "Smileys & Emotion", - description: "face screaming in fear", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜–", - aliases: ["confounded"], - tags: [], - category: "Smileys & Emotion", - description: "confounded face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฃ", - aliases: ["persevere"], - tags: ["struggling"], - category: "Smileys & Emotion", - description: "persevering face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ž", - aliases: ["disappointed"], - tags: ["sad"], - category: "Smileys & Emotion", - description: "disappointed face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜“", - aliases: ["sweat"], - tags: [], - category: "Smileys & Emotion", - description: "downcast face with sweat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฉ", - aliases: ["weary"], - tags: ["tired"], - category: "Smileys & Emotion", - description: "weary face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ซ", - aliases: ["tired_face"], - tags: ["upset", "whine"], - category: "Smileys & Emotion", - description: "tired face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅฑ", - aliases: ["yawning_face"], - tags: [], - category: "Smileys & Emotion", - description: "yawning face", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ˜ค", - aliases: ["triumph"], - tags: ["smug"], - category: "Smileys & Emotion", - description: "face with steam from nose", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ก", - aliases: ["rage", "pout"], - tags: ["angry"], - category: "Smileys & Emotion", - description: "pouting face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ ", - aliases: ["angry"], - tags: ["mad", "annoyed"], - category: "Smileys & Emotion", - description: "angry face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคฌ", - aliases: ["cursing_face"], - tags: ["foul"], - category: "Smileys & Emotion", - description: "face with symbols on mouth", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜ˆ", - aliases: ["smiling_imp"], - tags: ["devil", "evil", "horns"], - category: "Smileys & Emotion", - description: "smiling face with horns", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฟ", - aliases: ["imp"], - tags: ["angry", "devil", "evil", "horns"], - category: "Smileys & Emotion", - description: "angry face with horns", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’€", - aliases: ["skull"], - tags: ["dead", "danger", "poison"], - category: "Smileys & Emotion", - description: "skull", - unicode_version: "6.0", - }, - { - emoji: "โ˜ ๏ธ", - aliases: ["skull_and_crossbones"], - tags: ["danger", "pirate"], - category: "Smileys & Emotion", - description: "skull and crossbones", - unicode_version: "", - }, - { - emoji: "๐Ÿ’ฉ", - aliases: ["hankey", "poop", "shit"], - tags: ["crap"], - category: "Smileys & Emotion", - description: "pile of poo", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคก", - aliases: ["clown_face"], - tags: [], - category: "Smileys & Emotion", - description: "clown face", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ‘น", - aliases: ["japanese_ogre"], - tags: ["monster"], - category: "Smileys & Emotion", - description: "ogre", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘บ", - aliases: ["japanese_goblin"], - tags: [], - category: "Smileys & Emotion", - description: "goblin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ป", - aliases: ["ghost"], - tags: ["halloween"], - category: "Smileys & Emotion", - description: "ghost", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฝ", - aliases: ["alien"], - tags: ["ufo"], - category: "Smileys & Emotion", - description: "alien", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘พ", - aliases: ["space_invader"], - tags: ["game", "retro"], - category: "Smileys & Emotion", - description: "alien monster", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค–", - aliases: ["robot"], - tags: [], - category: "Smileys & Emotion", - description: "robot", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ˜บ", - aliases: ["smiley_cat"], - tags: [], - category: "Smileys & Emotion", - description: "grinning cat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ธ", - aliases: ["smile_cat"], - tags: [], - category: "Smileys & Emotion", - description: "grinning cat with smiling eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜น", - aliases: ["joy_cat"], - tags: [], - category: "Smileys & Emotion", - description: "cat with tears of joy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ป", - aliases: ["heart_eyes_cat"], - tags: [], - category: "Smileys & Emotion", - description: "smiling cat with heart-eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ผ", - aliases: ["smirk_cat"], - tags: [], - category: "Smileys & Emotion", - description: "cat with wry smile", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฝ", - aliases: ["kissing_cat"], - tags: [], - category: "Smileys & Emotion", - description: "kissing cat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™€", - aliases: ["scream_cat"], - tags: ["horror"], - category: "Smileys & Emotion", - description: "weary cat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜ฟ", - aliases: ["crying_cat_face"], - tags: ["sad", "tear"], - category: "Smileys & Emotion", - description: "crying cat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜พ", - aliases: ["pouting_cat"], - tags: [], - category: "Smileys & Emotion", - description: "pouting cat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™ˆ", - aliases: ["see_no_evil"], - tags: ["monkey", "blind", "ignore"], - category: "Smileys & Emotion", - description: "see-no-evil monkey", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™‰", - aliases: ["hear_no_evil"], - tags: ["monkey", "deaf"], - category: "Smileys & Emotion", - description: "hear-no-evil monkey", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™Š", - aliases: ["speak_no_evil"], - tags: ["monkey", "mute", "hush"], - category: "Smileys & Emotion", - description: "speak-no-evil monkey", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‹", - aliases: ["kiss"], - tags: ["lipstick"], - category: "Smileys & Emotion", - description: "kiss mark", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’Œ", - aliases: ["love_letter"], - tags: ["email", "envelope"], - category: "Smileys & Emotion", - description: "love letter", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’˜", - aliases: ["cupid"], - tags: ["love", "heart"], - category: "Smileys & Emotion", - description: "heart with arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["gift_heart"], - tags: ["chocolates"], - category: "Smileys & Emotion", - description: "heart with ribbon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’–", - aliases: ["sparkling_heart"], - tags: [], - category: "Smileys & Emotion", - description: "sparkling heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’—", - aliases: ["heartpulse"], - tags: [], - category: "Smileys & Emotion", - description: "growing heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’“", - aliases: ["heartbeat"], - tags: [], - category: "Smileys & Emotion", - description: "beating heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ž", - aliases: ["revolving_hearts"], - tags: [], - category: "Smileys & Emotion", - description: "revolving hearts", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’•", - aliases: ["two_hearts"], - tags: [], - category: "Smileys & Emotion", - description: "two hearts", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’Ÿ", - aliases: ["heart_decoration"], - tags: [], - category: "Smileys & Emotion", - description: "heart decoration", - unicode_version: "6.0", - }, - { - emoji: "โฃ๏ธ", - aliases: ["heavy_heart_exclamation"], - tags: [], - category: "Smileys & Emotion", - description: "heart exclamation", - unicode_version: "", - }, - { - emoji: "๐Ÿ’”", - aliases: ["broken_heart"], - tags: [], - category: "Smileys & Emotion", - description: "broken heart", - unicode_version: "6.0", - }, - { - emoji: "โค๏ธโ€๐Ÿ”ฅ", - aliases: ["heart_on_fire"], - tags: [], - category: "Smileys & Emotion", - description: "heart on fire", - unicode_version: "13.1", - }, - { - emoji: "โค๏ธโ€๐Ÿฉน", - aliases: ["mending_heart"], - tags: [], - category: "Smileys & Emotion", - description: "mending heart", - unicode_version: "13.1", - }, - { - emoji: "โค๏ธ", - aliases: ["heart"], - tags: ["love"], - category: "Smileys & Emotion", - description: "red heart", - unicode_version: "", - }, - { - emoji: "๐Ÿงก", - aliases: ["orange_heart"], - tags: [], - category: "Smileys & Emotion", - description: "orange heart", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’›", - aliases: ["yellow_heart"], - tags: [], - category: "Smileys & Emotion", - description: "yellow heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’š", - aliases: ["green_heart"], - tags: [], - category: "Smileys & Emotion", - description: "green heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’™", - aliases: ["blue_heart"], - tags: [], - category: "Smileys & Emotion", - description: "blue heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’œ", - aliases: ["purple_heart"], - tags: [], - category: "Smileys & Emotion", - description: "purple heart", - unicode_version: "6.0", - }, - { - emoji: "๐ŸคŽ", - aliases: ["brown_heart"], - tags: [], - category: "Smileys & Emotion", - description: "brown heart", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ–ค", - aliases: ["black_heart"], - tags: [], - category: "Smileys & Emotion", - description: "black heart", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿค", - aliases: ["white_heart"], - tags: [], - category: "Smileys & Emotion", - description: "white heart", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ’ฏ", - aliases: ["100"], - tags: ["score", "perfect"], - category: "Smileys & Emotion", - description: "hundred points", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ข", - aliases: ["anger"], - tags: ["angry"], - category: "Smileys & Emotion", - description: "anger symbol", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ฅ", - aliases: ["boom", "collision"], - tags: ["explode"], - category: "Smileys & Emotion", - description: "collision", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ซ", - aliases: ["dizzy"], - tags: ["star"], - category: "Smileys & Emotion", - description: "dizzy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ฆ", - aliases: ["sweat_drops"], - tags: ["water", "workout"], - category: "Smileys & Emotion", - description: "sweat droplets", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’จ", - aliases: ["dash"], - tags: ["wind", "blow", "fast"], - category: "Smileys & Emotion", - description: "dashing away", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ณ๏ธ", - aliases: ["hole"], - tags: [], - category: "Smileys & Emotion", - description: "hole", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ’ฃ", - aliases: ["bomb"], - tags: ["boom"], - category: "Smileys & Emotion", - description: "bomb", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ฌ", - aliases: ["speech_balloon"], - tags: ["comment"], - category: "Smileys & Emotion", - description: "speech balloon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ", - aliases: ["eye_speech_bubble"], - tags: [], - category: "Smileys & Emotion", - description: "eye in speech bubble", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ—จ๏ธ", - aliases: ["left_speech_bubble"], - tags: [], - category: "Smileys & Emotion", - description: "left speech bubble", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ—ฏ๏ธ", - aliases: ["right_anger_bubble"], - tags: [], - category: "Smileys & Emotion", - description: "right anger bubble", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ’ญ", - aliases: ["thought_balloon"], - tags: ["thinking"], - category: "Smileys & Emotion", - description: "thought balloon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ค", - aliases: ["zzz"], - tags: ["sleeping"], - category: "Smileys & Emotion", - description: "zzz", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘‹", - aliases: ["wave"], - tags: ["goodbye"], - category: "People & Body", - description: "waving hand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคš", - aliases: ["raised_back_of_hand"], - tags: [], - category: "People & Body", - description: "raised back of hand", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ–๏ธ", - aliases: ["raised_hand_with_fingers_splayed"], - tags: [], - category: "People & Body", - description: "hand with fingers splayed", - unicode_version: "7.0", - }, - { - emoji: "โœ‹", - aliases: ["hand", "raised_hand"], - tags: ["highfive", "stop"], - category: "People & Body", - description: "raised hand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ––", - aliases: ["vulcan_salute"], - tags: ["prosper", "spock"], - category: "People & Body", - description: "vulcan salute", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‘Œ", - aliases: ["ok_hand"], - tags: [], - category: "People & Body", - description: "OK hand", - unicode_version: "6.0", - }, - { - emoji: "๐ŸคŒ", - aliases: ["pinched_fingers"], - tags: [], - category: "People & Body", - description: "pinched fingers", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿค", - aliases: ["pinching_hand"], - tags: [], - category: "People & Body", - description: "pinching hand", - unicode_version: "12.0", - }, - { - emoji: "โœŒ๏ธ", - aliases: ["v"], - tags: ["victory", "peace"], - category: "People & Body", - description: "victory hand", - unicode_version: "", - }, - { - emoji: "๐Ÿคž", - aliases: ["crossed_fingers"], - tags: ["luck", "hopeful"], - category: "People & Body", - description: "crossed fingers", - unicode_version: "9.0", - }, - { - emoji: "๐ŸคŸ", - aliases: ["love_you_gesture"], - tags: [], - category: "People & Body", - description: "love-you gesture", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿค˜", - aliases: ["metal"], - tags: [], - category: "People & Body", - description: "sign of the horns", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿค™", - aliases: ["call_me_hand"], - tags: [], - category: "People & Body", - description: "call me hand", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ‘ˆ", - aliases: ["point_left"], - tags: [], - category: "People & Body", - description: "backhand index pointing left", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘‰", - aliases: ["point_right"], - tags: [], - category: "People & Body", - description: "backhand index pointing right", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘†", - aliases: ["point_up_2"], - tags: [], - category: "People & Body", - description: "backhand index pointing up", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ–•", - aliases: ["middle_finger", "fu"], - tags: [], - category: "People & Body", - description: "middle finger", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‘‡", - aliases: ["point_down"], - tags: [], - category: "People & Body", - description: "backhand index pointing down", - unicode_version: "6.0", - }, - { - emoji: "โ˜๏ธ", - aliases: ["point_up"], - tags: [], - category: "People & Body", - description: "index pointing up", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘", - aliases: ["+1", "thumbsup"], - tags: ["approve", "ok"], - category: "People & Body", - description: "thumbs up", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘Ž", - aliases: ["-1", "thumbsdown"], - tags: ["disapprove", "bury"], - category: "People & Body", - description: "thumbs down", - unicode_version: "6.0", - }, - { - emoji: "โœŠ", - aliases: ["fist_raised", "fist"], - tags: ["power"], - category: "People & Body", - description: "raised fist", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘Š", - aliases: ["fist_oncoming", "facepunch", "punch"], - tags: ["attack"], - category: "People & Body", - description: "oncoming fist", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค›", - aliases: ["fist_left"], - tags: [], - category: "People & Body", - description: "left-facing fist", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคœ", - aliases: ["fist_right"], - tags: [], - category: "People & Body", - description: "right-facing fist", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ‘", - aliases: ["clap"], - tags: ["praise", "applause"], - category: "People & Body", - description: "clapping hands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™Œ", - aliases: ["raised_hands"], - tags: ["hooray"], - category: "People & Body", - description: "raising hands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘", - aliases: ["open_hands"], - tags: [], - category: "People & Body", - description: "open hands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคฒ", - aliases: ["palms_up_together"], - tags: [], - category: "People & Body", - description: "palms up together", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿค", - aliases: ["handshake"], - tags: ["deal"], - category: "People & Body", - description: "handshake", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ™", - aliases: ["pray"], - tags: ["please", "hope", "wish"], - category: "People & Body", - description: "folded hands", - unicode_version: "6.0", - }, - { - emoji: "โœ๏ธ", - aliases: ["writing_hand"], - tags: [], - category: "People & Body", - description: "writing hand", - unicode_version: "", - }, - { - emoji: "๐Ÿ’…", - aliases: ["nail_care"], - tags: ["beauty", "manicure"], - category: "People & Body", - description: "nail polish", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคณ", - aliases: ["selfie"], - tags: [], - category: "People & Body", - description: "selfie", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ’ช", - aliases: ["muscle"], - tags: ["flex", "bicep", "strong", "workout"], - category: "People & Body", - description: "flexed biceps", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆพ", - aliases: ["mechanical_arm"], - tags: [], - category: "People & Body", - description: "mechanical arm", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆฟ", - aliases: ["mechanical_leg"], - tags: [], - category: "People & Body", - description: "mechanical leg", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆต", - aliases: ["leg"], - tags: [], - category: "People & Body", - description: "leg", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆถ", - aliases: ["foot"], - tags: [], - category: "People & Body", - description: "foot", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘‚", - aliases: ["ear"], - tags: ["hear", "sound", "listen"], - category: "People & Body", - description: "ear", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆป", - aliases: ["ear_with_hearing_aid"], - tags: [], - category: "People & Body", - description: "ear with hearing aid", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘ƒ", - aliases: ["nose"], - tags: ["smell"], - category: "People & Body", - description: "nose", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง ", - aliases: ["brain"], - tags: [], - category: "People & Body", - description: "brain", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿซ€", - aliases: ["anatomical_heart"], - tags: [], - category: "People & Body", - description: "anatomical heart", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿซ", - aliases: ["lungs"], - tags: [], - category: "People & Body", - description: "lungs", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆท", - aliases: ["tooth"], - tags: [], - category: "People & Body", - description: "tooth", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆด", - aliases: ["bone"], - tags: [], - category: "People & Body", - description: "bone", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘€", - aliases: ["eyes"], - tags: ["look", "see", "watch"], - category: "People & Body", - description: "eyes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘๏ธ", - aliases: ["eye"], - tags: [], - category: "People & Body", - description: "eye", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‘…", - aliases: ["tongue"], - tags: ["taste"], - category: "People & Body", - description: "tongue", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘„", - aliases: ["lips"], - tags: ["kiss"], - category: "People & Body", - description: "mouth", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ถ", - aliases: ["baby"], - tags: ["child", "newborn"], - category: "People & Body", - description: "baby", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง’", - aliases: ["child"], - tags: [], - category: "People & Body", - description: "child", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ฆ", - aliases: ["boy"], - tags: ["child"], - category: "People & Body", - description: "boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ง", - aliases: ["girl"], - tags: ["child"], - category: "People & Body", - description: "girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง‘", - aliases: ["adult"], - tags: [], - category: "People & Body", - description: "person", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ฑ", - aliases: ["blond_haired_person"], - tags: [], - category: "People & Body", - description: "person: blond hair", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จ", - aliases: ["man"], - tags: ["mustache", "father", "dad"], - category: "People & Body", - description: "man", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง”", - aliases: ["bearded_person"], - tags: [], - category: "People & Body", - description: "person: beard", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง”โ€โ™‚๏ธ", - aliases: ["man_beard"], - tags: [], - category: "People & Body", - description: "man: beard", - unicode_version: "13.1", - }, - { - emoji: "๐Ÿง”โ€โ™€๏ธ", - aliases: ["woman_beard"], - tags: [], - category: "People & Body", - description: "woman: beard", - unicode_version: "13.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆฐ", - aliases: ["red_haired_man"], - tags: [], - category: "People & Body", - description: "man: red hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆฑ", - aliases: ["curly_haired_man"], - tags: [], - category: "People & Body", - description: "man: curly hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆณ", - aliases: ["white_haired_man"], - tags: [], - category: "People & Body", - description: "man: white hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆฒ", - aliases: ["bald_man"], - tags: [], - category: "People & Body", - description: "man: bald", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ฉ", - aliases: ["woman"], - tags: ["girls"], - category: "People & Body", - description: "woman", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆฐ", - aliases: ["red_haired_woman"], - tags: [], - category: "People & Body", - description: "woman: red hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆฐ", - aliases: ["person_red_hair"], - tags: [], - category: "People & Body", - description: "person: red hair", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆฑ", - aliases: ["curly_haired_woman"], - tags: [], - category: "People & Body", - description: "woman: curly hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆฑ", - aliases: ["person_curly_hair"], - tags: [], - category: "People & Body", - description: "person: curly hair", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆณ", - aliases: ["white_haired_woman"], - tags: [], - category: "People & Body", - description: "woman: white hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆณ", - aliases: ["person_white_hair"], - tags: [], - category: "People & Body", - description: "person: white hair", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆฒ", - aliases: ["bald_woman"], - tags: [], - category: "People & Body", - description: "woman: bald", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆฒ", - aliases: ["person_bald"], - tags: [], - category: "People & Body", - description: "person: bald", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘ฑโ€โ™€๏ธ", - aliases: ["blond_haired_woman", "blonde_woman"], - tags: [], - category: "People & Body", - description: "woman: blond hair", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฑโ€โ™‚๏ธ", - aliases: ["blond_haired_man"], - tags: [], - category: "People & Body", - description: "man: blond hair", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง“", - aliases: ["older_adult"], - tags: [], - category: "People & Body", - description: "older person", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ด", - aliases: ["older_man"], - tags: [], - category: "People & Body", - description: "old man", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ต", - aliases: ["older_woman"], - tags: [], - category: "People & Body", - description: "old woman", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™", - aliases: ["frowning_person"], - tags: [], - category: "People & Body", - description: "person frowning", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™โ€โ™‚๏ธ", - aliases: ["frowning_man"], - tags: [], - category: "People & Body", - description: "man frowning", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™โ€โ™€๏ธ", - aliases: ["frowning_woman"], - tags: [], - category: "People & Body", - description: "woman frowning", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ™Ž", - aliases: ["pouting_face"], - tags: [], - category: "People & Body", - description: "person pouting", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™Žโ€โ™‚๏ธ", - aliases: ["pouting_man"], - tags: [], - category: "People & Body", - description: "man pouting", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™Žโ€โ™€๏ธ", - aliases: ["pouting_woman"], - tags: [], - category: "People & Body", - description: "woman pouting", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ™…", - aliases: ["no_good"], - tags: ["stop", "halt", "denied"], - category: "People & Body", - description: "person gesturing NO", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™…โ€โ™‚๏ธ", - aliases: ["no_good_man", "ng_man"], - tags: ["stop", "halt", "denied"], - category: "People & Body", - description: "man gesturing NO", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™…โ€โ™€๏ธ", - aliases: ["no_good_woman", "ng_woman"], - tags: ["stop", "halt", "denied"], - category: "People & Body", - description: "woman gesturing NO", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ™†", - aliases: ["ok_person"], - tags: [], - category: "People & Body", - description: "person gesturing OK", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™†โ€โ™‚๏ธ", - aliases: ["ok_man"], - tags: [], - category: "People & Body", - description: "man gesturing OK", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™†โ€โ™€๏ธ", - aliases: ["ok_woman"], - tags: [], - category: "People & Body", - description: "woman gesturing OK", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["tipping_hand_person", "information_desk_person"], - tags: [], - category: "People & Body", - description: "person tipping hand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’โ€โ™‚๏ธ", - aliases: ["tipping_hand_man", "sassy_man"], - tags: ["information"], - category: "People & Body", - description: "man tipping hand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’โ€โ™€๏ธ", - aliases: ["tipping_hand_woman", "sassy_woman"], - tags: ["information"], - category: "People & Body", - description: "woman tipping hand", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ™‹", - aliases: ["raising_hand"], - tags: [], - category: "People & Body", - description: "person raising hand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™‹โ€โ™‚๏ธ", - aliases: ["raising_hand_man"], - tags: [], - category: "People & Body", - description: "man raising hand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™‹โ€โ™€๏ธ", - aliases: ["raising_hand_woman"], - tags: [], - category: "People & Body", - description: "woman raising hand", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง", - aliases: ["deaf_person"], - tags: [], - category: "People & Body", - description: "deaf person", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿงโ€โ™‚๏ธ", - aliases: ["deaf_man"], - tags: [], - category: "People & Body", - description: "deaf man", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿงโ€โ™€๏ธ", - aliases: ["deaf_woman"], - tags: [], - category: "People & Body", - description: "deaf woman", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ™‡", - aliases: ["bow"], - tags: ["respect", "thanks"], - category: "People & Body", - description: "person bowing", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™‡โ€โ™‚๏ธ", - aliases: ["bowing_man"], - tags: ["respect", "thanks"], - category: "People & Body", - description: "man bowing", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ™‡โ€โ™€๏ธ", - aliases: ["bowing_woman"], - tags: ["respect", "thanks"], - category: "People & Body", - description: "woman bowing", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคฆ", - aliases: ["facepalm"], - tags: [], - category: "People & Body", - description: "person facepalming", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคฆโ€โ™‚๏ธ", - aliases: ["man_facepalming"], - tags: [], - category: "People & Body", - description: "man facepalming", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคฆโ€โ™€๏ธ", - aliases: ["woman_facepalming"], - tags: [], - category: "People & Body", - description: "woman facepalming", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคท", - aliases: ["shrug"], - tags: [], - category: "People & Body", - description: "person shrugging", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคทโ€โ™‚๏ธ", - aliases: ["man_shrugging"], - tags: [], - category: "People & Body", - description: "man shrugging", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคทโ€โ™€๏ธ", - aliases: ["woman_shrugging"], - tags: [], - category: "People & Body", - description: "woman shrugging", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿง‘โ€โš•๏ธ", - aliases: ["health_worker"], - tags: [], - category: "People & Body", - description: "health worker", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€โš•๏ธ", - aliases: ["man_health_worker"], - tags: ["doctor", "nurse"], - category: "People & Body", - description: "man health worker", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€โš•๏ธ", - aliases: ["woman_health_worker"], - tags: ["doctor", "nurse"], - category: "People & Body", - description: "woman health worker", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐ŸŽ“", - aliases: ["student"], - tags: [], - category: "People & Body", - description: "student", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐ŸŽ“", - aliases: ["man_student"], - tags: ["graduation"], - category: "People & Body", - description: "man student", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐ŸŽ“", - aliases: ["woman_student"], - tags: ["graduation"], - category: "People & Body", - description: "woman student", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿซ", - aliases: ["teacher"], - tags: [], - category: "People & Body", - description: "teacher", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿซ", - aliases: ["man_teacher"], - tags: ["school", "professor"], - category: "People & Body", - description: "man teacher", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿซ", - aliases: ["woman_teacher"], - tags: ["school", "professor"], - category: "People & Body", - description: "woman teacher", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€โš–๏ธ", - aliases: ["judge"], - tags: [], - category: "People & Body", - description: "judge", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€โš–๏ธ", - aliases: ["man_judge"], - tags: ["justice"], - category: "People & Body", - description: "man judge", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€โš–๏ธ", - aliases: ["woman_judge"], - tags: ["justice"], - category: "People & Body", - description: "woman judge", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐ŸŒพ", - aliases: ["farmer"], - tags: [], - category: "People & Body", - description: "farmer", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐ŸŒพ", - aliases: ["man_farmer"], - tags: [], - category: "People & Body", - description: "man farmer", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐ŸŒพ", - aliases: ["woman_farmer"], - tags: [], - category: "People & Body", - description: "woman farmer", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿณ", - aliases: ["cook"], - tags: [], - category: "People & Body", - description: "cook", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿณ", - aliases: ["man_cook"], - tags: ["chef"], - category: "People & Body", - description: "man cook", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿณ", - aliases: ["woman_cook"], - tags: ["chef"], - category: "People & Body", - description: "woman cook", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿ”ง", - aliases: ["mechanic"], - tags: [], - category: "People & Body", - description: "mechanic", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ”ง", - aliases: ["man_mechanic"], - tags: [], - category: "People & Body", - description: "man mechanic", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ”ง", - aliases: ["woman_mechanic"], - tags: [], - category: "People & Body", - description: "woman mechanic", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿญ", - aliases: ["factory_worker"], - tags: [], - category: "People & Body", - description: "factory worker", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿญ", - aliases: ["man_factory_worker"], - tags: [], - category: "People & Body", - description: "man factory worker", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿญ", - aliases: ["woman_factory_worker"], - tags: [], - category: "People & Body", - description: "woman factory worker", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿ’ผ", - aliases: ["office_worker"], - tags: [], - category: "People & Body", - description: "office worker", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ’ผ", - aliases: ["man_office_worker"], - tags: ["business"], - category: "People & Body", - description: "man office worker", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ’ผ", - aliases: ["woman_office_worker"], - tags: ["business"], - category: "People & Body", - description: "woman office worker", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿ”ฌ", - aliases: ["scientist"], - tags: [], - category: "People & Body", - description: "scientist", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ”ฌ", - aliases: ["man_scientist"], - tags: ["research"], - category: "People & Body", - description: "man scientist", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ”ฌ", - aliases: ["woman_scientist"], - tags: ["research"], - category: "People & Body", - description: "woman scientist", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿ’ป", - aliases: ["technologist"], - tags: [], - category: "People & Body", - description: "technologist", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ’ป", - aliases: ["man_technologist"], - tags: ["coder"], - category: "People & Body", - description: "man technologist", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ’ป", - aliases: ["woman_technologist"], - tags: ["coder"], - category: "People & Body", - description: "woman technologist", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐ŸŽค", - aliases: ["singer"], - tags: [], - category: "People & Body", - description: "singer", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐ŸŽค", - aliases: ["man_singer"], - tags: ["rockstar"], - category: "People & Body", - description: "man singer", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐ŸŽค", - aliases: ["woman_singer"], - tags: ["rockstar"], - category: "People & Body", - description: "woman singer", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐ŸŽจ", - aliases: ["artist"], - tags: [], - category: "People & Body", - description: "artist", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐ŸŽจ", - aliases: ["man_artist"], - tags: ["painter"], - category: "People & Body", - description: "man artist", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐ŸŽจ", - aliases: ["woman_artist"], - tags: ["painter"], - category: "People & Body", - description: "woman artist", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€โœˆ๏ธ", - aliases: ["pilot"], - tags: [], - category: "People & Body", - description: "pilot", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€โœˆ๏ธ", - aliases: ["man_pilot"], - tags: [], - category: "People & Body", - description: "man pilot", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€โœˆ๏ธ", - aliases: ["woman_pilot"], - tags: [], - category: "People & Body", - description: "woman pilot", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿš€", - aliases: ["astronaut"], - tags: [], - category: "People & Body", - description: "astronaut", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿš€", - aliases: ["man_astronaut"], - tags: ["space"], - category: "People & Body", - description: "man astronaut", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿš€", - aliases: ["woman_astronaut"], - tags: ["space"], - category: "People & Body", - description: "woman astronaut", - unicode_version: "", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿš’", - aliases: ["firefighter"], - tags: [], - category: "People & Body", - description: "firefighter", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿš’", - aliases: ["man_firefighter"], - tags: [], - category: "People & Body", - description: "man firefighter", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿš’", - aliases: ["woman_firefighter"], - tags: [], - category: "People & Body", - description: "woman firefighter", - unicode_version: "", - }, - { - emoji: "๐Ÿ‘ฎ", - aliases: ["police_officer", "cop"], - tags: ["law"], - category: "People & Body", - description: "police officer", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฎโ€โ™‚๏ธ", - aliases: ["policeman"], - tags: ["law", "cop"], - category: "People & Body", - description: "man police officer", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ฎโ€โ™€๏ธ", - aliases: ["policewoman"], - tags: ["law", "cop"], - category: "People & Body", - description: "woman police officer", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ต๏ธ", - aliases: ["detective"], - tags: ["sleuth"], - category: "People & Body", - description: "detective", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ•ต๏ธโ€โ™‚๏ธ", - aliases: ["male_detective"], - tags: ["sleuth"], - category: "People & Body", - description: "man detective", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ•ต๏ธโ€โ™€๏ธ", - aliases: ["female_detective"], - tags: ["sleuth"], - category: "People & Body", - description: "woman detective", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‚", - aliases: ["guard"], - tags: [], - category: "People & Body", - description: "guard", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‚โ€โ™‚๏ธ", - aliases: ["guardsman"], - tags: [], - category: "People & Body", - description: "man guard", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’‚โ€โ™€๏ธ", - aliases: ["guardswoman"], - tags: [], - category: "People & Body", - description: "woman guard", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅท", - aliases: ["ninja"], - tags: [], - category: "People & Body", - description: "ninja", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘ท", - aliases: ["construction_worker"], - tags: ["helmet"], - category: "People & Body", - description: "construction worker", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ทโ€โ™‚๏ธ", - aliases: ["construction_worker_man"], - tags: ["helmet"], - category: "People & Body", - description: "man construction worker", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ทโ€โ™€๏ธ", - aliases: ["construction_worker_woman"], - tags: ["helmet"], - category: "People & Body", - description: "woman construction worker", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคด", - aliases: ["prince"], - tags: ["crown", "royal"], - category: "People & Body", - description: "prince", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ‘ธ", - aliases: ["princess"], - tags: ["crown", "royal"], - category: "People & Body", - description: "princess", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ณ", - aliases: ["person_with_turban"], - tags: [], - category: "People & Body", - description: "person wearing turban", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ณโ€โ™‚๏ธ", - aliases: ["man_with_turban"], - tags: [], - category: "People & Body", - description: "man wearing turban", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ณโ€โ™€๏ธ", - aliases: ["woman_with_turban"], - tags: [], - category: "People & Body", - description: "woman wearing turban", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฒ", - aliases: ["man_with_gua_pi_mao"], - tags: [], - category: "People & Body", - description: "person with skullcap", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง•", - aliases: ["woman_with_headscarf"], - tags: ["hijab"], - category: "People & Body", - description: "woman with headscarf", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคต", - aliases: ["person_in_tuxedo"], - tags: ["groom", "marriage", "wedding"], - category: "People & Body", - description: "person in tuxedo", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคตโ€โ™‚๏ธ", - aliases: ["man_in_tuxedo"], - tags: [], - category: "People & Body", - description: "man in tuxedo", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿคตโ€โ™€๏ธ", - aliases: ["woman_in_tuxedo"], - tags: [], - category: "People & Body", - description: "woman in tuxedo", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘ฐ", - aliases: ["person_with_veil"], - tags: ["marriage", "wedding"], - category: "People & Body", - description: "person with veil", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฐโ€โ™‚๏ธ", - aliases: ["man_with_veil"], - tags: [], - category: "People & Body", - description: "man with veil", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘ฐโ€โ™€๏ธ", - aliases: ["woman_with_veil", "bride_with_veil"], - tags: [], - category: "People & Body", - description: "woman with veil", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿคฐ", - aliases: ["pregnant_woman"], - tags: [], - category: "People & Body", - description: "pregnant woman", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคฑ", - aliases: ["breast_feeding"], - tags: ["nursing"], - category: "People & Body", - description: "breast-feeding", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿผ", - aliases: ["woman_feeding_baby"], - tags: [], - category: "People & Body", - description: "woman feeding baby", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿผ", - aliases: ["man_feeding_baby"], - tags: [], - category: "People & Body", - description: "man feeding baby", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿผ", - aliases: ["person_feeding_baby"], - tags: [], - category: "People & Body", - description: "person feeding baby", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘ผ", - aliases: ["angel"], - tags: [], - category: "People & Body", - description: "baby angel", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ…", - aliases: ["santa"], - tags: ["christmas"], - category: "People & Body", - description: "Santa Claus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคถ", - aliases: ["mrs_claus"], - tags: ["santa"], - category: "People & Body", - description: "Mrs. Claus", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿง‘โ€๐ŸŽ„", - aliases: ["mx_claus"], - tags: [], - category: "People & Body", - description: "mx claus", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆธ", - aliases: ["superhero"], - tags: [], - category: "People & Body", - description: "superhero", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆธโ€โ™‚๏ธ", - aliases: ["superhero_man"], - tags: [], - category: "People & Body", - description: "man superhero", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆธโ€โ™€๏ธ", - aliases: ["superhero_woman"], - tags: [], - category: "People & Body", - description: "woman superhero", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆน", - aliases: ["supervillain"], - tags: [], - category: "People & Body", - description: "supervillain", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆนโ€โ™‚๏ธ", - aliases: ["supervillain_man"], - tags: [], - category: "People & Body", - description: "man supervillain", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆนโ€โ™€๏ธ", - aliases: ["supervillain_woman"], - tags: [], - category: "People & Body", - description: "woman supervillain", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง™", - aliases: ["mage"], - tags: ["wizard"], - category: "People & Body", - description: "mage", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง™โ€โ™‚๏ธ", - aliases: ["mage_man"], - tags: ["wizard"], - category: "People & Body", - description: "man mage", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง™โ€โ™€๏ธ", - aliases: ["mage_woman"], - tags: ["wizard"], - category: "People & Body", - description: "woman mage", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงš", - aliases: ["fairy"], - tags: [], - category: "People & Body", - description: "fairy", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงšโ€โ™‚๏ธ", - aliases: ["fairy_man"], - tags: [], - category: "People & Body", - description: "man fairy", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงšโ€โ™€๏ธ", - aliases: ["fairy_woman"], - tags: [], - category: "People & Body", - description: "woman fairy", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง›", - aliases: ["vampire"], - tags: [], - category: "People & Body", - description: "vampire", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง›โ€โ™‚๏ธ", - aliases: ["vampire_man"], - tags: [], - category: "People & Body", - description: "man vampire", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง›โ€โ™€๏ธ", - aliases: ["vampire_woman"], - tags: [], - category: "People & Body", - description: "woman vampire", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงœ", - aliases: ["merperson"], - tags: [], - category: "People & Body", - description: "merperson", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงœโ€โ™‚๏ธ", - aliases: ["merman"], - tags: [], - category: "People & Body", - description: "merman", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงœโ€โ™€๏ธ", - aliases: ["mermaid"], - tags: [], - category: "People & Body", - description: "mermaid", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง", - aliases: ["elf"], - tags: [], - category: "People & Body", - description: "elf", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงโ€โ™‚๏ธ", - aliases: ["elf_man"], - tags: [], - category: "People & Body", - description: "man elf", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงโ€โ™€๏ธ", - aliases: ["elf_woman"], - tags: [], - category: "People & Body", - description: "woman elf", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงž", - aliases: ["genie"], - tags: [], - category: "People & Body", - description: "genie", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงžโ€โ™‚๏ธ", - aliases: ["genie_man"], - tags: [], - category: "People & Body", - description: "man genie", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงžโ€โ™€๏ธ", - aliases: ["genie_woman"], - tags: [], - category: "People & Body", - description: "woman genie", - unicode_version: "11.0", - }, - { - emoji: "๐ŸงŸ", - aliases: ["zombie"], - tags: [], - category: "People & Body", - description: "zombie", - unicode_version: "11.0", - }, - { - emoji: "๐ŸงŸโ€โ™‚๏ธ", - aliases: ["zombie_man"], - tags: [], - category: "People & Body", - description: "man zombie", - unicode_version: "11.0", - }, - { - emoji: "๐ŸงŸโ€โ™€๏ธ", - aliases: ["zombie_woman"], - tags: [], - category: "People & Body", - description: "woman zombie", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’†", - aliases: ["massage"], - tags: ["spa"], - category: "People & Body", - description: "person getting massage", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’†โ€โ™‚๏ธ", - aliases: ["massage_man"], - tags: ["spa"], - category: "People & Body", - description: "man getting massage", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’†โ€โ™€๏ธ", - aliases: ["massage_woman"], - tags: ["spa"], - category: "People & Body", - description: "woman getting massage", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’‡", - aliases: ["haircut"], - tags: ["beauty"], - category: "People & Body", - description: "person getting haircut", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‡โ€โ™‚๏ธ", - aliases: ["haircut_man"], - tags: [], - category: "People & Body", - description: "man getting haircut", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‡โ€โ™€๏ธ", - aliases: ["haircut_woman"], - tags: [], - category: "People & Body", - description: "woman getting haircut", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿšถ", - aliases: ["walking"], - tags: [], - category: "People & Body", - description: "person walking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšถโ€โ™‚๏ธ", - aliases: ["walking_man"], - tags: [], - category: "People & Body", - description: "man walking", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿšถโ€โ™€๏ธ", - aliases: ["walking_woman"], - tags: [], - category: "People & Body", - description: "woman walking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง", - aliases: ["standing_person"], - tags: [], - category: "People & Body", - description: "person standing", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿงโ€โ™‚๏ธ", - aliases: ["standing_man"], - tags: [], - category: "People & Body", - description: "man standing", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿงโ€โ™€๏ธ", - aliases: ["standing_woman"], - tags: [], - category: "People & Body", - description: "woman standing", - unicode_version: "12.0", - }, - { - emoji: "๐ŸงŽ", - aliases: ["kneeling_person"], - tags: [], - category: "People & Body", - description: "person kneeling", - unicode_version: "12.0", - }, - { - emoji: "๐ŸงŽโ€โ™‚๏ธ", - aliases: ["kneeling_man"], - tags: [], - category: "People & Body", - description: "man kneeling", - unicode_version: "12.0", - }, - { - emoji: "๐ŸงŽโ€โ™€๏ธ", - aliases: ["kneeling_woman"], - tags: [], - category: "People & Body", - description: "woman kneeling", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆฏ", - aliases: ["person_with_probing_cane"], - tags: [], - category: "People & Body", - description: "person with white cane", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆฏ", - aliases: ["man_with_probing_cane"], - tags: [], - category: "People & Body", - description: "man with white cane", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆฏ", - aliases: ["woman_with_probing_cane"], - tags: [], - category: "People & Body", - description: "woman with white cane", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆผ", - aliases: ["person_in_motorized_wheelchair"], - tags: [], - category: "People & Body", - description: "person in motorized wheelchair", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆผ", - aliases: ["man_in_motorized_wheelchair"], - tags: [], - category: "People & Body", - description: "man in motorized wheelchair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆผ", - aliases: ["woman_in_motorized_wheelchair"], - tags: [], - category: "People & Body", - description: "woman in motorized wheelchair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿฆฝ", - aliases: ["person_in_manual_wheelchair"], - tags: [], - category: "People & Body", - description: "person in manual wheelchair", - unicode_version: "12.1", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿฆฝ", - aliases: ["man_in_manual_wheelchair"], - tags: [], - category: "People & Body", - description: "man in manual wheelchair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿฆฝ", - aliases: ["woman_in_manual_wheelchair"], - tags: [], - category: "People & Body", - description: "woman in manual wheelchair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿƒ", - aliases: ["runner", "running"], - tags: ["exercise", "workout", "marathon"], - category: "People & Body", - description: "person running", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿƒโ€โ™‚๏ธ", - aliases: ["running_man"], - tags: ["exercise", "workout", "marathon"], - category: "People & Body", - description: "man running", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿƒโ€โ™€๏ธ", - aliases: ["running_woman"], - tags: ["exercise", "workout", "marathon"], - category: "People & Body", - description: "woman running", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ƒ", - aliases: ["woman_dancing", "dancer"], - tags: ["dress"], - category: "People & Body", - description: "woman dancing", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•บ", - aliases: ["man_dancing"], - tags: ["dancer"], - category: "People & Body", - description: "man dancing", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ•ด๏ธ", - aliases: ["business_suit_levitating"], - tags: [], - category: "People & Body", - description: "person in suit levitating", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‘ฏ", - aliases: ["dancers"], - tags: ["bunny"], - category: "People & Body", - description: "people with bunny ears", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฏโ€โ™‚๏ธ", - aliases: ["dancing_men"], - tags: ["bunny"], - category: "People & Body", - description: "men with bunny ears", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฏโ€โ™€๏ธ", - aliases: ["dancing_women"], - tags: ["bunny"], - category: "People & Body", - description: "women with bunny ears", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง–", - aliases: ["sauna_person"], - tags: ["steamy"], - category: "People & Body", - description: "person in steamy room", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง–โ€โ™‚๏ธ", - aliases: ["sauna_man"], - tags: ["steamy"], - category: "People & Body", - description: "man in steamy room", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง–โ€โ™€๏ธ", - aliases: ["sauna_woman"], - tags: ["steamy"], - category: "People & Body", - description: "woman in steamy room", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง—", - aliases: ["climbing"], - tags: ["bouldering"], - category: "People & Body", - description: "person climbing", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง—โ€โ™‚๏ธ", - aliases: ["climbing_man"], - tags: ["bouldering"], - category: "People & Body", - description: "man climbing", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง—โ€โ™€๏ธ", - aliases: ["climbing_woman"], - tags: ["bouldering"], - category: "People & Body", - description: "woman climbing", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคบ", - aliases: ["person_fencing"], - tags: [], - category: "People & Body", - description: "person fencing", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ‡", - aliases: ["horse_racing"], - tags: [], - category: "People & Body", - description: "horse racing", - unicode_version: "6.0", - }, - { - emoji: "โ›ท๏ธ", - aliases: ["skier"], - tags: [], - category: "People & Body", - description: "skier", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ‚", - aliases: ["snowboarder"], - tags: [], - category: "People & Body", - description: "snowboarder", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ๏ธ", - aliases: ["golfing"], - tags: [], - category: "People & Body", - description: "person golfing", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒ๏ธโ€โ™‚๏ธ", - aliases: ["golfing_man"], - tags: [], - category: "People & Body", - description: "man golfing", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŒ๏ธโ€โ™€๏ธ", - aliases: ["golfing_woman"], - tags: [], - category: "People & Body", - description: "woman golfing", - unicode_version: "", - }, - { - emoji: "๐Ÿ„", - aliases: ["surfer"], - tags: [], - category: "People & Body", - description: "person surfing", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ„โ€โ™‚๏ธ", - aliases: ["surfing_man"], - tags: [], - category: "People & Body", - description: "man surfing", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ„โ€โ™€๏ธ", - aliases: ["surfing_woman"], - tags: [], - category: "People & Body", - description: "woman surfing", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿšฃ", - aliases: ["rowboat"], - tags: [], - category: "People & Body", - description: "person rowing boat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฃโ€โ™‚๏ธ", - aliases: ["rowing_man"], - tags: [], - category: "People & Body", - description: "man rowing boat", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿšฃโ€โ™€๏ธ", - aliases: ["rowing_woman"], - tags: [], - category: "People & Body", - description: "woman rowing boat", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŠ", - aliases: ["swimmer"], - tags: [], - category: "People & Body", - description: "person swimming", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŠโ€โ™‚๏ธ", - aliases: ["swimming_man"], - tags: [], - category: "People & Body", - description: "man swimming", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŠโ€โ™€๏ธ", - aliases: ["swimming_woman"], - tags: [], - category: "People & Body", - description: "woman swimming", - unicode_version: "6.0", - }, - { - emoji: "โ›น๏ธ", - aliases: ["bouncing_ball_person"], - tags: ["basketball"], - category: "People & Body", - description: "person bouncing ball", - unicode_version: "5.2", - }, - { - emoji: "โ›น๏ธโ€โ™‚๏ธ", - aliases: ["bouncing_ball_man", "basketball_man"], - tags: [], - category: "People & Body", - description: "man bouncing ball", - unicode_version: "11.0", - }, - { - emoji: "โ›น๏ธโ€โ™€๏ธ", - aliases: ["bouncing_ball_woman", "basketball_woman"], - tags: [], - category: "People & Body", - description: "woman bouncing ball", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‹๏ธ", - aliases: ["weight_lifting"], - tags: ["gym", "workout"], - category: "People & Body", - description: "person lifting weights", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‹๏ธโ€โ™‚๏ธ", - aliases: ["weight_lifting_man"], - tags: ["gym", "workout"], - category: "People & Body", - description: "man lifting weights", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‹๏ธโ€โ™€๏ธ", - aliases: ["weight_lifting_woman"], - tags: ["gym", "workout"], - category: "People & Body", - description: "woman lifting weights", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšด", - aliases: ["bicyclist"], - tags: [], - category: "People & Body", - description: "person biking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšดโ€โ™‚๏ธ", - aliases: ["biking_man"], - tags: [], - category: "People & Body", - description: "man biking", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿšดโ€โ™€๏ธ", - aliases: ["biking_woman"], - tags: [], - category: "People & Body", - description: "woman biking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšต", - aliases: ["mountain_bicyclist"], - tags: [], - category: "People & Body", - description: "person mountain biking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšตโ€โ™‚๏ธ", - aliases: ["mountain_biking_man"], - tags: [], - category: "People & Body", - description: "man mountain biking", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿšตโ€โ™€๏ธ", - aliases: ["mountain_biking_woman"], - tags: [], - category: "People & Body", - description: "woman mountain biking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคธ", - aliases: ["cartwheeling"], - tags: [], - category: "People & Body", - description: "person cartwheeling", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคธโ€โ™‚๏ธ", - aliases: ["man_cartwheeling"], - tags: [], - category: "People & Body", - description: "man cartwheeling", - unicode_version: "", - }, - { - emoji: "๐Ÿคธโ€โ™€๏ธ", - aliases: ["woman_cartwheeling"], - tags: [], - category: "People & Body", - description: "woman cartwheeling", - unicode_version: "", - }, - { - emoji: "๐Ÿคผ", - aliases: ["wrestling"], - tags: [], - category: "People & Body", - description: "people wrestling", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคผโ€โ™‚๏ธ", - aliases: ["men_wrestling"], - tags: [], - category: "People & Body", - description: "men wrestling", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคผโ€โ™€๏ธ", - aliases: ["women_wrestling"], - tags: [], - category: "People & Body", - description: "women wrestling", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคฝ", - aliases: ["water_polo"], - tags: [], - category: "People & Body", - description: "person playing water polo", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคฝโ€โ™‚๏ธ", - aliases: ["man_playing_water_polo"], - tags: [], - category: "People & Body", - description: "man playing water polo", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคฝโ€โ™€๏ธ", - aliases: ["woman_playing_water_polo"], - tags: [], - category: "People & Body", - description: "woman playing water polo", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคพ", - aliases: ["handball_person"], - tags: [], - category: "People & Body", - description: "person playing handball", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคพโ€โ™‚๏ธ", - aliases: ["man_playing_handball"], - tags: [], - category: "People & Body", - description: "man playing handball", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคพโ€โ™€๏ธ", - aliases: ["woman_playing_handball"], - tags: [], - category: "People & Body", - description: "woman playing handball", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคน", - aliases: ["juggling_person"], - tags: [], - category: "People & Body", - description: "person juggling", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿคนโ€โ™‚๏ธ", - aliases: ["man_juggling"], - tags: [], - category: "People & Body", - description: "man juggling", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿคนโ€โ™€๏ธ", - aliases: ["woman_juggling"], - tags: [], - category: "People & Body", - description: "woman juggling", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿง˜", - aliases: ["lotus_position"], - tags: ["meditation"], - category: "People & Body", - description: "person in lotus position", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง˜โ€โ™‚๏ธ", - aliases: ["lotus_position_man"], - tags: ["meditation"], - category: "People & Body", - description: "man in lotus position", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง˜โ€โ™€๏ธ", - aliases: ["lotus_position_woman"], - tags: ["meditation"], - category: "People & Body", - description: "woman in lotus position", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ›€", - aliases: ["bath"], - tags: ["shower"], - category: "People & Body", - description: "person taking bath", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›Œ", - aliases: ["sleeping_bed"], - tags: [], - category: "People & Body", - description: "person in bed", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘", - aliases: ["people_holding_hands"], - tags: ["couple", "date"], - category: "People & Body", - description: "people holding hands", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘ญ", - aliases: ["two_women_holding_hands"], - tags: ["couple", "date"], - category: "People & Body", - description: "women holding hands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ซ", - aliases: ["couple"], - tags: ["date"], - category: "People & Body", - description: "woman and man holding hands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฌ", - aliases: ["two_men_holding_hands"], - tags: ["couple", "date"], - category: "People & Body", - description: "men holding hands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["couplekiss"], - tags: [], - category: "People & Body", - description: "kiss", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", - aliases: ["couplekiss_man_woman"], - tags: [], - category: "People & Body", - description: "kiss: woman, man", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ", - aliases: ["couplekiss_man_man"], - tags: [], - category: "People & Body", - description: "kiss: man, man", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ", - aliases: ["couplekiss_woman_woman"], - tags: [], - category: "People & Body", - description: "kiss: woman, woman", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‘", - aliases: ["couple_with_heart"], - tags: [], - category: "People & Body", - description: "couple with heart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ", - aliases: ["couple_with_heart_woman_man"], - tags: [], - category: "People & Body", - description: "couple with heart: woman, man", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ", - aliases: ["couple_with_heart_man_man"], - tags: [], - category: "People & Body", - description: "couple with heart: man, man", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ", - aliases: ["couple_with_heart_woman_woman"], - tags: [], - category: "People & Body", - description: "couple with heart: woman, woman", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ช", - aliases: ["family"], - tags: ["home", "parents", "child"], - category: "People & Body", - description: "family", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ", - aliases: ["family_man_woman_boy"], - tags: [], - category: "People & Body", - description: "family: man, woman, boy", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง", - aliases: ["family_man_woman_girl"], - tags: [], - category: "People & Body", - description: "family: man, woman, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ", - aliases: ["family_man_woman_girl_boy"], - tags: [], - category: "People & Body", - description: "family: man, woman, girl, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ", - aliases: ["family_man_woman_boy_boy"], - tags: [], - category: "People & Body", - description: "family: man, woman, boy, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง", - aliases: ["family_man_woman_girl_girl"], - tags: [], - category: "People & Body", - description: "family: man, woman, girl, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ", - aliases: ["family_man_man_boy"], - tags: [], - category: "People & Body", - description: "family: man, man, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง", - aliases: ["family_man_man_girl"], - tags: [], - category: "People & Body", - description: "family: man, man, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ", - aliases: ["family_man_man_girl_boy"], - tags: [], - category: "People & Body", - description: "family: man, man, girl, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ", - aliases: ["family_man_man_boy_boy"], - tags: [], - category: "People & Body", - description: "family: man, man, boy, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง", - aliases: ["family_man_man_girl_girl"], - tags: [], - category: "People & Body", - description: "family: man, man, girl, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ", - aliases: ["family_woman_woman_boy"], - tags: [], - category: "People & Body", - description: "family: woman, woman, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง", - aliases: ["family_woman_woman_girl"], - tags: [], - category: "People & Body", - description: "family: woman, woman, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ", - aliases: ["family_woman_woman_girl_boy"], - tags: [], - category: "People & Body", - description: "family: woman, woman, girl, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ", - aliases: ["family_woman_woman_boy_boy"], - tags: [], - category: "People & Body", - description: "family: woman, woman, boy, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง", - aliases: ["family_woman_woman_girl_girl"], - tags: [], - category: "People & Body", - description: "family: woman, woman, girl, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฆ", - aliases: ["family_man_boy"], - tags: [], - category: "People & Body", - description: "family: man, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ", - aliases: ["family_man_boy_boy"], - tags: [], - category: "People & Body", - description: "family: man, boy, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘ง", - aliases: ["family_man_girl"], - tags: [], - category: "People & Body", - description: "family: man, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ", - aliases: ["family_man_girl_boy"], - tags: [], - category: "People & Body", - description: "family: man, girl, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง", - aliases: ["family_man_girl_girl"], - tags: [], - category: "People & Body", - description: "family: man, girl, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฆ", - aliases: ["family_woman_boy"], - tags: [], - category: "People & Body", - description: "family: woman, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ", - aliases: ["family_woman_boy_boy"], - tags: [], - category: "People & Body", - description: "family: woman, boy, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘ง", - aliases: ["family_woman_girl"], - tags: [], - category: "People & Body", - description: "family: woman, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ", - aliases: ["family_woman_girl_boy"], - tags: [], - category: "People & Body", - description: "family: woman, girl, boy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง", - aliases: ["family_woman_girl_girl"], - tags: [], - category: "People & Body", - description: "family: woman, girl, girl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—ฃ๏ธ", - aliases: ["speaking_head"], - tags: [], - category: "People & Body", - description: "speaking head", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ‘ค", - aliases: ["bust_in_silhouette"], - tags: ["user"], - category: "People & Body", - description: "bust in silhouette", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ฅ", - aliases: ["busts_in_silhouette"], - tags: ["users", "group", "team"], - category: "People & Body", - description: "busts in silhouette", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿซ‚", - aliases: ["people_hugging"], - tags: [], - category: "People & Body", - description: "people hugging", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘ฃ", - aliases: ["footprints"], - tags: ["feet", "tracks"], - category: "People & Body", - description: "footprints", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿต", - aliases: ["monkey_face"], - tags: [], - category: "Animals & Nature", - description: "monkey face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["monkey"], - tags: [], - category: "Animals & Nature", - description: "monkey", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["gorilla"], - tags: [], - category: "Animals & Nature", - description: "gorilla", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆง", - aliases: ["orangutan"], - tags: [], - category: "Animals & Nature", - description: "orangutan", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿถ", - aliases: ["dog"], - tags: ["pet"], - category: "Animals & Nature", - description: "dog face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•", - aliases: ["dog2"], - tags: [], - category: "Animals & Nature", - description: "dog", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆฎ", - aliases: ["guide_dog"], - tags: [], - category: "Animals & Nature", - description: "guide dog", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ•โ€๐Ÿฆบ", - aliases: ["service_dog"], - tags: [], - category: "Animals & Nature", - description: "service dog", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฉ", - aliases: ["poodle"], - tags: ["dog"], - category: "Animals & Nature", - description: "poodle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿบ", - aliases: ["wolf"], - tags: [], - category: "Animals & Nature", - description: "wolf", - unicode_version: "6.0", - }, - { - emoji: "๐ŸฆŠ", - aliases: ["fox_face"], - tags: [], - category: "Animals & Nature", - description: "fox", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["raccoon"], - tags: [], - category: "Animals & Nature", - description: "raccoon", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฑ", - aliases: ["cat"], - tags: ["pet"], - category: "Animals & Nature", - description: "cat face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆ", - aliases: ["cat2"], - tags: [], - category: "Animals & Nature", - description: "cat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆโ€โฌ›", - aliases: ["black_cat"], - tags: [], - category: "Animals & Nature", - description: "black cat", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["lion"], - tags: [], - category: "Animals & Nature", - description: "lion", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿฏ", - aliases: ["tiger"], - tags: [], - category: "Animals & Nature", - description: "tiger face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ…", - aliases: ["tiger2"], - tags: [], - category: "Animals & Nature", - description: "tiger", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†", - aliases: ["leopard"], - tags: [], - category: "Animals & Nature", - description: "leopard", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿด", - aliases: ["horse"], - tags: [], - category: "Animals & Nature", - description: "horse face", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ", - aliases: ["racehorse"], - tags: ["speed"], - category: "Animals & Nature", - description: "horse", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ„", - aliases: ["unicorn"], - tags: [], - category: "Animals & Nature", - description: "unicorn", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿฆ“", - aliases: ["zebra"], - tags: [], - category: "Animals & Nature", - description: "zebra", - unicode_version: "11.0", - }, - { - emoji: "๐ŸฆŒ", - aliases: ["deer"], - tags: [], - category: "Animals & Nature", - description: "deer", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆฌ", - aliases: ["bison"], - tags: [], - category: "Animals & Nature", - description: "bison", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฎ", - aliases: ["cow"], - tags: [], - category: "Animals & Nature", - description: "cow face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‚", - aliases: ["ox"], - tags: [], - category: "Animals & Nature", - description: "ox", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿƒ", - aliases: ["water_buffalo"], - tags: [], - category: "Animals & Nature", - description: "water buffalo", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ„", - aliases: ["cow2"], - tags: [], - category: "Animals & Nature", - description: "cow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿท", - aliases: ["pig"], - tags: [], - category: "Animals & Nature", - description: "pig face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ–", - aliases: ["pig2"], - tags: [], - category: "Animals & Nature", - description: "pig", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—", - aliases: ["boar"], - tags: [], - category: "Animals & Nature", - description: "boar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฝ", - aliases: ["pig_nose"], - tags: [], - category: "Animals & Nature", - description: "pig nose", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["ram"], - tags: [], - category: "Animals & Nature", - description: "ram", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘", - aliases: ["sheep"], - tags: [], - category: "Animals & Nature", - description: "ewe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["goat"], - tags: [], - category: "Animals & Nature", - description: "goat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช", - aliases: ["dromedary_camel"], - tags: ["desert"], - category: "Animals & Nature", - description: "camel", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿซ", - aliases: ["camel"], - tags: [], - category: "Animals & Nature", - description: "two-hump camel", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ™", - aliases: ["llama"], - tags: [], - category: "Animals & Nature", - description: "llama", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆ’", - aliases: ["giraffe"], - tags: [], - category: "Animals & Nature", - description: "giraffe", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ˜", - aliases: ["elephant"], - tags: [], - category: "Animals & Nature", - description: "elephant", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆฃ", - aliases: ["mammoth"], - tags: [], - category: "Animals & Nature", - description: "mammoth", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["rhinoceros"], - tags: [], - category: "Animals & Nature", - description: "rhinoceros", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆ›", - aliases: ["hippopotamus"], - tags: [], - category: "Animals & Nature", - description: "hippopotamus", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿญ", - aliases: ["mouse"], - tags: [], - category: "Animals & Nature", - description: "mouse face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["mouse2"], - tags: [], - category: "Animals & Nature", - description: "mouse", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ€", - aliases: ["rat"], - tags: [], - category: "Animals & Nature", - description: "rat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿน", - aliases: ["hamster"], - tags: ["pet"], - category: "Animals & Nature", - description: "hamster", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฐ", - aliases: ["rabbit"], - tags: ["bunny"], - category: "Animals & Nature", - description: "rabbit face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡", - aliases: ["rabbit2"], - tags: [], - category: "Animals & Nature", - description: "rabbit", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฟ๏ธ", - aliases: ["chipmunk"], - tags: [], - category: "Animals & Nature", - description: "chipmunk", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿฆซ", - aliases: ["beaver"], - tags: [], - category: "Animals & Nature", - description: "beaver", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆ”", - aliases: ["hedgehog"], - tags: [], - category: "Animals & Nature", - description: "hedgehog", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆ‡", - aliases: ["bat"], - tags: [], - category: "Animals & Nature", - description: "bat", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿป", - aliases: ["bear"], - tags: [], - category: "Animals & Nature", - description: "bear", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿปโ€โ„๏ธ", - aliases: ["polar_bear"], - tags: [], - category: "Animals & Nature", - description: "polar bear", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿจ", - aliases: ["koala"], - tags: [], - category: "Animals & Nature", - description: "koala", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿผ", - aliases: ["panda_face"], - tags: [], - category: "Animals & Nature", - description: "panda", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆฅ", - aliases: ["sloth"], - tags: [], - category: "Animals & Nature", - description: "sloth", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆฆ", - aliases: ["otter"], - tags: [], - category: "Animals & Nature", - description: "otter", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆจ", - aliases: ["skunk"], - tags: [], - category: "Animals & Nature", - description: "skunk", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆ˜", - aliases: ["kangaroo"], - tags: [], - category: "Animals & Nature", - description: "kangaroo", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆก", - aliases: ["badger"], - tags: [], - category: "Animals & Nature", - description: "badger", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿพ", - aliases: ["feet", "paw_prints"], - tags: [], - category: "Animals & Nature", - description: "paw prints", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆƒ", - aliases: ["turkey"], - tags: ["thanksgiving"], - category: "Animals & Nature", - description: "turkey", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["chicken"], - tags: [], - category: "Animals & Nature", - description: "chicken", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["rooster"], - tags: [], - category: "Animals & Nature", - description: "rooster", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฃ", - aliases: ["hatching_chick"], - tags: [], - category: "Animals & Nature", - description: "hatching chick", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค", - aliases: ["baby_chick"], - tags: [], - category: "Animals & Nature", - description: "baby chick", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["hatched_chick"], - tags: [], - category: "Animals & Nature", - description: "front-facing baby chick", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["bird"], - tags: [], - category: "Animals & Nature", - description: "bird", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง", - aliases: ["penguin"], - tags: [], - category: "Animals & Nature", - description: "penguin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•Š๏ธ", - aliases: ["dove"], - tags: ["peace"], - category: "Animals & Nature", - description: "dove", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿฆ…", - aliases: ["eagle"], - tags: [], - category: "Animals & Nature", - description: "eagle", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆ†", - aliases: ["duck"], - tags: [], - category: "Animals & Nature", - description: "duck", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆข", - aliases: ["swan"], - tags: [], - category: "Animals & Nature", - description: "swan", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆ‰", - aliases: ["owl"], - tags: [], - category: "Animals & Nature", - description: "owl", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆค", - aliases: ["dodo"], - tags: [], - category: "Animals & Nature", - description: "dodo", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿชถ", - aliases: ["feather"], - tags: [], - category: "Animals & Nature", - description: "feather", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆฉ", - aliases: ["flamingo"], - tags: [], - category: "Animals & Nature", - description: "flamingo", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆš", - aliases: ["peacock"], - tags: [], - category: "Animals & Nature", - description: "peacock", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆœ", - aliases: ["parrot"], - tags: [], - category: "Animals & Nature", - description: "parrot", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿธ", - aliases: ["frog"], - tags: [], - category: "Animals & Nature", - description: "frog", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŠ", - aliases: ["crocodile"], - tags: [], - category: "Animals & Nature", - description: "crocodile", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿข", - aliases: ["turtle"], - tags: ["slow"], - category: "Animals & Nature", - description: "turtle", - unicode_version: "6.0", - }, - { - emoji: "๐ŸฆŽ", - aliases: ["lizard"], - tags: [], - category: "Animals & Nature", - description: "lizard", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ", - aliases: ["snake"], - tags: [], - category: "Animals & Nature", - description: "snake", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฒ", - aliases: ["dragon_face"], - tags: [], - category: "Animals & Nature", - description: "dragon face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‰", - aliases: ["dragon"], - tags: [], - category: "Animals & Nature", - description: "dragon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ•", - aliases: ["sauropod"], - tags: ["dinosaur"], - category: "Animals & Nature", - description: "sauropod", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆ–", - aliases: ["t-rex"], - tags: ["dinosaur"], - category: "Animals & Nature", - description: "T-Rex", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿณ", - aliases: ["whale"], - tags: ["sea"], - category: "Animals & Nature", - description: "spouting whale", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‹", - aliases: ["whale2"], - tags: [], - category: "Animals & Nature", - description: "whale", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฌ", - aliases: ["dolphin", "flipper"], - tags: [], - category: "Animals & Nature", - description: "dolphin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆญ", - aliases: ["seal"], - tags: [], - category: "Animals & Nature", - description: "seal", - unicode_version: "13.0", - }, - { - emoji: "๐ŸŸ", - aliases: ["fish"], - tags: [], - category: "Animals & Nature", - description: "fish", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ ", - aliases: ["tropical_fish"], - tags: [], - category: "Animals & Nature", - description: "tropical fish", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿก", - aliases: ["blowfish"], - tags: [], - category: "Animals & Nature", - description: "blowfish", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆˆ", - aliases: ["shark"], - tags: [], - category: "Animals & Nature", - description: "shark", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ™", - aliases: ["octopus"], - tags: [], - category: "Animals & Nature", - description: "octopus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš", - aliases: ["shell"], - tags: ["sea", "beach"], - category: "Animals & Nature", - description: "spiral shell", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ", - aliases: ["snail"], - tags: ["slow"], - category: "Animals & Nature", - description: "snail", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ‹", - aliases: ["butterfly"], - tags: [], - category: "Animals & Nature", - description: "butterfly", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ›", - aliases: ["bug"], - tags: [], - category: "Animals & Nature", - description: "bug", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿœ", - aliases: ["ant"], - tags: [], - category: "Animals & Nature", - description: "ant", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["bee", "honeybee"], - tags: [], - category: "Animals & Nature", - description: "honeybee", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿชฒ", - aliases: ["beetle"], - tags: [], - category: "Animals & Nature", - description: "beetle", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿž", - aliases: ["lady_beetle"], - tags: ["bug"], - category: "Animals & Nature", - description: "lady beetle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ—", - aliases: ["cricket"], - tags: [], - category: "Animals & Nature", - description: "cricket", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชณ", - aliases: ["cockroach"], - tags: [], - category: "Animals & Nature", - description: "cockroach", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ•ท๏ธ", - aliases: ["spider"], - tags: [], - category: "Animals & Nature", - description: "spider", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ•ธ๏ธ", - aliases: ["spider_web"], - tags: [], - category: "Animals & Nature", - description: "spider web", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿฆ‚", - aliases: ["scorpion"], - tags: [], - category: "Animals & Nature", - description: "scorpion", - unicode_version: "8.0", - }, - { - emoji: "๐ŸฆŸ", - aliases: ["mosquito"], - tags: [], - category: "Animals & Nature", - description: "mosquito", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชฐ", - aliases: ["fly"], - tags: [], - category: "Animals & Nature", - description: "fly", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿชฑ", - aliases: ["worm"], - tags: [], - category: "Animals & Nature", - description: "worm", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฆ ", - aliases: ["microbe"], - tags: ["germ"], - category: "Animals & Nature", - description: "microbe", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["bouquet"], - tags: ["flowers"], - category: "Animals & Nature", - description: "bouquet", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒธ", - aliases: ["cherry_blossom"], - tags: ["flower", "spring"], - category: "Animals & Nature", - description: "cherry blossom", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ฎ", - aliases: ["white_flower"], - tags: [], - category: "Animals & Nature", - description: "white flower", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿต๏ธ", - aliases: ["rosette"], - tags: [], - category: "Animals & Nature", - description: "rosette", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒน", - aliases: ["rose"], - tags: ["flower"], - category: "Animals & Nature", - description: "rose", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ€", - aliases: ["wilted_flower"], - tags: [], - category: "Animals & Nature", - description: "wilted flower", - unicode_version: "9.0", - }, - { - emoji: "๐ŸŒบ", - aliases: ["hibiscus"], - tags: [], - category: "Animals & Nature", - description: "hibiscus", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒป", - aliases: ["sunflower"], - tags: [], - category: "Animals & Nature", - description: "sunflower", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒผ", - aliases: ["blossom"], - tags: [], - category: "Animals & Nature", - description: "blossom", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒท", - aliases: ["tulip"], - tags: ["flower"], - category: "Animals & Nature", - description: "tulip", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒฑ", - aliases: ["seedling"], - tags: ["plant"], - category: "Animals & Nature", - description: "seedling", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿชด", - aliases: ["potted_plant"], - tags: [], - category: "Animals & Nature", - description: "potted plant", - unicode_version: "13.0", - }, - { - emoji: "๐ŸŒฒ", - aliases: ["evergreen_tree"], - tags: ["wood"], - category: "Animals & Nature", - description: "evergreen tree", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒณ", - aliases: ["deciduous_tree"], - tags: ["wood"], - category: "Animals & Nature", - description: "deciduous tree", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒด", - aliases: ["palm_tree"], - tags: [], - category: "Animals & Nature", - description: "palm tree", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒต", - aliases: ["cactus"], - tags: [], - category: "Animals & Nature", - description: "cactus", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒพ", - aliases: ["ear_of_rice"], - tags: [], - category: "Animals & Nature", - description: "sheaf of rice", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒฟ", - aliases: ["herb"], - tags: [], - category: "Animals & Nature", - description: "herb", - unicode_version: "6.0", - }, - { - emoji: "โ˜˜๏ธ", - aliases: ["shamrock"], - tags: [], - category: "Animals & Nature", - description: "shamrock", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ€", - aliases: ["four_leaf_clover"], - tags: ["luck"], - category: "Animals & Nature", - description: "four leaf clover", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["maple_leaf"], - tags: ["canada"], - category: "Animals & Nature", - description: "maple leaf", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‚", - aliases: ["fallen_leaf"], - tags: ["autumn"], - category: "Animals & Nature", - description: "fallen leaf", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿƒ", - aliases: ["leaves"], - tags: ["leaf"], - category: "Animals & Nature", - description: "leaf fluttering in wind", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡", - aliases: ["grapes"], - tags: [], - category: "Food & Drink", - description: "grapes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆ", - aliases: ["melon"], - tags: [], - category: "Food & Drink", - description: "melon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‰", - aliases: ["watermelon"], - tags: [], - category: "Food & Drink", - description: "watermelon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŠ", - aliases: ["tangerine", "orange", "mandarin"], - tags: [], - category: "Food & Drink", - description: "tangerine", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‹", - aliases: ["lemon"], - tags: [], - category: "Food & Drink", - description: "lemon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ", - aliases: ["banana"], - tags: ["fruit"], - category: "Food & Drink", - description: "banana", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["pineapple"], - tags: [], - category: "Food & Drink", - description: "pineapple", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅญ", - aliases: ["mango"], - tags: [], - category: "Food & Drink", - description: "mango", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽ", - aliases: ["apple"], - tags: [], - category: "Food & Drink", - description: "red apple", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["green_apple"], - tags: ["fruit"], - category: "Food & Drink", - description: "green apple", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["pear"], - tags: [], - category: "Food & Drink", - description: "pear", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘", - aliases: ["peach"], - tags: [], - category: "Food & Drink", - description: "peach", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["cherries"], - tags: ["fruit"], - category: "Food & Drink", - description: "cherries", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["strawberry"], - tags: ["fruit"], - category: "Food & Drink", - description: "strawberry", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿซ", - aliases: ["blueberries"], - tags: [], - category: "Food & Drink", - description: "blueberries", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["kiwi_fruit"], - tags: [], - category: "Food & Drink", - description: "kiwi fruit", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ…", - aliases: ["tomato"], - tags: [], - category: "Food & Drink", - description: "tomato", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿซ’", - aliases: ["olive"], - tags: [], - category: "Food & Drink", - description: "olive", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฅฅ", - aliases: ["coconut"], - tags: [], - category: "Food & Drink", - description: "coconut", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅ‘", - aliases: ["avocado"], - tags: [], - category: "Food & Drink", - description: "avocado", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ†", - aliases: ["eggplant"], - tags: ["aubergine"], - category: "Food & Drink", - description: "eggplant", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ”", - aliases: ["potato"], - tags: [], - category: "Food & Drink", - description: "potato", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅ•", - aliases: ["carrot"], - tags: [], - category: "Food & Drink", - description: "carrot", - unicode_version: "9.0", - }, - { - emoji: "๐ŸŒฝ", - aliases: ["corn"], - tags: [], - category: "Food & Drink", - description: "ear of corn", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒถ๏ธ", - aliases: ["hot_pepper"], - tags: ["spicy"], - category: "Food & Drink", - description: "hot pepper", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿซ‘", - aliases: ["bell_pepper"], - tags: [], - category: "Food & Drink", - description: "bell pepper", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฅ’", - aliases: ["cucumber"], - tags: [], - category: "Food & Drink", - description: "cucumber", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅฌ", - aliases: ["leafy_green"], - tags: [], - category: "Food & Drink", - description: "leafy green", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅฆ", - aliases: ["broccoli"], - tags: [], - category: "Food & Drink", - description: "broccoli", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง„", - aliases: ["garlic"], - tags: [], - category: "Food & Drink", - description: "garlic", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง…", - aliases: ["onion"], - tags: [], - category: "Food & Drink", - description: "onion", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ„", - aliases: ["mushroom"], - tags: [], - category: "Food & Drink", - description: "mushroom", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅœ", - aliases: ["peanuts"], - tags: [], - category: "Food & Drink", - description: "peanuts", - unicode_version: "9.0", - }, - { - emoji: "๐ŸŒฐ", - aliases: ["chestnut"], - tags: [], - category: "Food & Drink", - description: "chestnut", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿž", - aliases: ["bread"], - tags: ["toast"], - category: "Food & Drink", - description: "bread", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["croissant"], - tags: [], - category: "Food & Drink", - description: "croissant", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅ–", - aliases: ["baguette_bread"], - tags: [], - category: "Food & Drink", - description: "baguette bread", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿซ“", - aliases: ["flatbread"], - tags: [], - category: "Food & Drink", - description: "flatbread", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฅจ", - aliases: ["pretzel"], - tags: [], - category: "Food & Drink", - description: "pretzel", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅฏ", - aliases: ["bagel"], - tags: [], - category: "Food & Drink", - description: "bagel", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅž", - aliases: ["pancakes"], - tags: [], - category: "Food & Drink", - description: "pancakes", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿง‡", - aliases: ["waffle"], - tags: [], - category: "Food & Drink", - description: "waffle", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง€", - aliases: ["cheese"], - tags: [], - category: "Food & Drink", - description: "cheese wedge", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ–", - aliases: ["meat_on_bone"], - tags: [], - category: "Food & Drink", - description: "meat on bone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—", - aliases: ["poultry_leg"], - tags: ["meat", "chicken"], - category: "Food & Drink", - description: "poultry leg", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅฉ", - aliases: ["cut_of_meat"], - tags: [], - category: "Food & Drink", - description: "cut of meat", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅ“", - aliases: ["bacon"], - tags: [], - category: "Food & Drink", - description: "bacon", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["hamburger"], - tags: ["burger"], - category: "Food & Drink", - description: "hamburger", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŸ", - aliases: ["fries"], - tags: [], - category: "Food & Drink", - description: "french fries", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•", - aliases: ["pizza"], - tags: [], - category: "Food & Drink", - description: "pizza", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒญ", - aliases: ["hotdog"], - tags: [], - category: "Food & Drink", - description: "hot dog", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿฅช", - aliases: ["sandwich"], - tags: [], - category: "Food & Drink", - description: "sandwich", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŒฎ", - aliases: ["taco"], - tags: [], - category: "Food & Drink", - description: "taco", - unicode_version: "8.0", - }, - { - emoji: "๐ŸŒฏ", - aliases: ["burrito"], - tags: [], - category: "Food & Drink", - description: "burrito", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿซ”", - aliases: ["tamale"], - tags: [], - category: "Food & Drink", - description: "tamale", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฅ™", - aliases: ["stuffed_flatbread"], - tags: [], - category: "Food & Drink", - description: "stuffed flatbread", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿง†", - aliases: ["falafel"], - tags: [], - category: "Food & Drink", - description: "falafel", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฅš", - aliases: ["egg"], - tags: [], - category: "Food & Drink", - description: "egg", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿณ", - aliases: ["fried_egg"], - tags: ["breakfast"], - category: "Food & Drink", - description: "cooking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ˜", - aliases: ["shallow_pan_of_food"], - tags: ["paella", "curry"], - category: "Food & Drink", - description: "shallow pan of food", - unicode_version: "", - }, - { - emoji: "๐Ÿฒ", - aliases: ["stew"], - tags: [], - category: "Food & Drink", - description: "pot of food", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿซ•", - aliases: ["fondue"], - tags: [], - category: "Food & Drink", - description: "fondue", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿฅฃ", - aliases: ["bowl_with_spoon"], - tags: [], - category: "Food & Drink", - description: "bowl with spoon", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅ—", - aliases: ["green_salad"], - tags: [], - category: "Food & Drink", - description: "green salad", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฟ", - aliases: ["popcorn"], - tags: [], - category: "Food & Drink", - description: "popcorn", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿงˆ", - aliases: ["butter"], - tags: [], - category: "Food & Drink", - description: "butter", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง‚", - aliases: ["salt"], - tags: [], - category: "Food & Drink", - description: "salt", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅซ", - aliases: ["canned_food"], - tags: [], - category: "Food & Drink", - description: "canned food", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฑ", - aliases: ["bento"], - tags: [], - category: "Food & Drink", - description: "bento box", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ˜", - aliases: ["rice_cracker"], - tags: [], - category: "Food & Drink", - description: "rice cracker", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™", - aliases: ["rice_ball"], - tags: [], - category: "Food & Drink", - description: "rice ball", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš", - aliases: ["rice"], - tags: [], - category: "Food & Drink", - description: "cooked rice", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›", - aliases: ["curry"], - tags: [], - category: "Food & Drink", - description: "curry rice", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿœ", - aliases: ["ramen"], - tags: ["noodle"], - category: "Food & Drink", - description: "steaming bowl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["spaghetti"], - tags: ["pasta"], - category: "Food & Drink", - description: "spaghetti", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ ", - aliases: ["sweet_potato"], - tags: [], - category: "Food & Drink", - description: "roasted sweet potato", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿข", - aliases: ["oden"], - tags: [], - category: "Food & Drink", - description: "oden", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฃ", - aliases: ["sushi"], - tags: [], - category: "Food & Drink", - description: "sushi", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค", - aliases: ["fried_shrimp"], - tags: ["tempura"], - category: "Food & Drink", - description: "fried shrimp", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["fish_cake"], - tags: [], - category: "Food & Drink", - description: "fish cake with swirl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅฎ", - aliases: ["moon_cake"], - tags: [], - category: "Food & Drink", - description: "moon cake", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿก", - aliases: ["dango"], - tags: [], - category: "Food & Drink", - description: "dango", - unicode_version: "6.0", - }, - { - emoji: "๐ŸฅŸ", - aliases: ["dumpling"], - tags: [], - category: "Food & Drink", - description: "dumpling", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅ ", - aliases: ["fortune_cookie"], - tags: [], - category: "Food & Drink", - description: "fortune cookie", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅก", - aliases: ["takeout_box"], - tags: [], - category: "Food & Drink", - description: "takeout box", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆ€", - aliases: ["crab"], - tags: [], - category: "Food & Drink", - description: "crab", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿฆž", - aliases: ["lobster"], - tags: [], - category: "Food & Drink", - description: "lobster", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["shrimp"], - tags: [], - category: "Food & Drink", - description: "shrimp", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆ‘", - aliases: ["squid"], - tags: [], - category: "Food & Drink", - description: "squid", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆช", - aliases: ["oyster"], - tags: [], - category: "Food & Drink", - description: "oyster", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["icecream"], - tags: [], - category: "Food & Drink", - description: "soft ice cream", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง", - aliases: ["shaved_ice"], - tags: [], - category: "Food & Drink", - description: "shaved ice", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿจ", - aliases: ["ice_cream"], - tags: [], - category: "Food & Drink", - description: "ice cream", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฉ", - aliases: ["doughnut"], - tags: [], - category: "Food & Drink", - description: "doughnut", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช", - aliases: ["cookie"], - tags: [], - category: "Food & Drink", - description: "cookie", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ‚", - aliases: ["birthday"], - tags: ["party"], - category: "Food & Drink", - description: "birthday cake", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฐ", - aliases: ["cake"], - tags: ["dessert"], - category: "Food & Drink", - description: "shortcake", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿง", - aliases: ["cupcake"], - tags: [], - category: "Food & Drink", - description: "cupcake", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅง", - aliases: ["pie"], - tags: [], - category: "Food & Drink", - description: "pie", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿซ", - aliases: ["chocolate_bar"], - tags: [], - category: "Food & Drink", - description: "chocolate bar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฌ", - aliases: ["candy"], - tags: ["sweet"], - category: "Food & Drink", - description: "candy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿญ", - aliases: ["lollipop"], - tags: [], - category: "Food & Drink", - description: "lollipop", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฎ", - aliases: ["custard"], - tags: [], - category: "Food & Drink", - description: "custard", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฏ", - aliases: ["honey_pot"], - tags: [], - category: "Food & Drink", - description: "honey pot", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿผ", - aliases: ["baby_bottle"], - tags: ["milk"], - category: "Food & Drink", - description: "baby bottle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ›", - aliases: ["milk_glass"], - tags: [], - category: "Food & Drink", - description: "glass of milk", - unicode_version: "9.0", - }, - { - emoji: "โ˜•", - aliases: ["coffee"], - tags: ["cafe", "espresso"], - category: "Food & Drink", - description: "hot beverage", - unicode_version: "4.0", - }, - { - emoji: "๐Ÿซ–", - aliases: ["teapot"], - tags: [], - category: "Food & Drink", - description: "teapot", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿต", - aliases: ["tea"], - tags: ["green", "breakfast"], - category: "Food & Drink", - description: "teacup without handle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿถ", - aliases: ["sake"], - tags: [], - category: "Food & Drink", - description: "sake", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿพ", - aliases: ["champagne"], - tags: ["bottle", "bubbly", "celebration"], - category: "Food & Drink", - description: "bottle with popping cork", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿท", - aliases: ["wine_glass"], - tags: [], - category: "Food & Drink", - description: "wine glass", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿธ", - aliases: ["cocktail"], - tags: ["drink"], - category: "Food & Drink", - description: "cocktail glass", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿน", - aliases: ["tropical_drink"], - tags: ["summer", "vacation"], - category: "Food & Drink", - description: "tropical drink", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿบ", - aliases: ["beer"], - tags: ["drink"], - category: "Food & Drink", - description: "beer mug", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿป", - aliases: ["beers"], - tags: ["drinks"], - category: "Food & Drink", - description: "clinking beer mugs", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ‚", - aliases: ["clinking_glasses"], - tags: ["cheers", "toast"], - category: "Food & Drink", - description: "clinking glasses", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅƒ", - aliases: ["tumbler_glass"], - tags: ["whisky"], - category: "Food & Drink", - description: "tumbler glass", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅค", - aliases: ["cup_with_straw"], - tags: [], - category: "Food & Drink", - description: "cup with straw", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿง‹", - aliases: ["bubble_tea"], - tags: [], - category: "Food & Drink", - description: "bubble tea", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿงƒ", - aliases: ["beverage_box"], - tags: [], - category: "Food & Drink", - description: "beverage box", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿง‰", - aliases: ["mate"], - tags: [], - category: "Food & Drink", - description: "mate", - unicode_version: "12.0", - }, - { - emoji: "๐ŸงŠ", - aliases: ["ice_cube"], - tags: [], - category: "Food & Drink", - description: "ice", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฅข", - aliases: ["chopsticks"], - tags: [], - category: "Food & Drink", - description: "chopsticks", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฝ๏ธ", - aliases: ["plate_with_cutlery"], - tags: ["dining", "dinner"], - category: "Food & Drink", - description: "fork and knife with plate", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿด", - aliases: ["fork_and_knife"], - tags: ["cutlery"], - category: "Food & Drink", - description: "fork and knife", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ„", - aliases: ["spoon"], - tags: [], - category: "Food & Drink", - description: "spoon", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ”ช", - aliases: ["hocho", "knife"], - tags: ["cut", "chop"], - category: "Food & Drink", - description: "kitchen knife", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿบ", - aliases: ["amphora"], - tags: [], - category: "Food & Drink", - description: "amphora", - unicode_version: "8.0", - }, - { - emoji: "๐ŸŒ", - aliases: ["earth_africa"], - tags: ["globe", "world", "international"], - category: "Travel & Places", - description: "globe showing Europe-Africa", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒŽ", - aliases: ["earth_americas"], - tags: ["globe", "world", "international"], - category: "Travel & Places", - description: "globe showing Americas", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ", - aliases: ["earth_asia"], - tags: ["globe", "world", "international"], - category: "Travel & Places", - description: "globe showing Asia-Australia", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ", - aliases: ["globe_with_meridians"], - tags: ["world", "global", "international"], - category: "Travel & Places", - description: "globe with meridians", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—บ๏ธ", - aliases: ["world_map"], - tags: ["travel"], - category: "Travel & Places", - description: "world map", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ—พ", - aliases: ["japan"], - tags: [], - category: "Travel & Places", - description: "map of Japan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงญ", - aliases: ["compass"], - tags: [], - category: "Travel & Places", - description: "compass", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ”๏ธ", - aliases: ["mountain_snow"], - tags: [], - category: "Travel & Places", - description: "snow-capped mountain", - unicode_version: "7.0", - }, - { - emoji: "โ›ฐ๏ธ", - aliases: ["mountain"], - tags: [], - category: "Travel & Places", - description: "mountain", - unicode_version: "5.2", - }, - { - emoji: "๐ŸŒ‹", - aliases: ["volcano"], - tags: [], - category: "Travel & Places", - description: "volcano", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—ป", - aliases: ["mount_fuji"], - tags: [], - category: "Travel & Places", - description: "mount fuji", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•๏ธ", - aliases: ["camping"], - tags: [], - category: "Travel & Places", - description: "camping", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ–๏ธ", - aliases: ["beach_umbrella"], - tags: [], - category: "Travel & Places", - description: "beach with umbrella", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿœ๏ธ", - aliases: ["desert"], - tags: [], - category: "Travel & Places", - description: "desert", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ๏ธ", - aliases: ["desert_island"], - tags: [], - category: "Travel & Places", - description: "desert island", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿž๏ธ", - aliases: ["national_park"], - tags: [], - category: "Travel & Places", - description: "national park", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŸ๏ธ", - aliases: ["stadium"], - tags: [], - category: "Travel & Places", - description: "stadium", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›๏ธ", - aliases: ["classical_building"], - tags: [], - category: "Travel & Places", - description: "classical building", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ—๏ธ", - aliases: ["building_construction"], - tags: [], - category: "Travel & Places", - description: "building construction", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿงฑ", - aliases: ["bricks"], - tags: [], - category: "Travel & Places", - description: "brick", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชจ", - aliases: ["rock"], - tags: [], - category: "Travel & Places", - description: "rock", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿชต", - aliases: ["wood"], - tags: [], - category: "Travel & Places", - description: "wood", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ›–", - aliases: ["hut"], - tags: [], - category: "Travel & Places", - description: "hut", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ˜๏ธ", - aliases: ["houses"], - tags: [], - category: "Travel & Places", - description: "houses", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿš๏ธ", - aliases: ["derelict_house"], - tags: [], - category: "Travel & Places", - description: "derelict house", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ ", - aliases: ["house"], - tags: [], - category: "Travel & Places", - description: "house", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿก", - aliases: ["house_with_garden"], - tags: [], - category: "Travel & Places", - description: "house with garden", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿข", - aliases: ["office"], - tags: [], - category: "Travel & Places", - description: "office building", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฃ", - aliases: ["post_office"], - tags: [], - category: "Travel & Places", - description: "Japanese post office", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿค", - aliases: ["european_post_office"], - tags: [], - category: "Travel & Places", - description: "post office", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["hospital"], - tags: [], - category: "Travel & Places", - description: "hospital", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฆ", - aliases: ["bank"], - tags: [], - category: "Travel & Places", - description: "bank", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿจ", - aliases: ["hotel"], - tags: [], - category: "Travel & Places", - description: "hotel", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฉ", - aliases: ["love_hotel"], - tags: [], - category: "Travel & Places", - description: "love hotel", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช", - aliases: ["convenience_store"], - tags: [], - category: "Travel & Places", - description: "convenience store", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿซ", - aliases: ["school"], - tags: [], - category: "Travel & Places", - description: "school", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฌ", - aliases: ["department_store"], - tags: [], - category: "Travel & Places", - description: "department store", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿญ", - aliases: ["factory"], - tags: [], - category: "Travel & Places", - description: "factory", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฏ", - aliases: ["japanese_castle"], - tags: [], - category: "Travel & Places", - description: "Japanese castle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฐ", - aliases: ["european_castle"], - tags: [], - category: "Travel & Places", - description: "castle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’’", - aliases: ["wedding"], - tags: ["marriage"], - category: "Travel & Places", - description: "wedding", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—ผ", - aliases: ["tokyo_tower"], - tags: [], - category: "Travel & Places", - description: "Tokyo tower", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—ฝ", - aliases: ["statue_of_liberty"], - tags: [], - category: "Travel & Places", - description: "Statue of Liberty", - unicode_version: "6.0", - }, - { - emoji: "โ›ช", - aliases: ["church"], - tags: [], - category: "Travel & Places", - description: "church", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ•Œ", - aliases: ["mosque"], - tags: [], - category: "Travel & Places", - description: "mosque", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ›•", - aliases: ["hindu_temple"], - tags: [], - category: "Travel & Places", - description: "hindu temple", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ•", - aliases: ["synagogue"], - tags: [], - category: "Travel & Places", - description: "synagogue", - unicode_version: "8.0", - }, - { - emoji: "โ›ฉ๏ธ", - aliases: ["shinto_shrine"], - tags: [], - category: "Travel & Places", - description: "shinto shrine", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ•‹", - aliases: ["kaaba"], - tags: [], - category: "Travel & Places", - description: "kaaba", - unicode_version: "8.0", - }, - { - emoji: "โ›ฒ", - aliases: ["fountain"], - tags: [], - category: "Travel & Places", - description: "fountain", - unicode_version: "5.2", - }, - { - emoji: "โ›บ", - aliases: ["tent"], - tags: ["camping"], - category: "Travel & Places", - description: "tent", - unicode_version: "5.2", - }, - { - emoji: "๐ŸŒ", - aliases: ["foggy"], - tags: ["karl"], - category: "Travel & Places", - description: "foggy", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒƒ", - aliases: ["night_with_stars"], - tags: [], - category: "Travel & Places", - description: "night with stars", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ™๏ธ", - aliases: ["cityscape"], - tags: ["skyline"], - category: "Travel & Places", - description: "cityscape", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒ„", - aliases: ["sunrise_over_mountains"], - tags: [], - category: "Travel & Places", - description: "sunrise over mountains", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ…", - aliases: ["sunrise"], - tags: [], - category: "Travel & Places", - description: "sunrise", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ†", - aliases: ["city_sunset"], - tags: [], - category: "Travel & Places", - description: "cityscape at dusk", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ‡", - aliases: ["city_sunrise"], - tags: [], - category: "Travel & Places", - description: "sunset", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ‰", - aliases: ["bridge_at_night"], - tags: [], - category: "Travel & Places", - description: "bridge at night", - unicode_version: "6.0", - }, - { - emoji: "โ™จ๏ธ", - aliases: ["hotsprings"], - tags: [], - category: "Travel & Places", - description: "hot springs", - unicode_version: "", - }, - { - emoji: "๐ŸŽ ", - aliases: ["carousel_horse"], - tags: [], - category: "Travel & Places", - description: "carousel horse", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽก", - aliases: ["ferris_wheel"], - tags: [], - category: "Travel & Places", - description: "ferris wheel", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽข", - aliases: ["roller_coaster"], - tags: [], - category: "Travel & Places", - description: "roller coaster", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ˆ", - aliases: ["barber"], - tags: [], - category: "Travel & Places", - description: "barber pole", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽช", - aliases: ["circus_tent"], - tags: [], - category: "Travel & Places", - description: "circus tent", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš‚", - aliases: ["steam_locomotive"], - tags: ["train"], - category: "Travel & Places", - description: "locomotive", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšƒ", - aliases: ["railway_car"], - tags: [], - category: "Travel & Places", - description: "railway car", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš„", - aliases: ["bullettrain_side"], - tags: ["train"], - category: "Travel & Places", - description: "high-speed train", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš…", - aliases: ["bullettrain_front"], - tags: ["train"], - category: "Travel & Places", - description: "bullet train", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš†", - aliases: ["train2"], - tags: [], - category: "Travel & Places", - description: "train", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš‡", - aliases: ["metro"], - tags: [], - category: "Travel & Places", - description: "metro", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšˆ", - aliases: ["light_rail"], - tags: [], - category: "Travel & Places", - description: "light rail", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš‰", - aliases: ["station"], - tags: [], - category: "Travel & Places", - description: "station", - unicode_version: "6.0", - }, - { - emoji: "๐ŸšŠ", - aliases: ["tram"], - tags: [], - category: "Travel & Places", - description: "tram", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš", - aliases: ["monorail"], - tags: [], - category: "Travel & Places", - description: "monorail", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšž", - aliases: ["mountain_railway"], - tags: [], - category: "Travel & Places", - description: "mountain railway", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš‹", - aliases: ["train"], - tags: [], - category: "Travel & Places", - description: "tram car", - unicode_version: "6.0", - }, - { - emoji: "๐ŸšŒ", - aliases: ["bus"], - tags: [], - category: "Travel & Places", - description: "bus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš", - aliases: ["oncoming_bus"], - tags: [], - category: "Travel & Places", - description: "oncoming bus", - unicode_version: "6.0", - }, - { - emoji: "๐ŸšŽ", - aliases: ["trolleybus"], - tags: [], - category: "Travel & Places", - description: "trolleybus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš", - aliases: ["minibus"], - tags: [], - category: "Travel & Places", - description: "minibus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš‘", - aliases: ["ambulance"], - tags: [], - category: "Travel & Places", - description: "ambulance", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš’", - aliases: ["fire_engine"], - tags: [], - category: "Travel & Places", - description: "fire engine", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš“", - aliases: ["police_car"], - tags: [], - category: "Travel & Places", - description: "police car", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš”", - aliases: ["oncoming_police_car"], - tags: [], - category: "Travel & Places", - description: "oncoming police car", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš•", - aliases: ["taxi"], - tags: [], - category: "Travel & Places", - description: "taxi", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš–", - aliases: ["oncoming_taxi"], - tags: [], - category: "Travel & Places", - description: "oncoming taxi", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš—", - aliases: ["car", "red_car"], - tags: [], - category: "Travel & Places", - description: "automobile", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš˜", - aliases: ["oncoming_automobile"], - tags: [], - category: "Travel & Places", - description: "oncoming automobile", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš™", - aliases: ["blue_car"], - tags: [], - category: "Travel & Places", - description: "sport utility vehicle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ป", - aliases: ["pickup_truck"], - tags: [], - category: "Travel & Places", - description: "pickup truck", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿšš", - aliases: ["truck"], - tags: [], - category: "Travel & Places", - description: "delivery truck", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš›", - aliases: ["articulated_lorry"], - tags: [], - category: "Travel & Places", - description: "articulated lorry", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšœ", - aliases: ["tractor"], - tags: [], - category: "Travel & Places", - description: "tractor", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ๏ธ", - aliases: ["racing_car"], - tags: [], - category: "Travel & Places", - description: "racing car", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ๏ธ", - aliases: ["motorcycle"], - tags: [], - category: "Travel & Places", - description: "motorcycle", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›ต", - aliases: ["motor_scooter"], - tags: [], - category: "Travel & Places", - description: "motor scooter", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฆฝ", - aliases: ["manual_wheelchair"], - tags: [], - category: "Travel & Places", - description: "manual wheelchair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฆผ", - aliases: ["motorized_wheelchair"], - tags: [], - category: "Travel & Places", - description: "motorized wheelchair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ›บ", - aliases: ["auto_rickshaw"], - tags: [], - category: "Travel & Places", - description: "auto rickshaw", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿšฒ", - aliases: ["bike"], - tags: ["bicycle"], - category: "Travel & Places", - description: "bicycle", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ด", - aliases: ["kick_scooter"], - tags: [], - category: "Travel & Places", - description: "kick scooter", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿ›น", - aliases: ["skateboard"], - tags: [], - category: "Travel & Places", - description: "skateboard", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ›ผ", - aliases: ["roller_skate"], - tags: [], - category: "Travel & Places", - description: "roller skate", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿš", - aliases: ["busstop"], - tags: [], - category: "Travel & Places", - description: "bus stop", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ฃ๏ธ", - aliases: ["motorway"], - tags: [], - category: "Travel & Places", - description: "motorway", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›ค๏ธ", - aliases: ["railway_track"], - tags: [], - category: "Travel & Places", - description: "railway track", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›ข๏ธ", - aliases: ["oil_drum"], - tags: [], - category: "Travel & Places", - description: "oil drum", - unicode_version: "7.0", - }, - { - emoji: "โ›ฝ", - aliases: ["fuelpump"], - tags: [], - category: "Travel & Places", - description: "fuel pump", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿšจ", - aliases: ["rotating_light"], - tags: ["911", "emergency"], - category: "Travel & Places", - description: "police car light", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฅ", - aliases: ["traffic_light"], - tags: [], - category: "Travel & Places", - description: "horizontal traffic light", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฆ", - aliases: ["vertical_traffic_light"], - tags: ["semaphore"], - category: "Travel & Places", - description: "vertical traffic light", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›‘", - aliases: ["stop_sign"], - tags: [], - category: "Travel & Places", - description: "stop sign", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿšง", - aliases: ["construction"], - tags: ["wip"], - category: "Travel & Places", - description: "construction", - unicode_version: "6.0", - }, - { - emoji: "โš“", - aliases: ["anchor"], - tags: ["ship"], - category: "Travel & Places", - description: "anchor", - unicode_version: "4.1", - }, - { - emoji: "โ›ต", - aliases: ["boat", "sailboat"], - tags: [], - category: "Travel & Places", - description: "sailboat", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ›ถ", - aliases: ["canoe"], - tags: [], - category: "Travel & Places", - description: "canoe", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿšค", - aliases: ["speedboat"], - tags: ["ship"], - category: "Travel & Places", - description: "speedboat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ณ๏ธ", - aliases: ["passenger_ship"], - tags: ["cruise"], - category: "Travel & Places", - description: "passenger ship", - unicode_version: "7.0", - }, - { - emoji: "โ›ด๏ธ", - aliases: ["ferry"], - tags: [], - category: "Travel & Places", - description: "ferry", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ›ฅ๏ธ", - aliases: ["motor_boat"], - tags: [], - category: "Travel & Places", - description: "motor boat", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿšข", - aliases: ["ship"], - tags: [], - category: "Travel & Places", - description: "ship", - unicode_version: "6.0", - }, - { - emoji: "โœˆ๏ธ", - aliases: ["airplane"], - tags: ["flight"], - category: "Travel & Places", - description: "airplane", - unicode_version: "", - }, - { - emoji: "๐Ÿ›ฉ๏ธ", - aliases: ["small_airplane"], - tags: ["flight"], - category: "Travel & Places", - description: "small airplane", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›ซ", - aliases: ["flight_departure"], - tags: [], - category: "Travel & Places", - description: "airplane departure", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›ฌ", - aliases: ["flight_arrival"], - tags: [], - category: "Travel & Places", - description: "airplane arrival", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿช‚", - aliases: ["parachute"], - tags: [], - category: "Travel & Places", - description: "parachute", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ’บ", - aliases: ["seat"], - tags: [], - category: "Travel & Places", - description: "seat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš", - aliases: ["helicopter"], - tags: [], - category: "Travel & Places", - description: "helicopter", - unicode_version: "6.0", - }, - { - emoji: "๐ŸšŸ", - aliases: ["suspension_railway"], - tags: [], - category: "Travel & Places", - description: "suspension railway", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿš ", - aliases: ["mountain_cableway"], - tags: [], - category: "Travel & Places", - description: "mountain cableway", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšก", - aliases: ["aerial_tramway"], - tags: [], - category: "Travel & Places", - description: "aerial tramway", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ฐ๏ธ", - aliases: ["artificial_satellite"], - tags: ["orbit", "space"], - category: "Travel & Places", - description: "satellite", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿš€", - aliases: ["rocket"], - tags: ["ship", "launch"], - category: "Travel & Places", - description: "rocket", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ธ", - aliases: ["flying_saucer"], - tags: ["ufo"], - category: "Travel & Places", - description: "flying saucer", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ›Ž๏ธ", - aliases: ["bellhop_bell"], - tags: [], - category: "Travel & Places", - description: "bellhop bell", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿงณ", - aliases: ["luggage"], - tags: [], - category: "Travel & Places", - description: "luggage", - unicode_version: "11.0", - }, - { - emoji: "โŒ›", - aliases: ["hourglass"], - tags: ["time"], - category: "Travel & Places", - description: "hourglass done", - unicode_version: "", - }, - { - emoji: "โณ", - aliases: ["hourglass_flowing_sand"], - tags: ["time"], - category: "Travel & Places", - description: "hourglass not done", - unicode_version: "6.0", - }, - { - emoji: "โŒš", - aliases: ["watch"], - tags: ["time"], - category: "Travel & Places", - description: "watch", - unicode_version: "", - }, - { - emoji: "โฐ", - aliases: ["alarm_clock"], - tags: ["morning"], - category: "Travel & Places", - description: "alarm clock", - unicode_version: "6.0", - }, - { - emoji: "โฑ๏ธ", - aliases: ["stopwatch"], - tags: [], - category: "Travel & Places", - description: "stopwatch", - unicode_version: "6.0", - }, - { - emoji: "โฒ๏ธ", - aliases: ["timer_clock"], - tags: [], - category: "Travel & Places", - description: "timer clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ฐ๏ธ", - aliases: ["mantelpiece_clock"], - tags: [], - category: "Travel & Places", - description: "mantelpiece clock", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ•›", - aliases: ["clock12"], - tags: [], - category: "Travel & Places", - description: "twelve oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ง", - aliases: ["clock1230"], - tags: [], - category: "Travel & Places", - description: "twelve-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•", - aliases: ["clock1"], - tags: [], - category: "Travel & Places", - description: "one oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•œ", - aliases: ["clock130"], - tags: [], - category: "Travel & Places", - description: "one-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•‘", - aliases: ["clock2"], - tags: [], - category: "Travel & Places", - description: "two oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•", - aliases: ["clock230"], - tags: [], - category: "Travel & Places", - description: "two-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•’", - aliases: ["clock3"], - tags: [], - category: "Travel & Places", - description: "three oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ž", - aliases: ["clock330"], - tags: [], - category: "Travel & Places", - description: "three-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•“", - aliases: ["clock4"], - tags: [], - category: "Travel & Places", - description: "four oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•Ÿ", - aliases: ["clock430"], - tags: [], - category: "Travel & Places", - description: "four-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•”", - aliases: ["clock5"], - tags: [], - category: "Travel & Places", - description: "five oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ• ", - aliases: ["clock530"], - tags: [], - category: "Travel & Places", - description: "five-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ••", - aliases: ["clock6"], - tags: [], - category: "Travel & Places", - description: "six oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ก", - aliases: ["clock630"], - tags: [], - category: "Travel & Places", - description: "six-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•–", - aliases: ["clock7"], - tags: [], - category: "Travel & Places", - description: "seven oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ข", - aliases: ["clock730"], - tags: [], - category: "Travel & Places", - description: "seven-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•—", - aliases: ["clock8"], - tags: [], - category: "Travel & Places", - description: "eight oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ฃ", - aliases: ["clock830"], - tags: [], - category: "Travel & Places", - description: "eight-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•˜", - aliases: ["clock9"], - tags: [], - category: "Travel & Places", - description: "nine oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ค", - aliases: ["clock930"], - tags: [], - category: "Travel & Places", - description: "nine-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•™", - aliases: ["clock10"], - tags: [], - category: "Travel & Places", - description: "ten oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ฅ", - aliases: ["clock1030"], - tags: [], - category: "Travel & Places", - description: "ten-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•š", - aliases: ["clock11"], - tags: [], - category: "Travel & Places", - description: "eleven oโ€™clock", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ฆ", - aliases: ["clock1130"], - tags: [], - category: "Travel & Places", - description: "eleven-thirty", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ‘", - aliases: ["new_moon"], - tags: [], - category: "Travel & Places", - description: "new moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ’", - aliases: ["waxing_crescent_moon"], - tags: [], - category: "Travel & Places", - description: "waxing crescent moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ“", - aliases: ["first_quarter_moon"], - tags: [], - category: "Travel & Places", - description: "first quarter moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ”", - aliases: ["moon", "waxing_gibbous_moon"], - tags: [], - category: "Travel & Places", - description: "waxing gibbous moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ•", - aliases: ["full_moon"], - tags: [], - category: "Travel & Places", - description: "full moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ–", - aliases: ["waning_gibbous_moon"], - tags: [], - category: "Travel & Places", - description: "waning gibbous moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ—", - aliases: ["last_quarter_moon"], - tags: [], - category: "Travel & Places", - description: "last quarter moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ˜", - aliases: ["waning_crescent_moon"], - tags: [], - category: "Travel & Places", - description: "waning crescent moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ™", - aliases: ["crescent_moon"], - tags: ["night"], - category: "Travel & Places", - description: "crescent moon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒš", - aliases: ["new_moon_with_face"], - tags: [], - category: "Travel & Places", - description: "new moon face", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ›", - aliases: ["first_quarter_moon_with_face"], - tags: [], - category: "Travel & Places", - description: "first quarter moon face", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒœ", - aliases: ["last_quarter_moon_with_face"], - tags: [], - category: "Travel & Places", - description: "last quarter moon face", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒก๏ธ", - aliases: ["thermometer"], - tags: [], - category: "Travel & Places", - description: "thermometer", - unicode_version: "7.0", - }, - { - emoji: "โ˜€๏ธ", - aliases: ["sunny"], - tags: ["weather"], - category: "Travel & Places", - description: "sun", - unicode_version: "", - }, - { - emoji: "๐ŸŒ", - aliases: ["full_moon_with_face"], - tags: [], - category: "Travel & Places", - description: "full moon face", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒž", - aliases: ["sun_with_face"], - tags: ["summer"], - category: "Travel & Places", - description: "sun with face", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช", - aliases: ["ringed_planet"], - tags: [], - category: "Travel & Places", - description: "ringed planet", - unicode_version: "12.0", - }, - { - emoji: "โญ", - aliases: ["star"], - tags: [], - category: "Travel & Places", - description: "star", - unicode_version: "5.1", - }, - { - emoji: "๐ŸŒŸ", - aliases: ["star2"], - tags: [], - category: "Travel & Places", - description: "glowing star", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ ", - aliases: ["stars"], - tags: [], - category: "Travel & Places", - description: "shooting star", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒŒ", - aliases: ["milky_way"], - tags: [], - category: "Travel & Places", - description: "milky way", - unicode_version: "6.0", - }, - { - emoji: "โ˜๏ธ", - aliases: ["cloud"], - tags: [], - category: "Travel & Places", - description: "cloud", - unicode_version: "", - }, - { - emoji: "โ›…", - aliases: ["partly_sunny"], - tags: ["weather", "cloud"], - category: "Travel & Places", - description: "sun behind cloud", - unicode_version: "5.2", - }, - { - emoji: "โ›ˆ๏ธ", - aliases: ["cloud_with_lightning_and_rain"], - tags: [], - category: "Travel & Places", - description: "cloud with lightning and rain", - unicode_version: "5.2", - }, - { - emoji: "๐ŸŒค๏ธ", - aliases: ["sun_behind_small_cloud"], - tags: [], - category: "Travel & Places", - description: "sun behind small cloud", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒฅ๏ธ", - aliases: ["sun_behind_large_cloud"], - tags: [], - category: "Travel & Places", - description: "sun behind large cloud", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒฆ๏ธ", - aliases: ["sun_behind_rain_cloud"], - tags: [], - category: "Travel & Places", - description: "sun behind rain cloud", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒง๏ธ", - aliases: ["cloud_with_rain"], - tags: [], - category: "Travel & Places", - description: "cloud with rain", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒจ๏ธ", - aliases: ["cloud_with_snow"], - tags: [], - category: "Travel & Places", - description: "cloud with snow", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒฉ๏ธ", - aliases: ["cloud_with_lightning"], - tags: [], - category: "Travel & Places", - description: "cloud with lightning", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒช๏ธ", - aliases: ["tornado"], - tags: [], - category: "Travel & Places", - description: "tornado", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒซ๏ธ", - aliases: ["fog"], - tags: [], - category: "Travel & Places", - description: "fog", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒฌ๏ธ", - aliases: ["wind_face"], - tags: [], - category: "Travel & Places", - description: "wind face", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŒ€", - aliases: ["cyclone"], - tags: ["swirl"], - category: "Travel & Places", - description: "cyclone", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒˆ", - aliases: ["rainbow"], - tags: [], - category: "Travel & Places", - description: "rainbow", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒ‚", - aliases: ["closed_umbrella"], - tags: ["weather", "rain"], - category: "Travel & Places", - description: "closed umbrella", - unicode_version: "6.0", - }, - { - emoji: "โ˜‚๏ธ", - aliases: ["open_umbrella"], - tags: [], - category: "Travel & Places", - description: "umbrella", - unicode_version: "", - }, - { - emoji: "โ˜”", - aliases: ["umbrella"], - tags: ["rain", "weather"], - category: "Travel & Places", - description: "umbrella with rain drops", - unicode_version: "4.0", - }, - { - emoji: "โ›ฑ๏ธ", - aliases: ["parasol_on_ground"], - tags: ["beach_umbrella"], - category: "Travel & Places", - description: "umbrella on ground", - unicode_version: "5.2", - }, - { - emoji: "โšก", - aliases: ["zap"], - tags: ["lightning", "thunder"], - category: "Travel & Places", - description: "high voltage", - unicode_version: "4.0", - }, - { - emoji: "โ„๏ธ", - aliases: ["snowflake"], - tags: ["winter", "cold", "weather"], - category: "Travel & Places", - description: "snowflake", - unicode_version: "", - }, - { - emoji: "โ˜ƒ๏ธ", - aliases: ["snowman_with_snow"], - tags: ["winter", "christmas"], - category: "Travel & Places", - description: "snowman", - unicode_version: "", - }, - { - emoji: "โ›„", - aliases: ["snowman"], - tags: ["winter"], - category: "Travel & Places", - description: "snowman without snow", - unicode_version: "5.2", - }, - { - emoji: "โ˜„๏ธ", - aliases: ["comet"], - tags: [], - category: "Travel & Places", - description: "comet", - unicode_version: "", - }, - { - emoji: "๐Ÿ”ฅ", - aliases: ["fire"], - tags: ["burn"], - category: "Travel & Places", - description: "fire", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ง", - aliases: ["droplet"], - tags: ["water"], - category: "Travel & Places", - description: "droplet", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŒŠ", - aliases: ["ocean"], - tags: ["sea"], - category: "Travel & Places", - description: "water wave", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽƒ", - aliases: ["jack_o_lantern"], - tags: ["halloween"], - category: "Activities", - description: "jack-o-lantern", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ„", - aliases: ["christmas_tree"], - tags: [], - category: "Activities", - description: "Christmas tree", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ†", - aliases: ["fireworks"], - tags: ["festival", "celebration"], - category: "Activities", - description: "fireworks", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ‡", - aliases: ["sparkler"], - tags: [], - category: "Activities", - description: "sparkler", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงจ", - aliases: ["firecracker"], - tags: [], - category: "Activities", - description: "firecracker", - unicode_version: "11.0", - }, - { - emoji: "โœจ", - aliases: ["sparkles"], - tags: ["shiny"], - category: "Activities", - description: "sparkles", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽˆ", - aliases: ["balloon"], - tags: ["party", "birthday"], - category: "Activities", - description: "balloon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ‰", - aliases: ["tada"], - tags: ["hooray", "party"], - category: "Activities", - description: "party popper", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽŠ", - aliases: ["confetti_ball"], - tags: [], - category: "Activities", - description: "confetti ball", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ‹", - aliases: ["tanabata_tree"], - tags: [], - category: "Activities", - description: "tanabata tree", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ", - aliases: ["bamboo"], - tags: [], - category: "Activities", - description: "pine decoration", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽŽ", - aliases: ["dolls"], - tags: [], - category: "Activities", - description: "Japanese dolls", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ", - aliases: ["flags"], - tags: [], - category: "Activities", - description: "carp streamer", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ", - aliases: ["wind_chime"], - tags: [], - category: "Activities", - description: "wind chime", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ‘", - aliases: ["rice_scene"], - tags: [], - category: "Activities", - description: "moon viewing ceremony", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงง", - aliases: ["red_envelope"], - tags: [], - category: "Activities", - description: "red envelope", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽ€", - aliases: ["ribbon"], - tags: [], - category: "Activities", - description: "ribbon", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ", - aliases: ["gift"], - tags: ["present", "birthday", "christmas"], - category: "Activities", - description: "wrapped gift", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ—๏ธ", - aliases: ["reminder_ribbon"], - tags: [], - category: "Activities", - description: "reminder ribbon", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽŸ๏ธ", - aliases: ["tickets"], - tags: [], - category: "Activities", - description: "admission tickets", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽซ", - aliases: ["ticket"], - tags: [], - category: "Activities", - description: "ticket", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ–๏ธ", - aliases: ["medal_military"], - tags: [], - category: "Activities", - description: "military medal", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ†", - aliases: ["trophy"], - tags: ["award", "contest", "winner"], - category: "Activities", - description: "trophy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ…", - aliases: ["medal_sports"], - tags: ["gold", "winner"], - category: "Activities", - description: "sports medal", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿฅ‡", - aliases: ["1st_place_medal"], - tags: ["gold"], - category: "Activities", - description: "1st place medal", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅˆ", - aliases: ["2nd_place_medal"], - tags: ["silver"], - category: "Activities", - description: "2nd place medal", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅ‰", - aliases: ["3rd_place_medal"], - tags: ["bronze"], - category: "Activities", - description: "3rd place medal", - unicode_version: "9.0", - }, - { - emoji: "โšฝ", - aliases: ["soccer"], - tags: ["sports"], - category: "Activities", - description: "soccer ball", - unicode_version: "5.2", - }, - { - emoji: "โšพ", - aliases: ["baseball"], - tags: ["sports"], - category: "Activities", - description: "baseball", - unicode_version: "5.2", - }, - { - emoji: "๐ŸฅŽ", - aliases: ["softball"], - tags: [], - category: "Activities", - description: "softball", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ€", - aliases: ["basketball"], - tags: ["sports"], - category: "Activities", - description: "basketball", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["volleyball"], - tags: [], - category: "Activities", - description: "volleyball", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿˆ", - aliases: ["football"], - tags: ["sports"], - category: "Activities", - description: "american football", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‰", - aliases: ["rugby_football"], - tags: [], - category: "Activities", - description: "rugby football", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽพ", - aliases: ["tennis"], - tags: ["sports"], - category: "Activities", - description: "tennis", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["flying_disc"], - tags: [], - category: "Activities", - description: "flying disc", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽณ", - aliases: ["bowling"], - tags: [], - category: "Activities", - description: "bowling", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["cricket_game"], - tags: [], - category: "Activities", - description: "cricket game", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ‘", - aliases: ["field_hockey"], - tags: [], - category: "Activities", - description: "field hockey", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["ice_hockey"], - tags: [], - category: "Activities", - description: "ice hockey", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["lacrosse"], - tags: [], - category: "Activities", - description: "lacrosse", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["ping_pong"], - tags: [], - category: "Activities", - description: "ping pong", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿธ", - aliases: ["badminton"], - tags: [], - category: "Activities", - description: "badminton", - unicode_version: "8.0", - }, - { - emoji: "๐ŸฅŠ", - aliases: ["boxing_glove"], - tags: [], - category: "Activities", - description: "boxing glove", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅ‹", - aliases: ["martial_arts_uniform"], - tags: [], - category: "Activities", - description: "martial arts uniform", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿฅ…", - aliases: ["goal_net"], - tags: [], - category: "Activities", - description: "goal net", - unicode_version: "9.0", - }, - { - emoji: "โ›ณ", - aliases: ["golf"], - tags: [], - category: "Activities", - description: "flag in hole", - unicode_version: "5.2", - }, - { - emoji: "โ›ธ๏ธ", - aliases: ["ice_skate"], - tags: ["skating"], - category: "Activities", - description: "ice skate", - unicode_version: "5.2", - }, - { - emoji: "๐ŸŽฃ", - aliases: ["fishing_pole_and_fish"], - tags: [], - category: "Activities", - description: "fishing pole", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿคฟ", - aliases: ["diving_mask"], - tags: [], - category: "Activities", - description: "diving mask", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŽฝ", - aliases: ["running_shirt_with_sash"], - tags: ["marathon"], - category: "Activities", - description: "running shirt", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽฟ", - aliases: ["ski"], - tags: [], - category: "Activities", - description: "skis", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ท", - aliases: ["sled"], - tags: [], - category: "Activities", - description: "sled", - unicode_version: "11.0", - }, - { - emoji: "๐ŸฅŒ", - aliases: ["curling_stone"], - tags: [], - category: "Activities", - description: "curling stone", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽฏ", - aliases: ["dart"], - tags: ["target"], - category: "Activities", - description: "bullseye", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช€", - aliases: ["yo_yo"], - tags: [], - category: "Activities", - description: "yo-yo", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿช", - aliases: ["kite"], - tags: [], - category: "Activities", - description: "kite", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŽฑ", - aliases: ["8ball"], - tags: ["pool", "billiards"], - category: "Activities", - description: "pool 8 ball", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ฎ", - aliases: ["crystal_ball"], - tags: ["fortune"], - category: "Activities", - description: "crystal ball", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช„", - aliases: ["magic_wand"], - tags: [], - category: "Activities", - description: "magic wand", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿงฟ", - aliases: ["nazar_amulet"], - tags: [], - category: "Activities", - description: "nazar amulet", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽฎ", - aliases: ["video_game"], - tags: ["play", "controller", "console"], - category: "Activities", - description: "video game", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•น๏ธ", - aliases: ["joystick"], - tags: [], - category: "Activities", - description: "joystick", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽฐ", - aliases: ["slot_machine"], - tags: [], - category: "Activities", - description: "slot machine", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽฒ", - aliases: ["game_die"], - tags: ["dice", "gambling"], - category: "Activities", - description: "game die", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงฉ", - aliases: ["jigsaw"], - tags: [], - category: "Activities", - description: "puzzle piece", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงธ", - aliases: ["teddy_bear"], - tags: [], - category: "Activities", - description: "teddy bear", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿช…", - aliases: ["pinata"], - tags: [], - category: "Activities", - description: "piรฑata", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿช†", - aliases: ["nesting_dolls"], - tags: [], - category: "Activities", - description: "nesting dolls", - unicode_version: "13.0", - }, - { - emoji: "โ™ ๏ธ", - aliases: ["spades"], - tags: [], - category: "Activities", - description: "spade suit", - unicode_version: "", - }, - { - emoji: "โ™ฅ๏ธ", - aliases: ["hearts"], - tags: [], - category: "Activities", - description: "heart suit", - unicode_version: "", - }, - { - emoji: "โ™ฆ๏ธ", - aliases: ["diamonds"], - tags: [], - category: "Activities", - description: "diamond suit", - unicode_version: "", - }, - { - emoji: "โ™ฃ๏ธ", - aliases: ["clubs"], - tags: [], - category: "Activities", - description: "club suit", - unicode_version: "", - }, - { - emoji: "โ™Ÿ๏ธ", - aliases: ["chess_pawn"], - tags: [], - category: "Activities", - description: "chess pawn", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿƒ", - aliases: ["black_joker"], - tags: [], - category: "Activities", - description: "joker", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ€„", - aliases: ["mahjong"], - tags: [], - category: "Activities", - description: "mahjong red dragon", - unicode_version: "", - }, - { - emoji: "๐ŸŽด", - aliases: ["flower_playing_cards"], - tags: [], - category: "Activities", - description: "flower playing cards", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽญ", - aliases: ["performing_arts"], - tags: ["theater", "drama"], - category: "Activities", - description: "performing arts", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ–ผ๏ธ", - aliases: ["framed_picture"], - tags: [], - category: "Activities", - description: "framed picture", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽจ", - aliases: ["art"], - tags: ["design", "paint"], - category: "Activities", - description: "artist palette", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงต", - aliases: ["thread"], - tags: [], - category: "Activities", - description: "thread", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชก", - aliases: ["sewing_needle"], - tags: [], - category: "Activities", - description: "sewing needle", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿงถ", - aliases: ["yarn"], - tags: [], - category: "Activities", - description: "yarn", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชข", - aliases: ["knot"], - tags: [], - category: "Activities", - description: "knot", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘“", - aliases: ["eyeglasses"], - tags: ["glasses"], - category: "Objects", - description: "glasses", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ถ๏ธ", - aliases: ["dark_sunglasses"], - tags: [], - category: "Objects", - description: "sunglasses", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿฅฝ", - aliases: ["goggles"], - tags: [], - category: "Objects", - description: "goggles", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅผ", - aliases: ["lab_coat"], - tags: [], - category: "Objects", - description: "lab coat", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฆบ", - aliases: ["safety_vest"], - tags: [], - category: "Objects", - description: "safety vest", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘”", - aliases: ["necktie"], - tags: ["shirt", "formal"], - category: "Objects", - description: "necktie", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘•", - aliases: ["shirt", "tshirt"], - tags: [], - category: "Objects", - description: "t-shirt", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘–", - aliases: ["jeans"], - tags: ["pants"], - category: "Objects", - description: "jeans", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงฃ", - aliases: ["scarf"], - tags: [], - category: "Objects", - description: "scarf", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงค", - aliases: ["gloves"], - tags: [], - category: "Objects", - description: "gloves", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงฅ", - aliases: ["coat"], - tags: [], - category: "Objects", - description: "coat", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงฆ", - aliases: ["socks"], - tags: [], - category: "Objects", - description: "socks", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘—", - aliases: ["dress"], - tags: [], - category: "Objects", - description: "dress", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘˜", - aliases: ["kimono"], - tags: [], - category: "Objects", - description: "kimono", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅป", - aliases: ["sari"], - tags: [], - category: "Objects", - description: "sari", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฉฑ", - aliases: ["one_piece_swimsuit"], - tags: [], - category: "Objects", - description: "one-piece swimsuit", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฉฒ", - aliases: ["swim_brief"], - tags: [], - category: "Objects", - description: "briefs", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฉณ", - aliases: ["shorts"], - tags: [], - category: "Objects", - description: "shorts", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘™", - aliases: ["bikini"], - tags: ["beach"], - category: "Objects", - description: "bikini", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘š", - aliases: ["womans_clothes"], - tags: [], - category: "Objects", - description: "womanโ€™s clothes", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘›", - aliases: ["purse"], - tags: [], - category: "Objects", - description: "purse", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘œ", - aliases: ["handbag"], - tags: ["bag"], - category: "Objects", - description: "handbag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘", - aliases: ["pouch"], - tags: ["bag"], - category: "Objects", - description: "clutch bag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›๏ธ", - aliases: ["shopping"], - tags: ["bags"], - category: "Objects", - description: "shopping bags", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽ’", - aliases: ["school_satchel"], - tags: [], - category: "Objects", - description: "backpack", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฉด", - aliases: ["thong_sandal"], - tags: [], - category: "Objects", - description: "thong sandal", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ‘ž", - aliases: ["mans_shoe", "shoe"], - tags: [], - category: "Objects", - description: "manโ€™s shoe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘Ÿ", - aliases: ["athletic_shoe"], - tags: ["sneaker", "sport", "running"], - category: "Objects", - description: "running shoe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฅพ", - aliases: ["hiking_boot"], - tags: [], - category: "Objects", - description: "hiking boot", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿฅฟ", - aliases: ["flat_shoe"], - tags: [], - category: "Objects", - description: "flat shoe", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‘ ", - aliases: ["high_heel"], - tags: ["shoe"], - category: "Objects", - description: "high-heeled shoe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘ก", - aliases: ["sandal"], - tags: ["shoe"], - category: "Objects", - description: "womanโ€™s sandal", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฉฐ", - aliases: ["ballet_shoes"], - tags: [], - category: "Objects", - description: "ballet shoes", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ‘ข", - aliases: ["boot"], - tags: [], - category: "Objects", - description: "womanโ€™s boot", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘‘", - aliases: ["crown"], - tags: ["king", "queen", "royal"], - category: "Objects", - description: "crown", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‘’", - aliases: ["womans_hat"], - tags: [], - category: "Objects", - description: "womanโ€™s hat", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽฉ", - aliases: ["tophat"], - tags: ["hat", "classy"], - category: "Objects", - description: "top hat", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ“", - aliases: ["mortar_board"], - tags: ["education", "college", "university", "graduation"], - category: "Objects", - description: "graduation cap", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงข", - aliases: ["billed_cap"], - tags: [], - category: "Objects", - description: "billed cap", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿช–", - aliases: ["military_helmet"], - tags: [], - category: "Objects", - description: "military helmet", - unicode_version: "13.0", - }, - { - emoji: "โ›‘๏ธ", - aliases: ["rescue_worker_helmet"], - tags: [], - category: "Objects", - description: "rescue workerโ€™s helmet", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ“ฟ", - aliases: ["prayer_beads"], - tags: [], - category: "Objects", - description: "prayer beads", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ’„", - aliases: ["lipstick"], - tags: ["makeup"], - category: "Objects", - description: "lipstick", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’", - aliases: ["ring"], - tags: ["wedding", "marriage", "engaged"], - category: "Objects", - description: "ring", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’Ž", - aliases: ["gem"], - tags: ["diamond"], - category: "Objects", - description: "gem stone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”‡", - aliases: ["mute"], - tags: ["sound", "volume"], - category: "Objects", - description: "muted speaker", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ˆ", - aliases: ["speaker"], - tags: [], - category: "Objects", - description: "speaker low volume", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”‰", - aliases: ["sound"], - tags: ["volume"], - category: "Objects", - description: "speaker medium volume", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”Š", - aliases: ["loud_sound"], - tags: ["volume"], - category: "Objects", - description: "speaker high volume", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ข", - aliases: ["loudspeaker"], - tags: ["announcement"], - category: "Objects", - description: "loudspeaker", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฃ", - aliases: ["mega"], - tags: [], - category: "Objects", - description: "megaphone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฏ", - aliases: ["postal_horn"], - tags: [], - category: "Objects", - description: "postal horn", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ””", - aliases: ["bell"], - tags: ["sound", "notification"], - category: "Objects", - description: "bell", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”•", - aliases: ["no_bell"], - tags: ["volume", "off"], - category: "Objects", - description: "bell with slash", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽผ", - aliases: ["musical_score"], - tags: [], - category: "Objects", - description: "musical score", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽต", - aliases: ["musical_note"], - tags: [], - category: "Objects", - description: "musical note", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽถ", - aliases: ["notes"], - tags: ["music"], - category: "Objects", - description: "musical notes", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽ™๏ธ", - aliases: ["studio_microphone"], - tags: ["podcast"], - category: "Objects", - description: "studio microphone", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽš๏ธ", - aliases: ["level_slider"], - tags: [], - category: "Objects", - description: "level slider", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽ›๏ธ", - aliases: ["control_knobs"], - tags: [], - category: "Objects", - description: "control knobs", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽค", - aliases: ["microphone"], - tags: ["sing"], - category: "Objects", - description: "microphone", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽง", - aliases: ["headphones"], - tags: ["music", "earphones"], - category: "Objects", - description: "headphone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ป", - aliases: ["radio"], - tags: ["podcast"], - category: "Objects", - description: "radio", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽท", - aliases: ["saxophone"], - tags: [], - category: "Objects", - description: "saxophone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช—", - aliases: ["accordion"], - tags: [], - category: "Objects", - description: "accordion", - unicode_version: "13.0", - }, - { - emoji: "๐ŸŽธ", - aliases: ["guitar"], - tags: ["rock"], - category: "Objects", - description: "guitar", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽน", - aliases: ["musical_keyboard"], - tags: ["piano"], - category: "Objects", - description: "musical keyboard", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽบ", - aliases: ["trumpet"], - tags: [], - category: "Objects", - description: "trumpet", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽป", - aliases: ["violin"], - tags: [], - category: "Objects", - description: "violin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช•", - aliases: ["banjo"], - tags: [], - category: "Objects", - description: "banjo", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฅ", - aliases: ["drum"], - tags: [], - category: "Objects", - description: "drum", - unicode_version: "", - }, - { - emoji: "๐Ÿช˜", - aliases: ["long_drum"], - tags: [], - category: "Objects", - description: "long drum", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ“ฑ", - aliases: ["iphone"], - tags: ["smartphone", "mobile"], - category: "Objects", - description: "mobile phone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฒ", - aliases: ["calling"], - tags: ["call", "incoming"], - category: "Objects", - description: "mobile phone with arrow", - unicode_version: "6.0", - }, - { - emoji: "โ˜Ž๏ธ", - aliases: ["phone", "telephone"], - tags: [], - category: "Objects", - description: "telephone", - unicode_version: "", - }, - { - emoji: "๐Ÿ“ž", - aliases: ["telephone_receiver"], - tags: ["phone", "call"], - category: "Objects", - description: "telephone receiver", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“Ÿ", - aliases: ["pager"], - tags: [], - category: "Objects", - description: "pager", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ ", - aliases: ["fax"], - tags: [], - category: "Objects", - description: "fax machine", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”‹", - aliases: ["battery"], - tags: ["power"], - category: "Objects", - description: "battery", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”Œ", - aliases: ["electric_plug"], - tags: [], - category: "Objects", - description: "electric plug", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ป", - aliases: ["computer"], - tags: ["desktop", "screen"], - category: "Objects", - description: "laptop", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ–ฅ๏ธ", - aliases: ["desktop_computer"], - tags: [], - category: "Objects", - description: "desktop computer", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ–จ๏ธ", - aliases: ["printer"], - tags: [], - category: "Objects", - description: "printer", - unicode_version: "7.0", - }, - { - emoji: "โŒจ๏ธ", - aliases: ["keyboard"], - tags: [], - category: "Objects", - description: "keyboard", - unicode_version: "", - }, - { - emoji: "๐Ÿ–ฑ๏ธ", - aliases: ["computer_mouse"], - tags: [], - category: "Objects", - description: "computer mouse", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ–ฒ๏ธ", - aliases: ["trackball"], - tags: [], - category: "Objects", - description: "trackball", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ’ฝ", - aliases: ["minidisc"], - tags: [], - category: "Objects", - description: "computer disk", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’พ", - aliases: ["floppy_disk"], - tags: ["save"], - category: "Objects", - description: "floppy disk", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ฟ", - aliases: ["cd"], - tags: [], - category: "Objects", - description: "optical disk", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“€", - aliases: ["dvd"], - tags: [], - category: "Objects", - description: "dvd", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงฎ", - aliases: ["abacus"], - tags: [], - category: "Objects", - description: "abacus", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽฅ", - aliases: ["movie_camera"], - tags: ["film", "video"], - category: "Objects", - description: "movie camera", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽž๏ธ", - aliases: ["film_strip"], - tags: [], - category: "Objects", - description: "film frames", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“ฝ๏ธ", - aliases: ["film_projector"], - tags: [], - category: "Objects", - description: "film projector", - unicode_version: "7.0", - }, - { - emoji: "๐ŸŽฌ", - aliases: ["clapper"], - tags: ["film"], - category: "Objects", - description: "clapper board", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“บ", - aliases: ["tv"], - tags: [], - category: "Objects", - description: "television", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ท", - aliases: ["camera"], - tags: ["photo"], - category: "Objects", - description: "camera", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ธ", - aliases: ["camera_flash"], - tags: ["photo"], - category: "Objects", - description: "camera with flash", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“น", - aliases: ["video_camera"], - tags: [], - category: "Objects", - description: "video camera", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ผ", - aliases: ["vhs"], - tags: [], - category: "Objects", - description: "videocassette", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["mag"], - tags: ["search", "zoom"], - category: "Objects", - description: "magnifying glass tilted left", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”Ž", - aliases: ["mag_right"], - tags: [], - category: "Objects", - description: "magnifying glass tilted right", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ•ฏ๏ธ", - aliases: ["candle"], - tags: [], - category: "Objects", - description: "candle", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ’ก", - aliases: ["bulb"], - tags: ["idea", "light"], - category: "Objects", - description: "light bulb", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ฆ", - aliases: ["flashlight"], - tags: [], - category: "Objects", - description: "flashlight", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฎ", - aliases: ["izakaya_lantern", "lantern"], - tags: [], - category: "Objects", - description: "red paper lantern", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช”", - aliases: ["diya_lamp"], - tags: [], - category: "Objects", - description: "diya lamp", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ“”", - aliases: ["notebook_with_decorative_cover"], - tags: [], - category: "Objects", - description: "notebook with decorative cover", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“•", - aliases: ["closed_book"], - tags: [], - category: "Objects", - description: "closed book", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“–", - aliases: ["book", "open_book"], - tags: [], - category: "Objects", - description: "open book", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“—", - aliases: ["green_book"], - tags: [], - category: "Objects", - description: "green book", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“˜", - aliases: ["blue_book"], - tags: [], - category: "Objects", - description: "blue book", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“™", - aliases: ["orange_book"], - tags: [], - category: "Objects", - description: "orange book", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“š", - aliases: ["books"], - tags: ["library"], - category: "Objects", - description: "books", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ““", - aliases: ["notebook"], - tags: [], - category: "Objects", - description: "notebook", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“’", - aliases: ["ledger"], - tags: [], - category: "Objects", - description: "ledger", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ƒ", - aliases: ["page_with_curl"], - tags: [], - category: "Objects", - description: "page with curl", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“œ", - aliases: ["scroll"], - tags: ["document"], - category: "Objects", - description: "scroll", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“„", - aliases: ["page_facing_up"], - tags: ["document"], - category: "Objects", - description: "page facing up", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฐ", - aliases: ["newspaper"], - tags: ["press"], - category: "Objects", - description: "newspaper", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—ž๏ธ", - aliases: ["newspaper_roll"], - tags: ["press"], - category: "Objects", - description: "rolled-up newspaper", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“‘", - aliases: ["bookmark_tabs"], - tags: [], - category: "Objects", - description: "bookmark tabs", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”–", - aliases: ["bookmark"], - tags: [], - category: "Objects", - description: "bookmark", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿท๏ธ", - aliases: ["label"], - tags: ["tag"], - category: "Objects", - description: "label", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ’ฐ", - aliases: ["moneybag"], - tags: ["dollar", "cream"], - category: "Objects", - description: "money bag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช™", - aliases: ["coin"], - tags: [], - category: "Objects", - description: "coin", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ’ด", - aliases: ["yen"], - tags: [], - category: "Objects", - description: "yen banknote", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ต", - aliases: ["dollar"], - tags: ["money"], - category: "Objects", - description: "dollar banknote", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ถ", - aliases: ["euro"], - tags: [], - category: "Objects", - description: "euro banknote", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ท", - aliases: ["pound"], - tags: [], - category: "Objects", - description: "pound banknote", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ธ", - aliases: ["money_with_wings"], - tags: ["dollar"], - category: "Objects", - description: "money with wings", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ณ", - aliases: ["credit_card"], - tags: ["subscription"], - category: "Objects", - description: "credit card", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿงพ", - aliases: ["receipt"], - tags: [], - category: "Objects", - description: "receipt", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ’น", - aliases: ["chart"], - tags: [], - category: "Objects", - description: "chart increasing with yen", - unicode_version: "6.0", - }, - { - emoji: "โœ‰๏ธ", - aliases: ["envelope"], - tags: ["letter", "email"], - category: "Objects", - description: "envelope", - unicode_version: "", - }, - { - emoji: "๐Ÿ“ง", - aliases: ["email", "e-mail"], - tags: [], - category: "Objects", - description: "e-mail", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“จ", - aliases: ["incoming_envelope"], - tags: [], - category: "Objects", - description: "incoming envelope", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฉ", - aliases: ["envelope_with_arrow"], - tags: [], - category: "Objects", - description: "envelope with arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ค", - aliases: ["outbox_tray"], - tags: [], - category: "Objects", - description: "outbox tray", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฅ", - aliases: ["inbox_tray"], - tags: [], - category: "Objects", - description: "inbox tray", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฆ", - aliases: ["package"], - tags: ["shipping"], - category: "Objects", - description: "package", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ซ", - aliases: ["mailbox"], - tags: [], - category: "Objects", - description: "closed mailbox with raised flag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ช", - aliases: ["mailbox_closed"], - tags: [], - category: "Objects", - description: "closed mailbox with lowered flag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฌ", - aliases: ["mailbox_with_mail"], - tags: [], - category: "Objects", - description: "open mailbox with raised flag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ญ", - aliases: ["mailbox_with_no_mail"], - tags: [], - category: "Objects", - description: "open mailbox with lowered flag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ฎ", - aliases: ["postbox"], - tags: [], - category: "Objects", - description: "postbox", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—ณ๏ธ", - aliases: ["ballot_box"], - tags: [], - category: "Objects", - description: "ballot box with ballot", - unicode_version: "7.0", - }, - { - emoji: "โœ๏ธ", - aliases: ["pencil2"], - tags: [], - category: "Objects", - description: "pencil", - unicode_version: "", - }, - { - emoji: "โœ’๏ธ", - aliases: ["black_nib"], - tags: [], - category: "Objects", - description: "black nib", - unicode_version: "", - }, - { - emoji: "๐Ÿ–‹๏ธ", - aliases: ["fountain_pen"], - tags: [], - category: "Objects", - description: "fountain pen", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ–Š๏ธ", - aliases: ["pen"], - tags: [], - category: "Objects", - description: "pen", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ–Œ๏ธ", - aliases: ["paintbrush"], - tags: [], - category: "Objects", - description: "paintbrush", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ–๏ธ", - aliases: ["crayon"], - tags: [], - category: "Objects", - description: "crayon", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["memo", "pencil"], - tags: ["document", "note"], - category: "Objects", - description: "memo", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ผ", - aliases: ["briefcase"], - tags: ["business"], - category: "Objects", - description: "briefcase", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["file_folder"], - tags: ["directory"], - category: "Objects", - description: "file folder", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“‚", - aliases: ["open_file_folder"], - tags: [], - category: "Objects", - description: "open file folder", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—‚๏ธ", - aliases: ["card_index_dividers"], - tags: [], - category: "Objects", - description: "card index dividers", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“…", - aliases: ["date"], - tags: ["calendar", "schedule"], - category: "Objects", - description: "calendar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“†", - aliases: ["calendar"], - tags: ["schedule"], - category: "Objects", - description: "tear-off calendar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—’๏ธ", - aliases: ["spiral_notepad"], - tags: [], - category: "Objects", - description: "spiral notepad", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ—“๏ธ", - aliases: ["spiral_calendar"], - tags: [], - category: "Objects", - description: "spiral calendar", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“‡", - aliases: ["card_index"], - tags: [], - category: "Objects", - description: "card index", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ˆ", - aliases: ["chart_with_upwards_trend"], - tags: ["graph", "metrics"], - category: "Objects", - description: "chart increasing", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“‰", - aliases: ["chart_with_downwards_trend"], - tags: ["graph", "metrics"], - category: "Objects", - description: "chart decreasing", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“Š", - aliases: ["bar_chart"], - tags: ["stats", "metrics"], - category: "Objects", - description: "bar chart", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“‹", - aliases: ["clipboard"], - tags: [], - category: "Objects", - description: "clipboard", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“Œ", - aliases: ["pushpin"], - tags: ["location"], - category: "Objects", - description: "pushpin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["round_pushpin"], - tags: ["location"], - category: "Objects", - description: "round pushpin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“Ž", - aliases: ["paperclip"], - tags: [], - category: "Objects", - description: "paperclip", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ–‡๏ธ", - aliases: ["paperclips"], - tags: [], - category: "Objects", - description: "linked paperclips", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["straight_ruler"], - tags: [], - category: "Objects", - description: "straight ruler", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“", - aliases: ["triangular_ruler"], - tags: [], - category: "Objects", - description: "triangular ruler", - unicode_version: "6.0", - }, - { - emoji: "โœ‚๏ธ", - aliases: ["scissors"], - tags: ["cut"], - category: "Objects", - description: "scissors", - unicode_version: "", - }, - { - emoji: "๐Ÿ—ƒ๏ธ", - aliases: ["card_file_box"], - tags: [], - category: "Objects", - description: "card file box", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ—„๏ธ", - aliases: ["file_cabinet"], - tags: [], - category: "Objects", - description: "file cabinet", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ—‘๏ธ", - aliases: ["wastebasket"], - tags: ["trash"], - category: "Objects", - description: "wastebasket", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ”’", - aliases: ["lock"], - tags: ["security", "private"], - category: "Objects", - description: "locked", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”“", - aliases: ["unlock"], - tags: ["security"], - category: "Objects", - description: "unlocked", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["lock_with_ink_pen"], - tags: [], - category: "Objects", - description: "locked with pen", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["closed_lock_with_key"], - tags: ["security"], - category: "Objects", - description: "locked with key", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”‘", - aliases: ["key"], - tags: ["lock", "password"], - category: "Objects", - description: "key", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ—๏ธ", - aliases: ["old_key"], - tags: [], - category: "Objects", - description: "old key", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ”จ", - aliases: ["hammer"], - tags: ["tool"], - category: "Objects", - description: "hammer", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช“", - aliases: ["axe"], - tags: [], - category: "Objects", - description: "axe", - unicode_version: "12.0", - }, - { - emoji: "โ›๏ธ", - aliases: ["pick"], - tags: [], - category: "Objects", - description: "pick", - unicode_version: "5.2", - }, - { - emoji: "โš’๏ธ", - aliases: ["hammer_and_pick"], - tags: [], - category: "Objects", - description: "hammer and pick", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ› ๏ธ", - aliases: ["hammer_and_wrench"], - tags: [], - category: "Objects", - description: "hammer and wrench", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ—ก๏ธ", - aliases: ["dagger"], - tags: [], - category: "Objects", - description: "dagger", - unicode_version: "7.0", - }, - { - emoji: "โš”๏ธ", - aliases: ["crossed_swords"], - tags: [], - category: "Objects", - description: "crossed swords", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ”ซ", - aliases: ["gun"], - tags: ["shoot", "weapon"], - category: "Objects", - description: "water pistol", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿชƒ", - aliases: ["boomerang"], - tags: [], - category: "Objects", - description: "boomerang", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿน", - aliases: ["bow_and_arrow"], - tags: ["archery"], - category: "Objects", - description: "bow and arrow", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ›ก๏ธ", - aliases: ["shield"], - tags: [], - category: "Objects", - description: "shield", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿชš", - aliases: ["carpentry_saw"], - tags: [], - category: "Objects", - description: "carpentry saw", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ”ง", - aliases: ["wrench"], - tags: ["tool"], - category: "Objects", - description: "wrench", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช›", - aliases: ["screwdriver"], - tags: [], - category: "Objects", - description: "screwdriver", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ”ฉ", - aliases: ["nut_and_bolt"], - tags: [], - category: "Objects", - description: "nut and bolt", - unicode_version: "6.0", - }, - { - emoji: "โš™๏ธ", - aliases: ["gear"], - tags: [], - category: "Objects", - description: "gear", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ—œ๏ธ", - aliases: ["clamp"], - tags: [], - category: "Objects", - description: "clamp", - unicode_version: "7.0", - }, - { - emoji: "โš–๏ธ", - aliases: ["balance_scale"], - tags: [], - category: "Objects", - description: "balance scale", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿฆฏ", - aliases: ["probing_cane"], - tags: [], - category: "Objects", - description: "white cane", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ”—", - aliases: ["link"], - tags: [], - category: "Objects", - description: "link", - unicode_version: "6.0", - }, - { - emoji: "โ›“๏ธ", - aliases: ["chains"], - tags: [], - category: "Objects", - description: "chains", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿช", - aliases: ["hook"], - tags: [], - category: "Objects", - description: "hook", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿงฐ", - aliases: ["toolbox"], - tags: [], - category: "Objects", - description: "toolbox", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงฒ", - aliases: ["magnet"], - tags: [], - category: "Objects", - description: "magnet", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชœ", - aliases: ["ladder"], - tags: [], - category: "Objects", - description: "ladder", - unicode_version: "13.0", - }, - { - emoji: "โš—๏ธ", - aliases: ["alembic"], - tags: [], - category: "Objects", - description: "alembic", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿงช", - aliases: ["test_tube"], - tags: [], - category: "Objects", - description: "test tube", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงซ", - aliases: ["petri_dish"], - tags: [], - category: "Objects", - description: "petri dish", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงฌ", - aliases: ["dna"], - tags: [], - category: "Objects", - description: "dna", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ”ฌ", - aliases: ["microscope"], - tags: ["science", "laboratory", "investigate"], - category: "Objects", - description: "microscope", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ญ", - aliases: ["telescope"], - tags: [], - category: "Objects", - description: "telescope", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ก", - aliases: ["satellite"], - tags: ["signal"], - category: "Objects", - description: "satellite antenna", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’‰", - aliases: ["syringe"], - tags: ["health", "hospital", "needle"], - category: "Objects", - description: "syringe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฉธ", - aliases: ["drop_of_blood"], - tags: [], - category: "Objects", - description: "drop of blood", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ’Š", - aliases: ["pill"], - tags: ["health", "medicine"], - category: "Objects", - description: "pill", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿฉน", - aliases: ["adhesive_bandage"], - tags: [], - category: "Objects", - description: "adhesive bandage", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿฉบ", - aliases: ["stethoscope"], - tags: [], - category: "Objects", - description: "stethoscope", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿšช", - aliases: ["door"], - tags: [], - category: "Objects", - description: "door", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›—", - aliases: ["elevator"], - tags: [], - category: "Objects", - description: "elevator", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿชž", - aliases: ["mirror"], - tags: [], - category: "Objects", - description: "mirror", - unicode_version: "13.0", - }, - { - emoji: "๐ŸชŸ", - aliases: ["window"], - tags: [], - category: "Objects", - description: "window", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿ›๏ธ", - aliases: ["bed"], - tags: [], - category: "Objects", - description: "bed", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿ›‹๏ธ", - aliases: ["couch_and_lamp"], - tags: [], - category: "Objects", - description: "couch and lamp", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿช‘", - aliases: ["chair"], - tags: [], - category: "Objects", - description: "chair", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿšฝ", - aliases: ["toilet"], - tags: ["wc"], - category: "Objects", - description: "toilet", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿช ", - aliases: ["plunger"], - tags: [], - category: "Objects", - description: "plunger", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿšฟ", - aliases: ["shower"], - tags: ["bath"], - category: "Objects", - description: "shower", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›", - aliases: ["bathtub"], - tags: [], - category: "Objects", - description: "bathtub", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿชค", - aliases: ["mouse_trap"], - tags: [], - category: "Objects", - description: "mouse trap", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿช’", - aliases: ["razor"], - tags: [], - category: "Objects", - description: "razor", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿงด", - aliases: ["lotion_bottle"], - tags: [], - category: "Objects", - description: "lotion bottle", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงท", - aliases: ["safety_pin"], - tags: [], - category: "Objects", - description: "safety pin", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงน", - aliases: ["broom"], - tags: [], - category: "Objects", - description: "broom", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงบ", - aliases: ["basket"], - tags: [], - category: "Objects", - description: "basket", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงป", - aliases: ["roll_of_paper"], - tags: ["toilet"], - category: "Objects", - description: "roll of paper", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชฃ", - aliases: ["bucket"], - tags: [], - category: "Objects", - description: "bucket", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿงผ", - aliases: ["soap"], - tags: [], - category: "Objects", - description: "soap", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿชฅ", - aliases: ["toothbrush"], - tags: [], - category: "Objects", - description: "toothbrush", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿงฝ", - aliases: ["sponge"], - tags: [], - category: "Objects", - description: "sponge", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿงฏ", - aliases: ["fire_extinguisher"], - tags: [], - category: "Objects", - description: "fire extinguisher", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ›’", - aliases: ["shopping_cart"], - tags: [], - category: "Objects", - description: "shopping cart", - unicode_version: "9.0", - }, - { - emoji: "๐Ÿšฌ", - aliases: ["smoking"], - tags: ["cigarette"], - category: "Objects", - description: "cigarette", - unicode_version: "6.0", - }, - { - emoji: "โšฐ๏ธ", - aliases: ["coffin"], - tags: ["funeral"], - category: "Objects", - description: "coffin", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿชฆ", - aliases: ["headstone"], - tags: [], - category: "Objects", - description: "headstone", - unicode_version: "13.0", - }, - { - emoji: "โšฑ๏ธ", - aliases: ["funeral_urn"], - tags: [], - category: "Objects", - description: "funeral urn", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ—ฟ", - aliases: ["moyai"], - tags: ["stone"], - category: "Objects", - description: "moai", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿชง", - aliases: ["placard"], - tags: [], - category: "Objects", - description: "placard", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿง", - aliases: ["atm"], - tags: [], - category: "Symbols", - description: "ATM sign", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฎ", - aliases: ["put_litter_in_its_place"], - tags: [], - category: "Symbols", - description: "litter in bin sign", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฐ", - aliases: ["potable_water"], - tags: [], - category: "Symbols", - description: "potable water", - unicode_version: "6.0", - }, - { - emoji: "โ™ฟ", - aliases: ["wheelchair"], - tags: ["accessibility"], - category: "Symbols", - description: "wheelchair symbol", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿšน", - aliases: ["mens"], - tags: [], - category: "Symbols", - description: "menโ€™s room", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšบ", - aliases: ["womens"], - tags: [], - category: "Symbols", - description: "womenโ€™s room", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšป", - aliases: ["restroom"], - tags: ["toilet"], - category: "Symbols", - description: "restroom", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšผ", - aliases: ["baby_symbol"], - tags: [], - category: "Symbols", - description: "baby symbol", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšพ", - aliases: ["wc"], - tags: ["toilet", "restroom"], - category: "Symbols", - description: "water closet", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›‚", - aliases: ["passport_control"], - tags: [], - category: "Symbols", - description: "passport control", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›ƒ", - aliases: ["customs"], - tags: [], - category: "Symbols", - description: "customs", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›„", - aliases: ["baggage_claim"], - tags: ["airport"], - category: "Symbols", - description: "baggage claim", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›…", - aliases: ["left_luggage"], - tags: [], - category: "Symbols", - description: "left luggage", - unicode_version: "6.0", - }, - { - emoji: "โš ๏ธ", - aliases: ["warning"], - tags: ["wip"], - category: "Symbols", - description: "warning", - unicode_version: "4.0", - }, - { - emoji: "๐Ÿšธ", - aliases: ["children_crossing"], - tags: [], - category: "Symbols", - description: "children crossing", - unicode_version: "6.0", - }, - { - emoji: "โ›”", - aliases: ["no_entry"], - tags: ["limit"], - category: "Symbols", - description: "no entry", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿšซ", - aliases: ["no_entry_sign"], - tags: ["block", "forbidden"], - category: "Symbols", - description: "prohibited", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšณ", - aliases: ["no_bicycles"], - tags: [], - category: "Symbols", - description: "no bicycles", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšญ", - aliases: ["no_smoking"], - tags: [], - category: "Symbols", - description: "no smoking", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฏ", - aliases: ["do_not_litter"], - tags: [], - category: "Symbols", - description: "no littering", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฑ", - aliases: ["non-potable_water"], - tags: [], - category: "Symbols", - description: "non-potable water", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšท", - aliases: ["no_pedestrians"], - tags: [], - category: "Symbols", - description: "no pedestrians", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ต", - aliases: ["no_mobile_phones"], - tags: [], - category: "Symbols", - description: "no mobile phones", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ž", - aliases: ["underage"], - tags: [], - category: "Symbols", - description: "no one under eighteen", - unicode_version: "6.0", - }, - { - emoji: "โ˜ข๏ธ", - aliases: ["radioactive"], - tags: [], - category: "Symbols", - description: "radioactive", - unicode_version: "", - }, - { - emoji: "โ˜ฃ๏ธ", - aliases: ["biohazard"], - tags: [], - category: "Symbols", - description: "biohazard", - unicode_version: "", - }, - { - emoji: "โฌ†๏ธ", - aliases: ["arrow_up"], - tags: [], - category: "Symbols", - description: "up arrow", - unicode_version: "4.0", - }, - { - emoji: "โ†—๏ธ", - aliases: ["arrow_upper_right"], - tags: [], - category: "Symbols", - description: "up-right arrow", - unicode_version: "", - }, - { - emoji: "โžก๏ธ", - aliases: ["arrow_right"], - tags: [], - category: "Symbols", - description: "right arrow", - unicode_version: "", - }, - { - emoji: "โ†˜๏ธ", - aliases: ["arrow_lower_right"], - tags: [], - category: "Symbols", - description: "down-right arrow", - unicode_version: "", - }, - { - emoji: "โฌ‡๏ธ", - aliases: ["arrow_down"], - tags: [], - category: "Symbols", - description: "down arrow", - unicode_version: "4.0", - }, - { - emoji: "โ†™๏ธ", - aliases: ["arrow_lower_left"], - tags: [], - category: "Symbols", - description: "down-left arrow", - unicode_version: "", - }, - { - emoji: "โฌ…๏ธ", - aliases: ["arrow_left"], - tags: [], - category: "Symbols", - description: "left arrow", - unicode_version: "4.0", - }, - { - emoji: "โ†–๏ธ", - aliases: ["arrow_upper_left"], - tags: [], - category: "Symbols", - description: "up-left arrow", - unicode_version: "", - }, - { - emoji: "โ†•๏ธ", - aliases: ["arrow_up_down"], - tags: [], - category: "Symbols", - description: "up-down arrow", - unicode_version: "", - }, - { - emoji: "โ†”๏ธ", - aliases: ["left_right_arrow"], - tags: [], - category: "Symbols", - description: "left-right arrow", - unicode_version: "", - }, - { - emoji: "โ†ฉ๏ธ", - aliases: ["leftwards_arrow_with_hook"], - tags: ["return"], - category: "Symbols", - description: "right arrow curving left", - unicode_version: "", - }, - { - emoji: "โ†ช๏ธ", - aliases: ["arrow_right_hook"], - tags: [], - category: "Symbols", - description: "left arrow curving right", - unicode_version: "", - }, - { - emoji: "โคด๏ธ", - aliases: ["arrow_heading_up"], - tags: [], - category: "Symbols", - description: "right arrow curving up", - unicode_version: "", - }, - { - emoji: "โคต๏ธ", - aliases: ["arrow_heading_down"], - tags: [], - category: "Symbols", - description: "right arrow curving down", - unicode_version: "", - }, - { - emoji: "๐Ÿ”ƒ", - aliases: ["arrows_clockwise"], - tags: [], - category: "Symbols", - description: "clockwise vertical arrows", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”„", - aliases: ["arrows_counterclockwise"], - tags: ["sync"], - category: "Symbols", - description: "counterclockwise arrows button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”™", - aliases: ["back"], - tags: [], - category: "Symbols", - description: "BACK arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”š", - aliases: ["end"], - tags: [], - category: "Symbols", - description: "END arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”›", - aliases: ["on"], - tags: [], - category: "Symbols", - description: "ON! arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”œ", - aliases: ["soon"], - tags: [], - category: "Symbols", - description: "SOON arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["top"], - tags: [], - category: "Symbols", - description: "TOP arrow", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ›", - aliases: ["place_of_worship"], - tags: [], - category: "Symbols", - description: "place of worship", - unicode_version: "8.0", - }, - { - emoji: "โš›๏ธ", - aliases: ["atom_symbol"], - tags: [], - category: "Symbols", - description: "atom symbol", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ•‰๏ธ", - aliases: ["om"], - tags: [], - category: "Symbols", - description: "om", - unicode_version: "7.0", - }, - { - emoji: "โœก๏ธ", - aliases: ["star_of_david"], - tags: [], - category: "Symbols", - description: "star of David", - unicode_version: "", - }, - { - emoji: "โ˜ธ๏ธ", - aliases: ["wheel_of_dharma"], - tags: [], - category: "Symbols", - description: "wheel of dharma", - unicode_version: "", - }, - { - emoji: "โ˜ฏ๏ธ", - aliases: ["yin_yang"], - tags: [], - category: "Symbols", - description: "yin yang", - unicode_version: "", - }, - { - emoji: "โœ๏ธ", - aliases: ["latin_cross"], - tags: [], - category: "Symbols", - description: "latin cross", - unicode_version: "", - }, - { - emoji: "โ˜ฆ๏ธ", - aliases: ["orthodox_cross"], - tags: [], - category: "Symbols", - description: "orthodox cross", - unicode_version: "", - }, - { - emoji: "โ˜ช๏ธ", - aliases: ["star_and_crescent"], - tags: [], - category: "Symbols", - description: "star and crescent", - unicode_version: "", - }, - { - emoji: "โ˜ฎ๏ธ", - aliases: ["peace_symbol"], - tags: [], - category: "Symbols", - description: "peace symbol", - unicode_version: "", - }, - { - emoji: "๐Ÿ•Ž", - aliases: ["menorah"], - tags: [], - category: "Symbols", - description: "menorah", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ”ฏ", - aliases: ["six_pointed_star"], - tags: [], - category: "Symbols", - description: "dotted six-pointed star", - unicode_version: "6.0", - }, - { - emoji: "โ™ˆ", - aliases: ["aries"], - tags: [], - category: "Symbols", - description: "Aries", - unicode_version: "", - }, - { - emoji: "โ™‰", - aliases: ["taurus"], - tags: [], - category: "Symbols", - description: "Taurus", - unicode_version: "", - }, - { - emoji: "โ™Š", - aliases: ["gemini"], - tags: [], - category: "Symbols", - description: "Gemini", - unicode_version: "", - }, - { - emoji: "โ™‹", - aliases: ["cancer"], - tags: [], - category: "Symbols", - description: "Cancer", - unicode_version: "", - }, - { - emoji: "โ™Œ", - aliases: ["leo"], - tags: [], - category: "Symbols", - description: "Leo", - unicode_version: "", - }, - { - emoji: "โ™", - aliases: ["virgo"], - tags: [], - category: "Symbols", - description: "Virgo", - unicode_version: "", - }, - { - emoji: "โ™Ž", - aliases: ["libra"], - tags: [], - category: "Symbols", - description: "Libra", - unicode_version: "", - }, - { - emoji: "โ™", - aliases: ["scorpius"], - tags: [], - category: "Symbols", - description: "Scorpio", - unicode_version: "", - }, - { - emoji: "โ™", - aliases: ["sagittarius"], - tags: [], - category: "Symbols", - description: "Sagittarius", - unicode_version: "", - }, - { - emoji: "โ™‘", - aliases: ["capricorn"], - tags: [], - category: "Symbols", - description: "Capricorn", - unicode_version: "", - }, - { - emoji: "โ™’", - aliases: ["aquarius"], - tags: [], - category: "Symbols", - description: "Aquarius", - unicode_version: "", - }, - { - emoji: "โ™“", - aliases: ["pisces"], - tags: [], - category: "Symbols", - description: "Pisces", - unicode_version: "", - }, - { - emoji: "โ›Ž", - aliases: ["ophiuchus"], - tags: [], - category: "Symbols", - description: "Ophiuchus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”€", - aliases: ["twisted_rightwards_arrows"], - tags: ["shuffle"], - category: "Symbols", - description: "shuffle tracks button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”", - aliases: ["repeat"], - tags: ["loop"], - category: "Symbols", - description: "repeat button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”‚", - aliases: ["repeat_one"], - tags: [], - category: "Symbols", - description: "repeat single button", - unicode_version: "6.0", - }, - { - emoji: "โ–ถ๏ธ", - aliases: ["arrow_forward"], - tags: [], - category: "Symbols", - description: "play button", - unicode_version: "", - }, - { - emoji: "โฉ", - aliases: ["fast_forward"], - tags: [], - category: "Symbols", - description: "fast-forward button", - unicode_version: "6.0", - }, - { - emoji: "โญ๏ธ", - aliases: ["next_track_button"], - tags: [], - category: "Symbols", - description: "next track button", - unicode_version: "6.0", - }, - { - emoji: "โฏ๏ธ", - aliases: ["play_or_pause_button"], - tags: [], - category: "Symbols", - description: "play or pause button", - unicode_version: "6.0", - }, - { - emoji: "โ—€๏ธ", - aliases: ["arrow_backward"], - tags: [], - category: "Symbols", - description: "reverse button", - unicode_version: "", - }, - { - emoji: "โช", - aliases: ["rewind"], - tags: [], - category: "Symbols", - description: "fast reverse button", - unicode_version: "6.0", - }, - { - emoji: "โฎ๏ธ", - aliases: ["previous_track_button"], - tags: [], - category: "Symbols", - description: "last track button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ผ", - aliases: ["arrow_up_small"], - tags: [], - category: "Symbols", - description: "upwards button", - unicode_version: "6.0", - }, - { - emoji: "โซ", - aliases: ["arrow_double_up"], - tags: [], - category: "Symbols", - description: "fast up button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ฝ", - aliases: ["arrow_down_small"], - tags: [], - category: "Symbols", - description: "downwards button", - unicode_version: "6.0", - }, - { - emoji: "โฌ", - aliases: ["arrow_double_down"], - tags: [], - category: "Symbols", - description: "fast down button", - unicode_version: "6.0", - }, - { - emoji: "โธ๏ธ", - aliases: ["pause_button"], - tags: [], - category: "Symbols", - description: "pause button", - unicode_version: "7.0", - }, - { - emoji: "โน๏ธ", - aliases: ["stop_button"], - tags: [], - category: "Symbols", - description: "stop button", - unicode_version: "7.0", - }, - { - emoji: "โบ๏ธ", - aliases: ["record_button"], - tags: [], - category: "Symbols", - description: "record button", - unicode_version: "7.0", - }, - { - emoji: "โ๏ธ", - aliases: ["eject_button"], - tags: [], - category: "Symbols", - description: "eject button", - unicode_version: "11.0", - }, - { - emoji: "๐ŸŽฆ", - aliases: ["cinema"], - tags: ["film", "movie"], - category: "Symbols", - description: "cinema", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”…", - aliases: ["low_brightness"], - tags: [], - category: "Symbols", - description: "dim button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”†", - aliases: ["high_brightness"], - tags: [], - category: "Symbols", - description: "bright button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ถ", - aliases: ["signal_strength"], - tags: ["wifi"], - category: "Symbols", - description: "antenna bars", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ณ", - aliases: ["vibration_mode"], - tags: [], - category: "Symbols", - description: "vibration mode", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“ด", - aliases: ["mobile_phone_off"], - tags: ["mute", "off"], - category: "Symbols", - description: "mobile phone off", - unicode_version: "6.0", - }, - { - emoji: "โ™€๏ธ", - aliases: ["female_sign"], - tags: [], - category: "Symbols", - description: "female sign", - unicode_version: "11.0", - }, - { - emoji: "โ™‚๏ธ", - aliases: ["male_sign"], - tags: [], - category: "Symbols", - description: "male sign", - unicode_version: "11.0", - }, - { - emoji: "โšง๏ธ", - aliases: ["transgender_symbol"], - tags: [], - category: "Symbols", - description: "transgender symbol", - unicode_version: "13.0", - }, - { - emoji: "โœ–๏ธ", - aliases: ["heavy_multiplication_x"], - tags: [], - category: "Symbols", - description: "multiply", - unicode_version: "", - }, - { - emoji: "โž•", - aliases: ["heavy_plus_sign"], - tags: [], - category: "Symbols", - description: "plus", - unicode_version: "6.0", - }, - { - emoji: "โž–", - aliases: ["heavy_minus_sign"], - tags: [], - category: "Symbols", - description: "minus", - unicode_version: "6.0", - }, - { - emoji: "โž—", - aliases: ["heavy_division_sign"], - tags: [], - category: "Symbols", - description: "divide", - unicode_version: "6.0", - }, - { - emoji: "โ™พ๏ธ", - aliases: ["infinity"], - tags: [], - category: "Symbols", - description: "infinity", - unicode_version: "11.0", - }, - { - emoji: "โ€ผ๏ธ", - aliases: ["bangbang"], - tags: [], - category: "Symbols", - description: "double exclamation mark", - unicode_version: "", - }, - { - emoji: "โ‰๏ธ", - aliases: ["interrobang"], - tags: [], - category: "Symbols", - description: "exclamation question mark", - unicode_version: "3.0", - }, - { - emoji: "โ“", - aliases: ["question"], - tags: ["confused"], - category: "Symbols", - description: "red question mark", - unicode_version: "6.0", - }, - { - emoji: "โ”", - aliases: ["grey_question"], - tags: [], - category: "Symbols", - description: "white question mark", - unicode_version: "6.0", - }, - { - emoji: "โ•", - aliases: ["grey_exclamation"], - tags: [], - category: "Symbols", - description: "white exclamation mark", - unicode_version: "6.0", - }, - { - emoji: "โ—", - aliases: ["exclamation", "heavy_exclamation_mark"], - tags: ["bang"], - category: "Symbols", - description: "red exclamation mark", - unicode_version: "5.2", - }, - { - emoji: "ใ€ฐ๏ธ", - aliases: ["wavy_dash"], - tags: [], - category: "Symbols", - description: "wavy dash", - unicode_version: "", - }, - { - emoji: "๐Ÿ’ฑ", - aliases: ["currency_exchange"], - tags: [], - category: "Symbols", - description: "currency exchange", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ฒ", - aliases: ["heavy_dollar_sign"], - tags: [], - category: "Symbols", - description: "heavy dollar sign", - unicode_version: "6.0", - }, - { - emoji: "โš•๏ธ", - aliases: ["medical_symbol"], - tags: [], - category: "Symbols", - description: "medical symbol", - unicode_version: "11.0", - }, - { - emoji: "โ™ป๏ธ", - aliases: ["recycle"], - tags: ["environment", "green"], - category: "Symbols", - description: "recycling symbol", - unicode_version: "3.2", - }, - { - emoji: "โšœ๏ธ", - aliases: ["fleur_de_lis"], - tags: [], - category: "Symbols", - description: "fleur-de-lis", - unicode_version: "4.1", - }, - { - emoji: "๐Ÿ”ฑ", - aliases: ["trident"], - tags: [], - category: "Symbols", - description: "trident emblem", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ“›", - aliases: ["name_badge"], - tags: [], - category: "Symbols", - description: "name badge", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ฐ", - aliases: ["beginner"], - tags: [], - category: "Symbols", - description: "Japanese symbol for beginner", - unicode_version: "6.0", - }, - { - emoji: "โญ•", - aliases: ["o"], - tags: [], - category: "Symbols", - description: "hollow red circle", - unicode_version: "5.2", - }, - { - emoji: "โœ…", - aliases: ["white_check_mark"], - tags: [], - category: "Symbols", - description: "check mark button", - unicode_version: "6.0", - }, - { - emoji: "โ˜‘๏ธ", - aliases: ["ballot_box_with_check"], - tags: [], - category: "Symbols", - description: "check box with check", - unicode_version: "", - }, - { - emoji: "โœ”๏ธ", - aliases: ["heavy_check_mark"], - tags: [], - category: "Symbols", - description: "check mark", - unicode_version: "", - }, - { - emoji: "โŒ", - aliases: ["x"], - tags: [], - category: "Symbols", - description: "cross mark", - unicode_version: "6.0", - }, - { - emoji: "โŽ", - aliases: ["negative_squared_cross_mark"], - tags: [], - category: "Symbols", - description: "cross mark button", - unicode_version: "6.0", - }, - { - emoji: "โžฐ", - aliases: ["curly_loop"], - tags: [], - category: "Symbols", - description: "curly loop", - unicode_version: "6.0", - }, - { - emoji: "โžฟ", - aliases: ["loop"], - tags: [], - category: "Symbols", - description: "double curly loop", - unicode_version: "6.0", - }, - { - emoji: "ใ€ฝ๏ธ", - aliases: ["part_alternation_mark"], - tags: [], - category: "Symbols", - description: "part alternation mark", - unicode_version: "3.2", - }, - { - emoji: "โœณ๏ธ", - aliases: ["eight_spoked_asterisk"], - tags: [], - category: "Symbols", - description: "eight-spoked asterisk", - unicode_version: "", - }, - { - emoji: "โœด๏ธ", - aliases: ["eight_pointed_black_star"], - tags: [], - category: "Symbols", - description: "eight-pointed star", - unicode_version: "", - }, - { - emoji: "โ‡๏ธ", - aliases: ["sparkle"], - tags: [], - category: "Symbols", - description: "sparkle", - unicode_version: "", - }, - { - emoji: "ยฉ๏ธ", - aliases: ["copyright"], - tags: [], - category: "Symbols", - description: "copyright", - unicode_version: "", - }, - { - emoji: "ยฎ๏ธ", - aliases: ["registered"], - tags: [], - category: "Symbols", - description: "registered", - unicode_version: "", - }, - { - emoji: "โ„ข๏ธ", - aliases: ["tm"], - tags: ["trademark"], - category: "Symbols", - description: "trade mark", - unicode_version: "", - }, - { - emoji: "#๏ธโƒฃ", - aliases: ["hash"], - tags: ["number"], - category: "Symbols", - description: "keycap: #", - unicode_version: "", - }, - { - emoji: "*๏ธโƒฃ", - aliases: ["asterisk"], - tags: [], - category: "Symbols", - description: "keycap: *", - unicode_version: "", - }, - { - emoji: "0๏ธโƒฃ", - aliases: ["zero"], - tags: [], - category: "Symbols", - description: "keycap: 0", - unicode_version: "", - }, - { - emoji: "1๏ธโƒฃ", - aliases: ["one"], - tags: [], - category: "Symbols", - description: "keycap: 1", - unicode_version: "", - }, - { - emoji: "2๏ธโƒฃ", - aliases: ["two"], - tags: [], - category: "Symbols", - description: "keycap: 2", - unicode_version: "", - }, - { - emoji: "3๏ธโƒฃ", - aliases: ["three"], - tags: [], - category: "Symbols", - description: "keycap: 3", - unicode_version: "", - }, - { - emoji: "4๏ธโƒฃ", - aliases: ["four"], - tags: [], - category: "Symbols", - description: "keycap: 4", - unicode_version: "", - }, - { - emoji: "5๏ธโƒฃ", - aliases: ["five"], - tags: [], - category: "Symbols", - description: "keycap: 5", - unicode_version: "", - }, - { - emoji: "6๏ธโƒฃ", - aliases: ["six"], - tags: [], - category: "Symbols", - description: "keycap: 6", - unicode_version: "", - }, - { - emoji: "7๏ธโƒฃ", - aliases: ["seven"], - tags: [], - category: "Symbols", - description: "keycap: 7", - unicode_version: "", - }, - { - emoji: "8๏ธโƒฃ", - aliases: ["eight"], - tags: [], - category: "Symbols", - description: "keycap: 8", - unicode_version: "", - }, - { - emoji: "9๏ธโƒฃ", - aliases: ["nine"], - tags: [], - category: "Symbols", - description: "keycap: 9", - unicode_version: "", - }, - { - emoji: "๐Ÿ”Ÿ", - aliases: ["keycap_ten"], - tags: [], - category: "Symbols", - description: "keycap: 10", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ” ", - aliases: ["capital_abcd"], - tags: ["letters"], - category: "Symbols", - description: "input latin uppercase", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ก", - aliases: ["abcd"], - tags: [], - category: "Symbols", - description: "input latin lowercase", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ข", - aliases: ["1234"], - tags: ["numbers"], - category: "Symbols", - description: "input numbers", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ฃ", - aliases: ["symbols"], - tags: [], - category: "Symbols", - description: "input symbols", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ค", - aliases: ["abc"], - tags: ["alphabet"], - category: "Symbols", - description: "input latin letters", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ…ฐ๏ธ", - aliases: ["a"], - tags: [], - category: "Symbols", - description: "A button (blood type)", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†Ž", - aliases: ["ab"], - tags: [], - category: "Symbols", - description: "AB button (blood type)", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ…ฑ๏ธ", - aliases: ["b"], - tags: [], - category: "Symbols", - description: "B button (blood type)", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†‘", - aliases: ["cl"], - tags: [], - category: "Symbols", - description: "CL button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†’", - aliases: ["cool"], - tags: [], - category: "Symbols", - description: "COOL button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†“", - aliases: ["free"], - tags: [], - category: "Symbols", - description: "FREE button", - unicode_version: "6.0", - }, - { - emoji: "โ„น๏ธ", - aliases: ["information_source"], - tags: [], - category: "Symbols", - description: "information", - unicode_version: "3.0", - }, - { - emoji: "๐Ÿ†”", - aliases: ["id"], - tags: [], - category: "Symbols", - description: "ID button", - unicode_version: "6.0", - }, - { - emoji: "โ“‚๏ธ", - aliases: ["m"], - tags: [], - category: "Symbols", - description: "circled M", - unicode_version: "", - }, - { - emoji: "๐Ÿ†•", - aliases: ["new"], - tags: ["fresh"], - category: "Symbols", - description: "NEW button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†–", - aliases: ["ng"], - tags: [], - category: "Symbols", - description: "NG button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ…พ๏ธ", - aliases: ["o2"], - tags: [], - category: "Symbols", - description: "O button (blood type)", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†—", - aliases: ["ok"], - tags: ["yes"], - category: "Symbols", - description: "OK button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ…ฟ๏ธ", - aliases: ["parking"], - tags: [], - category: "Symbols", - description: "P button", - unicode_version: "5.2", - }, - { - emoji: "๐Ÿ†˜", - aliases: ["sos"], - tags: ["help", "emergency"], - category: "Symbols", - description: "SOS button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†™", - aliases: ["up"], - tags: [], - category: "Symbols", - description: "UP! button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ†š", - aliases: ["vs"], - tags: [], - category: "Symbols", - description: "VS button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆ", - aliases: ["koko"], - tags: [], - category: "Symbols", - description: "Japanese โ€œhereโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆ‚๏ธ", - aliases: ["sa"], - tags: [], - category: "Symbols", - description: "Japanese โ€œservice chargeโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆท๏ธ", - aliases: ["u6708"], - tags: [], - category: "Symbols", - description: "Japanese โ€œmonthly amountโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆถ", - aliases: ["u6709"], - tags: [], - category: "Symbols", - description: "Japanese โ€œnot free of chargeโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆฏ", - aliases: ["u6307"], - tags: [], - category: "Symbols", - description: "Japanese โ€œreservedโ€ button", - unicode_version: "", - }, - { - emoji: "๐Ÿ‰", - aliases: ["ideograph_advantage"], - tags: [], - category: "Symbols", - description: "Japanese โ€œbargainโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆน", - aliases: ["u5272"], - tags: [], - category: "Symbols", - description: "Japanese โ€œdiscountโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆš", - aliases: ["u7121"], - tags: [], - category: "Symbols", - description: "Japanese โ€œfree of chargeโ€ button", - unicode_version: "", - }, - { - emoji: "๐Ÿˆฒ", - aliases: ["u7981"], - tags: [], - category: "Symbols", - description: "Japanese โ€œprohibitedโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‰‘", - aliases: ["accept"], - tags: [], - category: "Symbols", - description: "Japanese โ€œacceptableโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆธ", - aliases: ["u7533"], - tags: [], - category: "Symbols", - description: "Japanese โ€œapplicationโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆด", - aliases: ["u5408"], - tags: [], - category: "Symbols", - description: "Japanese โ€œpassing gradeโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆณ", - aliases: ["u7a7a"], - tags: [], - category: "Symbols", - description: "Japanese โ€œvacancyโ€ button", - unicode_version: "6.0", - }, - { - emoji: "ใŠ—๏ธ", - aliases: ["congratulations"], - tags: [], - category: "Symbols", - description: "Japanese โ€œcongratulationsโ€ button", - unicode_version: "", - }, - { - emoji: "ใŠ™๏ธ", - aliases: ["secret"], - tags: [], - category: "Symbols", - description: "Japanese โ€œsecretโ€ button", - unicode_version: "", - }, - { - emoji: "๐Ÿˆบ", - aliases: ["u55b6"], - tags: [], - category: "Symbols", - description: "Japanese โ€œopen for businessโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿˆต", - aliases: ["u6e80"], - tags: [], - category: "Symbols", - description: "Japanese โ€œno vacancyโ€ button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ด", - aliases: ["red_circle"], - tags: [], - category: "Symbols", - description: "red circle", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŸ ", - aliases: ["orange_circle"], - tags: [], - category: "Symbols", - description: "orange circle", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸก", - aliases: ["yellow_circle"], - tags: [], - category: "Symbols", - description: "yellow circle", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸข", - aliases: ["green_circle"], - tags: [], - category: "Symbols", - description: "green circle", - unicode_version: "12.0", - }, - { - emoji: "๐Ÿ”ต", - aliases: ["large_blue_circle"], - tags: [], - category: "Symbols", - description: "blue circle", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŸฃ", - aliases: ["purple_circle"], - tags: [], - category: "Symbols", - description: "purple circle", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸค", - aliases: ["brown_circle"], - tags: [], - category: "Symbols", - description: "brown circle", - unicode_version: "12.0", - }, - { - emoji: "โšซ", - aliases: ["black_circle"], - tags: [], - category: "Symbols", - description: "black circle", - unicode_version: "4.1", - }, - { - emoji: "โšช", - aliases: ["white_circle"], - tags: [], - category: "Symbols", - description: "white circle", - unicode_version: "4.1", - }, - { - emoji: "๐ŸŸฅ", - aliases: ["red_square"], - tags: [], - category: "Symbols", - description: "red square", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸง", - aliases: ["orange_square"], - tags: [], - category: "Symbols", - description: "orange square", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸจ", - aliases: ["yellow_square"], - tags: [], - category: "Symbols", - description: "yellow square", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸฉ", - aliases: ["green_square"], - tags: [], - category: "Symbols", - description: "green square", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸฆ", - aliases: ["blue_square"], - tags: [], - category: "Symbols", - description: "blue square", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸช", - aliases: ["purple_square"], - tags: [], - category: "Symbols", - description: "purple square", - unicode_version: "12.0", - }, - { - emoji: "๐ŸŸซ", - aliases: ["brown_square"], - tags: [], - category: "Symbols", - description: "brown square", - unicode_version: "12.0", - }, - { - emoji: "โฌ›", - aliases: ["black_large_square"], - tags: [], - category: "Symbols", - description: "black large square", - unicode_version: "5.1", - }, - { - emoji: "โฌœ", - aliases: ["white_large_square"], - tags: [], - category: "Symbols", - description: "white large square", - unicode_version: "5.1", - }, - { - emoji: "โ—ผ๏ธ", - aliases: ["black_medium_square"], - tags: [], - category: "Symbols", - description: "black medium square", - unicode_version: "3.2", - }, - { - emoji: "โ—ป๏ธ", - aliases: ["white_medium_square"], - tags: [], - category: "Symbols", - description: "white medium square", - unicode_version: "3.2", - }, - { - emoji: "โ—พ", - aliases: ["black_medium_small_square"], - tags: [], - category: "Symbols", - description: "black medium-small square", - unicode_version: "3.2", - }, - { - emoji: "โ—ฝ", - aliases: ["white_medium_small_square"], - tags: [], - category: "Symbols", - description: "white medium-small square", - unicode_version: "3.2", - }, - { - emoji: "โ–ช๏ธ", - aliases: ["black_small_square"], - tags: [], - category: "Symbols", - description: "black small square", - unicode_version: "", - }, - { - emoji: "โ–ซ๏ธ", - aliases: ["white_small_square"], - tags: [], - category: "Symbols", - description: "white small square", - unicode_version: "", - }, - { - emoji: "๐Ÿ”ถ", - aliases: ["large_orange_diamond"], - tags: [], - category: "Symbols", - description: "large orange diamond", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ท", - aliases: ["large_blue_diamond"], - tags: [], - category: "Symbols", - description: "large blue diamond", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ธ", - aliases: ["small_orange_diamond"], - tags: [], - category: "Symbols", - description: "small orange diamond", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”น", - aliases: ["small_blue_diamond"], - tags: [], - category: "Symbols", - description: "small blue diamond", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”บ", - aliases: ["small_red_triangle"], - tags: [], - category: "Symbols", - description: "red triangle pointed up", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ป", - aliases: ["small_red_triangle_down"], - tags: [], - category: "Symbols", - description: "red triangle pointed down", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ’ ", - aliases: ["diamond_shape_with_a_dot_inside"], - tags: [], - category: "Symbols", - description: "diamond with a dot", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”˜", - aliases: ["radio_button"], - tags: [], - category: "Symbols", - description: "radio button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ณ", - aliases: ["white_square_button"], - tags: [], - category: "Symbols", - description: "white square button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ”ฒ", - aliases: ["black_square_button"], - tags: [], - category: "Symbols", - description: "black square button", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ", - aliases: ["checkered_flag"], - tags: ["milestone", "finish"], - category: "Flags", - description: "chequered flag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿšฉ", - aliases: ["triangular_flag_on_post"], - tags: [], - category: "Flags", - description: "triangular flag", - unicode_version: "6.0", - }, - { - emoji: "๐ŸŽŒ", - aliases: ["crossed_flags"], - tags: [], - category: "Flags", - description: "crossed flags", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿด", - aliases: ["black_flag"], - tags: [], - category: "Flags", - description: "black flag", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿณ๏ธ", - aliases: ["white_flag"], - tags: [], - category: "Flags", - description: "white flag", - unicode_version: "7.0", - }, - { - emoji: "๐Ÿณ๏ธโ€๐ŸŒˆ", - aliases: ["rainbow_flag"], - tags: ["pride"], - category: "Flags", - description: "rainbow flag", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿณ๏ธโ€โšง๏ธ", - aliases: ["transgender_flag"], - tags: [], - category: "Flags", - description: "transgender flag", - unicode_version: "13.0", - }, - { - emoji: "๐Ÿดโ€โ˜ ๏ธ", - aliases: ["pirate_flag"], - tags: [], - category: "Flags", - description: "pirate flag", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡จ", - aliases: ["ascension_island"], - tags: [], - category: "Flags", - description: "flag: Ascension Island", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฉ", - aliases: ["andorra"], - tags: [], - category: "Flags", - description: "flag: Andorra", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ช", - aliases: ["united_arab_emirates"], - tags: [], - category: "Flags", - description: "flag: United Arab Emirates", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ซ", - aliases: ["afghanistan"], - tags: [], - category: "Flags", - description: "flag: Afghanistan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฌ", - aliases: ["antigua_barbuda"], - tags: [], - category: "Flags", - description: "flag: Antigua & Barbuda", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฎ", - aliases: ["anguilla"], - tags: [], - category: "Flags", - description: "flag: Anguilla", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฑ", - aliases: ["albania"], - tags: [], - category: "Flags", - description: "flag: Albania", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฒ", - aliases: ["armenia"], - tags: [], - category: "Flags", - description: "flag: Armenia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ด", - aliases: ["angola"], - tags: [], - category: "Flags", - description: "flag: Angola", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ถ", - aliases: ["antarctica"], - tags: [], - category: "Flags", - description: "flag: Antarctica", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ท", - aliases: ["argentina"], - tags: [], - category: "Flags", - description: "flag: Argentina", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ธ", - aliases: ["american_samoa"], - tags: [], - category: "Flags", - description: "flag: American Samoa", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡น", - aliases: ["austria"], - tags: [], - category: "Flags", - description: "flag: Austria", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡บ", - aliases: ["australia"], - tags: [], - category: "Flags", - description: "flag: Australia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ผ", - aliases: ["aruba"], - tags: [], - category: "Flags", - description: "flag: Aruba", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฝ", - aliases: ["aland_islands"], - tags: [], - category: "Flags", - description: "flag: ร…land Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฆ๐Ÿ‡ฟ", - aliases: ["azerbaijan"], - tags: [], - category: "Flags", - description: "flag: Azerbaijan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฆ", - aliases: ["bosnia_herzegovina"], - tags: [], - category: "Flags", - description: "flag: Bosnia & Herzegovina", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ง", - aliases: ["barbados"], - tags: [], - category: "Flags", - description: "flag: Barbados", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฉ", - aliases: ["bangladesh"], - tags: [], - category: "Flags", - description: "flag: Bangladesh", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ช", - aliases: ["belgium"], - tags: [], - category: "Flags", - description: "flag: Belgium", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ซ", - aliases: ["burkina_faso"], - tags: [], - category: "Flags", - description: "flag: Burkina Faso", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฌ", - aliases: ["bulgaria"], - tags: [], - category: "Flags", - description: "flag: Bulgaria", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ญ", - aliases: ["bahrain"], - tags: [], - category: "Flags", - description: "flag: Bahrain", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฎ", - aliases: ["burundi"], - tags: [], - category: "Flags", - description: "flag: Burundi", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฏ", - aliases: ["benin"], - tags: [], - category: "Flags", - description: "flag: Benin", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฑ", - aliases: ["st_barthelemy"], - tags: [], - category: "Flags", - description: "flag: St. Barthรฉlemy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฒ", - aliases: ["bermuda"], - tags: [], - category: "Flags", - description: "flag: Bermuda", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ณ", - aliases: ["brunei"], - tags: [], - category: "Flags", - description: "flag: Brunei", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ด", - aliases: ["bolivia"], - tags: [], - category: "Flags", - description: "flag: Bolivia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ถ", - aliases: ["caribbean_netherlands"], - tags: [], - category: "Flags", - description: "flag: Caribbean Netherlands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ท", - aliases: ["brazil"], - tags: [], - category: "Flags", - description: "flag: Brazil", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ธ", - aliases: ["bahamas"], - tags: [], - category: "Flags", - description: "flag: Bahamas", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡น", - aliases: ["bhutan"], - tags: [], - category: "Flags", - description: "flag: Bhutan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ป", - aliases: ["bouvet_island"], - tags: [], - category: "Flags", - description: "flag: Bouvet Island", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ผ", - aliases: ["botswana"], - tags: [], - category: "Flags", - description: "flag: Botswana", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡พ", - aliases: ["belarus"], - tags: [], - category: "Flags", - description: "flag: Belarus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ง๐Ÿ‡ฟ", - aliases: ["belize"], - tags: [], - category: "Flags", - description: "flag: Belize", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฆ", - aliases: ["canada"], - tags: [], - category: "Flags", - description: "flag: Canada", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡จ", - aliases: ["cocos_islands"], - tags: ["keeling"], - category: "Flags", - description: "flag: Cocos (Keeling) Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฉ", - aliases: ["congo_kinshasa"], - tags: [], - category: "Flags", - description: "flag: Congo - Kinshasa", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ซ", - aliases: ["central_african_republic"], - tags: [], - category: "Flags", - description: "flag: Central African Republic", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฌ", - aliases: ["congo_brazzaville"], - tags: [], - category: "Flags", - description: "flag: Congo - Brazzaville", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ญ", - aliases: ["switzerland"], - tags: [], - category: "Flags", - description: "flag: Switzerland", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฎ", - aliases: ["cote_divoire"], - tags: ["ivory"], - category: "Flags", - description: "flag: Cรดte dโ€™Ivoire", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฐ", - aliases: ["cook_islands"], - tags: [], - category: "Flags", - description: "flag: Cook Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฑ", - aliases: ["chile"], - tags: [], - category: "Flags", - description: "flag: Chile", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฒ", - aliases: ["cameroon"], - tags: [], - category: "Flags", - description: "flag: Cameroon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ณ", - aliases: ["cn"], - tags: ["china"], - category: "Flags", - description: "flag: China", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ด", - aliases: ["colombia"], - tags: [], - category: "Flags", - description: "flag: Colombia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ต", - aliases: ["clipperton_island"], - tags: [], - category: "Flags", - description: "flag: Clipperton Island", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ท", - aliases: ["costa_rica"], - tags: [], - category: "Flags", - description: "flag: Costa Rica", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡บ", - aliases: ["cuba"], - tags: [], - category: "Flags", - description: "flag: Cuba", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ป", - aliases: ["cape_verde"], - tags: [], - category: "Flags", - description: "flag: Cape Verde", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ผ", - aliases: ["curacao"], - tags: [], - category: "Flags", - description: "flag: Curaรงao", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฝ", - aliases: ["christmas_island"], - tags: [], - category: "Flags", - description: "flag: Christmas Island", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡พ", - aliases: ["cyprus"], - tags: [], - category: "Flags", - description: "flag: Cyprus", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡จ๐Ÿ‡ฟ", - aliases: ["czech_republic"], - tags: [], - category: "Flags", - description: "flag: Czechia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ช", - aliases: ["de"], - tags: ["flag", "germany"], - category: "Flags", - description: "flag: Germany", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ฌ", - aliases: ["diego_garcia"], - tags: [], - category: "Flags", - description: "flag: Diego Garcia", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ฏ", - aliases: ["djibouti"], - tags: [], - category: "Flags", - description: "flag: Djibouti", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ฐ", - aliases: ["denmark"], - tags: [], - category: "Flags", - description: "flag: Denmark", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ฒ", - aliases: ["dominica"], - tags: [], - category: "Flags", - description: "flag: Dominica", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ด", - aliases: ["dominican_republic"], - tags: [], - category: "Flags", - description: "flag: Dominican Republic", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฉ๐Ÿ‡ฟ", - aliases: ["algeria"], - tags: [], - category: "Flags", - description: "flag: Algeria", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡ฆ", - aliases: ["ceuta_melilla"], - tags: [], - category: "Flags", - description: "flag: Ceuta & Melilla", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡จ", - aliases: ["ecuador"], - tags: [], - category: "Flags", - description: "flag: Ecuador", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡ช", - aliases: ["estonia"], - tags: [], - category: "Flags", - description: "flag: Estonia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡ฌ", - aliases: ["egypt"], - tags: [], - category: "Flags", - description: "flag: Egypt", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡ญ", - aliases: ["western_sahara"], - tags: [], - category: "Flags", - description: "flag: Western Sahara", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡ท", - aliases: ["eritrea"], - tags: [], - category: "Flags", - description: "flag: Eritrea", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡ธ", - aliases: ["es"], - tags: ["spain"], - category: "Flags", - description: "flag: Spain", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡น", - aliases: ["ethiopia"], - tags: [], - category: "Flags", - description: "flag: Ethiopia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ช๐Ÿ‡บ", - aliases: ["eu", "european_union"], - tags: [], - category: "Flags", - description: "flag: European Union", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ซ๐Ÿ‡ฎ", - aliases: ["finland"], - tags: [], - category: "Flags", - description: "flag: Finland", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ซ๐Ÿ‡ฏ", - aliases: ["fiji"], - tags: [], - category: "Flags", - description: "flag: Fiji", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ซ๐Ÿ‡ฐ", - aliases: ["falkland_islands"], - tags: [], - category: "Flags", - description: "flag: Falkland Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ซ๐Ÿ‡ฒ", - aliases: ["micronesia"], - tags: [], - category: "Flags", - description: "flag: Micronesia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ซ๐Ÿ‡ด", - aliases: ["faroe_islands"], - tags: [], - category: "Flags", - description: "flag: Faroe Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ซ๐Ÿ‡ท", - aliases: ["fr"], - tags: ["france", "french"], - category: "Flags", - description: "flag: France", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ฆ", - aliases: ["gabon"], - tags: [], - category: "Flags", - description: "flag: Gabon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ง", - aliases: ["gb", "uk"], - tags: ["flag", "british"], - category: "Flags", - description: "flag: United Kingdom", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ฉ", - aliases: ["grenada"], - tags: [], - category: "Flags", - description: "flag: Grenada", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ช", - aliases: ["georgia"], - tags: [], - category: "Flags", - description: "flag: Georgia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ซ", - aliases: ["french_guiana"], - tags: [], - category: "Flags", - description: "flag: French Guiana", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ฌ", - aliases: ["guernsey"], - tags: [], - category: "Flags", - description: "flag: Guernsey", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ญ", - aliases: ["ghana"], - tags: [], - category: "Flags", - description: "flag: Ghana", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ฎ", - aliases: ["gibraltar"], - tags: [], - category: "Flags", - description: "flag: Gibraltar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ฑ", - aliases: ["greenland"], - tags: [], - category: "Flags", - description: "flag: Greenland", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ฒ", - aliases: ["gambia"], - tags: [], - category: "Flags", - description: "flag: Gambia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ณ", - aliases: ["guinea"], - tags: [], - category: "Flags", - description: "flag: Guinea", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ต", - aliases: ["guadeloupe"], - tags: [], - category: "Flags", - description: "flag: Guadeloupe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ถ", - aliases: ["equatorial_guinea"], - tags: [], - category: "Flags", - description: "flag: Equatorial Guinea", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ท", - aliases: ["greece"], - tags: [], - category: "Flags", - description: "flag: Greece", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ธ", - aliases: ["south_georgia_south_sandwich_islands"], - tags: [], - category: "Flags", - description: "flag: South Georgia & South Sandwich Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡น", - aliases: ["guatemala"], - tags: [], - category: "Flags", - description: "flag: Guatemala", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡บ", - aliases: ["guam"], - tags: [], - category: "Flags", - description: "flag: Guam", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡ผ", - aliases: ["guinea_bissau"], - tags: [], - category: "Flags", - description: "flag: Guinea-Bissau", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฌ๐Ÿ‡พ", - aliases: ["guyana"], - tags: [], - category: "Flags", - description: "flag: Guyana", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ญ๐Ÿ‡ฐ", - aliases: ["hong_kong"], - tags: [], - category: "Flags", - description: "flag: Hong Kong SAR China", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ญ๐Ÿ‡ฒ", - aliases: ["heard_mcdonald_islands"], - tags: [], - category: "Flags", - description: "flag: Heard & McDonald Islands", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ญ๐Ÿ‡ณ", - aliases: ["honduras"], - tags: [], - category: "Flags", - description: "flag: Honduras", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ญ๐Ÿ‡ท", - aliases: ["croatia"], - tags: [], - category: "Flags", - description: "flag: Croatia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ญ๐Ÿ‡น", - aliases: ["haiti"], - tags: [], - category: "Flags", - description: "flag: Haiti", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ญ๐Ÿ‡บ", - aliases: ["hungary"], - tags: [], - category: "Flags", - description: "flag: Hungary", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡จ", - aliases: ["canary_islands"], - tags: [], - category: "Flags", - description: "flag: Canary Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ฉ", - aliases: ["indonesia"], - tags: [], - category: "Flags", - description: "flag: Indonesia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ช", - aliases: ["ireland"], - tags: [], - category: "Flags", - description: "flag: Ireland", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ฑ", - aliases: ["israel"], - tags: [], - category: "Flags", - description: "flag: Israel", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ฒ", - aliases: ["isle_of_man"], - tags: [], - category: "Flags", - description: "flag: Isle of Man", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ณ", - aliases: ["india"], - tags: [], - category: "Flags", - description: "flag: India", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ด", - aliases: ["british_indian_ocean_territory"], - tags: [], - category: "Flags", - description: "flag: British Indian Ocean Territory", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ถ", - aliases: ["iraq"], - tags: [], - category: "Flags", - description: "flag: Iraq", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ท", - aliases: ["iran"], - tags: [], - category: "Flags", - description: "flag: Iran", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡ธ", - aliases: ["iceland"], - tags: [], - category: "Flags", - description: "flag: Iceland", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฎ๐Ÿ‡น", - aliases: ["it"], - tags: ["italy"], - category: "Flags", - description: "flag: Italy", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฏ๐Ÿ‡ช", - aliases: ["jersey"], - tags: [], - category: "Flags", - description: "flag: Jersey", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฏ๐Ÿ‡ฒ", - aliases: ["jamaica"], - tags: [], - category: "Flags", - description: "flag: Jamaica", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฏ๐Ÿ‡ด", - aliases: ["jordan"], - tags: [], - category: "Flags", - description: "flag: Jordan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฏ๐Ÿ‡ต", - aliases: ["jp"], - tags: ["japan"], - category: "Flags", - description: "flag: Japan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ช", - aliases: ["kenya"], - tags: [], - category: "Flags", - description: "flag: Kenya", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ฌ", - aliases: ["kyrgyzstan"], - tags: [], - category: "Flags", - description: "flag: Kyrgyzstan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ญ", - aliases: ["cambodia"], - tags: [], - category: "Flags", - description: "flag: Cambodia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ฎ", - aliases: ["kiribati"], - tags: [], - category: "Flags", - description: "flag: Kiribati", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ฒ", - aliases: ["comoros"], - tags: [], - category: "Flags", - description: "flag: Comoros", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ณ", - aliases: ["st_kitts_nevis"], - tags: [], - category: "Flags", - description: "flag: St. Kitts & Nevis", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ต", - aliases: ["north_korea"], - tags: [], - category: "Flags", - description: "flag: North Korea", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ท", - aliases: ["kr"], - tags: ["korea"], - category: "Flags", - description: "flag: South Korea", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ผ", - aliases: ["kuwait"], - tags: [], - category: "Flags", - description: "flag: Kuwait", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡พ", - aliases: ["cayman_islands"], - tags: [], - category: "Flags", - description: "flag: Cayman Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฐ๐Ÿ‡ฟ", - aliases: ["kazakhstan"], - tags: [], - category: "Flags", - description: "flag: Kazakhstan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ฆ", - aliases: ["laos"], - tags: [], - category: "Flags", - description: "flag: Laos", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ง", - aliases: ["lebanon"], - tags: [], - category: "Flags", - description: "flag: Lebanon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡จ", - aliases: ["st_lucia"], - tags: [], - category: "Flags", - description: "flag: St. Lucia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ฎ", - aliases: ["liechtenstein"], - tags: [], - category: "Flags", - description: "flag: Liechtenstein", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ฐ", - aliases: ["sri_lanka"], - tags: [], - category: "Flags", - description: "flag: Sri Lanka", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ท", - aliases: ["liberia"], - tags: [], - category: "Flags", - description: "flag: Liberia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ธ", - aliases: ["lesotho"], - tags: [], - category: "Flags", - description: "flag: Lesotho", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡น", - aliases: ["lithuania"], - tags: [], - category: "Flags", - description: "flag: Lithuania", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡บ", - aliases: ["luxembourg"], - tags: [], - category: "Flags", - description: "flag: Luxembourg", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡ป", - aliases: ["latvia"], - tags: [], - category: "Flags", - description: "flag: Latvia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฑ๐Ÿ‡พ", - aliases: ["libya"], - tags: [], - category: "Flags", - description: "flag: Libya", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฆ", - aliases: ["morocco"], - tags: [], - category: "Flags", - description: "flag: Morocco", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡จ", - aliases: ["monaco"], - tags: [], - category: "Flags", - description: "flag: Monaco", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฉ", - aliases: ["moldova"], - tags: [], - category: "Flags", - description: "flag: Moldova", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ช", - aliases: ["montenegro"], - tags: [], - category: "Flags", - description: "flag: Montenegro", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ซ", - aliases: ["st_martin"], - tags: [], - category: "Flags", - description: "flag: St. Martin", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฌ", - aliases: ["madagascar"], - tags: [], - category: "Flags", - description: "flag: Madagascar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ญ", - aliases: ["marshall_islands"], - tags: [], - category: "Flags", - description: "flag: Marshall Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฐ", - aliases: ["macedonia"], - tags: [], - category: "Flags", - description: "flag: North Macedonia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฑ", - aliases: ["mali"], - tags: [], - category: "Flags", - description: "flag: Mali", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฒ", - aliases: ["myanmar"], - tags: ["burma"], - category: "Flags", - description: "flag: Myanmar (Burma)", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ณ", - aliases: ["mongolia"], - tags: [], - category: "Flags", - description: "flag: Mongolia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ด", - aliases: ["macau"], - tags: [], - category: "Flags", - description: "flag: Macao SAR China", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ต", - aliases: ["northern_mariana_islands"], - tags: [], - category: "Flags", - description: "flag: Northern Mariana Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ถ", - aliases: ["martinique"], - tags: [], - category: "Flags", - description: "flag: Martinique", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ท", - aliases: ["mauritania"], - tags: [], - category: "Flags", - description: "flag: Mauritania", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ธ", - aliases: ["montserrat"], - tags: [], - category: "Flags", - description: "flag: Montserrat", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡น", - aliases: ["malta"], - tags: [], - category: "Flags", - description: "flag: Malta", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡บ", - aliases: ["mauritius"], - tags: [], - category: "Flags", - description: "flag: Mauritius", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ป", - aliases: ["maldives"], - tags: [], - category: "Flags", - description: "flag: Maldives", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ผ", - aliases: ["malawi"], - tags: [], - category: "Flags", - description: "flag: Malawi", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฝ", - aliases: ["mexico"], - tags: [], - category: "Flags", - description: "flag: Mexico", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡พ", - aliases: ["malaysia"], - tags: [], - category: "Flags", - description: "flag: Malaysia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฒ๐Ÿ‡ฟ", - aliases: ["mozambique"], - tags: [], - category: "Flags", - description: "flag: Mozambique", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ฆ", - aliases: ["namibia"], - tags: [], - category: "Flags", - description: "flag: Namibia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡จ", - aliases: ["new_caledonia"], - tags: [], - category: "Flags", - description: "flag: New Caledonia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ช", - aliases: ["niger"], - tags: [], - category: "Flags", - description: "flag: Niger", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ซ", - aliases: ["norfolk_island"], - tags: [], - category: "Flags", - description: "flag: Norfolk Island", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ฌ", - aliases: ["nigeria"], - tags: [], - category: "Flags", - description: "flag: Nigeria", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ฎ", - aliases: ["nicaragua"], - tags: [], - category: "Flags", - description: "flag: Nicaragua", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ฑ", - aliases: ["netherlands"], - tags: [], - category: "Flags", - description: "flag: Netherlands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ด", - aliases: ["norway"], - tags: [], - category: "Flags", - description: "flag: Norway", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ต", - aliases: ["nepal"], - tags: [], - category: "Flags", - description: "flag: Nepal", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ท", - aliases: ["nauru"], - tags: [], - category: "Flags", - description: "flag: Nauru", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡บ", - aliases: ["niue"], - tags: [], - category: "Flags", - description: "flag: Niue", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ณ๐Ÿ‡ฟ", - aliases: ["new_zealand"], - tags: [], - category: "Flags", - description: "flag: New Zealand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ด๐Ÿ‡ฒ", - aliases: ["oman"], - tags: [], - category: "Flags", - description: "flag: Oman", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ฆ", - aliases: ["panama"], - tags: [], - category: "Flags", - description: "flag: Panama", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ช", - aliases: ["peru"], - tags: [], - category: "Flags", - description: "flag: Peru", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ซ", - aliases: ["french_polynesia"], - tags: [], - category: "Flags", - description: "flag: French Polynesia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ฌ", - aliases: ["papua_new_guinea"], - tags: [], - category: "Flags", - description: "flag: Papua New Guinea", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ญ", - aliases: ["philippines"], - tags: [], - category: "Flags", - description: "flag: Philippines", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ฐ", - aliases: ["pakistan"], - tags: [], - category: "Flags", - description: "flag: Pakistan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ฑ", - aliases: ["poland"], - tags: [], - category: "Flags", - description: "flag: Poland", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ฒ", - aliases: ["st_pierre_miquelon"], - tags: [], - category: "Flags", - description: "flag: St. Pierre & Miquelon", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ณ", - aliases: ["pitcairn_islands"], - tags: [], - category: "Flags", - description: "flag: Pitcairn Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ท", - aliases: ["puerto_rico"], - tags: [], - category: "Flags", - description: "flag: Puerto Rico", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ธ", - aliases: ["palestinian_territories"], - tags: [], - category: "Flags", - description: "flag: Palestinian Territories", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡น", - aliases: ["portugal"], - tags: [], - category: "Flags", - description: "flag: Portugal", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡ผ", - aliases: ["palau"], - tags: [], - category: "Flags", - description: "flag: Palau", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ต๐Ÿ‡พ", - aliases: ["paraguay"], - tags: [], - category: "Flags", - description: "flag: Paraguay", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ถ๐Ÿ‡ฆ", - aliases: ["qatar"], - tags: [], - category: "Flags", - description: "flag: Qatar", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ท๐Ÿ‡ช", - aliases: ["reunion"], - tags: [], - category: "Flags", - description: "flag: Rรฉunion", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ท๐Ÿ‡ด", - aliases: ["romania"], - tags: [], - category: "Flags", - description: "flag: Romania", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ท๐Ÿ‡ธ", - aliases: ["serbia"], - tags: [], - category: "Flags", - description: "flag: Serbia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ท๐Ÿ‡บ", - aliases: ["ru"], - tags: ["russia"], - category: "Flags", - description: "flag: Russia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ท๐Ÿ‡ผ", - aliases: ["rwanda"], - tags: [], - category: "Flags", - description: "flag: Rwanda", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฆ", - aliases: ["saudi_arabia"], - tags: [], - category: "Flags", - description: "flag: Saudi Arabia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ง", - aliases: ["solomon_islands"], - tags: [], - category: "Flags", - description: "flag: Solomon Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡จ", - aliases: ["seychelles"], - tags: [], - category: "Flags", - description: "flag: Seychelles", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฉ", - aliases: ["sudan"], - tags: [], - category: "Flags", - description: "flag: Sudan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ช", - aliases: ["sweden"], - tags: [], - category: "Flags", - description: "flag: Sweden", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฌ", - aliases: ["singapore"], - tags: [], - category: "Flags", - description: "flag: Singapore", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ญ", - aliases: ["st_helena"], - tags: [], - category: "Flags", - description: "flag: St. Helena", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฎ", - aliases: ["slovenia"], - tags: [], - category: "Flags", - description: "flag: Slovenia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฏ", - aliases: ["svalbard_jan_mayen"], - tags: [], - category: "Flags", - description: "flag: Svalbard & Jan Mayen", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฐ", - aliases: ["slovakia"], - tags: [], - category: "Flags", - description: "flag: Slovakia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฑ", - aliases: ["sierra_leone"], - tags: [], - category: "Flags", - description: "flag: Sierra Leone", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฒ", - aliases: ["san_marino"], - tags: [], - category: "Flags", - description: "flag: San Marino", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ณ", - aliases: ["senegal"], - tags: [], - category: "Flags", - description: "flag: Senegal", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ด", - aliases: ["somalia"], - tags: [], - category: "Flags", - description: "flag: Somalia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ท", - aliases: ["suriname"], - tags: [], - category: "Flags", - description: "flag: Suriname", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ธ", - aliases: ["south_sudan"], - tags: [], - category: "Flags", - description: "flag: South Sudan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡น", - aliases: ["sao_tome_principe"], - tags: [], - category: "Flags", - description: "flag: Sรฃo Tomรฉ & Prรญncipe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ป", - aliases: ["el_salvador"], - tags: [], - category: "Flags", - description: "flag: El Salvador", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฝ", - aliases: ["sint_maarten"], - tags: [], - category: "Flags", - description: "flag: Sint Maarten", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡พ", - aliases: ["syria"], - tags: [], - category: "Flags", - description: "flag: Syria", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ธ๐Ÿ‡ฟ", - aliases: ["swaziland"], - tags: [], - category: "Flags", - description: "flag: Eswatini", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฆ", - aliases: ["tristan_da_cunha"], - tags: [], - category: "Flags", - description: "flag: Tristan da Cunha", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡จ", - aliases: ["turks_caicos_islands"], - tags: [], - category: "Flags", - description: "flag: Turks & Caicos Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฉ", - aliases: ["chad"], - tags: [], - category: "Flags", - description: "flag: Chad", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ซ", - aliases: ["french_southern_territories"], - tags: [], - category: "Flags", - description: "flag: French Southern Territories", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฌ", - aliases: ["togo"], - tags: [], - category: "Flags", - description: "flag: Togo", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ญ", - aliases: ["thailand"], - tags: [], - category: "Flags", - description: "flag: Thailand", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฏ", - aliases: ["tajikistan"], - tags: [], - category: "Flags", - description: "flag: Tajikistan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฐ", - aliases: ["tokelau"], - tags: [], - category: "Flags", - description: "flag: Tokelau", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฑ", - aliases: ["timor_leste"], - tags: [], - category: "Flags", - description: "flag: Timor-Leste", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฒ", - aliases: ["turkmenistan"], - tags: [], - category: "Flags", - description: "flag: Turkmenistan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ณ", - aliases: ["tunisia"], - tags: [], - category: "Flags", - description: "flag: Tunisia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ด", - aliases: ["tonga"], - tags: [], - category: "Flags", - description: "flag: Tonga", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ท", - aliases: ["tr"], - tags: ["turkey"], - category: "Flags", - description: "flag: Turkey", - unicode_version: "8.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡น", - aliases: ["trinidad_tobago"], - tags: [], - category: "Flags", - description: "flag: Trinidad & Tobago", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ป", - aliases: ["tuvalu"], - tags: [], - category: "Flags", - description: "flag: Tuvalu", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ผ", - aliases: ["taiwan"], - tags: [], - category: "Flags", - description: "flag: Taiwan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡น๐Ÿ‡ฟ", - aliases: ["tanzania"], - tags: [], - category: "Flags", - description: "flag: Tanzania", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡ฆ", - aliases: ["ukraine"], - tags: [], - category: "Flags", - description: "flag: Ukraine", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡ฌ", - aliases: ["uganda"], - tags: [], - category: "Flags", - description: "flag: Uganda", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡ฒ", - aliases: ["us_outlying_islands"], - tags: [], - category: "Flags", - description: "flag: U.S. Outlying Islands", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡ณ", - aliases: ["united_nations"], - tags: [], - category: "Flags", - description: "flag: United Nations", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡ธ", - aliases: ["us"], - tags: ["flag", "united", "america"], - category: "Flags", - description: "flag: United States", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡พ", - aliases: ["uruguay"], - tags: [], - category: "Flags", - description: "flag: Uruguay", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡บ๐Ÿ‡ฟ", - aliases: ["uzbekistan"], - tags: [], - category: "Flags", - description: "flag: Uzbekistan", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡ฆ", - aliases: ["vatican_city"], - tags: [], - category: "Flags", - description: "flag: Vatican City", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡จ", - aliases: ["st_vincent_grenadines"], - tags: [], - category: "Flags", - description: "flag: St. Vincent & Grenadines", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡ช", - aliases: ["venezuela"], - tags: [], - category: "Flags", - description: "flag: Venezuela", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡ฌ", - aliases: ["british_virgin_islands"], - tags: [], - category: "Flags", - description: "flag: British Virgin Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡ฎ", - aliases: ["us_virgin_islands"], - tags: [], - category: "Flags", - description: "flag: U.S. Virgin Islands", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡ณ", - aliases: ["vietnam"], - tags: [], - category: "Flags", - description: "flag: Vietnam", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ป๐Ÿ‡บ", - aliases: ["vanuatu"], - tags: [], - category: "Flags", - description: "flag: Vanuatu", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ผ๐Ÿ‡ซ", - aliases: ["wallis_futuna"], - tags: [], - category: "Flags", - description: "flag: Wallis & Futuna", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ผ๐Ÿ‡ธ", - aliases: ["samoa"], - tags: [], - category: "Flags", - description: "flag: Samoa", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฝ๐Ÿ‡ฐ", - aliases: ["kosovo"], - tags: [], - category: "Flags", - description: "flag: Kosovo", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡พ๐Ÿ‡ช", - aliases: ["yemen"], - tags: [], - category: "Flags", - description: "flag: Yemen", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡พ๐Ÿ‡น", - aliases: ["mayotte"], - tags: [], - category: "Flags", - description: "flag: Mayotte", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฟ๐Ÿ‡ฆ", - aliases: ["south_africa"], - tags: [], - category: "Flags", - description: "flag: South Africa", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฟ๐Ÿ‡ฒ", - aliases: ["zambia"], - tags: [], - category: "Flags", - description: "flag: Zambia", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿ‡ฟ๐Ÿ‡ผ", - aliases: ["zimbabwe"], - tags: [], - category: "Flags", - description: "flag: Zimbabwe", - unicode_version: "6.0", - }, - { - emoji: "๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ", - aliases: ["england"], - tags: [], - category: "Flags", - description: "flag: England", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ", - aliases: ["scotland"], - tags: [], - category: "Flags", - description: "flag: Scotland", - unicode_version: "11.0", - }, - { - emoji: "๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ", - aliases: ["wales"], - tags: [], - category: "Flags", - description: "flag: Wales", - unicode_version: "11.0", - }, -]; +export const rawEmojis = [{"emoji":"๐Ÿ˜€","aliases":["grinning"],"tags":["smile","happy"],"category":"Smileys & Emotion","description":"grinning face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ƒ","aliases":["smiley"],"tags":["happy","joy","haha"],"category":"Smileys & Emotion","description":"grinning face with big eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜„","aliases":["smile"],"tags":["happy","joy","laugh","pleased"],"category":"Smileys & Emotion","description":"grinning face with smiling eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜","aliases":["grin"],"tags":[],"category":"Smileys & Emotion","description":"beaming face with smiling eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜†","aliases":["laughing","satisfied"],"tags":["happy","haha"],"category":"Smileys & Emotion","description":"grinning squinting face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜…","aliases":["sweat_smile"],"tags":["hot"],"category":"Smileys & Emotion","description":"grinning face with sweat","unicode_version":"6.0"},{"emoji":"๐Ÿคฃ","aliases":["rofl"],"tags":["lol","laughing"],"category":"Smileys & Emotion","description":"rolling on the floor laughing","unicode_version":"9.0"},{"emoji":"๐Ÿ˜‚","aliases":["joy"],"tags":["tears"],"category":"Smileys & Emotion","description":"face with tears of joy","unicode_version":"6.0"},{"emoji":"๐Ÿ™‚","aliases":["slightly_smiling_face"],"tags":[],"category":"Smileys & Emotion","description":"slightly smiling face","unicode_version":"7.0"},{"emoji":"๐Ÿ™ƒ","aliases":["upside_down_face"],"tags":[],"category":"Smileys & Emotion","description":"upside-down face","unicode_version":"8.0"},{"emoji":"๐Ÿ˜‰","aliases":["wink"],"tags":["flirt"],"category":"Smileys & Emotion","description":"winking face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜Š","aliases":["blush"],"tags":["proud"],"category":"Smileys & Emotion","description":"smiling face with smiling eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜‡","aliases":["innocent"],"tags":["angel"],"category":"Smileys & Emotion","description":"smiling face with halo","unicode_version":"6.0"},{"emoji":"๐Ÿฅฐ","aliases":["smiling_face_with_three_hearts"],"tags":["love"],"category":"Smileys & Emotion","description":"smiling face with hearts","unicode_version":"11.0"},{"emoji":"๐Ÿ˜","aliases":["heart_eyes"],"tags":["love","crush"],"category":"Smileys & Emotion","description":"smiling face with heart-eyes","unicode_version":"6.0"},{"emoji":"๐Ÿคฉ","aliases":["star_struck"],"tags":["eyes"],"category":"Smileys & Emotion","description":"star-struck","unicode_version":"11.0"},{"emoji":"๐Ÿ˜˜","aliases":["kissing_heart"],"tags":["flirt"],"category":"Smileys & Emotion","description":"face blowing a kiss","unicode_version":"6.0"},{"emoji":"๐Ÿ˜—","aliases":["kissing"],"tags":[],"category":"Smileys & Emotion","description":"kissing face","unicode_version":"6.1"},{"emoji":"โ˜บ๏ธ","aliases":["relaxed"],"tags":["blush","pleased"],"category":"Smileys & Emotion","description":"smiling face","unicode_version":""},{"emoji":"๐Ÿ˜š","aliases":["kissing_closed_eyes"],"tags":[],"category":"Smileys & Emotion","description":"kissing face with closed eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜™","aliases":["kissing_smiling_eyes"],"tags":[],"category":"Smileys & Emotion","description":"kissing face with smiling eyes","unicode_version":"6.1"},{"emoji":"๐Ÿฅฒ","aliases":["smiling_face_with_tear"],"tags":[],"category":"Smileys & Emotion","description":"smiling face with tear","unicode_version":"13.0"},{"emoji":"๐Ÿ˜‹","aliases":["yum"],"tags":["tongue","lick"],"category":"Smileys & Emotion","description":"face savoring food","unicode_version":"6.0"},{"emoji":"๐Ÿ˜›","aliases":["stuck_out_tongue"],"tags":[],"category":"Smileys & Emotion","description":"face with tongue","unicode_version":"6.1"},{"emoji":"๐Ÿ˜œ","aliases":["stuck_out_tongue_winking_eye"],"tags":["prank","silly"],"category":"Smileys & Emotion","description":"winking face with tongue","unicode_version":"6.0"},{"emoji":"๐Ÿคช","aliases":["zany_face"],"tags":["goofy","wacky"],"category":"Smileys & Emotion","description":"zany face","unicode_version":"11.0"},{"emoji":"๐Ÿ˜","aliases":["stuck_out_tongue_closed_eyes"],"tags":["prank"],"category":"Smileys & Emotion","description":"squinting face with tongue","unicode_version":"6.0"},{"emoji":"๐Ÿค‘","aliases":["money_mouth_face"],"tags":["rich"],"category":"Smileys & Emotion","description":"money-mouth face","unicode_version":"8.0"},{"emoji":"๐Ÿค—","aliases":["hugs"],"tags":[],"category":"Smileys & Emotion","description":"hugging face","unicode_version":"8.0"},{"emoji":"๐Ÿคญ","aliases":["hand_over_mouth"],"tags":["quiet","whoops"],"category":"Smileys & Emotion","description":"face with hand over mouth","unicode_version":"11.0"},{"emoji":"๐Ÿคซ","aliases":["shushing_face"],"tags":["silence","quiet"],"category":"Smileys & Emotion","description":"shushing face","unicode_version":"11.0"},{"emoji":"๐Ÿค”","aliases":["thinking"],"tags":[],"category":"Smileys & Emotion","description":"thinking face","unicode_version":"8.0"},{"emoji":"๐Ÿค","aliases":["zipper_mouth_face"],"tags":["silence","hush"],"category":"Smileys & Emotion","description":"zipper-mouth face","unicode_version":"8.0"},{"emoji":"๐Ÿคจ","aliases":["raised_eyebrow"],"tags":["suspicious"],"category":"Smileys & Emotion","description":"face with raised eyebrow","unicode_version":"11.0"},{"emoji":"๐Ÿ˜","aliases":["neutral_face"],"tags":["meh"],"category":"Smileys & Emotion","description":"neutral face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜‘","aliases":["expressionless"],"tags":[],"category":"Smileys & Emotion","description":"expressionless face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ถ","aliases":["no_mouth"],"tags":["mute","silence"],"category":"Smileys & Emotion","description":"face without mouth","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ถโ€๐ŸŒซ๏ธ","aliases":["face_in_clouds"],"tags":[],"category":"Smileys & Emotion","description":"face in clouds","unicode_version":"13.1"},{"emoji":"๐Ÿ˜","aliases":["smirk"],"tags":["smug"],"category":"Smileys & Emotion","description":"smirking face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜’","aliases":["unamused"],"tags":["meh"],"category":"Smileys & Emotion","description":"unamused face","unicode_version":"6.0"},{"emoji":"๐Ÿ™„","aliases":["roll_eyes"],"tags":[],"category":"Smileys & Emotion","description":"face with rolling eyes","unicode_version":"8.0"},{"emoji":"๐Ÿ˜ฌ","aliases":["grimacing"],"tags":[],"category":"Smileys & Emotion","description":"grimacing face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ฎโ€๐Ÿ’จ","aliases":["face_exhaling"],"tags":[],"category":"Smileys & Emotion","description":"face exhaling","unicode_version":"13.1"},{"emoji":"๐Ÿคฅ","aliases":["lying_face"],"tags":["liar"],"category":"Smileys & Emotion","description":"lying face","unicode_version":"9.0"},{"emoji":"๐Ÿ˜Œ","aliases":["relieved"],"tags":["whew"],"category":"Smileys & Emotion","description":"relieved face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜”","aliases":["pensive"],"tags":[],"category":"Smileys & Emotion","description":"pensive face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ช","aliases":["sleepy"],"tags":["tired"],"category":"Smileys & Emotion","description":"sleepy face","unicode_version":"6.0"},{"emoji":"๐Ÿคค","aliases":["drooling_face"],"tags":[],"category":"Smileys & Emotion","description":"drooling face","unicode_version":"9.0"},{"emoji":"๐Ÿ˜ด","aliases":["sleeping"],"tags":["zzz"],"category":"Smileys & Emotion","description":"sleeping face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ท","aliases":["mask"],"tags":["sick","ill"],"category":"Smileys & Emotion","description":"face with medical mask","unicode_version":"6.0"},{"emoji":"๐Ÿค’","aliases":["face_with_thermometer"],"tags":["sick"],"category":"Smileys & Emotion","description":"face with thermometer","unicode_version":"8.0"},{"emoji":"๐Ÿค•","aliases":["face_with_head_bandage"],"tags":["hurt"],"category":"Smileys & Emotion","description":"face with head-bandage","unicode_version":"8.0"},{"emoji":"๐Ÿคข","aliases":["nauseated_face"],"tags":["sick","barf","disgusted"],"category":"Smileys & Emotion","description":"nauseated face","unicode_version":"9.0"},{"emoji":"๐Ÿคฎ","aliases":["vomiting_face"],"tags":["barf","sick"],"category":"Smileys & Emotion","description":"face vomiting","unicode_version":"11.0"},{"emoji":"๐Ÿคง","aliases":["sneezing_face"],"tags":["achoo","sick"],"category":"Smileys & Emotion","description":"sneezing face","unicode_version":"9.0"},{"emoji":"๐Ÿฅต","aliases":["hot_face"],"tags":["heat","sweating"],"category":"Smileys & Emotion","description":"hot face","unicode_version":"11.0"},{"emoji":"๐Ÿฅถ","aliases":["cold_face"],"tags":["freezing","ice"],"category":"Smileys & Emotion","description":"cold face","unicode_version":"11.0"},{"emoji":"๐Ÿฅด","aliases":["woozy_face"],"tags":["groggy"],"category":"Smileys & Emotion","description":"woozy face","unicode_version":"11.0"},{"emoji":"๐Ÿ˜ต","aliases":["dizzy_face"],"tags":[],"category":"Smileys & Emotion","description":"knocked-out face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ตโ€๐Ÿ’ซ","aliases":["face_with_spiral_eyes"],"tags":[],"category":"Smileys & Emotion","description":"face with spiral eyes","unicode_version":"13.1"},{"emoji":"๐Ÿคฏ","aliases":["exploding_head"],"tags":["mind","blown"],"category":"Smileys & Emotion","description":"exploding head","unicode_version":"11.0"},{"emoji":"๐Ÿค ","aliases":["cowboy_hat_face"],"tags":[],"category":"Smileys & Emotion","description":"cowboy hat face","unicode_version":"9.0"},{"emoji":"๐Ÿฅณ","aliases":["partying_face"],"tags":["celebration","birthday"],"category":"Smileys & Emotion","description":"partying face","unicode_version":"11.0"},{"emoji":"๐Ÿฅธ","aliases":["disguised_face"],"tags":[],"category":"Smileys & Emotion","description":"disguised face","unicode_version":"13.0"},{"emoji":"๐Ÿ˜Ž","aliases":["sunglasses"],"tags":["cool"],"category":"Smileys & Emotion","description":"smiling face with sunglasses","unicode_version":"6.0"},{"emoji":"๐Ÿค“","aliases":["nerd_face"],"tags":["geek","glasses"],"category":"Smileys & Emotion","description":"nerd face","unicode_version":"8.0"},{"emoji":"๐Ÿง","aliases":["monocle_face"],"tags":[],"category":"Smileys & Emotion","description":"face with monocle","unicode_version":"11.0"},{"emoji":"๐Ÿ˜•","aliases":["confused"],"tags":[],"category":"Smileys & Emotion","description":"confused face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜Ÿ","aliases":["worried"],"tags":["nervous"],"category":"Smileys & Emotion","description":"worried face","unicode_version":"6.1"},{"emoji":"๐Ÿ™","aliases":["slightly_frowning_face"],"tags":[],"category":"Smileys & Emotion","description":"slightly frowning face","unicode_version":"7.0"},{"emoji":"โ˜น๏ธ","aliases":["frowning_face"],"tags":[],"category":"Smileys & Emotion","description":"frowning face","unicode_version":""},{"emoji":"๐Ÿ˜ฎ","aliases":["open_mouth"],"tags":["surprise","impressed","wow"],"category":"Smileys & Emotion","description":"face with open mouth","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ฏ","aliases":["hushed"],"tags":["silence","speechless"],"category":"Smileys & Emotion","description":"hushed face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ฒ","aliases":["astonished"],"tags":["amazed","gasp"],"category":"Smileys & Emotion","description":"astonished face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ณ","aliases":["flushed"],"tags":[],"category":"Smileys & Emotion","description":"flushed face","unicode_version":"6.0"},{"emoji":"๐Ÿฅบ","aliases":["pleading_face"],"tags":["puppy","eyes"],"category":"Smileys & Emotion","description":"pleading face","unicode_version":"11.0"},{"emoji":"๐Ÿ˜ฆ","aliases":["frowning"],"tags":[],"category":"Smileys & Emotion","description":"frowning face with open mouth","unicode_version":"6.1"},{"emoji":"๐Ÿ˜ง","aliases":["anguished"],"tags":["stunned"],"category":"Smileys & Emotion","description":"anguished face","unicode_version":"6.1"},{"emoji":"๐Ÿ˜จ","aliases":["fearful"],"tags":["scared","shocked","oops"],"category":"Smileys & Emotion","description":"fearful face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฐ","aliases":["cold_sweat"],"tags":["nervous"],"category":"Smileys & Emotion","description":"anxious face with sweat","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฅ","aliases":["disappointed_relieved"],"tags":["phew","sweat","nervous"],"category":"Smileys & Emotion","description":"sad but relieved face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ข","aliases":["cry"],"tags":["sad","tear"],"category":"Smileys & Emotion","description":"crying face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ญ","aliases":["sob"],"tags":["sad","cry","bawling"],"category":"Smileys & Emotion","description":"loudly crying face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฑ","aliases":["scream"],"tags":["horror","shocked"],"category":"Smileys & Emotion","description":"face screaming in fear","unicode_version":"6.0"},{"emoji":"๐Ÿ˜–","aliases":["confounded"],"tags":[],"category":"Smileys & Emotion","description":"confounded face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฃ","aliases":["persevere"],"tags":["struggling"],"category":"Smileys & Emotion","description":"persevering face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ž","aliases":["disappointed"],"tags":["sad"],"category":"Smileys & Emotion","description":"disappointed face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜“","aliases":["sweat"],"tags":[],"category":"Smileys & Emotion","description":"downcast face with sweat","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฉ","aliases":["weary"],"tags":["tired"],"category":"Smileys & Emotion","description":"weary face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ซ","aliases":["tired_face"],"tags":["upset","whine"],"category":"Smileys & Emotion","description":"tired face","unicode_version":"6.0"},{"emoji":"๐Ÿฅฑ","aliases":["yawning_face"],"tags":[],"category":"Smileys & Emotion","description":"yawning face","unicode_version":"12.0"},{"emoji":"๐Ÿ˜ค","aliases":["triumph"],"tags":["smug"],"category":"Smileys & Emotion","description":"face with steam from nose","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ก","aliases":["rage","pout"],"tags":["angry"],"category":"Smileys & Emotion","description":"pouting face","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ ","aliases":["angry"],"tags":["mad","annoyed"],"category":"Smileys & Emotion","description":"angry face","unicode_version":"6.0"},{"emoji":"๐Ÿคฌ","aliases":["cursing_face"],"tags":["foul"],"category":"Smileys & Emotion","description":"face with symbols on mouth","unicode_version":"11.0"},{"emoji":"๐Ÿ˜ˆ","aliases":["smiling_imp"],"tags":["devil","evil","horns"],"category":"Smileys & Emotion","description":"smiling face with horns","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฟ","aliases":["imp"],"tags":["angry","devil","evil","horns"],"category":"Smileys & Emotion","description":"angry face with horns","unicode_version":"6.0"},{"emoji":"๐Ÿ’€","aliases":["skull"],"tags":["dead","danger","poison"],"category":"Smileys & Emotion","description":"skull","unicode_version":"6.0"},{"emoji":"โ˜ ๏ธ","aliases":["skull_and_crossbones"],"tags":["danger","pirate"],"category":"Smileys & Emotion","description":"skull and crossbones","unicode_version":""},{"emoji":"๐Ÿ’ฉ","aliases":["hankey","poop","shit"],"tags":["crap"],"category":"Smileys & Emotion","description":"pile of poo","unicode_version":"6.0"},{"emoji":"๐Ÿคก","aliases":["clown_face"],"tags":[],"category":"Smileys & Emotion","description":"clown face","unicode_version":"9.0"},{"emoji":"๐Ÿ‘น","aliases":["japanese_ogre"],"tags":["monster"],"category":"Smileys & Emotion","description":"ogre","unicode_version":"6.0"},{"emoji":"๐Ÿ‘บ","aliases":["japanese_goblin"],"tags":[],"category":"Smileys & Emotion","description":"goblin","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ป","aliases":["ghost"],"tags":["halloween"],"category":"Smileys & Emotion","description":"ghost","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฝ","aliases":["alien"],"tags":["ufo"],"category":"Smileys & Emotion","description":"alien","unicode_version":"6.0"},{"emoji":"๐Ÿ‘พ","aliases":["space_invader"],"tags":["game","retro"],"category":"Smileys & Emotion","description":"alien monster","unicode_version":"6.0"},{"emoji":"๐Ÿค–","aliases":["robot"],"tags":[],"category":"Smileys & Emotion","description":"robot","unicode_version":"8.0"},{"emoji":"๐Ÿ˜บ","aliases":["smiley_cat"],"tags":[],"category":"Smileys & Emotion","description":"grinning cat","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ธ","aliases":["smile_cat"],"tags":[],"category":"Smileys & Emotion","description":"grinning cat with smiling eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜น","aliases":["joy_cat"],"tags":[],"category":"Smileys & Emotion","description":"cat with tears of joy","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ป","aliases":["heart_eyes_cat"],"tags":[],"category":"Smileys & Emotion","description":"smiling cat with heart-eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ผ","aliases":["smirk_cat"],"tags":[],"category":"Smileys & Emotion","description":"cat with wry smile","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฝ","aliases":["kissing_cat"],"tags":[],"category":"Smileys & Emotion","description":"kissing cat","unicode_version":"6.0"},{"emoji":"๐Ÿ™€","aliases":["scream_cat"],"tags":["horror"],"category":"Smileys & Emotion","description":"weary cat","unicode_version":"6.0"},{"emoji":"๐Ÿ˜ฟ","aliases":["crying_cat_face"],"tags":["sad","tear"],"category":"Smileys & Emotion","description":"crying cat","unicode_version":"6.0"},{"emoji":"๐Ÿ˜พ","aliases":["pouting_cat"],"tags":[],"category":"Smileys & Emotion","description":"pouting cat","unicode_version":"6.0"},{"emoji":"๐Ÿ™ˆ","aliases":["see_no_evil"],"tags":["monkey","blind","ignore"],"category":"Smileys & Emotion","description":"see-no-evil monkey","unicode_version":"6.0"},{"emoji":"๐Ÿ™‰","aliases":["hear_no_evil"],"tags":["monkey","deaf"],"category":"Smileys & Emotion","description":"hear-no-evil monkey","unicode_version":"6.0"},{"emoji":"๐Ÿ™Š","aliases":["speak_no_evil"],"tags":["monkey","mute","hush"],"category":"Smileys & Emotion","description":"speak-no-evil monkey","unicode_version":"6.0"},{"emoji":"๐Ÿ’‹","aliases":["kiss"],"tags":["lipstick"],"category":"Smileys & Emotion","description":"kiss mark","unicode_version":"6.0"},{"emoji":"๐Ÿ’Œ","aliases":["love_letter"],"tags":["email","envelope"],"category":"Smileys & Emotion","description":"love letter","unicode_version":"6.0"},{"emoji":"๐Ÿ’˜","aliases":["cupid"],"tags":["love","heart"],"category":"Smileys & Emotion","description":"heart with arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ’","aliases":["gift_heart"],"tags":["chocolates"],"category":"Smileys & Emotion","description":"heart with ribbon","unicode_version":"6.0"},{"emoji":"๐Ÿ’–","aliases":["sparkling_heart"],"tags":[],"category":"Smileys & Emotion","description":"sparkling heart","unicode_version":"6.0"},{"emoji":"๐Ÿ’—","aliases":["heartpulse"],"tags":[],"category":"Smileys & Emotion","description":"growing heart","unicode_version":"6.0"},{"emoji":"๐Ÿ’“","aliases":["heartbeat"],"tags":[],"category":"Smileys & Emotion","description":"beating heart","unicode_version":"6.0"},{"emoji":"๐Ÿ’ž","aliases":["revolving_hearts"],"tags":[],"category":"Smileys & Emotion","description":"revolving hearts","unicode_version":"6.0"},{"emoji":"๐Ÿ’•","aliases":["two_hearts"],"tags":[],"category":"Smileys & Emotion","description":"two hearts","unicode_version":"6.0"},{"emoji":"๐Ÿ’Ÿ","aliases":["heart_decoration"],"tags":[],"category":"Smileys & Emotion","description":"heart decoration","unicode_version":"6.0"},{"emoji":"โฃ๏ธ","aliases":["heavy_heart_exclamation"],"tags":[],"category":"Smileys & Emotion","description":"heart exclamation","unicode_version":""},{"emoji":"๐Ÿ’”","aliases":["broken_heart"],"tags":[],"category":"Smileys & Emotion","description":"broken heart","unicode_version":"6.0"},{"emoji":"โค๏ธโ€๐Ÿ”ฅ","aliases":["heart_on_fire"],"tags":[],"category":"Smileys & Emotion","description":"heart on fire","unicode_version":"13.1"},{"emoji":"โค๏ธโ€๐Ÿฉน","aliases":["mending_heart"],"tags":[],"category":"Smileys & Emotion","description":"mending heart","unicode_version":"13.1"},{"emoji":"โค๏ธ","aliases":["heart"],"tags":["love"],"category":"Smileys & Emotion","description":"red heart","unicode_version":""},{"emoji":"๐Ÿงก","aliases":["orange_heart"],"tags":[],"category":"Smileys & Emotion","description":"orange heart","unicode_version":"11.0"},{"emoji":"๐Ÿ’›","aliases":["yellow_heart"],"tags":[],"category":"Smileys & Emotion","description":"yellow heart","unicode_version":"6.0"},{"emoji":"๐Ÿ’š","aliases":["green_heart"],"tags":[],"category":"Smileys & Emotion","description":"green heart","unicode_version":"6.0"},{"emoji":"๐Ÿ’™","aliases":["blue_heart"],"tags":[],"category":"Smileys & Emotion","description":"blue heart","unicode_version":"6.0"},{"emoji":"๐Ÿ’œ","aliases":["purple_heart"],"tags":[],"category":"Smileys & Emotion","description":"purple heart","unicode_version":"6.0"},{"emoji":"๐ŸคŽ","aliases":["brown_heart"],"tags":[],"category":"Smileys & Emotion","description":"brown heart","unicode_version":"12.0"},{"emoji":"๐Ÿ–ค","aliases":["black_heart"],"tags":[],"category":"Smileys & Emotion","description":"black heart","unicode_version":"9.0"},{"emoji":"๐Ÿค","aliases":["white_heart"],"tags":[],"category":"Smileys & Emotion","description":"white heart","unicode_version":"12.0"},{"emoji":"๐Ÿ’ฏ","aliases":["100"],"tags":["score","perfect"],"category":"Smileys & Emotion","description":"hundred points","unicode_version":"6.0"},{"emoji":"๐Ÿ’ข","aliases":["anger"],"tags":["angry"],"category":"Smileys & Emotion","description":"anger symbol","unicode_version":"6.0"},{"emoji":"๐Ÿ’ฅ","aliases":["boom","collision"],"tags":["explode"],"category":"Smileys & Emotion","description":"collision","unicode_version":"6.0"},{"emoji":"๐Ÿ’ซ","aliases":["dizzy"],"tags":["star"],"category":"Smileys & Emotion","description":"dizzy","unicode_version":"6.0"},{"emoji":"๐Ÿ’ฆ","aliases":["sweat_drops"],"tags":["water","workout"],"category":"Smileys & Emotion","description":"sweat droplets","unicode_version":"6.0"},{"emoji":"๐Ÿ’จ","aliases":["dash"],"tags":["wind","blow","fast"],"category":"Smileys & Emotion","description":"dashing away","unicode_version":"6.0"},{"emoji":"๐Ÿ•ณ๏ธ","aliases":["hole"],"tags":[],"category":"Smileys & Emotion","description":"hole","unicode_version":"7.0"},{"emoji":"๐Ÿ’ฃ","aliases":["bomb"],"tags":["boom"],"category":"Smileys & Emotion","description":"bomb","unicode_version":"6.0"},{"emoji":"๐Ÿ’ฌ","aliases":["speech_balloon"],"tags":["comment"],"category":"Smileys & Emotion","description":"speech balloon","unicode_version":"6.0"},{"emoji":"๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ","aliases":["eye_speech_bubble"],"tags":[],"category":"Smileys & Emotion","description":"eye in speech bubble","unicode_version":"11.0"},{"emoji":"๐Ÿ—จ๏ธ","aliases":["left_speech_bubble"],"tags":[],"category":"Smileys & Emotion","description":"left speech bubble","unicode_version":"11.0"},{"emoji":"๐Ÿ—ฏ๏ธ","aliases":["right_anger_bubble"],"tags":[],"category":"Smileys & Emotion","description":"right anger bubble","unicode_version":"7.0"},{"emoji":"๐Ÿ’ญ","aliases":["thought_balloon"],"tags":["thinking"],"category":"Smileys & Emotion","description":"thought balloon","unicode_version":"6.0"},{"emoji":"๐Ÿ’ค","aliases":["zzz"],"tags":["sleeping"],"category":"Smileys & Emotion","description":"zzz","unicode_version":"6.0"},{"emoji":"๐Ÿ‘‹","aliases":["wave"],"tags":["goodbye"],"category":"People & Body","description":"waving hand","unicode_version":"6.0"},{"emoji":"๐Ÿคš","aliases":["raised_back_of_hand"],"tags":[],"category":"People & Body","description":"raised back of hand","unicode_version":"9.0"},{"emoji":"๐Ÿ–๏ธ","aliases":["raised_hand_with_fingers_splayed"],"tags":[],"category":"People & Body","description":"hand with fingers splayed","unicode_version":"7.0"},{"emoji":"โœ‹","aliases":["hand","raised_hand"],"tags":["highfive","stop"],"category":"People & Body","description":"raised hand","unicode_version":"6.0"},{"emoji":"๐Ÿ––","aliases":["vulcan_salute"],"tags":["prosper","spock"],"category":"People & Body","description":"vulcan salute","unicode_version":"7.0"},{"emoji":"๐Ÿ‘Œ","aliases":["ok_hand"],"tags":[],"category":"People & Body","description":"OK hand","unicode_version":"6.0"},{"emoji":"๐ŸคŒ","aliases":["pinched_fingers"],"tags":[],"category":"People & Body","description":"pinched fingers","unicode_version":"13.0"},{"emoji":"๐Ÿค","aliases":["pinching_hand"],"tags":[],"category":"People & Body","description":"pinching hand","unicode_version":"12.0"},{"emoji":"โœŒ๏ธ","aliases":["v"],"tags":["victory","peace"],"category":"People & Body","description":"victory hand","unicode_version":""},{"emoji":"๐Ÿคž","aliases":["crossed_fingers"],"tags":["luck","hopeful"],"category":"People & Body","description":"crossed fingers","unicode_version":"9.0"},{"emoji":"๐ŸคŸ","aliases":["love_you_gesture"],"tags":[],"category":"People & Body","description":"love-you gesture","unicode_version":"11.0"},{"emoji":"๐Ÿค˜","aliases":["metal"],"tags":[],"category":"People & Body","description":"sign of the horns","unicode_version":"8.0"},{"emoji":"๐Ÿค™","aliases":["call_me_hand"],"tags":[],"category":"People & Body","description":"call me hand","unicode_version":"9.0"},{"emoji":"๐Ÿ‘ˆ","aliases":["point_left"],"tags":[],"category":"People & Body","description":"backhand index pointing left","unicode_version":"6.0"},{"emoji":"๐Ÿ‘‰","aliases":["point_right"],"tags":[],"category":"People & Body","description":"backhand index pointing right","unicode_version":"6.0"},{"emoji":"๐Ÿ‘†","aliases":["point_up_2"],"tags":[],"category":"People & Body","description":"backhand index pointing up","unicode_version":"6.0"},{"emoji":"๐Ÿ–•","aliases":["middle_finger","fu"],"tags":[],"category":"People & Body","description":"middle finger","unicode_version":"7.0"},{"emoji":"๐Ÿ‘‡","aliases":["point_down"],"tags":[],"category":"People & Body","description":"backhand index pointing down","unicode_version":"6.0"},{"emoji":"โ˜๏ธ","aliases":["point_up"],"tags":[],"category":"People & Body","description":"index pointing up","unicode_version":""},{"emoji":"๐Ÿ‘","aliases":["+1","thumbsup"],"tags":["approve","ok"],"category":"People & Body","description":"thumbs up","unicode_version":"6.0"},{"emoji":"๐Ÿ‘Ž","aliases":["-1","thumbsdown"],"tags":["disapprove","bury"],"category":"People & Body","description":"thumbs down","unicode_version":"6.0"},{"emoji":"โœŠ","aliases":["fist_raised","fist"],"tags":["power"],"category":"People & Body","description":"raised fist","unicode_version":"6.0"},{"emoji":"๐Ÿ‘Š","aliases":["fist_oncoming","facepunch","punch"],"tags":["attack"],"category":"People & Body","description":"oncoming fist","unicode_version":"6.0"},{"emoji":"๐Ÿค›","aliases":["fist_left"],"tags":[],"category":"People & Body","description":"left-facing fist","unicode_version":"9.0"},{"emoji":"๐Ÿคœ","aliases":["fist_right"],"tags":[],"category":"People & Body","description":"right-facing fist","unicode_version":"9.0"},{"emoji":"๐Ÿ‘","aliases":["clap"],"tags":["praise","applause"],"category":"People & Body","description":"clapping hands","unicode_version":"6.0"},{"emoji":"๐Ÿ™Œ","aliases":["raised_hands"],"tags":["hooray"],"category":"People & Body","description":"raising hands","unicode_version":"6.0"},{"emoji":"๐Ÿ‘","aliases":["open_hands"],"tags":[],"category":"People & Body","description":"open hands","unicode_version":"6.0"},{"emoji":"๐Ÿคฒ","aliases":["palms_up_together"],"tags":[],"category":"People & Body","description":"palms up together","unicode_version":"11.0"},{"emoji":"๐Ÿค","aliases":["handshake"],"tags":["deal"],"category":"People & Body","description":"handshake","unicode_version":"9.0"},{"emoji":"๐Ÿ™","aliases":["pray"],"tags":["please","hope","wish"],"category":"People & Body","description":"folded hands","unicode_version":"6.0"},{"emoji":"โœ๏ธ","aliases":["writing_hand"],"tags":[],"category":"People & Body","description":"writing hand","unicode_version":""},{"emoji":"๐Ÿ’…","aliases":["nail_care"],"tags":["beauty","manicure"],"category":"People & Body","description":"nail polish","unicode_version":"6.0"},{"emoji":"๐Ÿคณ","aliases":["selfie"],"tags":[],"category":"People & Body","description":"selfie","unicode_version":"9.0"},{"emoji":"๐Ÿ’ช","aliases":["muscle"],"tags":["flex","bicep","strong","workout"],"category":"People & Body","description":"flexed biceps","unicode_version":"6.0"},{"emoji":"๐Ÿฆพ","aliases":["mechanical_arm"],"tags":[],"category":"People & Body","description":"mechanical arm","unicode_version":"12.0"},{"emoji":"๐Ÿฆฟ","aliases":["mechanical_leg"],"tags":[],"category":"People & Body","description":"mechanical leg","unicode_version":"12.0"},{"emoji":"๐Ÿฆต","aliases":["leg"],"tags":[],"category":"People & Body","description":"leg","unicode_version":"11.0"},{"emoji":"๐Ÿฆถ","aliases":["foot"],"tags":[],"category":"People & Body","description":"foot","unicode_version":"11.0"},{"emoji":"๐Ÿ‘‚","aliases":["ear"],"tags":["hear","sound","listen"],"category":"People & Body","description":"ear","unicode_version":"6.0"},{"emoji":"๐Ÿฆป","aliases":["ear_with_hearing_aid"],"tags":[],"category":"People & Body","description":"ear with hearing aid","unicode_version":"12.0"},{"emoji":"๐Ÿ‘ƒ","aliases":["nose"],"tags":["smell"],"category":"People & Body","description":"nose","unicode_version":"6.0"},{"emoji":"๐Ÿง ","aliases":["brain"],"tags":[],"category":"People & Body","description":"brain","unicode_version":"11.0"},{"emoji":"๐Ÿซ€","aliases":["anatomical_heart"],"tags":[],"category":"People & Body","description":"anatomical heart","unicode_version":"13.0"},{"emoji":"๐Ÿซ","aliases":["lungs"],"tags":[],"category":"People & Body","description":"lungs","unicode_version":"13.0"},{"emoji":"๐Ÿฆท","aliases":["tooth"],"tags":[],"category":"People & Body","description":"tooth","unicode_version":"11.0"},{"emoji":"๐Ÿฆด","aliases":["bone"],"tags":[],"category":"People & Body","description":"bone","unicode_version":"11.0"},{"emoji":"๐Ÿ‘€","aliases":["eyes"],"tags":["look","see","watch"],"category":"People & Body","description":"eyes","unicode_version":"6.0"},{"emoji":"๐Ÿ‘๏ธ","aliases":["eye"],"tags":[],"category":"People & Body","description":"eye","unicode_version":"7.0"},{"emoji":"๐Ÿ‘…","aliases":["tongue"],"tags":["taste"],"category":"People & Body","description":"tongue","unicode_version":"6.0"},{"emoji":"๐Ÿ‘„","aliases":["lips"],"tags":["kiss"],"category":"People & Body","description":"mouth","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ถ","aliases":["baby"],"tags":["child","newborn"],"category":"People & Body","description":"baby","unicode_version":"6.0"},{"emoji":"๐Ÿง’","aliases":["child"],"tags":[],"category":"People & Body","description":"child","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ฆ","aliases":["boy"],"tags":["child"],"category":"People & Body","description":"boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ง","aliases":["girl"],"tags":["child"],"category":"People & Body","description":"girl","unicode_version":"6.0"},{"emoji":"๐Ÿง‘","aliases":["adult"],"tags":[],"category":"People & Body","description":"person","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ฑ","aliases":["blond_haired_person"],"tags":[],"category":"People & Body","description":"person: blond hair","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จ","aliases":["man"],"tags":["mustache","father","dad"],"category":"People & Body","description":"man","unicode_version":"6.0"},{"emoji":"๐Ÿง”","aliases":["bearded_person"],"tags":[],"category":"People & Body","description":"person: beard","unicode_version":"11.0"},{"emoji":"๐Ÿง”โ€โ™‚๏ธ","aliases":["man_beard"],"tags":[],"category":"People & Body","description":"man: beard","unicode_version":"13.1"},{"emoji":"๐Ÿง”โ€โ™€๏ธ","aliases":["woman_beard"],"tags":[],"category":"People & Body","description":"woman: beard","unicode_version":"13.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฐ","aliases":["red_haired_man"],"tags":[],"category":"People & Body","description":"man: red hair","unicode_version":"11.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฑ","aliases":["curly_haired_man"],"tags":[],"category":"People & Body","description":"man: curly hair","unicode_version":"11.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆณ","aliases":["white_haired_man"],"tags":[],"category":"People & Body","description":"man: white hair","unicode_version":"11.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฒ","aliases":["bald_man"],"tags":[],"category":"People & Body","description":"man: bald","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ฉ","aliases":["woman"],"tags":["girls"],"category":"People & Body","description":"woman","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฐ","aliases":["red_haired_woman"],"tags":[],"category":"People & Body","description":"woman: red hair","unicode_version":"11.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆฐ","aliases":["person_red_hair"],"tags":[],"category":"People & Body","description":"person: red hair","unicode_version":"12.1"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฑ","aliases":["curly_haired_woman"],"tags":[],"category":"People & Body","description":"woman: curly hair","unicode_version":"11.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆฑ","aliases":["person_curly_hair"],"tags":[],"category":"People & Body","description":"person: curly hair","unicode_version":"12.1"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆณ","aliases":["white_haired_woman"],"tags":[],"category":"People & Body","description":"woman: white hair","unicode_version":"11.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆณ","aliases":["person_white_hair"],"tags":[],"category":"People & Body","description":"person: white hair","unicode_version":"12.1"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฒ","aliases":["bald_woman"],"tags":[],"category":"People & Body","description":"woman: bald","unicode_version":"11.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆฒ","aliases":["person_bald"],"tags":[],"category":"People & Body","description":"person: bald","unicode_version":"12.1"},{"emoji":"๐Ÿ‘ฑโ€โ™€๏ธ","aliases":["blond_haired_woman","blonde_woman"],"tags":[],"category":"People & Body","description":"woman: blond hair","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฑโ€โ™‚๏ธ","aliases":["blond_haired_man"],"tags":[],"category":"People & Body","description":"man: blond hair","unicode_version":"11.0"},{"emoji":"๐Ÿง“","aliases":["older_adult"],"tags":[],"category":"People & Body","description":"older person","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ด","aliases":["older_man"],"tags":[],"category":"People & Body","description":"old man","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ต","aliases":["older_woman"],"tags":[],"category":"People & Body","description":"old woman","unicode_version":"6.0"},{"emoji":"๐Ÿ™","aliases":["frowning_person"],"tags":[],"category":"People & Body","description":"person frowning","unicode_version":"6.0"},{"emoji":"๐Ÿ™โ€โ™‚๏ธ","aliases":["frowning_man"],"tags":[],"category":"People & Body","description":"man frowning","unicode_version":"6.0"},{"emoji":"๐Ÿ™โ€โ™€๏ธ","aliases":["frowning_woman"],"tags":[],"category":"People & Body","description":"woman frowning","unicode_version":"11.0"},{"emoji":"๐Ÿ™Ž","aliases":["pouting_face"],"tags":[],"category":"People & Body","description":"person pouting","unicode_version":"6.0"},{"emoji":"๐Ÿ™Žโ€โ™‚๏ธ","aliases":["pouting_man"],"tags":[],"category":"People & Body","description":"man pouting","unicode_version":"6.0"},{"emoji":"๐Ÿ™Žโ€โ™€๏ธ","aliases":["pouting_woman"],"tags":[],"category":"People & Body","description":"woman pouting","unicode_version":"11.0"},{"emoji":"๐Ÿ™…","aliases":["no_good"],"tags":["stop","halt","denied"],"category":"People & Body","description":"person gesturing NO","unicode_version":"6.0"},{"emoji":"๐Ÿ™…โ€โ™‚๏ธ","aliases":["no_good_man","ng_man"],"tags":["stop","halt","denied"],"category":"People & Body","description":"man gesturing NO","unicode_version":"6.0"},{"emoji":"๐Ÿ™…โ€โ™€๏ธ","aliases":["no_good_woman","ng_woman"],"tags":["stop","halt","denied"],"category":"People & Body","description":"woman gesturing NO","unicode_version":"11.0"},{"emoji":"๐Ÿ™†","aliases":["ok_person"],"tags":[],"category":"People & Body","description":"person gesturing OK","unicode_version":"6.0"},{"emoji":"๐Ÿ™†โ€โ™‚๏ธ","aliases":["ok_man"],"tags":[],"category":"People & Body","description":"man gesturing OK","unicode_version":"6.0"},{"emoji":"๐Ÿ™†โ€โ™€๏ธ","aliases":["ok_woman"],"tags":[],"category":"People & Body","description":"woman gesturing OK","unicode_version":"11.0"},{"emoji":"๐Ÿ’","aliases":["tipping_hand_person","information_desk_person"],"tags":[],"category":"People & Body","description":"person tipping hand","unicode_version":"6.0"},{"emoji":"๐Ÿ’โ€โ™‚๏ธ","aliases":["tipping_hand_man","sassy_man"],"tags":["information"],"category":"People & Body","description":"man tipping hand","unicode_version":"6.0"},{"emoji":"๐Ÿ’โ€โ™€๏ธ","aliases":["tipping_hand_woman","sassy_woman"],"tags":["information"],"category":"People & Body","description":"woman tipping hand","unicode_version":"11.0"},{"emoji":"๐Ÿ™‹","aliases":["raising_hand"],"tags":[],"category":"People & Body","description":"person raising hand","unicode_version":"6.0"},{"emoji":"๐Ÿ™‹โ€โ™‚๏ธ","aliases":["raising_hand_man"],"tags":[],"category":"People & Body","description":"man raising hand","unicode_version":"6.0"},{"emoji":"๐Ÿ™‹โ€โ™€๏ธ","aliases":["raising_hand_woman"],"tags":[],"category":"People & Body","description":"woman raising hand","unicode_version":"11.0"},{"emoji":"๐Ÿง","aliases":["deaf_person"],"tags":[],"category":"People & Body","description":"deaf person","unicode_version":"12.0"},{"emoji":"๐Ÿงโ€โ™‚๏ธ","aliases":["deaf_man"],"tags":[],"category":"People & Body","description":"deaf man","unicode_version":"12.0"},{"emoji":"๐Ÿงโ€โ™€๏ธ","aliases":["deaf_woman"],"tags":[],"category":"People & Body","description":"deaf woman","unicode_version":"12.0"},{"emoji":"๐Ÿ™‡","aliases":["bow"],"tags":["respect","thanks"],"category":"People & Body","description":"person bowing","unicode_version":"6.0"},{"emoji":"๐Ÿ™‡โ€โ™‚๏ธ","aliases":["bowing_man"],"tags":["respect","thanks"],"category":"People & Body","description":"man bowing","unicode_version":"11.0"},{"emoji":"๐Ÿ™‡โ€โ™€๏ธ","aliases":["bowing_woman"],"tags":["respect","thanks"],"category":"People & Body","description":"woman bowing","unicode_version":"6.0"},{"emoji":"๐Ÿคฆ","aliases":["facepalm"],"tags":[],"category":"People & Body","description":"person facepalming","unicode_version":"11.0"},{"emoji":"๐Ÿคฆโ€โ™‚๏ธ","aliases":["man_facepalming"],"tags":[],"category":"People & Body","description":"man facepalming","unicode_version":"9.0"},{"emoji":"๐Ÿคฆโ€โ™€๏ธ","aliases":["woman_facepalming"],"tags":[],"category":"People & Body","description":"woman facepalming","unicode_version":"9.0"},{"emoji":"๐Ÿคท","aliases":["shrug"],"tags":[],"category":"People & Body","description":"person shrugging","unicode_version":"11.0"},{"emoji":"๐Ÿคทโ€โ™‚๏ธ","aliases":["man_shrugging"],"tags":[],"category":"People & Body","description":"man shrugging","unicode_version":"9.0"},{"emoji":"๐Ÿคทโ€โ™€๏ธ","aliases":["woman_shrugging"],"tags":[],"category":"People & Body","description":"woman shrugging","unicode_version":"9.0"},{"emoji":"๐Ÿง‘โ€โš•๏ธ","aliases":["health_worker"],"tags":[],"category":"People & Body","description":"health worker","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€โš•๏ธ","aliases":["man_health_worker"],"tags":["doctor","nurse"],"category":"People & Body","description":"man health worker","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€โš•๏ธ","aliases":["woman_health_worker"],"tags":["doctor","nurse"],"category":"People & Body","description":"woman health worker","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐ŸŽ“","aliases":["student"],"tags":[],"category":"People & Body","description":"student","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐ŸŽ“","aliases":["man_student"],"tags":["graduation"],"category":"People & Body","description":"man student","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐ŸŽ“","aliases":["woman_student"],"tags":["graduation"],"category":"People & Body","description":"woman student","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿซ","aliases":["teacher"],"tags":[],"category":"People & Body","description":"teacher","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿซ","aliases":["man_teacher"],"tags":["school","professor"],"category":"People & Body","description":"man teacher","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿซ","aliases":["woman_teacher"],"tags":["school","professor"],"category":"People & Body","description":"woman teacher","unicode_version":""},{"emoji":"๐Ÿง‘โ€โš–๏ธ","aliases":["judge"],"tags":[],"category":"People & Body","description":"judge","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€โš–๏ธ","aliases":["man_judge"],"tags":["justice"],"category":"People & Body","description":"man judge","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€โš–๏ธ","aliases":["woman_judge"],"tags":["justice"],"category":"People & Body","description":"woman judge","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐ŸŒพ","aliases":["farmer"],"tags":[],"category":"People & Body","description":"farmer","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐ŸŒพ","aliases":["man_farmer"],"tags":[],"category":"People & Body","description":"man farmer","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐ŸŒพ","aliases":["woman_farmer"],"tags":[],"category":"People & Body","description":"woman farmer","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿณ","aliases":["cook"],"tags":[],"category":"People & Body","description":"cook","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿณ","aliases":["man_cook"],"tags":["chef"],"category":"People & Body","description":"man cook","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿณ","aliases":["woman_cook"],"tags":["chef"],"category":"People & Body","description":"woman cook","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿ”ง","aliases":["mechanic"],"tags":[],"category":"People & Body","description":"mechanic","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿ”ง","aliases":["man_mechanic"],"tags":[],"category":"People & Body","description":"man mechanic","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ”ง","aliases":["woman_mechanic"],"tags":[],"category":"People & Body","description":"woman mechanic","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿญ","aliases":["factory_worker"],"tags":[],"category":"People & Body","description":"factory worker","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿญ","aliases":["man_factory_worker"],"tags":[],"category":"People & Body","description":"man factory worker","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿญ","aliases":["woman_factory_worker"],"tags":[],"category":"People & Body","description":"woman factory worker","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿ’ผ","aliases":["office_worker"],"tags":[],"category":"People & Body","description":"office worker","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿ’ผ","aliases":["man_office_worker"],"tags":["business"],"category":"People & Body","description":"man office worker","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ’ผ","aliases":["woman_office_worker"],"tags":["business"],"category":"People & Body","description":"woman office worker","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿ”ฌ","aliases":["scientist"],"tags":[],"category":"People & Body","description":"scientist","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿ”ฌ","aliases":["man_scientist"],"tags":["research"],"category":"People & Body","description":"man scientist","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ”ฌ","aliases":["woman_scientist"],"tags":["research"],"category":"People & Body","description":"woman scientist","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿ’ป","aliases":["technologist"],"tags":[],"category":"People & Body","description":"technologist","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿ’ป","aliases":["man_technologist"],"tags":["coder"],"category":"People & Body","description":"man technologist","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ’ป","aliases":["woman_technologist"],"tags":["coder"],"category":"People & Body","description":"woman technologist","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐ŸŽค","aliases":["singer"],"tags":[],"category":"People & Body","description":"singer","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐ŸŽค","aliases":["man_singer"],"tags":["rockstar"],"category":"People & Body","description":"man singer","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐ŸŽค","aliases":["woman_singer"],"tags":["rockstar"],"category":"People & Body","description":"woman singer","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐ŸŽจ","aliases":["artist"],"tags":[],"category":"People & Body","description":"artist","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐ŸŽจ","aliases":["man_artist"],"tags":["painter"],"category":"People & Body","description":"man artist","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐ŸŽจ","aliases":["woman_artist"],"tags":["painter"],"category":"People & Body","description":"woman artist","unicode_version":""},{"emoji":"๐Ÿง‘โ€โœˆ๏ธ","aliases":["pilot"],"tags":[],"category":"People & Body","description":"pilot","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€โœˆ๏ธ","aliases":["man_pilot"],"tags":[],"category":"People & Body","description":"man pilot","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€โœˆ๏ธ","aliases":["woman_pilot"],"tags":[],"category":"People & Body","description":"woman pilot","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿš€","aliases":["astronaut"],"tags":[],"category":"People & Body","description":"astronaut","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿš€","aliases":["man_astronaut"],"tags":["space"],"category":"People & Body","description":"man astronaut","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿš€","aliases":["woman_astronaut"],"tags":["space"],"category":"People & Body","description":"woman astronaut","unicode_version":""},{"emoji":"๐Ÿง‘โ€๐Ÿš’","aliases":["firefighter"],"tags":[],"category":"People & Body","description":"firefighter","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿš’","aliases":["man_firefighter"],"tags":[],"category":"People & Body","description":"man firefighter","unicode_version":""},{"emoji":"๐Ÿ‘ฉโ€๐Ÿš’","aliases":["woman_firefighter"],"tags":[],"category":"People & Body","description":"woman firefighter","unicode_version":""},{"emoji":"๐Ÿ‘ฎ","aliases":["police_officer","cop"],"tags":["law"],"category":"People & Body","description":"police officer","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฎโ€โ™‚๏ธ","aliases":["policeman"],"tags":["law","cop"],"category":"People & Body","description":"man police officer","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ฎโ€โ™€๏ธ","aliases":["policewoman"],"tags":["law","cop"],"category":"People & Body","description":"woman police officer","unicode_version":"6.0"},{"emoji":"๐Ÿ•ต๏ธ","aliases":["detective"],"tags":["sleuth"],"category":"People & Body","description":"detective","unicode_version":"7.0"},{"emoji":"๐Ÿ•ต๏ธโ€โ™‚๏ธ","aliases":["male_detective"],"tags":["sleuth"],"category":"People & Body","description":"man detective","unicode_version":"11.0"},{"emoji":"๐Ÿ•ต๏ธโ€โ™€๏ธ","aliases":["female_detective"],"tags":["sleuth"],"category":"People & Body","description":"woman detective","unicode_version":"6.0"},{"emoji":"๐Ÿ’‚","aliases":["guard"],"tags":[],"category":"People & Body","description":"guard","unicode_version":"6.0"},{"emoji":"๐Ÿ’‚โ€โ™‚๏ธ","aliases":["guardsman"],"tags":[],"category":"People & Body","description":"man guard","unicode_version":"11.0"},{"emoji":"๐Ÿ’‚โ€โ™€๏ธ","aliases":["guardswoman"],"tags":[],"category":"People & Body","description":"woman guard","unicode_version":"6.0"},{"emoji":"๐Ÿฅท","aliases":["ninja"],"tags":[],"category":"People & Body","description":"ninja","unicode_version":"13.0"},{"emoji":"๐Ÿ‘ท","aliases":["construction_worker"],"tags":["helmet"],"category":"People & Body","description":"construction worker","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ทโ€โ™‚๏ธ","aliases":["construction_worker_man"],"tags":["helmet"],"category":"People & Body","description":"man construction worker","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ทโ€โ™€๏ธ","aliases":["construction_worker_woman"],"tags":["helmet"],"category":"People & Body","description":"woman construction worker","unicode_version":"6.0"},{"emoji":"๐Ÿคด","aliases":["prince"],"tags":["crown","royal"],"category":"People & Body","description":"prince","unicode_version":"9.0"},{"emoji":"๐Ÿ‘ธ","aliases":["princess"],"tags":["crown","royal"],"category":"People & Body","description":"princess","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ณ","aliases":["person_with_turban"],"tags":[],"category":"People & Body","description":"person wearing turban","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ณโ€โ™‚๏ธ","aliases":["man_with_turban"],"tags":[],"category":"People & Body","description":"man wearing turban","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ณโ€โ™€๏ธ","aliases":["woman_with_turban"],"tags":[],"category":"People & Body","description":"woman wearing turban","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฒ","aliases":["man_with_gua_pi_mao"],"tags":[],"category":"People & Body","description":"person with skullcap","unicode_version":"6.0"},{"emoji":"๐Ÿง•","aliases":["woman_with_headscarf"],"tags":["hijab"],"category":"People & Body","description":"woman with headscarf","unicode_version":"11.0"},{"emoji":"๐Ÿคต","aliases":["person_in_tuxedo"],"tags":["groom","marriage","wedding"],"category":"People & Body","description":"person in tuxedo","unicode_version":"9.0"},{"emoji":"๐Ÿคตโ€โ™‚๏ธ","aliases":["man_in_tuxedo"],"tags":[],"category":"People & Body","description":"man in tuxedo","unicode_version":"13.0"},{"emoji":"๐Ÿคตโ€โ™€๏ธ","aliases":["woman_in_tuxedo"],"tags":[],"category":"People & Body","description":"woman in tuxedo","unicode_version":"13.0"},{"emoji":"๐Ÿ‘ฐ","aliases":["person_with_veil"],"tags":["marriage","wedding"],"category":"People & Body","description":"person with veil","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฐโ€โ™‚๏ธ","aliases":["man_with_veil"],"tags":[],"category":"People & Body","description":"man with veil","unicode_version":"13.0"},{"emoji":"๐Ÿ‘ฐโ€โ™€๏ธ","aliases":["woman_with_veil","bride_with_veil"],"tags":[],"category":"People & Body","description":"woman with veil","unicode_version":"13.0"},{"emoji":"๐Ÿคฐ","aliases":["pregnant_woman"],"tags":[],"category":"People & Body","description":"pregnant woman","unicode_version":"9.0"},{"emoji":"๐Ÿคฑ","aliases":["breast_feeding"],"tags":["nursing"],"category":"People & Body","description":"breast-feeding","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿผ","aliases":["woman_feeding_baby"],"tags":[],"category":"People & Body","description":"woman feeding baby","unicode_version":"13.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿผ","aliases":["man_feeding_baby"],"tags":[],"category":"People & Body","description":"man feeding baby","unicode_version":"13.0"},{"emoji":"๐Ÿง‘โ€๐Ÿผ","aliases":["person_feeding_baby"],"tags":[],"category":"People & Body","description":"person feeding baby","unicode_version":"13.0"},{"emoji":"๐Ÿ‘ผ","aliases":["angel"],"tags":[],"category":"People & Body","description":"baby angel","unicode_version":"6.0"},{"emoji":"๐ŸŽ…","aliases":["santa"],"tags":["christmas"],"category":"People & Body","description":"Santa Claus","unicode_version":"6.0"},{"emoji":"๐Ÿคถ","aliases":["mrs_claus"],"tags":["santa"],"category":"People & Body","description":"Mrs. Claus","unicode_version":"9.0"},{"emoji":"๐Ÿง‘โ€๐ŸŽ„","aliases":["mx_claus"],"tags":[],"category":"People & Body","description":"mx claus","unicode_version":"13.0"},{"emoji":"๐Ÿฆธ","aliases":["superhero"],"tags":[],"category":"People & Body","description":"superhero","unicode_version":"11.0"},{"emoji":"๐Ÿฆธโ€โ™‚๏ธ","aliases":["superhero_man"],"tags":[],"category":"People & Body","description":"man superhero","unicode_version":"11.0"},{"emoji":"๐Ÿฆธโ€โ™€๏ธ","aliases":["superhero_woman"],"tags":[],"category":"People & Body","description":"woman superhero","unicode_version":"11.0"},{"emoji":"๐Ÿฆน","aliases":["supervillain"],"tags":[],"category":"People & Body","description":"supervillain","unicode_version":"11.0"},{"emoji":"๐Ÿฆนโ€โ™‚๏ธ","aliases":["supervillain_man"],"tags":[],"category":"People & Body","description":"man supervillain","unicode_version":"11.0"},{"emoji":"๐Ÿฆนโ€โ™€๏ธ","aliases":["supervillain_woman"],"tags":[],"category":"People & Body","description":"woman supervillain","unicode_version":"11.0"},{"emoji":"๐Ÿง™","aliases":["mage"],"tags":["wizard"],"category":"People & Body","description":"mage","unicode_version":"11.0"},{"emoji":"๐Ÿง™โ€โ™‚๏ธ","aliases":["mage_man"],"tags":["wizard"],"category":"People & Body","description":"man mage","unicode_version":"11.0"},{"emoji":"๐Ÿง™โ€โ™€๏ธ","aliases":["mage_woman"],"tags":["wizard"],"category":"People & Body","description":"woman mage","unicode_version":"11.0"},{"emoji":"๐Ÿงš","aliases":["fairy"],"tags":[],"category":"People & Body","description":"fairy","unicode_version":"11.0"},{"emoji":"๐Ÿงšโ€โ™‚๏ธ","aliases":["fairy_man"],"tags":[],"category":"People & Body","description":"man fairy","unicode_version":"11.0"},{"emoji":"๐Ÿงšโ€โ™€๏ธ","aliases":["fairy_woman"],"tags":[],"category":"People & Body","description":"woman fairy","unicode_version":"11.0"},{"emoji":"๐Ÿง›","aliases":["vampire"],"tags":[],"category":"People & Body","description":"vampire","unicode_version":"11.0"},{"emoji":"๐Ÿง›โ€โ™‚๏ธ","aliases":["vampire_man"],"tags":[],"category":"People & Body","description":"man vampire","unicode_version":"11.0"},{"emoji":"๐Ÿง›โ€โ™€๏ธ","aliases":["vampire_woman"],"tags":[],"category":"People & Body","description":"woman vampire","unicode_version":"11.0"},{"emoji":"๐Ÿงœ","aliases":["merperson"],"tags":[],"category":"People & Body","description":"merperson","unicode_version":"11.0"},{"emoji":"๐Ÿงœโ€โ™‚๏ธ","aliases":["merman"],"tags":[],"category":"People & Body","description":"merman","unicode_version":"11.0"},{"emoji":"๐Ÿงœโ€โ™€๏ธ","aliases":["mermaid"],"tags":[],"category":"People & Body","description":"mermaid","unicode_version":"11.0"},{"emoji":"๐Ÿง","aliases":["elf"],"tags":[],"category":"People & Body","description":"elf","unicode_version":"11.0"},{"emoji":"๐Ÿงโ€โ™‚๏ธ","aliases":["elf_man"],"tags":[],"category":"People & Body","description":"man elf","unicode_version":"11.0"},{"emoji":"๐Ÿงโ€โ™€๏ธ","aliases":["elf_woman"],"tags":[],"category":"People & Body","description":"woman elf","unicode_version":"11.0"},{"emoji":"๐Ÿงž","aliases":["genie"],"tags":[],"category":"People & Body","description":"genie","unicode_version":"11.0"},{"emoji":"๐Ÿงžโ€โ™‚๏ธ","aliases":["genie_man"],"tags":[],"category":"People & Body","description":"man genie","unicode_version":"11.0"},{"emoji":"๐Ÿงžโ€โ™€๏ธ","aliases":["genie_woman"],"tags":[],"category":"People & Body","description":"woman genie","unicode_version":"11.0"},{"emoji":"๐ŸงŸ","aliases":["zombie"],"tags":[],"category":"People & Body","description":"zombie","unicode_version":"11.0"},{"emoji":"๐ŸงŸโ€โ™‚๏ธ","aliases":["zombie_man"],"tags":[],"category":"People & Body","description":"man zombie","unicode_version":"11.0"},{"emoji":"๐ŸงŸโ€โ™€๏ธ","aliases":["zombie_woman"],"tags":[],"category":"People & Body","description":"woman zombie","unicode_version":"11.0"},{"emoji":"๐Ÿ’†","aliases":["massage"],"tags":["spa"],"category":"People & Body","description":"person getting massage","unicode_version":"6.0"},{"emoji":"๐Ÿ’†โ€โ™‚๏ธ","aliases":["massage_man"],"tags":["spa"],"category":"People & Body","description":"man getting massage","unicode_version":"6.0"},{"emoji":"๐Ÿ’†โ€โ™€๏ธ","aliases":["massage_woman"],"tags":["spa"],"category":"People & Body","description":"woman getting massage","unicode_version":"11.0"},{"emoji":"๐Ÿ’‡","aliases":["haircut"],"tags":["beauty"],"category":"People & Body","description":"person getting haircut","unicode_version":"6.0"},{"emoji":"๐Ÿ’‡โ€โ™‚๏ธ","aliases":["haircut_man"],"tags":[],"category":"People & Body","description":"man getting haircut","unicode_version":"6.0"},{"emoji":"๐Ÿ’‡โ€โ™€๏ธ","aliases":["haircut_woman"],"tags":[],"category":"People & Body","description":"woman getting haircut","unicode_version":"11.0"},{"emoji":"๐Ÿšถ","aliases":["walking"],"tags":[],"category":"People & Body","description":"person walking","unicode_version":"6.0"},{"emoji":"๐Ÿšถโ€โ™‚๏ธ","aliases":["walking_man"],"tags":[],"category":"People & Body","description":"man walking","unicode_version":"11.0"},{"emoji":"๐Ÿšถโ€โ™€๏ธ","aliases":["walking_woman"],"tags":[],"category":"People & Body","description":"woman walking","unicode_version":"6.0"},{"emoji":"๐Ÿง","aliases":["standing_person"],"tags":[],"category":"People & Body","description":"person standing","unicode_version":"12.0"},{"emoji":"๐Ÿงโ€โ™‚๏ธ","aliases":["standing_man"],"tags":[],"category":"People & Body","description":"man standing","unicode_version":"12.0"},{"emoji":"๐Ÿงโ€โ™€๏ธ","aliases":["standing_woman"],"tags":[],"category":"People & Body","description":"woman standing","unicode_version":"12.0"},{"emoji":"๐ŸงŽ","aliases":["kneeling_person"],"tags":[],"category":"People & Body","description":"person kneeling","unicode_version":"12.0"},{"emoji":"๐ŸงŽโ€โ™‚๏ธ","aliases":["kneeling_man"],"tags":[],"category":"People & Body","description":"man kneeling","unicode_version":"12.0"},{"emoji":"๐ŸงŽโ€โ™€๏ธ","aliases":["kneeling_woman"],"tags":[],"category":"People & Body","description":"woman kneeling","unicode_version":"12.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆฏ","aliases":["person_with_probing_cane"],"tags":[],"category":"People & Body","description":"person with white cane","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฏ","aliases":["man_with_probing_cane"],"tags":[],"category":"People & Body","description":"man with white cane","unicode_version":"12.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฏ","aliases":["woman_with_probing_cane"],"tags":[],"category":"People & Body","description":"woman with white cane","unicode_version":"12.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆผ","aliases":["person_in_motorized_wheelchair"],"tags":[],"category":"People & Body","description":"person in motorized wheelchair","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆผ","aliases":["man_in_motorized_wheelchair"],"tags":[],"category":"People & Body","description":"man in motorized wheelchair","unicode_version":"12.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆผ","aliases":["woman_in_motorized_wheelchair"],"tags":[],"category":"People & Body","description":"woman in motorized wheelchair","unicode_version":"12.0"},{"emoji":"๐Ÿง‘โ€๐Ÿฆฝ","aliases":["person_in_manual_wheelchair"],"tags":[],"category":"People & Body","description":"person in manual wheelchair","unicode_version":"12.1"},{"emoji":"๐Ÿ‘จโ€๐Ÿฆฝ","aliases":["man_in_manual_wheelchair"],"tags":[],"category":"People & Body","description":"man in manual wheelchair","unicode_version":"12.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿฆฝ","aliases":["woman_in_manual_wheelchair"],"tags":[],"category":"People & Body","description":"woman in manual wheelchair","unicode_version":"12.0"},{"emoji":"๐Ÿƒ","aliases":["runner","running"],"tags":["exercise","workout","marathon"],"category":"People & Body","description":"person running","unicode_version":"6.0"},{"emoji":"๐Ÿƒโ€โ™‚๏ธ","aliases":["running_man"],"tags":["exercise","workout","marathon"],"category":"People & Body","description":"man running","unicode_version":"11.0"},{"emoji":"๐Ÿƒโ€โ™€๏ธ","aliases":["running_woman"],"tags":["exercise","workout","marathon"],"category":"People & Body","description":"woman running","unicode_version":"6.0"},{"emoji":"๐Ÿ’ƒ","aliases":["woman_dancing","dancer"],"tags":["dress"],"category":"People & Body","description":"woman dancing","unicode_version":"6.0"},{"emoji":"๐Ÿ•บ","aliases":["man_dancing"],"tags":["dancer"],"category":"People & Body","description":"man dancing","unicode_version":"9.0"},{"emoji":"๐Ÿ•ด๏ธ","aliases":["business_suit_levitating"],"tags":[],"category":"People & Body","description":"person in suit levitating","unicode_version":"7.0"},{"emoji":"๐Ÿ‘ฏ","aliases":["dancers"],"tags":["bunny"],"category":"People & Body","description":"people with bunny ears","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฏโ€โ™‚๏ธ","aliases":["dancing_men"],"tags":["bunny"],"category":"People & Body","description":"men with bunny ears","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฏโ€โ™€๏ธ","aliases":["dancing_women"],"tags":["bunny"],"category":"People & Body","description":"women with bunny ears","unicode_version":"11.0"},{"emoji":"๐Ÿง–","aliases":["sauna_person"],"tags":["steamy"],"category":"People & Body","description":"person in steamy room","unicode_version":"11.0"},{"emoji":"๐Ÿง–โ€โ™‚๏ธ","aliases":["sauna_man"],"tags":["steamy"],"category":"People & Body","description":"man in steamy room","unicode_version":"11.0"},{"emoji":"๐Ÿง–โ€โ™€๏ธ","aliases":["sauna_woman"],"tags":["steamy"],"category":"People & Body","description":"woman in steamy room","unicode_version":"11.0"},{"emoji":"๐Ÿง—","aliases":["climbing"],"tags":["bouldering"],"category":"People & Body","description":"person climbing","unicode_version":"11.0"},{"emoji":"๐Ÿง—โ€โ™‚๏ธ","aliases":["climbing_man"],"tags":["bouldering"],"category":"People & Body","description":"man climbing","unicode_version":"11.0"},{"emoji":"๐Ÿง—โ€โ™€๏ธ","aliases":["climbing_woman"],"tags":["bouldering"],"category":"People & Body","description":"woman climbing","unicode_version":"11.0"},{"emoji":"๐Ÿคบ","aliases":["person_fencing"],"tags":[],"category":"People & Body","description":"person fencing","unicode_version":"9.0"},{"emoji":"๐Ÿ‡","aliases":["horse_racing"],"tags":[],"category":"People & Body","description":"horse racing","unicode_version":"6.0"},{"emoji":"โ›ท๏ธ","aliases":["skier"],"tags":[],"category":"People & Body","description":"skier","unicode_version":"5.2"},{"emoji":"๐Ÿ‚","aliases":["snowboarder"],"tags":[],"category":"People & Body","description":"snowboarder","unicode_version":"6.0"},{"emoji":"๐ŸŒ๏ธ","aliases":["golfing"],"tags":[],"category":"People & Body","description":"person golfing","unicode_version":"7.0"},{"emoji":"๐ŸŒ๏ธโ€โ™‚๏ธ","aliases":["golfing_man"],"tags":[],"category":"People & Body","description":"man golfing","unicode_version":"11.0"},{"emoji":"๐ŸŒ๏ธโ€โ™€๏ธ","aliases":["golfing_woman"],"tags":[],"category":"People & Body","description":"woman golfing","unicode_version":""},{"emoji":"๐Ÿ„","aliases":["surfer"],"tags":[],"category":"People & Body","description":"person surfing","unicode_version":"6.0"},{"emoji":"๐Ÿ„โ€โ™‚๏ธ","aliases":["surfing_man"],"tags":[],"category":"People & Body","description":"man surfing","unicode_version":"11.0"},{"emoji":"๐Ÿ„โ€โ™€๏ธ","aliases":["surfing_woman"],"tags":[],"category":"People & Body","description":"woman surfing","unicode_version":"7.0"},{"emoji":"๐Ÿšฃ","aliases":["rowboat"],"tags":[],"category":"People & Body","description":"person rowing boat","unicode_version":"6.0"},{"emoji":"๐Ÿšฃโ€โ™‚๏ธ","aliases":["rowing_man"],"tags":[],"category":"People & Body","description":"man rowing boat","unicode_version":"11.0"},{"emoji":"๐Ÿšฃโ€โ™€๏ธ","aliases":["rowing_woman"],"tags":[],"category":"People & Body","description":"woman rowing boat","unicode_version":"6.0"},{"emoji":"๐ŸŠ","aliases":["swimmer"],"tags":[],"category":"People & Body","description":"person swimming","unicode_version":"6.0"},{"emoji":"๐ŸŠโ€โ™‚๏ธ","aliases":["swimming_man"],"tags":[],"category":"People & Body","description":"man swimming","unicode_version":"11.0"},{"emoji":"๐ŸŠโ€โ™€๏ธ","aliases":["swimming_woman"],"tags":[],"category":"People & Body","description":"woman swimming","unicode_version":"6.0"},{"emoji":"โ›น๏ธ","aliases":["bouncing_ball_person"],"tags":["basketball"],"category":"People & Body","description":"person bouncing ball","unicode_version":"5.2"},{"emoji":"โ›น๏ธโ€โ™‚๏ธ","aliases":["bouncing_ball_man","basketball_man"],"tags":[],"category":"People & Body","description":"man bouncing ball","unicode_version":"11.0"},{"emoji":"โ›น๏ธโ€โ™€๏ธ","aliases":["bouncing_ball_woman","basketball_woman"],"tags":[],"category":"People & Body","description":"woman bouncing ball","unicode_version":"7.0"},{"emoji":"๐Ÿ‹๏ธ","aliases":["weight_lifting"],"tags":["gym","workout"],"category":"People & Body","description":"person lifting weights","unicode_version":"7.0"},{"emoji":"๐Ÿ‹๏ธโ€โ™‚๏ธ","aliases":["weight_lifting_man"],"tags":["gym","workout"],"category":"People & Body","description":"man lifting weights","unicode_version":"11.0"},{"emoji":"๐Ÿ‹๏ธโ€โ™€๏ธ","aliases":["weight_lifting_woman"],"tags":["gym","workout"],"category":"People & Body","description":"woman lifting weights","unicode_version":"6.0"},{"emoji":"๐Ÿšด","aliases":["bicyclist"],"tags":[],"category":"People & Body","description":"person biking","unicode_version":"6.0"},{"emoji":"๐Ÿšดโ€โ™‚๏ธ","aliases":["biking_man"],"tags":[],"category":"People & Body","description":"man biking","unicode_version":"11.0"},{"emoji":"๐Ÿšดโ€โ™€๏ธ","aliases":["biking_woman"],"tags":[],"category":"People & Body","description":"woman biking","unicode_version":"6.0"},{"emoji":"๐Ÿšต","aliases":["mountain_bicyclist"],"tags":[],"category":"People & Body","description":"person mountain biking","unicode_version":"6.0"},{"emoji":"๐Ÿšตโ€โ™‚๏ธ","aliases":["mountain_biking_man"],"tags":[],"category":"People & Body","description":"man mountain biking","unicode_version":"11.0"},{"emoji":"๐Ÿšตโ€โ™€๏ธ","aliases":["mountain_biking_woman"],"tags":[],"category":"People & Body","description":"woman mountain biking","unicode_version":"6.0"},{"emoji":"๐Ÿคธ","aliases":["cartwheeling"],"tags":[],"category":"People & Body","description":"person cartwheeling","unicode_version":"11.0"},{"emoji":"๐Ÿคธโ€โ™‚๏ธ","aliases":["man_cartwheeling"],"tags":[],"category":"People & Body","description":"man cartwheeling","unicode_version":""},{"emoji":"๐Ÿคธโ€โ™€๏ธ","aliases":["woman_cartwheeling"],"tags":[],"category":"People & Body","description":"woman cartwheeling","unicode_version":""},{"emoji":"๐Ÿคผ","aliases":["wrestling"],"tags":[],"category":"People & Body","description":"people wrestling","unicode_version":"11.0"},{"emoji":"๐Ÿคผโ€โ™‚๏ธ","aliases":["men_wrestling"],"tags":[],"category":"People & Body","description":"men wrestling","unicode_version":"9.0"},{"emoji":"๐Ÿคผโ€โ™€๏ธ","aliases":["women_wrestling"],"tags":[],"category":"People & Body","description":"women wrestling","unicode_version":"9.0"},{"emoji":"๐Ÿคฝ","aliases":["water_polo"],"tags":[],"category":"People & Body","description":"person playing water polo","unicode_version":"11.0"},{"emoji":"๐Ÿคฝโ€โ™‚๏ธ","aliases":["man_playing_water_polo"],"tags":[],"category":"People & Body","description":"man playing water polo","unicode_version":"9.0"},{"emoji":"๐Ÿคฝโ€โ™€๏ธ","aliases":["woman_playing_water_polo"],"tags":[],"category":"People & Body","description":"woman playing water polo","unicode_version":"9.0"},{"emoji":"๐Ÿคพ","aliases":["handball_person"],"tags":[],"category":"People & Body","description":"person playing handball","unicode_version":"11.0"},{"emoji":"๐Ÿคพโ€โ™‚๏ธ","aliases":["man_playing_handball"],"tags":[],"category":"People & Body","description":"man playing handball","unicode_version":"9.0"},{"emoji":"๐Ÿคพโ€โ™€๏ธ","aliases":["woman_playing_handball"],"tags":[],"category":"People & Body","description":"woman playing handball","unicode_version":"9.0"},{"emoji":"๐Ÿคน","aliases":["juggling_person"],"tags":[],"category":"People & Body","description":"person juggling","unicode_version":"11.0"},{"emoji":"๐Ÿคนโ€โ™‚๏ธ","aliases":["man_juggling"],"tags":[],"category":"People & Body","description":"man juggling","unicode_version":"9.0"},{"emoji":"๐Ÿคนโ€โ™€๏ธ","aliases":["woman_juggling"],"tags":[],"category":"People & Body","description":"woman juggling","unicode_version":"9.0"},{"emoji":"๐Ÿง˜","aliases":["lotus_position"],"tags":["meditation"],"category":"People & Body","description":"person in lotus position","unicode_version":"11.0"},{"emoji":"๐Ÿง˜โ€โ™‚๏ธ","aliases":["lotus_position_man"],"tags":["meditation"],"category":"People & Body","description":"man in lotus position","unicode_version":"11.0"},{"emoji":"๐Ÿง˜โ€โ™€๏ธ","aliases":["lotus_position_woman"],"tags":["meditation"],"category":"People & Body","description":"woman in lotus position","unicode_version":"11.0"},{"emoji":"๐Ÿ›€","aliases":["bath"],"tags":["shower"],"category":"People & Body","description":"person taking bath","unicode_version":"6.0"},{"emoji":"๐Ÿ›Œ","aliases":["sleeping_bed"],"tags":[],"category":"People & Body","description":"person in bed","unicode_version":"7.0"},{"emoji":"๐Ÿง‘โ€๐Ÿคโ€๐Ÿง‘","aliases":["people_holding_hands"],"tags":["couple","date"],"category":"People & Body","description":"people holding hands","unicode_version":"12.0"},{"emoji":"๐Ÿ‘ญ","aliases":["two_women_holding_hands"],"tags":["couple","date"],"category":"People & Body","description":"women holding hands","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ซ","aliases":["couple"],"tags":["date"],"category":"People & Body","description":"woman and man holding hands","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฌ","aliases":["two_men_holding_hands"],"tags":["couple","date"],"category":"People & Body","description":"men holding hands","unicode_version":"6.0"},{"emoji":"๐Ÿ’","aliases":["couplekiss"],"tags":[],"category":"People & Body","description":"kiss","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","aliases":["couplekiss_man_woman"],"tags":[],"category":"People & Body","description":"kiss: woman, man","unicode_version":"11.0"},{"emoji":"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘จ","aliases":["couplekiss_man_man"],"tags":[],"category":"People & Body","description":"kiss: man, man","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ’‹โ€๐Ÿ‘ฉ","aliases":["couplekiss_woman_woman"],"tags":[],"category":"People & Body","description":"kiss: woman, woman","unicode_version":"6.0"},{"emoji":"๐Ÿ’‘","aliases":["couple_with_heart"],"tags":[],"category":"People & Body","description":"couple with heart","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘จ","aliases":["couple_with_heart_woman_man"],"tags":[],"category":"People & Body","description":"couple with heart: woman, man","unicode_version":"11.0"},{"emoji":"๐Ÿ‘จโ€โค๏ธโ€๐Ÿ‘จ","aliases":["couple_with_heart_man_man"],"tags":[],"category":"People & Body","description":"couple with heart: man, man","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€โค๏ธโ€๐Ÿ‘ฉ","aliases":["couple_with_heart_woman_woman"],"tags":[],"category":"People & Body","description":"couple with heart: woman, woman","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ช","aliases":["family"],"tags":["home","parents","child"],"category":"People & Body","description":"family","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","aliases":["family_man_woman_boy"],"tags":[],"category":"People & Body","description":"family: man, woman, boy","unicode_version":"11.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","aliases":["family_man_woman_girl"],"tags":[],"category":"People & Body","description":"family: man, woman, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","aliases":["family_man_woman_girl_boy"],"tags":[],"category":"People & Body","description":"family: man, woman, girl, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","aliases":["family_man_woman_boy_boy"],"tags":[],"category":"People & Body","description":"family: man, woman, boy, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","aliases":["family_man_woman_girl_girl"],"tags":[],"category":"People & Body","description":"family: man, woman, girl, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆ","aliases":["family_man_man_boy"],"tags":[],"category":"People & Body","description":"family: man, man, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ง","aliases":["family_man_man_girl"],"tags":[],"category":"People & Body","description":"family: man, man, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","aliases":["family_man_man_girl_boy"],"tags":[],"category":"People & Body","description":"family: man, man, girl, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","aliases":["family_man_man_boy_boy"],"tags":[],"category":"People & Body","description":"family: man, man, boy, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","aliases":["family_man_man_girl_girl"],"tags":[],"category":"People & Body","description":"family: man, man, girl, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ","aliases":["family_woman_woman_boy"],"tags":[],"category":"People & Body","description":"family: woman, woman, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ง","aliases":["family_woman_woman_girl"],"tags":[],"category":"People & Body","description":"family: woman, woman, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","aliases":["family_woman_woman_girl_boy"],"tags":[],"category":"People & Body","description":"family: woman, woman, girl, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","aliases":["family_woman_woman_boy_boy"],"tags":[],"category":"People & Body","description":"family: woman, woman, boy, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","aliases":["family_woman_woman_girl_girl"],"tags":[],"category":"People & Body","description":"family: woman, woman, girl, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฆ","aliases":["family_man_boy"],"tags":[],"category":"People & Body","description":"family: man, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","aliases":["family_man_boy_boy"],"tags":[],"category":"People & Body","description":"family: man, boy, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘ง","aliases":["family_man_girl"],"tags":[],"category":"People & Body","description":"family: man, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","aliases":["family_man_girl_boy"],"tags":[],"category":"People & Body","description":"family: man, girl, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘จโ€๐Ÿ‘งโ€๐Ÿ‘ง","aliases":["family_man_girl_girl"],"tags":[],"category":"People & Body","description":"family: man, girl, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฆ","aliases":["family_woman_boy"],"tags":[],"category":"People & Body","description":"family: woman, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ","aliases":["family_woman_boy_boy"],"tags":[],"category":"People & Body","description":"family: woman, boy, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘ง","aliases":["family_woman_girl"],"tags":[],"category":"People & Body","description":"family: woman, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ","aliases":["family_woman_girl_boy"],"tags":[],"category":"People & Body","description":"family: woman, girl, boy","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง","aliases":["family_woman_girl_girl"],"tags":[],"category":"People & Body","description":"family: woman, girl, girl","unicode_version":"6.0"},{"emoji":"๐Ÿ—ฃ๏ธ","aliases":["speaking_head"],"tags":[],"category":"People & Body","description":"speaking head","unicode_version":"7.0"},{"emoji":"๐Ÿ‘ค","aliases":["bust_in_silhouette"],"tags":["user"],"category":"People & Body","description":"bust in silhouette","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ฅ","aliases":["busts_in_silhouette"],"tags":["users","group","team"],"category":"People & Body","description":"busts in silhouette","unicode_version":"6.0"},{"emoji":"๐Ÿซ‚","aliases":["people_hugging"],"tags":[],"category":"People & Body","description":"people hugging","unicode_version":"13.0"},{"emoji":"๐Ÿ‘ฃ","aliases":["footprints"],"tags":["feet","tracks"],"category":"People & Body","description":"footprints","unicode_version":"6.0"},{"emoji":"๐Ÿต","aliases":["monkey_face"],"tags":[],"category":"Animals & Nature","description":"monkey face","unicode_version":"6.0"},{"emoji":"๐Ÿ’","aliases":["monkey"],"tags":[],"category":"Animals & Nature","description":"monkey","unicode_version":"6.0"},{"emoji":"๐Ÿฆ","aliases":["gorilla"],"tags":[],"category":"Animals & Nature","description":"gorilla","unicode_version":"9.0"},{"emoji":"๐Ÿฆง","aliases":["orangutan"],"tags":[],"category":"Animals & Nature","description":"orangutan","unicode_version":"12.0"},{"emoji":"๐Ÿถ","aliases":["dog"],"tags":["pet"],"category":"Animals & Nature","description":"dog face","unicode_version":"6.0"},{"emoji":"๐Ÿ•","aliases":["dog2"],"tags":[],"category":"Animals & Nature","description":"dog","unicode_version":"6.0"},{"emoji":"๐Ÿฆฎ","aliases":["guide_dog"],"tags":[],"category":"Animals & Nature","description":"guide dog","unicode_version":"12.0"},{"emoji":"๐Ÿ•โ€๐Ÿฆบ","aliases":["service_dog"],"tags":[],"category":"Animals & Nature","description":"service dog","unicode_version":"12.0"},{"emoji":"๐Ÿฉ","aliases":["poodle"],"tags":["dog"],"category":"Animals & Nature","description":"poodle","unicode_version":"6.0"},{"emoji":"๐Ÿบ","aliases":["wolf"],"tags":[],"category":"Animals & Nature","description":"wolf","unicode_version":"6.0"},{"emoji":"๐ŸฆŠ","aliases":["fox_face"],"tags":[],"category":"Animals & Nature","description":"fox","unicode_version":"9.0"},{"emoji":"๐Ÿฆ","aliases":["raccoon"],"tags":[],"category":"Animals & Nature","description":"raccoon","unicode_version":"11.0"},{"emoji":"๐Ÿฑ","aliases":["cat"],"tags":["pet"],"category":"Animals & Nature","description":"cat face","unicode_version":"6.0"},{"emoji":"๐Ÿˆ","aliases":["cat2"],"tags":[],"category":"Animals & Nature","description":"cat","unicode_version":"6.0"},{"emoji":"๐Ÿˆโ€โฌ›","aliases":["black_cat"],"tags":[],"category":"Animals & Nature","description":"black cat","unicode_version":"13.0"},{"emoji":"๐Ÿฆ","aliases":["lion"],"tags":[],"category":"Animals & Nature","description":"lion","unicode_version":"8.0"},{"emoji":"๐Ÿฏ","aliases":["tiger"],"tags":[],"category":"Animals & Nature","description":"tiger face","unicode_version":"6.0"},{"emoji":"๐Ÿ…","aliases":["tiger2"],"tags":[],"category":"Animals & Nature","description":"tiger","unicode_version":"6.0"},{"emoji":"๐Ÿ†","aliases":["leopard"],"tags":[],"category":"Animals & Nature","description":"leopard","unicode_version":"6.0"},{"emoji":"๐Ÿด","aliases":["horse"],"tags":[],"category":"Animals & Nature","description":"horse face","unicode_version":"6.0"},{"emoji":"๐ŸŽ","aliases":["racehorse"],"tags":["speed"],"category":"Animals & Nature","description":"horse","unicode_version":"6.0"},{"emoji":"๐Ÿฆ„","aliases":["unicorn"],"tags":[],"category":"Animals & Nature","description":"unicorn","unicode_version":"8.0"},{"emoji":"๐Ÿฆ“","aliases":["zebra"],"tags":[],"category":"Animals & Nature","description":"zebra","unicode_version":"11.0"},{"emoji":"๐ŸฆŒ","aliases":["deer"],"tags":[],"category":"Animals & Nature","description":"deer","unicode_version":"9.0"},{"emoji":"๐Ÿฆฌ","aliases":["bison"],"tags":[],"category":"Animals & Nature","description":"bison","unicode_version":"13.0"},{"emoji":"๐Ÿฎ","aliases":["cow"],"tags":[],"category":"Animals & Nature","description":"cow face","unicode_version":"6.0"},{"emoji":"๐Ÿ‚","aliases":["ox"],"tags":[],"category":"Animals & Nature","description":"ox","unicode_version":"6.0"},{"emoji":"๐Ÿƒ","aliases":["water_buffalo"],"tags":[],"category":"Animals & Nature","description":"water buffalo","unicode_version":"6.0"},{"emoji":"๐Ÿ„","aliases":["cow2"],"tags":[],"category":"Animals & Nature","description":"cow","unicode_version":"6.0"},{"emoji":"๐Ÿท","aliases":["pig"],"tags":[],"category":"Animals & Nature","description":"pig face","unicode_version":"6.0"},{"emoji":"๐Ÿ–","aliases":["pig2"],"tags":[],"category":"Animals & Nature","description":"pig","unicode_version":"6.0"},{"emoji":"๐Ÿ—","aliases":["boar"],"tags":[],"category":"Animals & Nature","description":"boar","unicode_version":"6.0"},{"emoji":"๐Ÿฝ","aliases":["pig_nose"],"tags":[],"category":"Animals & Nature","description":"pig nose","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["ram"],"tags":[],"category":"Animals & Nature","description":"ram","unicode_version":"6.0"},{"emoji":"๐Ÿ‘","aliases":["sheep"],"tags":[],"category":"Animals & Nature","description":"ewe","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["goat"],"tags":[],"category":"Animals & Nature","description":"goat","unicode_version":"6.0"},{"emoji":"๐Ÿช","aliases":["dromedary_camel"],"tags":["desert"],"category":"Animals & Nature","description":"camel","unicode_version":"6.0"},{"emoji":"๐Ÿซ","aliases":["camel"],"tags":[],"category":"Animals & Nature","description":"two-hump camel","unicode_version":"6.0"},{"emoji":"๐Ÿฆ™","aliases":["llama"],"tags":[],"category":"Animals & Nature","description":"llama","unicode_version":"11.0"},{"emoji":"๐Ÿฆ’","aliases":["giraffe"],"tags":[],"category":"Animals & Nature","description":"giraffe","unicode_version":"11.0"},{"emoji":"๐Ÿ˜","aliases":["elephant"],"tags":[],"category":"Animals & Nature","description":"elephant","unicode_version":"6.0"},{"emoji":"๐Ÿฆฃ","aliases":["mammoth"],"tags":[],"category":"Animals & Nature","description":"mammoth","unicode_version":"13.0"},{"emoji":"๐Ÿฆ","aliases":["rhinoceros"],"tags":[],"category":"Animals & Nature","description":"rhinoceros","unicode_version":"9.0"},{"emoji":"๐Ÿฆ›","aliases":["hippopotamus"],"tags":[],"category":"Animals & Nature","description":"hippopotamus","unicode_version":"11.0"},{"emoji":"๐Ÿญ","aliases":["mouse"],"tags":[],"category":"Animals & Nature","description":"mouse face","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["mouse2"],"tags":[],"category":"Animals & Nature","description":"mouse","unicode_version":"6.0"},{"emoji":"๐Ÿ€","aliases":["rat"],"tags":[],"category":"Animals & Nature","description":"rat","unicode_version":"6.0"},{"emoji":"๐Ÿน","aliases":["hamster"],"tags":["pet"],"category":"Animals & Nature","description":"hamster","unicode_version":"6.0"},{"emoji":"๐Ÿฐ","aliases":["rabbit"],"tags":["bunny"],"category":"Animals & Nature","description":"rabbit face","unicode_version":"6.0"},{"emoji":"๐Ÿ‡","aliases":["rabbit2"],"tags":[],"category":"Animals & Nature","description":"rabbit","unicode_version":"6.0"},{"emoji":"๐Ÿฟ๏ธ","aliases":["chipmunk"],"tags":[],"category":"Animals & Nature","description":"chipmunk","unicode_version":"7.0"},{"emoji":"๐Ÿฆซ","aliases":["beaver"],"tags":[],"category":"Animals & Nature","description":"beaver","unicode_version":"13.0"},{"emoji":"๐Ÿฆ”","aliases":["hedgehog"],"tags":[],"category":"Animals & Nature","description":"hedgehog","unicode_version":"11.0"},{"emoji":"๐Ÿฆ‡","aliases":["bat"],"tags":[],"category":"Animals & Nature","description":"bat","unicode_version":"9.0"},{"emoji":"๐Ÿป","aliases":["bear"],"tags":[],"category":"Animals & Nature","description":"bear","unicode_version":"6.0"},{"emoji":"๐Ÿปโ€โ„๏ธ","aliases":["polar_bear"],"tags":[],"category":"Animals & Nature","description":"polar bear","unicode_version":"13.0"},{"emoji":"๐Ÿจ","aliases":["koala"],"tags":[],"category":"Animals & Nature","description":"koala","unicode_version":"6.0"},{"emoji":"๐Ÿผ","aliases":["panda_face"],"tags":[],"category":"Animals & Nature","description":"panda","unicode_version":"6.0"},{"emoji":"๐Ÿฆฅ","aliases":["sloth"],"tags":[],"category":"Animals & Nature","description":"sloth","unicode_version":"12.0"},{"emoji":"๐Ÿฆฆ","aliases":["otter"],"tags":[],"category":"Animals & Nature","description":"otter","unicode_version":"12.0"},{"emoji":"๐Ÿฆจ","aliases":["skunk"],"tags":[],"category":"Animals & Nature","description":"skunk","unicode_version":"12.0"},{"emoji":"๐Ÿฆ˜","aliases":["kangaroo"],"tags":[],"category":"Animals & Nature","description":"kangaroo","unicode_version":"11.0"},{"emoji":"๐Ÿฆก","aliases":["badger"],"tags":[],"category":"Animals & Nature","description":"badger","unicode_version":"11.0"},{"emoji":"๐Ÿพ","aliases":["feet","paw_prints"],"tags":[],"category":"Animals & Nature","description":"paw prints","unicode_version":"6.0"},{"emoji":"๐Ÿฆƒ","aliases":["turkey"],"tags":["thanksgiving"],"category":"Animals & Nature","description":"turkey","unicode_version":"8.0"},{"emoji":"๐Ÿ”","aliases":["chicken"],"tags":[],"category":"Animals & Nature","description":"chicken","unicode_version":"6.0"},{"emoji":"๐Ÿ“","aliases":["rooster"],"tags":[],"category":"Animals & Nature","description":"rooster","unicode_version":"6.0"},{"emoji":"๐Ÿฃ","aliases":["hatching_chick"],"tags":[],"category":"Animals & Nature","description":"hatching chick","unicode_version":"6.0"},{"emoji":"๐Ÿค","aliases":["baby_chick"],"tags":[],"category":"Animals & Nature","description":"baby chick","unicode_version":"6.0"},{"emoji":"๐Ÿฅ","aliases":["hatched_chick"],"tags":[],"category":"Animals & Nature","description":"front-facing baby chick","unicode_version":"6.0"},{"emoji":"๐Ÿฆ","aliases":["bird"],"tags":[],"category":"Animals & Nature","description":"bird","unicode_version":"6.0"},{"emoji":"๐Ÿง","aliases":["penguin"],"tags":[],"category":"Animals & Nature","description":"penguin","unicode_version":"6.0"},{"emoji":"๐Ÿ•Š๏ธ","aliases":["dove"],"tags":["peace"],"category":"Animals & Nature","description":"dove","unicode_version":"7.0"},{"emoji":"๐Ÿฆ…","aliases":["eagle"],"tags":[],"category":"Animals & Nature","description":"eagle","unicode_version":"9.0"},{"emoji":"๐Ÿฆ†","aliases":["duck"],"tags":[],"category":"Animals & Nature","description":"duck","unicode_version":"9.0"},{"emoji":"๐Ÿฆข","aliases":["swan"],"tags":[],"category":"Animals & Nature","description":"swan","unicode_version":"11.0"},{"emoji":"๐Ÿฆ‰","aliases":["owl"],"tags":[],"category":"Animals & Nature","description":"owl","unicode_version":"9.0"},{"emoji":"๐Ÿฆค","aliases":["dodo"],"tags":[],"category":"Animals & Nature","description":"dodo","unicode_version":"13.0"},{"emoji":"๐Ÿชถ","aliases":["feather"],"tags":[],"category":"Animals & Nature","description":"feather","unicode_version":"13.0"},{"emoji":"๐Ÿฆฉ","aliases":["flamingo"],"tags":[],"category":"Animals & Nature","description":"flamingo","unicode_version":"12.0"},{"emoji":"๐Ÿฆš","aliases":["peacock"],"tags":[],"category":"Animals & Nature","description":"peacock","unicode_version":"11.0"},{"emoji":"๐Ÿฆœ","aliases":["parrot"],"tags":[],"category":"Animals & Nature","description":"parrot","unicode_version":"11.0"},{"emoji":"๐Ÿธ","aliases":["frog"],"tags":[],"category":"Animals & Nature","description":"frog","unicode_version":"6.0"},{"emoji":"๐ŸŠ","aliases":["crocodile"],"tags":[],"category":"Animals & Nature","description":"crocodile","unicode_version":"6.0"},{"emoji":"๐Ÿข","aliases":["turtle"],"tags":["slow"],"category":"Animals & Nature","description":"turtle","unicode_version":"6.0"},{"emoji":"๐ŸฆŽ","aliases":["lizard"],"tags":[],"category":"Animals & Nature","description":"lizard","unicode_version":"9.0"},{"emoji":"๐Ÿ","aliases":["snake"],"tags":[],"category":"Animals & Nature","description":"snake","unicode_version":"6.0"},{"emoji":"๐Ÿฒ","aliases":["dragon_face"],"tags":[],"category":"Animals & Nature","description":"dragon face","unicode_version":"6.0"},{"emoji":"๐Ÿ‰","aliases":["dragon"],"tags":[],"category":"Animals & Nature","description":"dragon","unicode_version":"6.0"},{"emoji":"๐Ÿฆ•","aliases":["sauropod"],"tags":["dinosaur"],"category":"Animals & Nature","description":"sauropod","unicode_version":"11.0"},{"emoji":"๐Ÿฆ–","aliases":["t-rex"],"tags":["dinosaur"],"category":"Animals & Nature","description":"T-Rex","unicode_version":"11.0"},{"emoji":"๐Ÿณ","aliases":["whale"],"tags":["sea"],"category":"Animals & Nature","description":"spouting whale","unicode_version":"6.0"},{"emoji":"๐Ÿ‹","aliases":["whale2"],"tags":[],"category":"Animals & Nature","description":"whale","unicode_version":"6.0"},{"emoji":"๐Ÿฌ","aliases":["dolphin","flipper"],"tags":[],"category":"Animals & Nature","description":"dolphin","unicode_version":"6.0"},{"emoji":"๐Ÿฆญ","aliases":["seal"],"tags":[],"category":"Animals & Nature","description":"seal","unicode_version":"13.0"},{"emoji":"๐ŸŸ","aliases":["fish"],"tags":[],"category":"Animals & Nature","description":"fish","unicode_version":"6.0"},{"emoji":"๐Ÿ ","aliases":["tropical_fish"],"tags":[],"category":"Animals & Nature","description":"tropical fish","unicode_version":"6.0"},{"emoji":"๐Ÿก","aliases":["blowfish"],"tags":[],"category":"Animals & Nature","description":"blowfish","unicode_version":"6.0"},{"emoji":"๐Ÿฆˆ","aliases":["shark"],"tags":[],"category":"Animals & Nature","description":"shark","unicode_version":"9.0"},{"emoji":"๐Ÿ™","aliases":["octopus"],"tags":[],"category":"Animals & Nature","description":"octopus","unicode_version":"6.0"},{"emoji":"๐Ÿš","aliases":["shell"],"tags":["sea","beach"],"category":"Animals & Nature","description":"spiral shell","unicode_version":"6.0"},{"emoji":"๐ŸŒ","aliases":["snail"],"tags":["slow"],"category":"Animals & Nature","description":"snail","unicode_version":"6.0"},{"emoji":"๐Ÿฆ‹","aliases":["butterfly"],"tags":[],"category":"Animals & Nature","description":"butterfly","unicode_version":"9.0"},{"emoji":"๐Ÿ›","aliases":["bug"],"tags":[],"category":"Animals & Nature","description":"bug","unicode_version":"6.0"},{"emoji":"๐Ÿœ","aliases":["ant"],"tags":[],"category":"Animals & Nature","description":"ant","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["bee","honeybee"],"tags":[],"category":"Animals & Nature","description":"honeybee","unicode_version":"6.0"},{"emoji":"๐Ÿชฒ","aliases":["beetle"],"tags":[],"category":"Animals & Nature","description":"beetle","unicode_version":"13.0"},{"emoji":"๐Ÿž","aliases":["lady_beetle"],"tags":["bug"],"category":"Animals & Nature","description":"lady beetle","unicode_version":"6.0"},{"emoji":"๐Ÿฆ—","aliases":["cricket"],"tags":[],"category":"Animals & Nature","description":"cricket","unicode_version":"11.0"},{"emoji":"๐Ÿชณ","aliases":["cockroach"],"tags":[],"category":"Animals & Nature","description":"cockroach","unicode_version":"13.0"},{"emoji":"๐Ÿ•ท๏ธ","aliases":["spider"],"tags":[],"category":"Animals & Nature","description":"spider","unicode_version":"7.0"},{"emoji":"๐Ÿ•ธ๏ธ","aliases":["spider_web"],"tags":[],"category":"Animals & Nature","description":"spider web","unicode_version":"7.0"},{"emoji":"๐Ÿฆ‚","aliases":["scorpion"],"tags":[],"category":"Animals & Nature","description":"scorpion","unicode_version":"8.0"},{"emoji":"๐ŸฆŸ","aliases":["mosquito"],"tags":[],"category":"Animals & Nature","description":"mosquito","unicode_version":"11.0"},{"emoji":"๐Ÿชฐ","aliases":["fly"],"tags":[],"category":"Animals & Nature","description":"fly","unicode_version":"13.0"},{"emoji":"๐Ÿชฑ","aliases":["worm"],"tags":[],"category":"Animals & Nature","description":"worm","unicode_version":"13.0"},{"emoji":"๐Ÿฆ ","aliases":["microbe"],"tags":["germ"],"category":"Animals & Nature","description":"microbe","unicode_version":"11.0"},{"emoji":"๐Ÿ’","aliases":["bouquet"],"tags":["flowers"],"category":"Animals & Nature","description":"bouquet","unicode_version":"6.0"},{"emoji":"๐ŸŒธ","aliases":["cherry_blossom"],"tags":["flower","spring"],"category":"Animals & Nature","description":"cherry blossom","unicode_version":"6.0"},{"emoji":"๐Ÿ’ฎ","aliases":["white_flower"],"tags":[],"category":"Animals & Nature","description":"white flower","unicode_version":"6.0"},{"emoji":"๐Ÿต๏ธ","aliases":["rosette"],"tags":[],"category":"Animals & Nature","description":"rosette","unicode_version":"7.0"},{"emoji":"๐ŸŒน","aliases":["rose"],"tags":["flower"],"category":"Animals & Nature","description":"rose","unicode_version":"6.0"},{"emoji":"๐Ÿฅ€","aliases":["wilted_flower"],"tags":[],"category":"Animals & Nature","description":"wilted flower","unicode_version":"9.0"},{"emoji":"๐ŸŒบ","aliases":["hibiscus"],"tags":[],"category":"Animals & Nature","description":"hibiscus","unicode_version":"6.0"},{"emoji":"๐ŸŒป","aliases":["sunflower"],"tags":[],"category":"Animals & Nature","description":"sunflower","unicode_version":"6.0"},{"emoji":"๐ŸŒผ","aliases":["blossom"],"tags":[],"category":"Animals & Nature","description":"blossom","unicode_version":"6.0"},{"emoji":"๐ŸŒท","aliases":["tulip"],"tags":["flower"],"category":"Animals & Nature","description":"tulip","unicode_version":"6.0"},{"emoji":"๐ŸŒฑ","aliases":["seedling"],"tags":["plant"],"category":"Animals & Nature","description":"seedling","unicode_version":"6.0"},{"emoji":"๐Ÿชด","aliases":["potted_plant"],"tags":[],"category":"Animals & Nature","description":"potted plant","unicode_version":"13.0"},{"emoji":"๐ŸŒฒ","aliases":["evergreen_tree"],"tags":["wood"],"category":"Animals & Nature","description":"evergreen tree","unicode_version":"6.0"},{"emoji":"๐ŸŒณ","aliases":["deciduous_tree"],"tags":["wood"],"category":"Animals & Nature","description":"deciduous tree","unicode_version":"6.0"},{"emoji":"๐ŸŒด","aliases":["palm_tree"],"tags":[],"category":"Animals & Nature","description":"palm tree","unicode_version":"6.0"},{"emoji":"๐ŸŒต","aliases":["cactus"],"tags":[],"category":"Animals & Nature","description":"cactus","unicode_version":"6.0"},{"emoji":"๐ŸŒพ","aliases":["ear_of_rice"],"tags":[],"category":"Animals & Nature","description":"sheaf of rice","unicode_version":"6.0"},{"emoji":"๐ŸŒฟ","aliases":["herb"],"tags":[],"category":"Animals & Nature","description":"herb","unicode_version":"6.0"},{"emoji":"โ˜˜๏ธ","aliases":["shamrock"],"tags":[],"category":"Animals & Nature","description":"shamrock","unicode_version":"4.1"},{"emoji":"๐Ÿ€","aliases":["four_leaf_clover"],"tags":["luck"],"category":"Animals & Nature","description":"four leaf clover","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["maple_leaf"],"tags":["canada"],"category":"Animals & Nature","description":"maple leaf","unicode_version":"6.0"},{"emoji":"๐Ÿ‚","aliases":["fallen_leaf"],"tags":["autumn"],"category":"Animals & Nature","description":"fallen leaf","unicode_version":"6.0"},{"emoji":"๐Ÿƒ","aliases":["leaves"],"tags":["leaf"],"category":"Animals & Nature","description":"leaf fluttering in wind","unicode_version":"6.0"},{"emoji":"๐Ÿ‡","aliases":["grapes"],"tags":[],"category":"Food & Drink","description":"grapes","unicode_version":"6.0"},{"emoji":"๐Ÿˆ","aliases":["melon"],"tags":[],"category":"Food & Drink","description":"melon","unicode_version":"6.0"},{"emoji":"๐Ÿ‰","aliases":["watermelon"],"tags":[],"category":"Food & Drink","description":"watermelon","unicode_version":"6.0"},{"emoji":"๐ŸŠ","aliases":["tangerine","orange","mandarin"],"tags":[],"category":"Food & Drink","description":"tangerine","unicode_version":"6.0"},{"emoji":"๐Ÿ‹","aliases":["lemon"],"tags":[],"category":"Food & Drink","description":"lemon","unicode_version":"6.0"},{"emoji":"๐ŸŒ","aliases":["banana"],"tags":["fruit"],"category":"Food & Drink","description":"banana","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["pineapple"],"tags":[],"category":"Food & Drink","description":"pineapple","unicode_version":"6.0"},{"emoji":"๐Ÿฅญ","aliases":["mango"],"tags":[],"category":"Food & Drink","description":"mango","unicode_version":"11.0"},{"emoji":"๐ŸŽ","aliases":["apple"],"tags":[],"category":"Food & Drink","description":"red apple","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["green_apple"],"tags":["fruit"],"category":"Food & Drink","description":"green apple","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["pear"],"tags":[],"category":"Food & Drink","description":"pear","unicode_version":"6.0"},{"emoji":"๐Ÿ‘","aliases":["peach"],"tags":[],"category":"Food & Drink","description":"peach","unicode_version":"6.0"},{"emoji":"๐Ÿ’","aliases":["cherries"],"tags":["fruit"],"category":"Food & Drink","description":"cherries","unicode_version":"6.0"},{"emoji":"๐Ÿ“","aliases":["strawberry"],"tags":["fruit"],"category":"Food & Drink","description":"strawberry","unicode_version":"6.0"},{"emoji":"๐Ÿซ","aliases":["blueberries"],"tags":[],"category":"Food & Drink","description":"blueberries","unicode_version":"13.0"},{"emoji":"๐Ÿฅ","aliases":["kiwi_fruit"],"tags":[],"category":"Food & Drink","description":"kiwi fruit","unicode_version":"9.0"},{"emoji":"๐Ÿ…","aliases":["tomato"],"tags":[],"category":"Food & Drink","description":"tomato","unicode_version":"6.0"},{"emoji":"๐Ÿซ’","aliases":["olive"],"tags":[],"category":"Food & Drink","description":"olive","unicode_version":"13.0"},{"emoji":"๐Ÿฅฅ","aliases":["coconut"],"tags":[],"category":"Food & Drink","description":"coconut","unicode_version":"11.0"},{"emoji":"๐Ÿฅ‘","aliases":["avocado"],"tags":[],"category":"Food & Drink","description":"avocado","unicode_version":"9.0"},{"emoji":"๐Ÿ†","aliases":["eggplant"],"tags":["aubergine"],"category":"Food & Drink","description":"eggplant","unicode_version":"6.0"},{"emoji":"๐Ÿฅ”","aliases":["potato"],"tags":[],"category":"Food & Drink","description":"potato","unicode_version":"9.0"},{"emoji":"๐Ÿฅ•","aliases":["carrot"],"tags":[],"category":"Food & Drink","description":"carrot","unicode_version":"9.0"},{"emoji":"๐ŸŒฝ","aliases":["corn"],"tags":[],"category":"Food & Drink","description":"ear of corn","unicode_version":"6.0"},{"emoji":"๐ŸŒถ๏ธ","aliases":["hot_pepper"],"tags":["spicy"],"category":"Food & Drink","description":"hot pepper","unicode_version":"7.0"},{"emoji":"๐Ÿซ‘","aliases":["bell_pepper"],"tags":[],"category":"Food & Drink","description":"bell pepper","unicode_version":"13.0"},{"emoji":"๐Ÿฅ’","aliases":["cucumber"],"tags":[],"category":"Food & Drink","description":"cucumber","unicode_version":"9.0"},{"emoji":"๐Ÿฅฌ","aliases":["leafy_green"],"tags":[],"category":"Food & Drink","description":"leafy green","unicode_version":"11.0"},{"emoji":"๐Ÿฅฆ","aliases":["broccoli"],"tags":[],"category":"Food & Drink","description":"broccoli","unicode_version":"11.0"},{"emoji":"๐Ÿง„","aliases":["garlic"],"tags":[],"category":"Food & Drink","description":"garlic","unicode_version":"12.0"},{"emoji":"๐Ÿง…","aliases":["onion"],"tags":[],"category":"Food & Drink","description":"onion","unicode_version":"12.0"},{"emoji":"๐Ÿ„","aliases":["mushroom"],"tags":[],"category":"Food & Drink","description":"mushroom","unicode_version":"6.0"},{"emoji":"๐Ÿฅœ","aliases":["peanuts"],"tags":[],"category":"Food & Drink","description":"peanuts","unicode_version":"9.0"},{"emoji":"๐ŸŒฐ","aliases":["chestnut"],"tags":[],"category":"Food & Drink","description":"chestnut","unicode_version":"6.0"},{"emoji":"๐Ÿž","aliases":["bread"],"tags":["toast"],"category":"Food & Drink","description":"bread","unicode_version":"6.0"},{"emoji":"๐Ÿฅ","aliases":["croissant"],"tags":[],"category":"Food & Drink","description":"croissant","unicode_version":"9.0"},{"emoji":"๐Ÿฅ–","aliases":["baguette_bread"],"tags":[],"category":"Food & Drink","description":"baguette bread","unicode_version":"9.0"},{"emoji":"๐Ÿซ“","aliases":["flatbread"],"tags":[],"category":"Food & Drink","description":"flatbread","unicode_version":"13.0"},{"emoji":"๐Ÿฅจ","aliases":["pretzel"],"tags":[],"category":"Food & Drink","description":"pretzel","unicode_version":"11.0"},{"emoji":"๐Ÿฅฏ","aliases":["bagel"],"tags":[],"category":"Food & Drink","description":"bagel","unicode_version":"11.0"},{"emoji":"๐Ÿฅž","aliases":["pancakes"],"tags":[],"category":"Food & Drink","description":"pancakes","unicode_version":"9.0"},{"emoji":"๐Ÿง‡","aliases":["waffle"],"tags":[],"category":"Food & Drink","description":"waffle","unicode_version":"12.0"},{"emoji":"๐Ÿง€","aliases":["cheese"],"tags":[],"category":"Food & Drink","description":"cheese wedge","unicode_version":"8.0"},{"emoji":"๐Ÿ–","aliases":["meat_on_bone"],"tags":[],"category":"Food & Drink","description":"meat on bone","unicode_version":"6.0"},{"emoji":"๐Ÿ—","aliases":["poultry_leg"],"tags":["meat","chicken"],"category":"Food & Drink","description":"poultry leg","unicode_version":"6.0"},{"emoji":"๐Ÿฅฉ","aliases":["cut_of_meat"],"tags":[],"category":"Food & Drink","description":"cut of meat","unicode_version":"11.0"},{"emoji":"๐Ÿฅ“","aliases":["bacon"],"tags":[],"category":"Food & Drink","description":"bacon","unicode_version":"9.0"},{"emoji":"๐Ÿ”","aliases":["hamburger"],"tags":["burger"],"category":"Food & Drink","description":"hamburger","unicode_version":"6.0"},{"emoji":"๐ŸŸ","aliases":["fries"],"tags":[],"category":"Food & Drink","description":"french fries","unicode_version":"6.0"},{"emoji":"๐Ÿ•","aliases":["pizza"],"tags":[],"category":"Food & Drink","description":"pizza","unicode_version":"6.0"},{"emoji":"๐ŸŒญ","aliases":["hotdog"],"tags":[],"category":"Food & Drink","description":"hot dog","unicode_version":"8.0"},{"emoji":"๐Ÿฅช","aliases":["sandwich"],"tags":[],"category":"Food & Drink","description":"sandwich","unicode_version":"11.0"},{"emoji":"๐ŸŒฎ","aliases":["taco"],"tags":[],"category":"Food & Drink","description":"taco","unicode_version":"8.0"},{"emoji":"๐ŸŒฏ","aliases":["burrito"],"tags":[],"category":"Food & Drink","description":"burrito","unicode_version":"8.0"},{"emoji":"๐Ÿซ”","aliases":["tamale"],"tags":[],"category":"Food & Drink","description":"tamale","unicode_version":"13.0"},{"emoji":"๐Ÿฅ™","aliases":["stuffed_flatbread"],"tags":[],"category":"Food & Drink","description":"stuffed flatbread","unicode_version":"9.0"},{"emoji":"๐Ÿง†","aliases":["falafel"],"tags":[],"category":"Food & Drink","description":"falafel","unicode_version":"12.0"},{"emoji":"๐Ÿฅš","aliases":["egg"],"tags":[],"category":"Food & Drink","description":"egg","unicode_version":"9.0"},{"emoji":"๐Ÿณ","aliases":["fried_egg"],"tags":["breakfast"],"category":"Food & Drink","description":"cooking","unicode_version":"6.0"},{"emoji":"๐Ÿฅ˜","aliases":["shallow_pan_of_food"],"tags":["paella","curry"],"category":"Food & Drink","description":"shallow pan of food","unicode_version":""},{"emoji":"๐Ÿฒ","aliases":["stew"],"tags":[],"category":"Food & Drink","description":"pot of food","unicode_version":"6.0"},{"emoji":"๐Ÿซ•","aliases":["fondue"],"tags":[],"category":"Food & Drink","description":"fondue","unicode_version":"13.0"},{"emoji":"๐Ÿฅฃ","aliases":["bowl_with_spoon"],"tags":[],"category":"Food & Drink","description":"bowl with spoon","unicode_version":"11.0"},{"emoji":"๐Ÿฅ—","aliases":["green_salad"],"tags":[],"category":"Food & Drink","description":"green salad","unicode_version":"9.0"},{"emoji":"๐Ÿฟ","aliases":["popcorn"],"tags":[],"category":"Food & Drink","description":"popcorn","unicode_version":"8.0"},{"emoji":"๐Ÿงˆ","aliases":["butter"],"tags":[],"category":"Food & Drink","description":"butter","unicode_version":"12.0"},{"emoji":"๐Ÿง‚","aliases":["salt"],"tags":[],"category":"Food & Drink","description":"salt","unicode_version":"11.0"},{"emoji":"๐Ÿฅซ","aliases":["canned_food"],"tags":[],"category":"Food & Drink","description":"canned food","unicode_version":"11.0"},{"emoji":"๐Ÿฑ","aliases":["bento"],"tags":[],"category":"Food & Drink","description":"bento box","unicode_version":"6.0"},{"emoji":"๐Ÿ˜","aliases":["rice_cracker"],"tags":[],"category":"Food & Drink","description":"rice cracker","unicode_version":"6.0"},{"emoji":"๐Ÿ™","aliases":["rice_ball"],"tags":[],"category":"Food & Drink","description":"rice ball","unicode_version":"6.0"},{"emoji":"๐Ÿš","aliases":["rice"],"tags":[],"category":"Food & Drink","description":"cooked rice","unicode_version":"6.0"},{"emoji":"๐Ÿ›","aliases":["curry"],"tags":[],"category":"Food & Drink","description":"curry rice","unicode_version":"6.0"},{"emoji":"๐Ÿœ","aliases":["ramen"],"tags":["noodle"],"category":"Food & Drink","description":"steaming bowl","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["spaghetti"],"tags":["pasta"],"category":"Food & Drink","description":"spaghetti","unicode_version":"6.0"},{"emoji":"๐Ÿ ","aliases":["sweet_potato"],"tags":[],"category":"Food & Drink","description":"roasted sweet potato","unicode_version":"6.0"},{"emoji":"๐Ÿข","aliases":["oden"],"tags":[],"category":"Food & Drink","description":"oden","unicode_version":"6.0"},{"emoji":"๐Ÿฃ","aliases":["sushi"],"tags":[],"category":"Food & Drink","description":"sushi","unicode_version":"6.0"},{"emoji":"๐Ÿค","aliases":["fried_shrimp"],"tags":["tempura"],"category":"Food & Drink","description":"fried shrimp","unicode_version":"6.0"},{"emoji":"๐Ÿฅ","aliases":["fish_cake"],"tags":[],"category":"Food & Drink","description":"fish cake with swirl","unicode_version":"6.0"},{"emoji":"๐Ÿฅฎ","aliases":["moon_cake"],"tags":[],"category":"Food & Drink","description":"moon cake","unicode_version":"11.0"},{"emoji":"๐Ÿก","aliases":["dango"],"tags":[],"category":"Food & Drink","description":"dango","unicode_version":"6.0"},{"emoji":"๐ŸฅŸ","aliases":["dumpling"],"tags":[],"category":"Food & Drink","description":"dumpling","unicode_version":"11.0"},{"emoji":"๐Ÿฅ ","aliases":["fortune_cookie"],"tags":[],"category":"Food & Drink","description":"fortune cookie","unicode_version":"11.0"},{"emoji":"๐Ÿฅก","aliases":["takeout_box"],"tags":[],"category":"Food & Drink","description":"takeout box","unicode_version":"11.0"},{"emoji":"๐Ÿฆ€","aliases":["crab"],"tags":[],"category":"Food & Drink","description":"crab","unicode_version":"8.0"},{"emoji":"๐Ÿฆž","aliases":["lobster"],"tags":[],"category":"Food & Drink","description":"lobster","unicode_version":"11.0"},{"emoji":"๐Ÿฆ","aliases":["shrimp"],"tags":[],"category":"Food & Drink","description":"shrimp","unicode_version":"9.0"},{"emoji":"๐Ÿฆ‘","aliases":["squid"],"tags":[],"category":"Food & Drink","description":"squid","unicode_version":"9.0"},{"emoji":"๐Ÿฆช","aliases":["oyster"],"tags":[],"category":"Food & Drink","description":"oyster","unicode_version":"12.0"},{"emoji":"๐Ÿฆ","aliases":["icecream"],"tags":[],"category":"Food & Drink","description":"soft ice cream","unicode_version":"6.0"},{"emoji":"๐Ÿง","aliases":["shaved_ice"],"tags":[],"category":"Food & Drink","description":"shaved ice","unicode_version":"6.0"},{"emoji":"๐Ÿจ","aliases":["ice_cream"],"tags":[],"category":"Food & Drink","description":"ice cream","unicode_version":"6.0"},{"emoji":"๐Ÿฉ","aliases":["doughnut"],"tags":[],"category":"Food & Drink","description":"doughnut","unicode_version":"6.0"},{"emoji":"๐Ÿช","aliases":["cookie"],"tags":[],"category":"Food & Drink","description":"cookie","unicode_version":"6.0"},{"emoji":"๐ŸŽ‚","aliases":["birthday"],"tags":["party"],"category":"Food & Drink","description":"birthday cake","unicode_version":"6.0"},{"emoji":"๐Ÿฐ","aliases":["cake"],"tags":["dessert"],"category":"Food & Drink","description":"shortcake","unicode_version":"6.0"},{"emoji":"๐Ÿง","aliases":["cupcake"],"tags":[],"category":"Food & Drink","description":"cupcake","unicode_version":"11.0"},{"emoji":"๐Ÿฅง","aliases":["pie"],"tags":[],"category":"Food & Drink","description":"pie","unicode_version":"11.0"},{"emoji":"๐Ÿซ","aliases":["chocolate_bar"],"tags":[],"category":"Food & Drink","description":"chocolate bar","unicode_version":"6.0"},{"emoji":"๐Ÿฌ","aliases":["candy"],"tags":["sweet"],"category":"Food & Drink","description":"candy","unicode_version":"6.0"},{"emoji":"๐Ÿญ","aliases":["lollipop"],"tags":[],"category":"Food & Drink","description":"lollipop","unicode_version":"6.0"},{"emoji":"๐Ÿฎ","aliases":["custard"],"tags":[],"category":"Food & Drink","description":"custard","unicode_version":"6.0"},{"emoji":"๐Ÿฏ","aliases":["honey_pot"],"tags":[],"category":"Food & Drink","description":"honey pot","unicode_version":"6.0"},{"emoji":"๐Ÿผ","aliases":["baby_bottle"],"tags":["milk"],"category":"Food & Drink","description":"baby bottle","unicode_version":"6.0"},{"emoji":"๐Ÿฅ›","aliases":["milk_glass"],"tags":[],"category":"Food & Drink","description":"glass of milk","unicode_version":"9.0"},{"emoji":"โ˜•","aliases":["coffee"],"tags":["cafe","espresso"],"category":"Food & Drink","description":"hot beverage","unicode_version":"4.0"},{"emoji":"๐Ÿซ–","aliases":["teapot"],"tags":[],"category":"Food & Drink","description":"teapot","unicode_version":"13.0"},{"emoji":"๐Ÿต","aliases":["tea"],"tags":["green","breakfast"],"category":"Food & Drink","description":"teacup without handle","unicode_version":"6.0"},{"emoji":"๐Ÿถ","aliases":["sake"],"tags":[],"category":"Food & Drink","description":"sake","unicode_version":"6.0"},{"emoji":"๐Ÿพ","aliases":["champagne"],"tags":["bottle","bubbly","celebration"],"category":"Food & Drink","description":"bottle with popping cork","unicode_version":"8.0"},{"emoji":"๐Ÿท","aliases":["wine_glass"],"tags":[],"category":"Food & Drink","description":"wine glass","unicode_version":"6.0"},{"emoji":"๐Ÿธ","aliases":["cocktail"],"tags":["drink"],"category":"Food & Drink","description":"cocktail glass","unicode_version":"6.0"},{"emoji":"๐Ÿน","aliases":["tropical_drink"],"tags":["summer","vacation"],"category":"Food & Drink","description":"tropical drink","unicode_version":"6.0"},{"emoji":"๐Ÿบ","aliases":["beer"],"tags":["drink"],"category":"Food & Drink","description":"beer mug","unicode_version":"6.0"},{"emoji":"๐Ÿป","aliases":["beers"],"tags":["drinks"],"category":"Food & Drink","description":"clinking beer mugs","unicode_version":"6.0"},{"emoji":"๐Ÿฅ‚","aliases":["clinking_glasses"],"tags":["cheers","toast"],"category":"Food & Drink","description":"clinking glasses","unicode_version":"9.0"},{"emoji":"๐Ÿฅƒ","aliases":["tumbler_glass"],"tags":["whisky"],"category":"Food & Drink","description":"tumbler glass","unicode_version":"9.0"},{"emoji":"๐Ÿฅค","aliases":["cup_with_straw"],"tags":[],"category":"Food & Drink","description":"cup with straw","unicode_version":"11.0"},{"emoji":"๐Ÿง‹","aliases":["bubble_tea"],"tags":[],"category":"Food & Drink","description":"bubble tea","unicode_version":"13.0"},{"emoji":"๐Ÿงƒ","aliases":["beverage_box"],"tags":[],"category":"Food & Drink","description":"beverage box","unicode_version":"12.0"},{"emoji":"๐Ÿง‰","aliases":["mate"],"tags":[],"category":"Food & Drink","description":"mate","unicode_version":"12.0"},{"emoji":"๐ŸงŠ","aliases":["ice_cube"],"tags":[],"category":"Food & Drink","description":"ice","unicode_version":"12.0"},{"emoji":"๐Ÿฅข","aliases":["chopsticks"],"tags":[],"category":"Food & Drink","description":"chopsticks","unicode_version":"11.0"},{"emoji":"๐Ÿฝ๏ธ","aliases":["plate_with_cutlery"],"tags":["dining","dinner"],"category":"Food & Drink","description":"fork and knife with plate","unicode_version":"7.0"},{"emoji":"๐Ÿด","aliases":["fork_and_knife"],"tags":["cutlery"],"category":"Food & Drink","description":"fork and knife","unicode_version":"6.0"},{"emoji":"๐Ÿฅ„","aliases":["spoon"],"tags":[],"category":"Food & Drink","description":"spoon","unicode_version":"9.0"},{"emoji":"๐Ÿ”ช","aliases":["hocho","knife"],"tags":["cut","chop"],"category":"Food & Drink","description":"kitchen knife","unicode_version":"6.0"},{"emoji":"๐Ÿบ","aliases":["amphora"],"tags":[],"category":"Food & Drink","description":"amphora","unicode_version":"8.0"},{"emoji":"๐ŸŒ","aliases":["earth_africa"],"tags":["globe","world","international"],"category":"Travel & Places","description":"globe showing Europe-Africa","unicode_version":"6.0"},{"emoji":"๐ŸŒŽ","aliases":["earth_americas"],"tags":["globe","world","international"],"category":"Travel & Places","description":"globe showing Americas","unicode_version":"6.0"},{"emoji":"๐ŸŒ","aliases":["earth_asia"],"tags":["globe","world","international"],"category":"Travel & Places","description":"globe showing Asia-Australia","unicode_version":"6.0"},{"emoji":"๐ŸŒ","aliases":["globe_with_meridians"],"tags":["world","global","international"],"category":"Travel & Places","description":"globe with meridians","unicode_version":"6.0"},{"emoji":"๐Ÿ—บ๏ธ","aliases":["world_map"],"tags":["travel"],"category":"Travel & Places","description":"world map","unicode_version":"7.0"},{"emoji":"๐Ÿ—พ","aliases":["japan"],"tags":[],"category":"Travel & Places","description":"map of Japan","unicode_version":"6.0"},{"emoji":"๐Ÿงญ","aliases":["compass"],"tags":[],"category":"Travel & Places","description":"compass","unicode_version":"11.0"},{"emoji":"๐Ÿ”๏ธ","aliases":["mountain_snow"],"tags":[],"category":"Travel & Places","description":"snow-capped mountain","unicode_version":"7.0"},{"emoji":"โ›ฐ๏ธ","aliases":["mountain"],"tags":[],"category":"Travel & Places","description":"mountain","unicode_version":"5.2"},{"emoji":"๐ŸŒ‹","aliases":["volcano"],"tags":[],"category":"Travel & Places","description":"volcano","unicode_version":"6.0"},{"emoji":"๐Ÿ—ป","aliases":["mount_fuji"],"tags":[],"category":"Travel & Places","description":"mount fuji","unicode_version":"6.0"},{"emoji":"๐Ÿ•๏ธ","aliases":["camping"],"tags":[],"category":"Travel & Places","description":"camping","unicode_version":"7.0"},{"emoji":"๐Ÿ–๏ธ","aliases":["beach_umbrella"],"tags":[],"category":"Travel & Places","description":"beach with umbrella","unicode_version":"7.0"},{"emoji":"๐Ÿœ๏ธ","aliases":["desert"],"tags":[],"category":"Travel & Places","description":"desert","unicode_version":"7.0"},{"emoji":"๐Ÿ๏ธ","aliases":["desert_island"],"tags":[],"category":"Travel & Places","description":"desert island","unicode_version":"7.0"},{"emoji":"๐Ÿž๏ธ","aliases":["national_park"],"tags":[],"category":"Travel & Places","description":"national park","unicode_version":"7.0"},{"emoji":"๐ŸŸ๏ธ","aliases":["stadium"],"tags":[],"category":"Travel & Places","description":"stadium","unicode_version":"7.0"},{"emoji":"๐Ÿ›๏ธ","aliases":["classical_building"],"tags":[],"category":"Travel & Places","description":"classical building","unicode_version":"7.0"},{"emoji":"๐Ÿ—๏ธ","aliases":["building_construction"],"tags":[],"category":"Travel & Places","description":"building construction","unicode_version":"7.0"},{"emoji":"๐Ÿงฑ","aliases":["bricks"],"tags":[],"category":"Travel & Places","description":"brick","unicode_version":"11.0"},{"emoji":"๐Ÿชจ","aliases":["rock"],"tags":[],"category":"Travel & Places","description":"rock","unicode_version":"13.0"},{"emoji":"๐Ÿชต","aliases":["wood"],"tags":[],"category":"Travel & Places","description":"wood","unicode_version":"13.0"},{"emoji":"๐Ÿ›–","aliases":["hut"],"tags":[],"category":"Travel & Places","description":"hut","unicode_version":"13.0"},{"emoji":"๐Ÿ˜๏ธ","aliases":["houses"],"tags":[],"category":"Travel & Places","description":"houses","unicode_version":"7.0"},{"emoji":"๐Ÿš๏ธ","aliases":["derelict_house"],"tags":[],"category":"Travel & Places","description":"derelict house","unicode_version":"7.0"},{"emoji":"๐Ÿ ","aliases":["house"],"tags":[],"category":"Travel & Places","description":"house","unicode_version":"6.0"},{"emoji":"๐Ÿก","aliases":["house_with_garden"],"tags":[],"category":"Travel & Places","description":"house with garden","unicode_version":"6.0"},{"emoji":"๐Ÿข","aliases":["office"],"tags":[],"category":"Travel & Places","description":"office building","unicode_version":"6.0"},{"emoji":"๐Ÿฃ","aliases":["post_office"],"tags":[],"category":"Travel & Places","description":"Japanese post office","unicode_version":"6.0"},{"emoji":"๐Ÿค","aliases":["european_post_office"],"tags":[],"category":"Travel & Places","description":"post office","unicode_version":"6.0"},{"emoji":"๐Ÿฅ","aliases":["hospital"],"tags":[],"category":"Travel & Places","description":"hospital","unicode_version":"6.0"},{"emoji":"๐Ÿฆ","aliases":["bank"],"tags":[],"category":"Travel & Places","description":"bank","unicode_version":"6.0"},{"emoji":"๐Ÿจ","aliases":["hotel"],"tags":[],"category":"Travel & Places","description":"hotel","unicode_version":"6.0"},{"emoji":"๐Ÿฉ","aliases":["love_hotel"],"tags":[],"category":"Travel & Places","description":"love hotel","unicode_version":"6.0"},{"emoji":"๐Ÿช","aliases":["convenience_store"],"tags":[],"category":"Travel & Places","description":"convenience store","unicode_version":"6.0"},{"emoji":"๐Ÿซ","aliases":["school"],"tags":[],"category":"Travel & Places","description":"school","unicode_version":"6.0"},{"emoji":"๐Ÿฌ","aliases":["department_store"],"tags":[],"category":"Travel & Places","description":"department store","unicode_version":"6.0"},{"emoji":"๐Ÿญ","aliases":["factory"],"tags":[],"category":"Travel & Places","description":"factory","unicode_version":"6.0"},{"emoji":"๐Ÿฏ","aliases":["japanese_castle"],"tags":[],"category":"Travel & Places","description":"Japanese castle","unicode_version":"6.0"},{"emoji":"๐Ÿฐ","aliases":["european_castle"],"tags":[],"category":"Travel & Places","description":"castle","unicode_version":"6.0"},{"emoji":"๐Ÿ’’","aliases":["wedding"],"tags":["marriage"],"category":"Travel & Places","description":"wedding","unicode_version":"6.0"},{"emoji":"๐Ÿ—ผ","aliases":["tokyo_tower"],"tags":[],"category":"Travel & Places","description":"Tokyo tower","unicode_version":"6.0"},{"emoji":"๐Ÿ—ฝ","aliases":["statue_of_liberty"],"tags":[],"category":"Travel & Places","description":"Statue of Liberty","unicode_version":"6.0"},{"emoji":"โ›ช","aliases":["church"],"tags":[],"category":"Travel & Places","description":"church","unicode_version":"5.2"},{"emoji":"๐Ÿ•Œ","aliases":["mosque"],"tags":[],"category":"Travel & Places","description":"mosque","unicode_version":"8.0"},{"emoji":"๐Ÿ›•","aliases":["hindu_temple"],"tags":[],"category":"Travel & Places","description":"hindu temple","unicode_version":"12.0"},{"emoji":"๐Ÿ•","aliases":["synagogue"],"tags":[],"category":"Travel & Places","description":"synagogue","unicode_version":"8.0"},{"emoji":"โ›ฉ๏ธ","aliases":["shinto_shrine"],"tags":[],"category":"Travel & Places","description":"shinto shrine","unicode_version":"5.2"},{"emoji":"๐Ÿ•‹","aliases":["kaaba"],"tags":[],"category":"Travel & Places","description":"kaaba","unicode_version":"8.0"},{"emoji":"โ›ฒ","aliases":["fountain"],"tags":[],"category":"Travel & Places","description":"fountain","unicode_version":"5.2"},{"emoji":"โ›บ","aliases":["tent"],"tags":["camping"],"category":"Travel & Places","description":"tent","unicode_version":"5.2"},{"emoji":"๐ŸŒ","aliases":["foggy"],"tags":["karl"],"category":"Travel & Places","description":"foggy","unicode_version":"6.0"},{"emoji":"๐ŸŒƒ","aliases":["night_with_stars"],"tags":[],"category":"Travel & Places","description":"night with stars","unicode_version":"6.0"},{"emoji":"๐Ÿ™๏ธ","aliases":["cityscape"],"tags":["skyline"],"category":"Travel & Places","description":"cityscape","unicode_version":"7.0"},{"emoji":"๐ŸŒ„","aliases":["sunrise_over_mountains"],"tags":[],"category":"Travel & Places","description":"sunrise over mountains","unicode_version":"6.0"},{"emoji":"๐ŸŒ…","aliases":["sunrise"],"tags":[],"category":"Travel & Places","description":"sunrise","unicode_version":"6.0"},{"emoji":"๐ŸŒ†","aliases":["city_sunset"],"tags":[],"category":"Travel & Places","description":"cityscape at dusk","unicode_version":"6.0"},{"emoji":"๐ŸŒ‡","aliases":["city_sunrise"],"tags":[],"category":"Travel & Places","description":"sunset","unicode_version":"6.0"},{"emoji":"๐ŸŒ‰","aliases":["bridge_at_night"],"tags":[],"category":"Travel & Places","description":"bridge at night","unicode_version":"6.0"},{"emoji":"โ™จ๏ธ","aliases":["hotsprings"],"tags":[],"category":"Travel & Places","description":"hot springs","unicode_version":""},{"emoji":"๐ŸŽ ","aliases":["carousel_horse"],"tags":[],"category":"Travel & Places","description":"carousel horse","unicode_version":"6.0"},{"emoji":"๐ŸŽก","aliases":["ferris_wheel"],"tags":[],"category":"Travel & Places","description":"ferris wheel","unicode_version":"6.0"},{"emoji":"๐ŸŽข","aliases":["roller_coaster"],"tags":[],"category":"Travel & Places","description":"roller coaster","unicode_version":"6.0"},{"emoji":"๐Ÿ’ˆ","aliases":["barber"],"tags":[],"category":"Travel & Places","description":"barber pole","unicode_version":"6.0"},{"emoji":"๐ŸŽช","aliases":["circus_tent"],"tags":[],"category":"Travel & Places","description":"circus tent","unicode_version":"6.0"},{"emoji":"๐Ÿš‚","aliases":["steam_locomotive"],"tags":["train"],"category":"Travel & Places","description":"locomotive","unicode_version":"6.0"},{"emoji":"๐Ÿšƒ","aliases":["railway_car"],"tags":[],"category":"Travel & Places","description":"railway car","unicode_version":"6.0"},{"emoji":"๐Ÿš„","aliases":["bullettrain_side"],"tags":["train"],"category":"Travel & Places","description":"high-speed train","unicode_version":"6.0"},{"emoji":"๐Ÿš…","aliases":["bullettrain_front"],"tags":["train"],"category":"Travel & Places","description":"bullet train","unicode_version":"6.0"},{"emoji":"๐Ÿš†","aliases":["train2"],"tags":[],"category":"Travel & Places","description":"train","unicode_version":"6.0"},{"emoji":"๐Ÿš‡","aliases":["metro"],"tags":[],"category":"Travel & Places","description":"metro","unicode_version":"6.0"},{"emoji":"๐Ÿšˆ","aliases":["light_rail"],"tags":[],"category":"Travel & Places","description":"light rail","unicode_version":"6.0"},{"emoji":"๐Ÿš‰","aliases":["station"],"tags":[],"category":"Travel & Places","description":"station","unicode_version":"6.0"},{"emoji":"๐ŸšŠ","aliases":["tram"],"tags":[],"category":"Travel & Places","description":"tram","unicode_version":"6.0"},{"emoji":"๐Ÿš","aliases":["monorail"],"tags":[],"category":"Travel & Places","description":"monorail","unicode_version":"6.0"},{"emoji":"๐Ÿšž","aliases":["mountain_railway"],"tags":[],"category":"Travel & Places","description":"mountain railway","unicode_version":"6.0"},{"emoji":"๐Ÿš‹","aliases":["train"],"tags":[],"category":"Travel & Places","description":"tram car","unicode_version":"6.0"},{"emoji":"๐ŸšŒ","aliases":["bus"],"tags":[],"category":"Travel & Places","description":"bus","unicode_version":"6.0"},{"emoji":"๐Ÿš","aliases":["oncoming_bus"],"tags":[],"category":"Travel & Places","description":"oncoming bus","unicode_version":"6.0"},{"emoji":"๐ŸšŽ","aliases":["trolleybus"],"tags":[],"category":"Travel & Places","description":"trolleybus","unicode_version":"6.0"},{"emoji":"๐Ÿš","aliases":["minibus"],"tags":[],"category":"Travel & Places","description":"minibus","unicode_version":"6.0"},{"emoji":"๐Ÿš‘","aliases":["ambulance"],"tags":[],"category":"Travel & Places","description":"ambulance","unicode_version":"6.0"},{"emoji":"๐Ÿš’","aliases":["fire_engine"],"tags":[],"category":"Travel & Places","description":"fire engine","unicode_version":"6.0"},{"emoji":"๐Ÿš“","aliases":["police_car"],"tags":[],"category":"Travel & Places","description":"police car","unicode_version":"6.0"},{"emoji":"๐Ÿš”","aliases":["oncoming_police_car"],"tags":[],"category":"Travel & Places","description":"oncoming police car","unicode_version":"6.0"},{"emoji":"๐Ÿš•","aliases":["taxi"],"tags":[],"category":"Travel & Places","description":"taxi","unicode_version":"6.0"},{"emoji":"๐Ÿš–","aliases":["oncoming_taxi"],"tags":[],"category":"Travel & Places","description":"oncoming taxi","unicode_version":"6.0"},{"emoji":"๐Ÿš—","aliases":["car","red_car"],"tags":[],"category":"Travel & Places","description":"automobile","unicode_version":"6.0"},{"emoji":"๐Ÿš˜","aliases":["oncoming_automobile"],"tags":[],"category":"Travel & Places","description":"oncoming automobile","unicode_version":"6.0"},{"emoji":"๐Ÿš™","aliases":["blue_car"],"tags":[],"category":"Travel & Places","description":"sport utility vehicle","unicode_version":"6.0"},{"emoji":"๐Ÿ›ป","aliases":["pickup_truck"],"tags":[],"category":"Travel & Places","description":"pickup truck","unicode_version":"13.0"},{"emoji":"๐Ÿšš","aliases":["truck"],"tags":[],"category":"Travel & Places","description":"delivery truck","unicode_version":"6.0"},{"emoji":"๐Ÿš›","aliases":["articulated_lorry"],"tags":[],"category":"Travel & Places","description":"articulated lorry","unicode_version":"6.0"},{"emoji":"๐Ÿšœ","aliases":["tractor"],"tags":[],"category":"Travel & Places","description":"tractor","unicode_version":"6.0"},{"emoji":"๐ŸŽ๏ธ","aliases":["racing_car"],"tags":[],"category":"Travel & Places","description":"racing car","unicode_version":"7.0"},{"emoji":"๐Ÿ๏ธ","aliases":["motorcycle"],"tags":[],"category":"Travel & Places","description":"motorcycle","unicode_version":"7.0"},{"emoji":"๐Ÿ›ต","aliases":["motor_scooter"],"tags":[],"category":"Travel & Places","description":"motor scooter","unicode_version":"9.0"},{"emoji":"๐Ÿฆฝ","aliases":["manual_wheelchair"],"tags":[],"category":"Travel & Places","description":"manual wheelchair","unicode_version":"12.0"},{"emoji":"๐Ÿฆผ","aliases":["motorized_wheelchair"],"tags":[],"category":"Travel & Places","description":"motorized wheelchair","unicode_version":"12.0"},{"emoji":"๐Ÿ›บ","aliases":["auto_rickshaw"],"tags":[],"category":"Travel & Places","description":"auto rickshaw","unicode_version":"12.0"},{"emoji":"๐Ÿšฒ","aliases":["bike"],"tags":["bicycle"],"category":"Travel & Places","description":"bicycle","unicode_version":"6.0"},{"emoji":"๐Ÿ›ด","aliases":["kick_scooter"],"tags":[],"category":"Travel & Places","description":"kick scooter","unicode_version":"9.0"},{"emoji":"๐Ÿ›น","aliases":["skateboard"],"tags":[],"category":"Travel & Places","description":"skateboard","unicode_version":"11.0"},{"emoji":"๐Ÿ›ผ","aliases":["roller_skate"],"tags":[],"category":"Travel & Places","description":"roller skate","unicode_version":"13.0"},{"emoji":"๐Ÿš","aliases":["busstop"],"tags":[],"category":"Travel & Places","description":"bus stop","unicode_version":"6.0"},{"emoji":"๐Ÿ›ฃ๏ธ","aliases":["motorway"],"tags":[],"category":"Travel & Places","description":"motorway","unicode_version":"7.0"},{"emoji":"๐Ÿ›ค๏ธ","aliases":["railway_track"],"tags":[],"category":"Travel & Places","description":"railway track","unicode_version":"7.0"},{"emoji":"๐Ÿ›ข๏ธ","aliases":["oil_drum"],"tags":[],"category":"Travel & Places","description":"oil drum","unicode_version":"7.0"},{"emoji":"โ›ฝ","aliases":["fuelpump"],"tags":[],"category":"Travel & Places","description":"fuel pump","unicode_version":"5.2"},{"emoji":"๐Ÿšจ","aliases":["rotating_light"],"tags":["911","emergency"],"category":"Travel & Places","description":"police car light","unicode_version":"6.0"},{"emoji":"๐Ÿšฅ","aliases":["traffic_light"],"tags":[],"category":"Travel & Places","description":"horizontal traffic light","unicode_version":"6.0"},{"emoji":"๐Ÿšฆ","aliases":["vertical_traffic_light"],"tags":["semaphore"],"category":"Travel & Places","description":"vertical traffic light","unicode_version":"6.0"},{"emoji":"๐Ÿ›‘","aliases":["stop_sign"],"tags":[],"category":"Travel & Places","description":"stop sign","unicode_version":"9.0"},{"emoji":"๐Ÿšง","aliases":["construction"],"tags":["wip"],"category":"Travel & Places","description":"construction","unicode_version":"6.0"},{"emoji":"โš“","aliases":["anchor"],"tags":["ship"],"category":"Travel & Places","description":"anchor","unicode_version":"4.1"},{"emoji":"โ›ต","aliases":["boat","sailboat"],"tags":[],"category":"Travel & Places","description":"sailboat","unicode_version":"5.2"},{"emoji":"๐Ÿ›ถ","aliases":["canoe"],"tags":[],"category":"Travel & Places","description":"canoe","unicode_version":"9.0"},{"emoji":"๐Ÿšค","aliases":["speedboat"],"tags":["ship"],"category":"Travel & Places","description":"speedboat","unicode_version":"6.0"},{"emoji":"๐Ÿ›ณ๏ธ","aliases":["passenger_ship"],"tags":["cruise"],"category":"Travel & Places","description":"passenger ship","unicode_version":"7.0"},{"emoji":"โ›ด๏ธ","aliases":["ferry"],"tags":[],"category":"Travel & Places","description":"ferry","unicode_version":"5.2"},{"emoji":"๐Ÿ›ฅ๏ธ","aliases":["motor_boat"],"tags":[],"category":"Travel & Places","description":"motor boat","unicode_version":"7.0"},{"emoji":"๐Ÿšข","aliases":["ship"],"tags":[],"category":"Travel & Places","description":"ship","unicode_version":"6.0"},{"emoji":"โœˆ๏ธ","aliases":["airplane"],"tags":["flight"],"category":"Travel & Places","description":"airplane","unicode_version":""},{"emoji":"๐Ÿ›ฉ๏ธ","aliases":["small_airplane"],"tags":["flight"],"category":"Travel & Places","description":"small airplane","unicode_version":"7.0"},{"emoji":"๐Ÿ›ซ","aliases":["flight_departure"],"tags":[],"category":"Travel & Places","description":"airplane departure","unicode_version":"7.0"},{"emoji":"๐Ÿ›ฌ","aliases":["flight_arrival"],"tags":[],"category":"Travel & Places","description":"airplane arrival","unicode_version":"7.0"},{"emoji":"๐Ÿช‚","aliases":["parachute"],"tags":[],"category":"Travel & Places","description":"parachute","unicode_version":"12.0"},{"emoji":"๐Ÿ’บ","aliases":["seat"],"tags":[],"category":"Travel & Places","description":"seat","unicode_version":"6.0"},{"emoji":"๐Ÿš","aliases":["helicopter"],"tags":[],"category":"Travel & Places","description":"helicopter","unicode_version":"6.0"},{"emoji":"๐ŸšŸ","aliases":["suspension_railway"],"tags":[],"category":"Travel & Places","description":"suspension railway","unicode_version":"6.0"},{"emoji":"๐Ÿš ","aliases":["mountain_cableway"],"tags":[],"category":"Travel & Places","description":"mountain cableway","unicode_version":"6.0"},{"emoji":"๐Ÿšก","aliases":["aerial_tramway"],"tags":[],"category":"Travel & Places","description":"aerial tramway","unicode_version":"6.0"},{"emoji":"๐Ÿ›ฐ๏ธ","aliases":["artificial_satellite"],"tags":["orbit","space"],"category":"Travel & Places","description":"satellite","unicode_version":"7.0"},{"emoji":"๐Ÿš€","aliases":["rocket"],"tags":["ship","launch"],"category":"Travel & Places","description":"rocket","unicode_version":"6.0"},{"emoji":"๐Ÿ›ธ","aliases":["flying_saucer"],"tags":["ufo"],"category":"Travel & Places","description":"flying saucer","unicode_version":"11.0"},{"emoji":"๐Ÿ›Ž๏ธ","aliases":["bellhop_bell"],"tags":[],"category":"Travel & Places","description":"bellhop bell","unicode_version":"7.0"},{"emoji":"๐Ÿงณ","aliases":["luggage"],"tags":[],"category":"Travel & Places","description":"luggage","unicode_version":"11.0"},{"emoji":"โŒ›","aliases":["hourglass"],"tags":["time"],"category":"Travel & Places","description":"hourglass done","unicode_version":""},{"emoji":"โณ","aliases":["hourglass_flowing_sand"],"tags":["time"],"category":"Travel & Places","description":"hourglass not done","unicode_version":"6.0"},{"emoji":"โŒš","aliases":["watch"],"tags":["time"],"category":"Travel & Places","description":"watch","unicode_version":""},{"emoji":"โฐ","aliases":["alarm_clock"],"tags":["morning"],"category":"Travel & Places","description":"alarm clock","unicode_version":"6.0"},{"emoji":"โฑ๏ธ","aliases":["stopwatch"],"tags":[],"category":"Travel & Places","description":"stopwatch","unicode_version":"6.0"},{"emoji":"โฒ๏ธ","aliases":["timer_clock"],"tags":[],"category":"Travel & Places","description":"timer clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ฐ๏ธ","aliases":["mantelpiece_clock"],"tags":[],"category":"Travel & Places","description":"mantelpiece clock","unicode_version":"7.0"},{"emoji":"๐Ÿ•›","aliases":["clock12"],"tags":[],"category":"Travel & Places","description":"twelve oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ง","aliases":["clock1230"],"tags":[],"category":"Travel & Places","description":"twelve-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•","aliases":["clock1"],"tags":[],"category":"Travel & Places","description":"one oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•œ","aliases":["clock130"],"tags":[],"category":"Travel & Places","description":"one-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•‘","aliases":["clock2"],"tags":[],"category":"Travel & Places","description":"two oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•","aliases":["clock230"],"tags":[],"category":"Travel & Places","description":"two-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•’","aliases":["clock3"],"tags":[],"category":"Travel & Places","description":"three oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ž","aliases":["clock330"],"tags":[],"category":"Travel & Places","description":"three-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•“","aliases":["clock4"],"tags":[],"category":"Travel & Places","description":"four oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•Ÿ","aliases":["clock430"],"tags":[],"category":"Travel & Places","description":"four-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•”","aliases":["clock5"],"tags":[],"category":"Travel & Places","description":"five oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ• ","aliases":["clock530"],"tags":[],"category":"Travel & Places","description":"five-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ••","aliases":["clock6"],"tags":[],"category":"Travel & Places","description":"six oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ก","aliases":["clock630"],"tags":[],"category":"Travel & Places","description":"six-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•–","aliases":["clock7"],"tags":[],"category":"Travel & Places","description":"seven oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ข","aliases":["clock730"],"tags":[],"category":"Travel & Places","description":"seven-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•—","aliases":["clock8"],"tags":[],"category":"Travel & Places","description":"eight oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ฃ","aliases":["clock830"],"tags":[],"category":"Travel & Places","description":"eight-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•˜","aliases":["clock9"],"tags":[],"category":"Travel & Places","description":"nine oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ค","aliases":["clock930"],"tags":[],"category":"Travel & Places","description":"nine-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•™","aliases":["clock10"],"tags":[],"category":"Travel & Places","description":"ten oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ฅ","aliases":["clock1030"],"tags":[],"category":"Travel & Places","description":"ten-thirty","unicode_version":"6.0"},{"emoji":"๐Ÿ•š","aliases":["clock11"],"tags":[],"category":"Travel & Places","description":"eleven oโ€™clock","unicode_version":"6.0"},{"emoji":"๐Ÿ•ฆ","aliases":["clock1130"],"tags":[],"category":"Travel & Places","description":"eleven-thirty","unicode_version":"6.0"},{"emoji":"๐ŸŒ‘","aliases":["new_moon"],"tags":[],"category":"Travel & Places","description":"new moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ’","aliases":["waxing_crescent_moon"],"tags":[],"category":"Travel & Places","description":"waxing crescent moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ“","aliases":["first_quarter_moon"],"tags":[],"category":"Travel & Places","description":"first quarter moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ”","aliases":["moon","waxing_gibbous_moon"],"tags":[],"category":"Travel & Places","description":"waxing gibbous moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ•","aliases":["full_moon"],"tags":[],"category":"Travel & Places","description":"full moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ–","aliases":["waning_gibbous_moon"],"tags":[],"category":"Travel & Places","description":"waning gibbous moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ—","aliases":["last_quarter_moon"],"tags":[],"category":"Travel & Places","description":"last quarter moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ˜","aliases":["waning_crescent_moon"],"tags":[],"category":"Travel & Places","description":"waning crescent moon","unicode_version":"6.0"},{"emoji":"๐ŸŒ™","aliases":["crescent_moon"],"tags":["night"],"category":"Travel & Places","description":"crescent moon","unicode_version":"6.0"},{"emoji":"๐ŸŒš","aliases":["new_moon_with_face"],"tags":[],"category":"Travel & Places","description":"new moon face","unicode_version":"6.0"},{"emoji":"๐ŸŒ›","aliases":["first_quarter_moon_with_face"],"tags":[],"category":"Travel & Places","description":"first quarter moon face","unicode_version":"6.0"},{"emoji":"๐ŸŒœ","aliases":["last_quarter_moon_with_face"],"tags":[],"category":"Travel & Places","description":"last quarter moon face","unicode_version":"6.0"},{"emoji":"๐ŸŒก๏ธ","aliases":["thermometer"],"tags":[],"category":"Travel & Places","description":"thermometer","unicode_version":"7.0"},{"emoji":"โ˜€๏ธ","aliases":["sunny"],"tags":["weather"],"category":"Travel & Places","description":"sun","unicode_version":""},{"emoji":"๐ŸŒ","aliases":["full_moon_with_face"],"tags":[],"category":"Travel & Places","description":"full moon face","unicode_version":"6.0"},{"emoji":"๐ŸŒž","aliases":["sun_with_face"],"tags":["summer"],"category":"Travel & Places","description":"sun with face","unicode_version":"6.0"},{"emoji":"๐Ÿช","aliases":["ringed_planet"],"tags":[],"category":"Travel & Places","description":"ringed planet","unicode_version":"12.0"},{"emoji":"โญ","aliases":["star"],"tags":[],"category":"Travel & Places","description":"star","unicode_version":"5.1"},{"emoji":"๐ŸŒŸ","aliases":["star2"],"tags":[],"category":"Travel & Places","description":"glowing star","unicode_version":"6.0"},{"emoji":"๐ŸŒ ","aliases":["stars"],"tags":[],"category":"Travel & Places","description":"shooting star","unicode_version":"6.0"},{"emoji":"๐ŸŒŒ","aliases":["milky_way"],"tags":[],"category":"Travel & Places","description":"milky way","unicode_version":"6.0"},{"emoji":"โ˜๏ธ","aliases":["cloud"],"tags":[],"category":"Travel & Places","description":"cloud","unicode_version":""},{"emoji":"โ›…","aliases":["partly_sunny"],"tags":["weather","cloud"],"category":"Travel & Places","description":"sun behind cloud","unicode_version":"5.2"},{"emoji":"โ›ˆ๏ธ","aliases":["cloud_with_lightning_and_rain"],"tags":[],"category":"Travel & Places","description":"cloud with lightning and rain","unicode_version":"5.2"},{"emoji":"๐ŸŒค๏ธ","aliases":["sun_behind_small_cloud"],"tags":[],"category":"Travel & Places","description":"sun behind small cloud","unicode_version":"7.0"},{"emoji":"๐ŸŒฅ๏ธ","aliases":["sun_behind_large_cloud"],"tags":[],"category":"Travel & Places","description":"sun behind large cloud","unicode_version":"7.0"},{"emoji":"๐ŸŒฆ๏ธ","aliases":["sun_behind_rain_cloud"],"tags":[],"category":"Travel & Places","description":"sun behind rain cloud","unicode_version":"7.0"},{"emoji":"๐ŸŒง๏ธ","aliases":["cloud_with_rain"],"tags":[],"category":"Travel & Places","description":"cloud with rain","unicode_version":"7.0"},{"emoji":"๐ŸŒจ๏ธ","aliases":["cloud_with_snow"],"tags":[],"category":"Travel & Places","description":"cloud with snow","unicode_version":"7.0"},{"emoji":"๐ŸŒฉ๏ธ","aliases":["cloud_with_lightning"],"tags":[],"category":"Travel & Places","description":"cloud with lightning","unicode_version":"7.0"},{"emoji":"๐ŸŒช๏ธ","aliases":["tornado"],"tags":[],"category":"Travel & Places","description":"tornado","unicode_version":"7.0"},{"emoji":"๐ŸŒซ๏ธ","aliases":["fog"],"tags":[],"category":"Travel & Places","description":"fog","unicode_version":"7.0"},{"emoji":"๐ŸŒฌ๏ธ","aliases":["wind_face"],"tags":[],"category":"Travel & Places","description":"wind face","unicode_version":"7.0"},{"emoji":"๐ŸŒ€","aliases":["cyclone"],"tags":["swirl"],"category":"Travel & Places","description":"cyclone","unicode_version":"6.0"},{"emoji":"๐ŸŒˆ","aliases":["rainbow"],"tags":[],"category":"Travel & Places","description":"rainbow","unicode_version":"6.0"},{"emoji":"๐ŸŒ‚","aliases":["closed_umbrella"],"tags":["weather","rain"],"category":"Travel & Places","description":"closed umbrella","unicode_version":"6.0"},{"emoji":"โ˜‚๏ธ","aliases":["open_umbrella"],"tags":[],"category":"Travel & Places","description":"umbrella","unicode_version":""},{"emoji":"โ˜”","aliases":["umbrella"],"tags":["rain","weather"],"category":"Travel & Places","description":"umbrella with rain drops","unicode_version":"4.0"},{"emoji":"โ›ฑ๏ธ","aliases":["parasol_on_ground"],"tags":["beach_umbrella"],"category":"Travel & Places","description":"umbrella on ground","unicode_version":"5.2"},{"emoji":"โšก","aliases":["zap"],"tags":["lightning","thunder"],"category":"Travel & Places","description":"high voltage","unicode_version":"4.0"},{"emoji":"โ„๏ธ","aliases":["snowflake"],"tags":["winter","cold","weather"],"category":"Travel & Places","description":"snowflake","unicode_version":""},{"emoji":"โ˜ƒ๏ธ","aliases":["snowman_with_snow"],"tags":["winter","christmas"],"category":"Travel & Places","description":"snowman","unicode_version":""},{"emoji":"โ›„","aliases":["snowman"],"tags":["winter"],"category":"Travel & Places","description":"snowman without snow","unicode_version":"5.2"},{"emoji":"โ˜„๏ธ","aliases":["comet"],"tags":[],"category":"Travel & Places","description":"comet","unicode_version":""},{"emoji":"๐Ÿ”ฅ","aliases":["fire"],"tags":["burn"],"category":"Travel & Places","description":"fire","unicode_version":"6.0"},{"emoji":"๐Ÿ’ง","aliases":["droplet"],"tags":["water"],"category":"Travel & Places","description":"droplet","unicode_version":"6.0"},{"emoji":"๐ŸŒŠ","aliases":["ocean"],"tags":["sea"],"category":"Travel & Places","description":"water wave","unicode_version":"6.0"},{"emoji":"๐ŸŽƒ","aliases":["jack_o_lantern"],"tags":["halloween"],"category":"Activities","description":"jack-o-lantern","unicode_version":"6.0"},{"emoji":"๐ŸŽ„","aliases":["christmas_tree"],"tags":[],"category":"Activities","description":"Christmas tree","unicode_version":"6.0"},{"emoji":"๐ŸŽ†","aliases":["fireworks"],"tags":["festival","celebration"],"category":"Activities","description":"fireworks","unicode_version":"6.0"},{"emoji":"๐ŸŽ‡","aliases":["sparkler"],"tags":[],"category":"Activities","description":"sparkler","unicode_version":"6.0"},{"emoji":"๐Ÿงจ","aliases":["firecracker"],"tags":[],"category":"Activities","description":"firecracker","unicode_version":"11.0"},{"emoji":"โœจ","aliases":["sparkles"],"tags":["shiny"],"category":"Activities","description":"sparkles","unicode_version":"6.0"},{"emoji":"๐ŸŽˆ","aliases":["balloon"],"tags":["party","birthday"],"category":"Activities","description":"balloon","unicode_version":"6.0"},{"emoji":"๐ŸŽ‰","aliases":["tada"],"tags":["hooray","party"],"category":"Activities","description":"party popper","unicode_version":"6.0"},{"emoji":"๐ŸŽŠ","aliases":["confetti_ball"],"tags":[],"category":"Activities","description":"confetti ball","unicode_version":"6.0"},{"emoji":"๐ŸŽ‹","aliases":["tanabata_tree"],"tags":[],"category":"Activities","description":"tanabata tree","unicode_version":"6.0"},{"emoji":"๐ŸŽ","aliases":["bamboo"],"tags":[],"category":"Activities","description":"pine decoration","unicode_version":"6.0"},{"emoji":"๐ŸŽŽ","aliases":["dolls"],"tags":[],"category":"Activities","description":"Japanese dolls","unicode_version":"6.0"},{"emoji":"๐ŸŽ","aliases":["flags"],"tags":[],"category":"Activities","description":"carp streamer","unicode_version":"6.0"},{"emoji":"๐ŸŽ","aliases":["wind_chime"],"tags":[],"category":"Activities","description":"wind chime","unicode_version":"6.0"},{"emoji":"๐ŸŽ‘","aliases":["rice_scene"],"tags":[],"category":"Activities","description":"moon viewing ceremony","unicode_version":"6.0"},{"emoji":"๐Ÿงง","aliases":["red_envelope"],"tags":[],"category":"Activities","description":"red envelope","unicode_version":"11.0"},{"emoji":"๐ŸŽ€","aliases":["ribbon"],"tags":[],"category":"Activities","description":"ribbon","unicode_version":"6.0"},{"emoji":"๐ŸŽ","aliases":["gift"],"tags":["present","birthday","christmas"],"category":"Activities","description":"wrapped gift","unicode_version":"6.0"},{"emoji":"๐ŸŽ—๏ธ","aliases":["reminder_ribbon"],"tags":[],"category":"Activities","description":"reminder ribbon","unicode_version":"7.0"},{"emoji":"๐ŸŽŸ๏ธ","aliases":["tickets"],"tags":[],"category":"Activities","description":"admission tickets","unicode_version":"7.0"},{"emoji":"๐ŸŽซ","aliases":["ticket"],"tags":[],"category":"Activities","description":"ticket","unicode_version":"6.0"},{"emoji":"๐ŸŽ–๏ธ","aliases":["medal_military"],"tags":[],"category":"Activities","description":"military medal","unicode_version":"7.0"},{"emoji":"๐Ÿ†","aliases":["trophy"],"tags":["award","contest","winner"],"category":"Activities","description":"trophy","unicode_version":"6.0"},{"emoji":"๐Ÿ…","aliases":["medal_sports"],"tags":["gold","winner"],"category":"Activities","description":"sports medal","unicode_version":"7.0"},{"emoji":"๐Ÿฅ‡","aliases":["1st_place_medal"],"tags":["gold"],"category":"Activities","description":"1st place medal","unicode_version":"9.0"},{"emoji":"๐Ÿฅˆ","aliases":["2nd_place_medal"],"tags":["silver"],"category":"Activities","description":"2nd place medal","unicode_version":"9.0"},{"emoji":"๐Ÿฅ‰","aliases":["3rd_place_medal"],"tags":["bronze"],"category":"Activities","description":"3rd place medal","unicode_version":"9.0"},{"emoji":"โšฝ","aliases":["soccer"],"tags":["sports"],"category":"Activities","description":"soccer ball","unicode_version":"5.2"},{"emoji":"โšพ","aliases":["baseball"],"tags":["sports"],"category":"Activities","description":"baseball","unicode_version":"5.2"},{"emoji":"๐ŸฅŽ","aliases":["softball"],"tags":[],"category":"Activities","description":"softball","unicode_version":"11.0"},{"emoji":"๐Ÿ€","aliases":["basketball"],"tags":["sports"],"category":"Activities","description":"basketball","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["volleyball"],"tags":[],"category":"Activities","description":"volleyball","unicode_version":"8.0"},{"emoji":"๐Ÿˆ","aliases":["football"],"tags":["sports"],"category":"Activities","description":"american football","unicode_version":"6.0"},{"emoji":"๐Ÿ‰","aliases":["rugby_football"],"tags":[],"category":"Activities","description":"rugby football","unicode_version":"6.0"},{"emoji":"๐ŸŽพ","aliases":["tennis"],"tags":["sports"],"category":"Activities","description":"tennis","unicode_version":"6.0"},{"emoji":"๐Ÿฅ","aliases":["flying_disc"],"tags":[],"category":"Activities","description":"flying disc","unicode_version":"11.0"},{"emoji":"๐ŸŽณ","aliases":["bowling"],"tags":[],"category":"Activities","description":"bowling","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["cricket_game"],"tags":[],"category":"Activities","description":"cricket game","unicode_version":"8.0"},{"emoji":"๐Ÿ‘","aliases":["field_hockey"],"tags":[],"category":"Activities","description":"field hockey","unicode_version":"8.0"},{"emoji":"๐Ÿ’","aliases":["ice_hockey"],"tags":[],"category":"Activities","description":"ice hockey","unicode_version":"8.0"},{"emoji":"๐Ÿฅ","aliases":["lacrosse"],"tags":[],"category":"Activities","description":"lacrosse","unicode_version":"11.0"},{"emoji":"๐Ÿ“","aliases":["ping_pong"],"tags":[],"category":"Activities","description":"ping pong","unicode_version":"8.0"},{"emoji":"๐Ÿธ","aliases":["badminton"],"tags":[],"category":"Activities","description":"badminton","unicode_version":"8.0"},{"emoji":"๐ŸฅŠ","aliases":["boxing_glove"],"tags":[],"category":"Activities","description":"boxing glove","unicode_version":"9.0"},{"emoji":"๐Ÿฅ‹","aliases":["martial_arts_uniform"],"tags":[],"category":"Activities","description":"martial arts uniform","unicode_version":"9.0"},{"emoji":"๐Ÿฅ…","aliases":["goal_net"],"tags":[],"category":"Activities","description":"goal net","unicode_version":"9.0"},{"emoji":"โ›ณ","aliases":["golf"],"tags":[],"category":"Activities","description":"flag in hole","unicode_version":"5.2"},{"emoji":"โ›ธ๏ธ","aliases":["ice_skate"],"tags":["skating"],"category":"Activities","description":"ice skate","unicode_version":"5.2"},{"emoji":"๐ŸŽฃ","aliases":["fishing_pole_and_fish"],"tags":[],"category":"Activities","description":"fishing pole","unicode_version":"6.0"},{"emoji":"๐Ÿคฟ","aliases":["diving_mask"],"tags":[],"category":"Activities","description":"diving mask","unicode_version":"12.0"},{"emoji":"๐ŸŽฝ","aliases":["running_shirt_with_sash"],"tags":["marathon"],"category":"Activities","description":"running shirt","unicode_version":"6.0"},{"emoji":"๐ŸŽฟ","aliases":["ski"],"tags":[],"category":"Activities","description":"skis","unicode_version":"6.0"},{"emoji":"๐Ÿ›ท","aliases":["sled"],"tags":[],"category":"Activities","description":"sled","unicode_version":"11.0"},{"emoji":"๐ŸฅŒ","aliases":["curling_stone"],"tags":[],"category":"Activities","description":"curling stone","unicode_version":"11.0"},{"emoji":"๐ŸŽฏ","aliases":["dart"],"tags":["target"],"category":"Activities","description":"bullseye","unicode_version":"6.0"},{"emoji":"๐Ÿช€","aliases":["yo_yo"],"tags":[],"category":"Activities","description":"yo-yo","unicode_version":"12.0"},{"emoji":"๐Ÿช","aliases":["kite"],"tags":[],"category":"Activities","description":"kite","unicode_version":"12.0"},{"emoji":"๐ŸŽฑ","aliases":["8ball"],"tags":["pool","billiards"],"category":"Activities","description":"pool 8 ball","unicode_version":"6.0"},{"emoji":"๐Ÿ”ฎ","aliases":["crystal_ball"],"tags":["fortune"],"category":"Activities","description":"crystal ball","unicode_version":"6.0"},{"emoji":"๐Ÿช„","aliases":["magic_wand"],"tags":[],"category":"Activities","description":"magic wand","unicode_version":"13.0"},{"emoji":"๐Ÿงฟ","aliases":["nazar_amulet"],"tags":[],"category":"Activities","description":"nazar amulet","unicode_version":"11.0"},{"emoji":"๐ŸŽฎ","aliases":["video_game"],"tags":["play","controller","console"],"category":"Activities","description":"video game","unicode_version":"6.0"},{"emoji":"๐Ÿ•น๏ธ","aliases":["joystick"],"tags":[],"category":"Activities","description":"joystick","unicode_version":"7.0"},{"emoji":"๐ŸŽฐ","aliases":["slot_machine"],"tags":[],"category":"Activities","description":"slot machine","unicode_version":"6.0"},{"emoji":"๐ŸŽฒ","aliases":["game_die"],"tags":["dice","gambling"],"category":"Activities","description":"game die","unicode_version":"6.0"},{"emoji":"๐Ÿงฉ","aliases":["jigsaw"],"tags":[],"category":"Activities","description":"puzzle piece","unicode_version":"11.0"},{"emoji":"๐Ÿงธ","aliases":["teddy_bear"],"tags":[],"category":"Activities","description":"teddy bear","unicode_version":"11.0"},{"emoji":"๐Ÿช…","aliases":["pinata"],"tags":[],"category":"Activities","description":"piรฑata","unicode_version":"13.0"},{"emoji":"๐Ÿช†","aliases":["nesting_dolls"],"tags":[],"category":"Activities","description":"nesting dolls","unicode_version":"13.0"},{"emoji":"โ™ ๏ธ","aliases":["spades"],"tags":[],"category":"Activities","description":"spade suit","unicode_version":""},{"emoji":"โ™ฅ๏ธ","aliases":["hearts"],"tags":[],"category":"Activities","description":"heart suit","unicode_version":""},{"emoji":"โ™ฆ๏ธ","aliases":["diamonds"],"tags":[],"category":"Activities","description":"diamond suit","unicode_version":""},{"emoji":"โ™ฃ๏ธ","aliases":["clubs"],"tags":[],"category":"Activities","description":"club suit","unicode_version":""},{"emoji":"โ™Ÿ๏ธ","aliases":["chess_pawn"],"tags":[],"category":"Activities","description":"chess pawn","unicode_version":"11.0"},{"emoji":"๐Ÿƒ","aliases":["black_joker"],"tags":[],"category":"Activities","description":"joker","unicode_version":"6.0"},{"emoji":"๐Ÿ€„","aliases":["mahjong"],"tags":[],"category":"Activities","description":"mahjong red dragon","unicode_version":""},{"emoji":"๐ŸŽด","aliases":["flower_playing_cards"],"tags":[],"category":"Activities","description":"flower playing cards","unicode_version":"6.0"},{"emoji":"๐ŸŽญ","aliases":["performing_arts"],"tags":["theater","drama"],"category":"Activities","description":"performing arts","unicode_version":"6.0"},{"emoji":"๐Ÿ–ผ๏ธ","aliases":["framed_picture"],"tags":[],"category":"Activities","description":"framed picture","unicode_version":"7.0"},{"emoji":"๐ŸŽจ","aliases":["art"],"tags":["design","paint"],"category":"Activities","description":"artist palette","unicode_version":"6.0"},{"emoji":"๐Ÿงต","aliases":["thread"],"tags":[],"category":"Activities","description":"thread","unicode_version":"11.0"},{"emoji":"๐Ÿชก","aliases":["sewing_needle"],"tags":[],"category":"Activities","description":"sewing needle","unicode_version":"13.0"},{"emoji":"๐Ÿงถ","aliases":["yarn"],"tags":[],"category":"Activities","description":"yarn","unicode_version":"11.0"},{"emoji":"๐Ÿชข","aliases":["knot"],"tags":[],"category":"Activities","description":"knot","unicode_version":"13.0"},{"emoji":"๐Ÿ‘“","aliases":["eyeglasses"],"tags":["glasses"],"category":"Objects","description":"glasses","unicode_version":"6.0"},{"emoji":"๐Ÿ•ถ๏ธ","aliases":["dark_sunglasses"],"tags":[],"category":"Objects","description":"sunglasses","unicode_version":"7.0"},{"emoji":"๐Ÿฅฝ","aliases":["goggles"],"tags":[],"category":"Objects","description":"goggles","unicode_version":"11.0"},{"emoji":"๐Ÿฅผ","aliases":["lab_coat"],"tags":[],"category":"Objects","description":"lab coat","unicode_version":"11.0"},{"emoji":"๐Ÿฆบ","aliases":["safety_vest"],"tags":[],"category":"Objects","description":"safety vest","unicode_version":"12.0"},{"emoji":"๐Ÿ‘”","aliases":["necktie"],"tags":["shirt","formal"],"category":"Objects","description":"necktie","unicode_version":"6.0"},{"emoji":"๐Ÿ‘•","aliases":["shirt","tshirt"],"tags":[],"category":"Objects","description":"t-shirt","unicode_version":"6.0"},{"emoji":"๐Ÿ‘–","aliases":["jeans"],"tags":["pants"],"category":"Objects","description":"jeans","unicode_version":"6.0"},{"emoji":"๐Ÿงฃ","aliases":["scarf"],"tags":[],"category":"Objects","description":"scarf","unicode_version":"11.0"},{"emoji":"๐Ÿงค","aliases":["gloves"],"tags":[],"category":"Objects","description":"gloves","unicode_version":"11.0"},{"emoji":"๐Ÿงฅ","aliases":["coat"],"tags":[],"category":"Objects","description":"coat","unicode_version":"11.0"},{"emoji":"๐Ÿงฆ","aliases":["socks"],"tags":[],"category":"Objects","description":"socks","unicode_version":"11.0"},{"emoji":"๐Ÿ‘—","aliases":["dress"],"tags":[],"category":"Objects","description":"dress","unicode_version":"6.0"},{"emoji":"๐Ÿ‘˜","aliases":["kimono"],"tags":[],"category":"Objects","description":"kimono","unicode_version":"6.0"},{"emoji":"๐Ÿฅป","aliases":["sari"],"tags":[],"category":"Objects","description":"sari","unicode_version":"12.0"},{"emoji":"๐Ÿฉฑ","aliases":["one_piece_swimsuit"],"tags":[],"category":"Objects","description":"one-piece swimsuit","unicode_version":"12.0"},{"emoji":"๐Ÿฉฒ","aliases":["swim_brief"],"tags":[],"category":"Objects","description":"briefs","unicode_version":"12.0"},{"emoji":"๐Ÿฉณ","aliases":["shorts"],"tags":[],"category":"Objects","description":"shorts","unicode_version":"12.0"},{"emoji":"๐Ÿ‘™","aliases":["bikini"],"tags":["beach"],"category":"Objects","description":"bikini","unicode_version":"6.0"},{"emoji":"๐Ÿ‘š","aliases":["womans_clothes"],"tags":[],"category":"Objects","description":"womanโ€™s clothes","unicode_version":"6.0"},{"emoji":"๐Ÿ‘›","aliases":["purse"],"tags":[],"category":"Objects","description":"purse","unicode_version":"6.0"},{"emoji":"๐Ÿ‘œ","aliases":["handbag"],"tags":["bag"],"category":"Objects","description":"handbag","unicode_version":"6.0"},{"emoji":"๐Ÿ‘","aliases":["pouch"],"tags":["bag"],"category":"Objects","description":"clutch bag","unicode_version":"6.0"},{"emoji":"๐Ÿ›๏ธ","aliases":["shopping"],"tags":["bags"],"category":"Objects","description":"shopping bags","unicode_version":"7.0"},{"emoji":"๐ŸŽ’","aliases":["school_satchel"],"tags":[],"category":"Objects","description":"backpack","unicode_version":"6.0"},{"emoji":"๐Ÿฉด","aliases":["thong_sandal"],"tags":[],"category":"Objects","description":"thong sandal","unicode_version":"13.0"},{"emoji":"๐Ÿ‘ž","aliases":["mans_shoe","shoe"],"tags":[],"category":"Objects","description":"manโ€™s shoe","unicode_version":"6.0"},{"emoji":"๐Ÿ‘Ÿ","aliases":["athletic_shoe"],"tags":["sneaker","sport","running"],"category":"Objects","description":"running shoe","unicode_version":"6.0"},{"emoji":"๐Ÿฅพ","aliases":["hiking_boot"],"tags":[],"category":"Objects","description":"hiking boot","unicode_version":"11.0"},{"emoji":"๐Ÿฅฟ","aliases":["flat_shoe"],"tags":[],"category":"Objects","description":"flat shoe","unicode_version":"11.0"},{"emoji":"๐Ÿ‘ ","aliases":["high_heel"],"tags":["shoe"],"category":"Objects","description":"high-heeled shoe","unicode_version":"6.0"},{"emoji":"๐Ÿ‘ก","aliases":["sandal"],"tags":["shoe"],"category":"Objects","description":"womanโ€™s sandal","unicode_version":"6.0"},{"emoji":"๐Ÿฉฐ","aliases":["ballet_shoes"],"tags":[],"category":"Objects","description":"ballet shoes","unicode_version":"12.0"},{"emoji":"๐Ÿ‘ข","aliases":["boot"],"tags":[],"category":"Objects","description":"womanโ€™s boot","unicode_version":"6.0"},{"emoji":"๐Ÿ‘‘","aliases":["crown"],"tags":["king","queen","royal"],"category":"Objects","description":"crown","unicode_version":"6.0"},{"emoji":"๐Ÿ‘’","aliases":["womans_hat"],"tags":[],"category":"Objects","description":"womanโ€™s hat","unicode_version":"6.0"},{"emoji":"๐ŸŽฉ","aliases":["tophat"],"tags":["hat","classy"],"category":"Objects","description":"top hat","unicode_version":"6.0"},{"emoji":"๐ŸŽ“","aliases":["mortar_board"],"tags":["education","college","university","graduation"],"category":"Objects","description":"graduation cap","unicode_version":"6.0"},{"emoji":"๐Ÿงข","aliases":["billed_cap"],"tags":[],"category":"Objects","description":"billed cap","unicode_version":"11.0"},{"emoji":"๐Ÿช–","aliases":["military_helmet"],"tags":[],"category":"Objects","description":"military helmet","unicode_version":"13.0"},{"emoji":"โ›‘๏ธ","aliases":["rescue_worker_helmet"],"tags":[],"category":"Objects","description":"rescue workerโ€™s helmet","unicode_version":"5.2"},{"emoji":"๐Ÿ“ฟ","aliases":["prayer_beads"],"tags":[],"category":"Objects","description":"prayer beads","unicode_version":"8.0"},{"emoji":"๐Ÿ’„","aliases":["lipstick"],"tags":["makeup"],"category":"Objects","description":"lipstick","unicode_version":"6.0"},{"emoji":"๐Ÿ’","aliases":["ring"],"tags":["wedding","marriage","engaged"],"category":"Objects","description":"ring","unicode_version":"6.0"},{"emoji":"๐Ÿ’Ž","aliases":["gem"],"tags":["diamond"],"category":"Objects","description":"gem stone","unicode_version":"6.0"},{"emoji":"๐Ÿ”‡","aliases":["mute"],"tags":["sound","volume"],"category":"Objects","description":"muted speaker","unicode_version":"6.0"},{"emoji":"๐Ÿ”ˆ","aliases":["speaker"],"tags":[],"category":"Objects","description":"speaker low volume","unicode_version":"6.0"},{"emoji":"๐Ÿ”‰","aliases":["sound"],"tags":["volume"],"category":"Objects","description":"speaker medium volume","unicode_version":"6.0"},{"emoji":"๐Ÿ”Š","aliases":["loud_sound"],"tags":["volume"],"category":"Objects","description":"speaker high volume","unicode_version":"6.0"},{"emoji":"๐Ÿ“ข","aliases":["loudspeaker"],"tags":["announcement"],"category":"Objects","description":"loudspeaker","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฃ","aliases":["mega"],"tags":[],"category":"Objects","description":"megaphone","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฏ","aliases":["postal_horn"],"tags":[],"category":"Objects","description":"postal horn","unicode_version":"6.0"},{"emoji":"๐Ÿ””","aliases":["bell"],"tags":["sound","notification"],"category":"Objects","description":"bell","unicode_version":"6.0"},{"emoji":"๐Ÿ”•","aliases":["no_bell"],"tags":["volume","off"],"category":"Objects","description":"bell with slash","unicode_version":"6.0"},{"emoji":"๐ŸŽผ","aliases":["musical_score"],"tags":[],"category":"Objects","description":"musical score","unicode_version":"6.0"},{"emoji":"๐ŸŽต","aliases":["musical_note"],"tags":[],"category":"Objects","description":"musical note","unicode_version":"6.0"},{"emoji":"๐ŸŽถ","aliases":["notes"],"tags":["music"],"category":"Objects","description":"musical notes","unicode_version":"6.0"},{"emoji":"๐ŸŽ™๏ธ","aliases":["studio_microphone"],"tags":["podcast"],"category":"Objects","description":"studio microphone","unicode_version":"7.0"},{"emoji":"๐ŸŽš๏ธ","aliases":["level_slider"],"tags":[],"category":"Objects","description":"level slider","unicode_version":"7.0"},{"emoji":"๐ŸŽ›๏ธ","aliases":["control_knobs"],"tags":[],"category":"Objects","description":"control knobs","unicode_version":"7.0"},{"emoji":"๐ŸŽค","aliases":["microphone"],"tags":["sing"],"category":"Objects","description":"microphone","unicode_version":"6.0"},{"emoji":"๐ŸŽง","aliases":["headphones"],"tags":["music","earphones"],"category":"Objects","description":"headphone","unicode_version":"6.0"},{"emoji":"๐Ÿ“ป","aliases":["radio"],"tags":["podcast"],"category":"Objects","description":"radio","unicode_version":"6.0"},{"emoji":"๐ŸŽท","aliases":["saxophone"],"tags":[],"category":"Objects","description":"saxophone","unicode_version":"6.0"},{"emoji":"๐Ÿช—","aliases":["accordion"],"tags":[],"category":"Objects","description":"accordion","unicode_version":"13.0"},{"emoji":"๐ŸŽธ","aliases":["guitar"],"tags":["rock"],"category":"Objects","description":"guitar","unicode_version":"6.0"},{"emoji":"๐ŸŽน","aliases":["musical_keyboard"],"tags":["piano"],"category":"Objects","description":"musical keyboard","unicode_version":"6.0"},{"emoji":"๐ŸŽบ","aliases":["trumpet"],"tags":[],"category":"Objects","description":"trumpet","unicode_version":"6.0"},{"emoji":"๐ŸŽป","aliases":["violin"],"tags":[],"category":"Objects","description":"violin","unicode_version":"6.0"},{"emoji":"๐Ÿช•","aliases":["banjo"],"tags":[],"category":"Objects","description":"banjo","unicode_version":"12.0"},{"emoji":"๐Ÿฅ","aliases":["drum"],"tags":[],"category":"Objects","description":"drum","unicode_version":""},{"emoji":"๐Ÿช˜","aliases":["long_drum"],"tags":[],"category":"Objects","description":"long drum","unicode_version":"13.0"},{"emoji":"๐Ÿ“ฑ","aliases":["iphone"],"tags":["smartphone","mobile"],"category":"Objects","description":"mobile phone","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฒ","aliases":["calling"],"tags":["call","incoming"],"category":"Objects","description":"mobile phone with arrow","unicode_version":"6.0"},{"emoji":"โ˜Ž๏ธ","aliases":["phone","telephone"],"tags":[],"category":"Objects","description":"telephone","unicode_version":""},{"emoji":"๐Ÿ“ž","aliases":["telephone_receiver"],"tags":["phone","call"],"category":"Objects","description":"telephone receiver","unicode_version":"6.0"},{"emoji":"๐Ÿ“Ÿ","aliases":["pager"],"tags":[],"category":"Objects","description":"pager","unicode_version":"6.0"},{"emoji":"๐Ÿ“ ","aliases":["fax"],"tags":[],"category":"Objects","description":"fax machine","unicode_version":"6.0"},{"emoji":"๐Ÿ”‹","aliases":["battery"],"tags":["power"],"category":"Objects","description":"battery","unicode_version":"6.0"},{"emoji":"๐Ÿ”Œ","aliases":["electric_plug"],"tags":[],"category":"Objects","description":"electric plug","unicode_version":"6.0"},{"emoji":"๐Ÿ’ป","aliases":["computer"],"tags":["desktop","screen"],"category":"Objects","description":"laptop","unicode_version":"6.0"},{"emoji":"๐Ÿ–ฅ๏ธ","aliases":["desktop_computer"],"tags":[],"category":"Objects","description":"desktop computer","unicode_version":"7.0"},{"emoji":"๐Ÿ–จ๏ธ","aliases":["printer"],"tags":[],"category":"Objects","description":"printer","unicode_version":"7.0"},{"emoji":"โŒจ๏ธ","aliases":["keyboard"],"tags":[],"category":"Objects","description":"keyboard","unicode_version":""},{"emoji":"๐Ÿ–ฑ๏ธ","aliases":["computer_mouse"],"tags":[],"category":"Objects","description":"computer mouse","unicode_version":"7.0"},{"emoji":"๐Ÿ–ฒ๏ธ","aliases":["trackball"],"tags":[],"category":"Objects","description":"trackball","unicode_version":"7.0"},{"emoji":"๐Ÿ’ฝ","aliases":["minidisc"],"tags":[],"category":"Objects","description":"computer disk","unicode_version":"6.0"},{"emoji":"๐Ÿ’พ","aliases":["floppy_disk"],"tags":["save"],"category":"Objects","description":"floppy disk","unicode_version":"6.0"},{"emoji":"๐Ÿ’ฟ","aliases":["cd"],"tags":[],"category":"Objects","description":"optical disk","unicode_version":"6.0"},{"emoji":"๐Ÿ“€","aliases":["dvd"],"tags":[],"category":"Objects","description":"dvd","unicode_version":"6.0"},{"emoji":"๐Ÿงฎ","aliases":["abacus"],"tags":[],"category":"Objects","description":"abacus","unicode_version":"11.0"},{"emoji":"๐ŸŽฅ","aliases":["movie_camera"],"tags":["film","video"],"category":"Objects","description":"movie camera","unicode_version":"6.0"},{"emoji":"๐ŸŽž๏ธ","aliases":["film_strip"],"tags":[],"category":"Objects","description":"film frames","unicode_version":"7.0"},{"emoji":"๐Ÿ“ฝ๏ธ","aliases":["film_projector"],"tags":[],"category":"Objects","description":"film projector","unicode_version":"7.0"},{"emoji":"๐ŸŽฌ","aliases":["clapper"],"tags":["film"],"category":"Objects","description":"clapper board","unicode_version":"6.0"},{"emoji":"๐Ÿ“บ","aliases":["tv"],"tags":[],"category":"Objects","description":"television","unicode_version":"6.0"},{"emoji":"๐Ÿ“ท","aliases":["camera"],"tags":["photo"],"category":"Objects","description":"camera","unicode_version":"6.0"},{"emoji":"๐Ÿ“ธ","aliases":["camera_flash"],"tags":["photo"],"category":"Objects","description":"camera with flash","unicode_version":"7.0"},{"emoji":"๐Ÿ“น","aliases":["video_camera"],"tags":[],"category":"Objects","description":"video camera","unicode_version":"6.0"},{"emoji":"๐Ÿ“ผ","aliases":["vhs"],"tags":[],"category":"Objects","description":"videocassette","unicode_version":"6.0"},{"emoji":"๐Ÿ”","aliases":["mag"],"tags":["search","zoom"],"category":"Objects","description":"magnifying glass tilted left","unicode_version":"6.0"},{"emoji":"๐Ÿ”Ž","aliases":["mag_right"],"tags":[],"category":"Objects","description":"magnifying glass tilted right","unicode_version":"6.0"},{"emoji":"๐Ÿ•ฏ๏ธ","aliases":["candle"],"tags":[],"category":"Objects","description":"candle","unicode_version":"7.0"},{"emoji":"๐Ÿ’ก","aliases":["bulb"],"tags":["idea","light"],"category":"Objects","description":"light bulb","unicode_version":"6.0"},{"emoji":"๐Ÿ”ฆ","aliases":["flashlight"],"tags":[],"category":"Objects","description":"flashlight","unicode_version":"6.0"},{"emoji":"๐Ÿฎ","aliases":["izakaya_lantern","lantern"],"tags":[],"category":"Objects","description":"red paper lantern","unicode_version":"6.0"},{"emoji":"๐Ÿช”","aliases":["diya_lamp"],"tags":[],"category":"Objects","description":"diya lamp","unicode_version":"12.0"},{"emoji":"๐Ÿ“”","aliases":["notebook_with_decorative_cover"],"tags":[],"category":"Objects","description":"notebook with decorative cover","unicode_version":"6.0"},{"emoji":"๐Ÿ“•","aliases":["closed_book"],"tags":[],"category":"Objects","description":"closed book","unicode_version":"6.0"},{"emoji":"๐Ÿ“–","aliases":["book","open_book"],"tags":[],"category":"Objects","description":"open book","unicode_version":"6.0"},{"emoji":"๐Ÿ“—","aliases":["green_book"],"tags":[],"category":"Objects","description":"green book","unicode_version":"6.0"},{"emoji":"๐Ÿ“˜","aliases":["blue_book"],"tags":[],"category":"Objects","description":"blue book","unicode_version":"6.0"},{"emoji":"๐Ÿ“™","aliases":["orange_book"],"tags":[],"category":"Objects","description":"orange book","unicode_version":"6.0"},{"emoji":"๐Ÿ“š","aliases":["books"],"tags":["library"],"category":"Objects","description":"books","unicode_version":"6.0"},{"emoji":"๐Ÿ““","aliases":["notebook"],"tags":[],"category":"Objects","description":"notebook","unicode_version":"6.0"},{"emoji":"๐Ÿ“’","aliases":["ledger"],"tags":[],"category":"Objects","description":"ledger","unicode_version":"6.0"},{"emoji":"๐Ÿ“ƒ","aliases":["page_with_curl"],"tags":[],"category":"Objects","description":"page with curl","unicode_version":"6.0"},{"emoji":"๐Ÿ“œ","aliases":["scroll"],"tags":["document"],"category":"Objects","description":"scroll","unicode_version":"6.0"},{"emoji":"๐Ÿ“„","aliases":["page_facing_up"],"tags":["document"],"category":"Objects","description":"page facing up","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฐ","aliases":["newspaper"],"tags":["press"],"category":"Objects","description":"newspaper","unicode_version":"6.0"},{"emoji":"๐Ÿ—ž๏ธ","aliases":["newspaper_roll"],"tags":["press"],"category":"Objects","description":"rolled-up newspaper","unicode_version":"7.0"},{"emoji":"๐Ÿ“‘","aliases":["bookmark_tabs"],"tags":[],"category":"Objects","description":"bookmark tabs","unicode_version":"6.0"},{"emoji":"๐Ÿ”–","aliases":["bookmark"],"tags":[],"category":"Objects","description":"bookmark","unicode_version":"6.0"},{"emoji":"๐Ÿท๏ธ","aliases":["label"],"tags":["tag"],"category":"Objects","description":"label","unicode_version":"7.0"},{"emoji":"๐Ÿ’ฐ","aliases":["moneybag"],"tags":["dollar","cream"],"category":"Objects","description":"money bag","unicode_version":"6.0"},{"emoji":"๐Ÿช™","aliases":["coin"],"tags":[],"category":"Objects","description":"coin","unicode_version":"13.0"},{"emoji":"๐Ÿ’ด","aliases":["yen"],"tags":[],"category":"Objects","description":"yen banknote","unicode_version":"6.0"},{"emoji":"๐Ÿ’ต","aliases":["dollar"],"tags":["money"],"category":"Objects","description":"dollar banknote","unicode_version":"6.0"},{"emoji":"๐Ÿ’ถ","aliases":["euro"],"tags":[],"category":"Objects","description":"euro banknote","unicode_version":"6.0"},{"emoji":"๐Ÿ’ท","aliases":["pound"],"tags":[],"category":"Objects","description":"pound banknote","unicode_version":"6.0"},{"emoji":"๐Ÿ’ธ","aliases":["money_with_wings"],"tags":["dollar"],"category":"Objects","description":"money with wings","unicode_version":"6.0"},{"emoji":"๐Ÿ’ณ","aliases":["credit_card"],"tags":["subscription"],"category":"Objects","description":"credit card","unicode_version":"6.0"},{"emoji":"๐Ÿงพ","aliases":["receipt"],"tags":[],"category":"Objects","description":"receipt","unicode_version":"11.0"},{"emoji":"๐Ÿ’น","aliases":["chart"],"tags":[],"category":"Objects","description":"chart increasing with yen","unicode_version":"6.0"},{"emoji":"โœ‰๏ธ","aliases":["envelope"],"tags":["letter","email"],"category":"Objects","description":"envelope","unicode_version":""},{"emoji":"๐Ÿ“ง","aliases":["email","e-mail"],"tags":[],"category":"Objects","description":"e-mail","unicode_version":"6.0"},{"emoji":"๐Ÿ“จ","aliases":["incoming_envelope"],"tags":[],"category":"Objects","description":"incoming envelope","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฉ","aliases":["envelope_with_arrow"],"tags":[],"category":"Objects","description":"envelope with arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ“ค","aliases":["outbox_tray"],"tags":[],"category":"Objects","description":"outbox tray","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฅ","aliases":["inbox_tray"],"tags":[],"category":"Objects","description":"inbox tray","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฆ","aliases":["package"],"tags":["shipping"],"category":"Objects","description":"package","unicode_version":"6.0"},{"emoji":"๐Ÿ“ซ","aliases":["mailbox"],"tags":[],"category":"Objects","description":"closed mailbox with raised flag","unicode_version":"6.0"},{"emoji":"๐Ÿ“ช","aliases":["mailbox_closed"],"tags":[],"category":"Objects","description":"closed mailbox with lowered flag","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฌ","aliases":["mailbox_with_mail"],"tags":[],"category":"Objects","description":"open mailbox with raised flag","unicode_version":"6.0"},{"emoji":"๐Ÿ“ญ","aliases":["mailbox_with_no_mail"],"tags":[],"category":"Objects","description":"open mailbox with lowered flag","unicode_version":"6.0"},{"emoji":"๐Ÿ“ฎ","aliases":["postbox"],"tags":[],"category":"Objects","description":"postbox","unicode_version":"6.0"},{"emoji":"๐Ÿ—ณ๏ธ","aliases":["ballot_box"],"tags":[],"category":"Objects","description":"ballot box with ballot","unicode_version":"7.0"},{"emoji":"โœ๏ธ","aliases":["pencil2"],"tags":[],"category":"Objects","description":"pencil","unicode_version":""},{"emoji":"โœ’๏ธ","aliases":["black_nib"],"tags":[],"category":"Objects","description":"black nib","unicode_version":""},{"emoji":"๐Ÿ–‹๏ธ","aliases":["fountain_pen"],"tags":[],"category":"Objects","description":"fountain pen","unicode_version":"7.0"},{"emoji":"๐Ÿ–Š๏ธ","aliases":["pen"],"tags":[],"category":"Objects","description":"pen","unicode_version":"7.0"},{"emoji":"๐Ÿ–Œ๏ธ","aliases":["paintbrush"],"tags":[],"category":"Objects","description":"paintbrush","unicode_version":"7.0"},{"emoji":"๐Ÿ–๏ธ","aliases":["crayon"],"tags":[],"category":"Objects","description":"crayon","unicode_version":"7.0"},{"emoji":"๐Ÿ“","aliases":["memo","pencil"],"tags":["document","note"],"category":"Objects","description":"memo","unicode_version":"6.0"},{"emoji":"๐Ÿ’ผ","aliases":["briefcase"],"tags":["business"],"category":"Objects","description":"briefcase","unicode_version":"6.0"},{"emoji":"๐Ÿ“","aliases":["file_folder"],"tags":["directory"],"category":"Objects","description":"file folder","unicode_version":"6.0"},{"emoji":"๐Ÿ“‚","aliases":["open_file_folder"],"tags":[],"category":"Objects","description":"open file folder","unicode_version":"6.0"},{"emoji":"๐Ÿ—‚๏ธ","aliases":["card_index_dividers"],"tags":[],"category":"Objects","description":"card index dividers","unicode_version":"7.0"},{"emoji":"๐Ÿ“…","aliases":["date"],"tags":["calendar","schedule"],"category":"Objects","description":"calendar","unicode_version":"6.0"},{"emoji":"๐Ÿ“†","aliases":["calendar"],"tags":["schedule"],"category":"Objects","description":"tear-off calendar","unicode_version":"6.0"},{"emoji":"๐Ÿ—’๏ธ","aliases":["spiral_notepad"],"tags":[],"category":"Objects","description":"spiral notepad","unicode_version":"7.0"},{"emoji":"๐Ÿ—“๏ธ","aliases":["spiral_calendar"],"tags":[],"category":"Objects","description":"spiral calendar","unicode_version":"7.0"},{"emoji":"๐Ÿ“‡","aliases":["card_index"],"tags":[],"category":"Objects","description":"card index","unicode_version":"6.0"},{"emoji":"๐Ÿ“ˆ","aliases":["chart_with_upwards_trend"],"tags":["graph","metrics"],"category":"Objects","description":"chart increasing","unicode_version":"6.0"},{"emoji":"๐Ÿ“‰","aliases":["chart_with_downwards_trend"],"tags":["graph","metrics"],"category":"Objects","description":"chart decreasing","unicode_version":"6.0"},{"emoji":"๐Ÿ“Š","aliases":["bar_chart"],"tags":["stats","metrics"],"category":"Objects","description":"bar chart","unicode_version":"6.0"},{"emoji":"๐Ÿ“‹","aliases":["clipboard"],"tags":[],"category":"Objects","description":"clipboard","unicode_version":"6.0"},{"emoji":"๐Ÿ“Œ","aliases":["pushpin"],"tags":["location"],"category":"Objects","description":"pushpin","unicode_version":"6.0"},{"emoji":"๐Ÿ“","aliases":["round_pushpin"],"tags":["location"],"category":"Objects","description":"round pushpin","unicode_version":"6.0"},{"emoji":"๐Ÿ“Ž","aliases":["paperclip"],"tags":[],"category":"Objects","description":"paperclip","unicode_version":"6.0"},{"emoji":"๐Ÿ–‡๏ธ","aliases":["paperclips"],"tags":[],"category":"Objects","description":"linked paperclips","unicode_version":"7.0"},{"emoji":"๐Ÿ“","aliases":["straight_ruler"],"tags":[],"category":"Objects","description":"straight ruler","unicode_version":"6.0"},{"emoji":"๐Ÿ“","aliases":["triangular_ruler"],"tags":[],"category":"Objects","description":"triangular ruler","unicode_version":"6.0"},{"emoji":"โœ‚๏ธ","aliases":["scissors"],"tags":["cut"],"category":"Objects","description":"scissors","unicode_version":""},{"emoji":"๐Ÿ—ƒ๏ธ","aliases":["card_file_box"],"tags":[],"category":"Objects","description":"card file box","unicode_version":"7.0"},{"emoji":"๐Ÿ—„๏ธ","aliases":["file_cabinet"],"tags":[],"category":"Objects","description":"file cabinet","unicode_version":"7.0"},{"emoji":"๐Ÿ—‘๏ธ","aliases":["wastebasket"],"tags":["trash"],"category":"Objects","description":"wastebasket","unicode_version":"7.0"},{"emoji":"๐Ÿ”’","aliases":["lock"],"tags":["security","private"],"category":"Objects","description":"locked","unicode_version":"6.0"},{"emoji":"๐Ÿ”“","aliases":["unlock"],"tags":["security"],"category":"Objects","description":"unlocked","unicode_version":"6.0"},{"emoji":"๐Ÿ”","aliases":["lock_with_ink_pen"],"tags":[],"category":"Objects","description":"locked with pen","unicode_version":"6.0"},{"emoji":"๐Ÿ”","aliases":["closed_lock_with_key"],"tags":["security"],"category":"Objects","description":"locked with key","unicode_version":"6.0"},{"emoji":"๐Ÿ”‘","aliases":["key"],"tags":["lock","password"],"category":"Objects","description":"key","unicode_version":"6.0"},{"emoji":"๐Ÿ—๏ธ","aliases":["old_key"],"tags":[],"category":"Objects","description":"old key","unicode_version":"7.0"},{"emoji":"๐Ÿ”จ","aliases":["hammer"],"tags":["tool"],"category":"Objects","description":"hammer","unicode_version":"6.0"},{"emoji":"๐Ÿช“","aliases":["axe"],"tags":[],"category":"Objects","description":"axe","unicode_version":"12.0"},{"emoji":"โ›๏ธ","aliases":["pick"],"tags":[],"category":"Objects","description":"pick","unicode_version":"5.2"},{"emoji":"โš’๏ธ","aliases":["hammer_and_pick"],"tags":[],"category":"Objects","description":"hammer and pick","unicode_version":"4.1"},{"emoji":"๐Ÿ› ๏ธ","aliases":["hammer_and_wrench"],"tags":[],"category":"Objects","description":"hammer and wrench","unicode_version":"7.0"},{"emoji":"๐Ÿ—ก๏ธ","aliases":["dagger"],"tags":[],"category":"Objects","description":"dagger","unicode_version":"7.0"},{"emoji":"โš”๏ธ","aliases":["crossed_swords"],"tags":[],"category":"Objects","description":"crossed swords","unicode_version":"4.1"},{"emoji":"๐Ÿ”ซ","aliases":["gun"],"tags":["shoot","weapon"],"category":"Objects","description":"water pistol","unicode_version":"6.0"},{"emoji":"๐Ÿชƒ","aliases":["boomerang"],"tags":[],"category":"Objects","description":"boomerang","unicode_version":"13.0"},{"emoji":"๐Ÿน","aliases":["bow_and_arrow"],"tags":["archery"],"category":"Objects","description":"bow and arrow","unicode_version":"8.0"},{"emoji":"๐Ÿ›ก๏ธ","aliases":["shield"],"tags":[],"category":"Objects","description":"shield","unicode_version":"7.0"},{"emoji":"๐Ÿชš","aliases":["carpentry_saw"],"tags":[],"category":"Objects","description":"carpentry saw","unicode_version":"13.0"},{"emoji":"๐Ÿ”ง","aliases":["wrench"],"tags":["tool"],"category":"Objects","description":"wrench","unicode_version":"6.0"},{"emoji":"๐Ÿช›","aliases":["screwdriver"],"tags":[],"category":"Objects","description":"screwdriver","unicode_version":"13.0"},{"emoji":"๐Ÿ”ฉ","aliases":["nut_and_bolt"],"tags":[],"category":"Objects","description":"nut and bolt","unicode_version":"6.0"},{"emoji":"โš™๏ธ","aliases":["gear"],"tags":[],"category":"Objects","description":"gear","unicode_version":"4.1"},{"emoji":"๐Ÿ—œ๏ธ","aliases":["clamp"],"tags":[],"category":"Objects","description":"clamp","unicode_version":"7.0"},{"emoji":"โš–๏ธ","aliases":["balance_scale"],"tags":[],"category":"Objects","description":"balance scale","unicode_version":"4.1"},{"emoji":"๐Ÿฆฏ","aliases":["probing_cane"],"tags":[],"category":"Objects","description":"white cane","unicode_version":"12.0"},{"emoji":"๐Ÿ”—","aliases":["link"],"tags":[],"category":"Objects","description":"link","unicode_version":"6.0"},{"emoji":"โ›“๏ธ","aliases":["chains"],"tags":[],"category":"Objects","description":"chains","unicode_version":"5.2"},{"emoji":"๐Ÿช","aliases":["hook"],"tags":[],"category":"Objects","description":"hook","unicode_version":"13.0"},{"emoji":"๐Ÿงฐ","aliases":["toolbox"],"tags":[],"category":"Objects","description":"toolbox","unicode_version":"11.0"},{"emoji":"๐Ÿงฒ","aliases":["magnet"],"tags":[],"category":"Objects","description":"magnet","unicode_version":"11.0"},{"emoji":"๐Ÿชœ","aliases":["ladder"],"tags":[],"category":"Objects","description":"ladder","unicode_version":"13.0"},{"emoji":"โš—๏ธ","aliases":["alembic"],"tags":[],"category":"Objects","description":"alembic","unicode_version":"4.1"},{"emoji":"๐Ÿงช","aliases":["test_tube"],"tags":[],"category":"Objects","description":"test tube","unicode_version":"11.0"},{"emoji":"๐Ÿงซ","aliases":["petri_dish"],"tags":[],"category":"Objects","description":"petri dish","unicode_version":"11.0"},{"emoji":"๐Ÿงฌ","aliases":["dna"],"tags":[],"category":"Objects","description":"dna","unicode_version":"11.0"},{"emoji":"๐Ÿ”ฌ","aliases":["microscope"],"tags":["science","laboratory","investigate"],"category":"Objects","description":"microscope","unicode_version":"6.0"},{"emoji":"๐Ÿ”ญ","aliases":["telescope"],"tags":[],"category":"Objects","description":"telescope","unicode_version":"6.0"},{"emoji":"๐Ÿ“ก","aliases":["satellite"],"tags":["signal"],"category":"Objects","description":"satellite antenna","unicode_version":"6.0"},{"emoji":"๐Ÿ’‰","aliases":["syringe"],"tags":["health","hospital","needle"],"category":"Objects","description":"syringe","unicode_version":"6.0"},{"emoji":"๐Ÿฉธ","aliases":["drop_of_blood"],"tags":[],"category":"Objects","description":"drop of blood","unicode_version":"12.0"},{"emoji":"๐Ÿ’Š","aliases":["pill"],"tags":["health","medicine"],"category":"Objects","description":"pill","unicode_version":"6.0"},{"emoji":"๐Ÿฉน","aliases":["adhesive_bandage"],"tags":[],"category":"Objects","description":"adhesive bandage","unicode_version":"12.0"},{"emoji":"๐Ÿฉบ","aliases":["stethoscope"],"tags":[],"category":"Objects","description":"stethoscope","unicode_version":"12.0"},{"emoji":"๐Ÿšช","aliases":["door"],"tags":[],"category":"Objects","description":"door","unicode_version":"6.0"},{"emoji":"๐Ÿ›—","aliases":["elevator"],"tags":[],"category":"Objects","description":"elevator","unicode_version":"13.0"},{"emoji":"๐Ÿชž","aliases":["mirror"],"tags":[],"category":"Objects","description":"mirror","unicode_version":"13.0"},{"emoji":"๐ŸชŸ","aliases":["window"],"tags":[],"category":"Objects","description":"window","unicode_version":"13.0"},{"emoji":"๐Ÿ›๏ธ","aliases":["bed"],"tags":[],"category":"Objects","description":"bed","unicode_version":"7.0"},{"emoji":"๐Ÿ›‹๏ธ","aliases":["couch_and_lamp"],"tags":[],"category":"Objects","description":"couch and lamp","unicode_version":"7.0"},{"emoji":"๐Ÿช‘","aliases":["chair"],"tags":[],"category":"Objects","description":"chair","unicode_version":"12.0"},{"emoji":"๐Ÿšฝ","aliases":["toilet"],"tags":["wc"],"category":"Objects","description":"toilet","unicode_version":"6.0"},{"emoji":"๐Ÿช ","aliases":["plunger"],"tags":[],"category":"Objects","description":"plunger","unicode_version":"13.0"},{"emoji":"๐Ÿšฟ","aliases":["shower"],"tags":["bath"],"category":"Objects","description":"shower","unicode_version":"6.0"},{"emoji":"๐Ÿ›","aliases":["bathtub"],"tags":[],"category":"Objects","description":"bathtub","unicode_version":"6.0"},{"emoji":"๐Ÿชค","aliases":["mouse_trap"],"tags":[],"category":"Objects","description":"mouse trap","unicode_version":"13.0"},{"emoji":"๐Ÿช’","aliases":["razor"],"tags":[],"category":"Objects","description":"razor","unicode_version":"12.0"},{"emoji":"๐Ÿงด","aliases":["lotion_bottle"],"tags":[],"category":"Objects","description":"lotion bottle","unicode_version":"11.0"},{"emoji":"๐Ÿงท","aliases":["safety_pin"],"tags":[],"category":"Objects","description":"safety pin","unicode_version":"11.0"},{"emoji":"๐Ÿงน","aliases":["broom"],"tags":[],"category":"Objects","description":"broom","unicode_version":"11.0"},{"emoji":"๐Ÿงบ","aliases":["basket"],"tags":[],"category":"Objects","description":"basket","unicode_version":"11.0"},{"emoji":"๐Ÿงป","aliases":["roll_of_paper"],"tags":["toilet"],"category":"Objects","description":"roll of paper","unicode_version":"11.0"},{"emoji":"๐Ÿชฃ","aliases":["bucket"],"tags":[],"category":"Objects","description":"bucket","unicode_version":"13.0"},{"emoji":"๐Ÿงผ","aliases":["soap"],"tags":[],"category":"Objects","description":"soap","unicode_version":"11.0"},{"emoji":"๐Ÿชฅ","aliases":["toothbrush"],"tags":[],"category":"Objects","description":"toothbrush","unicode_version":"13.0"},{"emoji":"๐Ÿงฝ","aliases":["sponge"],"tags":[],"category":"Objects","description":"sponge","unicode_version":"11.0"},{"emoji":"๐Ÿงฏ","aliases":["fire_extinguisher"],"tags":[],"category":"Objects","description":"fire extinguisher","unicode_version":"11.0"},{"emoji":"๐Ÿ›’","aliases":["shopping_cart"],"tags":[],"category":"Objects","description":"shopping cart","unicode_version":"9.0"},{"emoji":"๐Ÿšฌ","aliases":["smoking"],"tags":["cigarette"],"category":"Objects","description":"cigarette","unicode_version":"6.0"},{"emoji":"โšฐ๏ธ","aliases":["coffin"],"tags":["funeral"],"category":"Objects","description":"coffin","unicode_version":"4.1"},{"emoji":"๐Ÿชฆ","aliases":["headstone"],"tags":[],"category":"Objects","description":"headstone","unicode_version":"13.0"},{"emoji":"โšฑ๏ธ","aliases":["funeral_urn"],"tags":[],"category":"Objects","description":"funeral urn","unicode_version":"4.1"},{"emoji":"๐Ÿ—ฟ","aliases":["moyai"],"tags":["stone"],"category":"Objects","description":"moai","unicode_version":"6.0"},{"emoji":"๐Ÿชง","aliases":["placard"],"tags":[],"category":"Objects","description":"placard","unicode_version":"13.0"},{"emoji":"๐Ÿง","aliases":["atm"],"tags":[],"category":"Symbols","description":"ATM sign","unicode_version":"6.0"},{"emoji":"๐Ÿšฎ","aliases":["put_litter_in_its_place"],"tags":[],"category":"Symbols","description":"litter in bin sign","unicode_version":"6.0"},{"emoji":"๐Ÿšฐ","aliases":["potable_water"],"tags":[],"category":"Symbols","description":"potable water","unicode_version":"6.0"},{"emoji":"โ™ฟ","aliases":["wheelchair"],"tags":["accessibility"],"category":"Symbols","description":"wheelchair symbol","unicode_version":"4.1"},{"emoji":"๐Ÿšน","aliases":["mens"],"tags":[],"category":"Symbols","description":"menโ€™s room","unicode_version":"6.0"},{"emoji":"๐Ÿšบ","aliases":["womens"],"tags":[],"category":"Symbols","description":"womenโ€™s room","unicode_version":"6.0"},{"emoji":"๐Ÿšป","aliases":["restroom"],"tags":["toilet"],"category":"Symbols","description":"restroom","unicode_version":"6.0"},{"emoji":"๐Ÿšผ","aliases":["baby_symbol"],"tags":[],"category":"Symbols","description":"baby symbol","unicode_version":"6.0"},{"emoji":"๐Ÿšพ","aliases":["wc"],"tags":["toilet","restroom"],"category":"Symbols","description":"water closet","unicode_version":"6.0"},{"emoji":"๐Ÿ›‚","aliases":["passport_control"],"tags":[],"category":"Symbols","description":"passport control","unicode_version":"6.0"},{"emoji":"๐Ÿ›ƒ","aliases":["customs"],"tags":[],"category":"Symbols","description":"customs","unicode_version":"6.0"},{"emoji":"๐Ÿ›„","aliases":["baggage_claim"],"tags":["airport"],"category":"Symbols","description":"baggage claim","unicode_version":"6.0"},{"emoji":"๐Ÿ›…","aliases":["left_luggage"],"tags":[],"category":"Symbols","description":"left luggage","unicode_version":"6.0"},{"emoji":"โš ๏ธ","aliases":["warning"],"tags":["wip"],"category":"Symbols","description":"warning","unicode_version":"4.0"},{"emoji":"๐Ÿšธ","aliases":["children_crossing"],"tags":[],"category":"Symbols","description":"children crossing","unicode_version":"6.0"},{"emoji":"โ›”","aliases":["no_entry"],"tags":["limit"],"category":"Symbols","description":"no entry","unicode_version":"5.2"},{"emoji":"๐Ÿšซ","aliases":["no_entry_sign"],"tags":["block","forbidden"],"category":"Symbols","description":"prohibited","unicode_version":"6.0"},{"emoji":"๐Ÿšณ","aliases":["no_bicycles"],"tags":[],"category":"Symbols","description":"no bicycles","unicode_version":"6.0"},{"emoji":"๐Ÿšญ","aliases":["no_smoking"],"tags":[],"category":"Symbols","description":"no smoking","unicode_version":"6.0"},{"emoji":"๐Ÿšฏ","aliases":["do_not_litter"],"tags":[],"category":"Symbols","description":"no littering","unicode_version":"6.0"},{"emoji":"๐Ÿšฑ","aliases":["non-potable_water"],"tags":[],"category":"Symbols","description":"non-potable water","unicode_version":"6.0"},{"emoji":"๐Ÿšท","aliases":["no_pedestrians"],"tags":[],"category":"Symbols","description":"no pedestrians","unicode_version":"6.0"},{"emoji":"๐Ÿ“ต","aliases":["no_mobile_phones"],"tags":[],"category":"Symbols","description":"no mobile phones","unicode_version":"6.0"},{"emoji":"๐Ÿ”ž","aliases":["underage"],"tags":[],"category":"Symbols","description":"no one under eighteen","unicode_version":"6.0"},{"emoji":"โ˜ข๏ธ","aliases":["radioactive"],"tags":[],"category":"Symbols","description":"radioactive","unicode_version":""},{"emoji":"โ˜ฃ๏ธ","aliases":["biohazard"],"tags":[],"category":"Symbols","description":"biohazard","unicode_version":""},{"emoji":"โฌ†๏ธ","aliases":["arrow_up"],"tags":[],"category":"Symbols","description":"up arrow","unicode_version":"4.0"},{"emoji":"โ†—๏ธ","aliases":["arrow_upper_right"],"tags":[],"category":"Symbols","description":"up-right arrow","unicode_version":""},{"emoji":"โžก๏ธ","aliases":["arrow_right"],"tags":[],"category":"Symbols","description":"right arrow","unicode_version":""},{"emoji":"โ†˜๏ธ","aliases":["arrow_lower_right"],"tags":[],"category":"Symbols","description":"down-right arrow","unicode_version":""},{"emoji":"โฌ‡๏ธ","aliases":["arrow_down"],"tags":[],"category":"Symbols","description":"down arrow","unicode_version":"4.0"},{"emoji":"โ†™๏ธ","aliases":["arrow_lower_left"],"tags":[],"category":"Symbols","description":"down-left arrow","unicode_version":""},{"emoji":"โฌ…๏ธ","aliases":["arrow_left"],"tags":[],"category":"Symbols","description":"left arrow","unicode_version":"4.0"},{"emoji":"โ†–๏ธ","aliases":["arrow_upper_left"],"tags":[],"category":"Symbols","description":"up-left arrow","unicode_version":""},{"emoji":"โ†•๏ธ","aliases":["arrow_up_down"],"tags":[],"category":"Symbols","description":"up-down arrow","unicode_version":""},{"emoji":"โ†”๏ธ","aliases":["left_right_arrow"],"tags":[],"category":"Symbols","description":"left-right arrow","unicode_version":""},{"emoji":"โ†ฉ๏ธ","aliases":["leftwards_arrow_with_hook"],"tags":["return"],"category":"Symbols","description":"right arrow curving left","unicode_version":""},{"emoji":"โ†ช๏ธ","aliases":["arrow_right_hook"],"tags":[],"category":"Symbols","description":"left arrow curving right","unicode_version":""},{"emoji":"โคด๏ธ","aliases":["arrow_heading_up"],"tags":[],"category":"Symbols","description":"right arrow curving up","unicode_version":""},{"emoji":"โคต๏ธ","aliases":["arrow_heading_down"],"tags":[],"category":"Symbols","description":"right arrow curving down","unicode_version":""},{"emoji":"๐Ÿ”ƒ","aliases":["arrows_clockwise"],"tags":[],"category":"Symbols","description":"clockwise vertical arrows","unicode_version":"6.0"},{"emoji":"๐Ÿ”„","aliases":["arrows_counterclockwise"],"tags":["sync"],"category":"Symbols","description":"counterclockwise arrows button","unicode_version":"6.0"},{"emoji":"๐Ÿ”™","aliases":["back"],"tags":[],"category":"Symbols","description":"BACK arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ”š","aliases":["end"],"tags":[],"category":"Symbols","description":"END arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ”›","aliases":["on"],"tags":[],"category":"Symbols","description":"ON! arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ”œ","aliases":["soon"],"tags":[],"category":"Symbols","description":"SOON arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ”","aliases":["top"],"tags":[],"category":"Symbols","description":"TOP arrow","unicode_version":"6.0"},{"emoji":"๐Ÿ›","aliases":["place_of_worship"],"tags":[],"category":"Symbols","description":"place of worship","unicode_version":"8.0"},{"emoji":"โš›๏ธ","aliases":["atom_symbol"],"tags":[],"category":"Symbols","description":"atom symbol","unicode_version":"4.1"},{"emoji":"๐Ÿ•‰๏ธ","aliases":["om"],"tags":[],"category":"Symbols","description":"om","unicode_version":"7.0"},{"emoji":"โœก๏ธ","aliases":["star_of_david"],"tags":[],"category":"Symbols","description":"star of David","unicode_version":""},{"emoji":"โ˜ธ๏ธ","aliases":["wheel_of_dharma"],"tags":[],"category":"Symbols","description":"wheel of dharma","unicode_version":""},{"emoji":"โ˜ฏ๏ธ","aliases":["yin_yang"],"tags":[],"category":"Symbols","description":"yin yang","unicode_version":""},{"emoji":"โœ๏ธ","aliases":["latin_cross"],"tags":[],"category":"Symbols","description":"latin cross","unicode_version":""},{"emoji":"โ˜ฆ๏ธ","aliases":["orthodox_cross"],"tags":[],"category":"Symbols","description":"orthodox cross","unicode_version":""},{"emoji":"โ˜ช๏ธ","aliases":["star_and_crescent"],"tags":[],"category":"Symbols","description":"star and crescent","unicode_version":""},{"emoji":"โ˜ฎ๏ธ","aliases":["peace_symbol"],"tags":[],"category":"Symbols","description":"peace symbol","unicode_version":""},{"emoji":"๐Ÿ•Ž","aliases":["menorah"],"tags":[],"category":"Symbols","description":"menorah","unicode_version":"8.0"},{"emoji":"๐Ÿ”ฏ","aliases":["six_pointed_star"],"tags":[],"category":"Symbols","description":"dotted six-pointed star","unicode_version":"6.0"},{"emoji":"โ™ˆ","aliases":["aries"],"tags":[],"category":"Symbols","description":"Aries","unicode_version":""},{"emoji":"โ™‰","aliases":["taurus"],"tags":[],"category":"Symbols","description":"Taurus","unicode_version":""},{"emoji":"โ™Š","aliases":["gemini"],"tags":[],"category":"Symbols","description":"Gemini","unicode_version":""},{"emoji":"โ™‹","aliases":["cancer"],"tags":[],"category":"Symbols","description":"Cancer","unicode_version":""},{"emoji":"โ™Œ","aliases":["leo"],"tags":[],"category":"Symbols","description":"Leo","unicode_version":""},{"emoji":"โ™","aliases":["virgo"],"tags":[],"category":"Symbols","description":"Virgo","unicode_version":""},{"emoji":"โ™Ž","aliases":["libra"],"tags":[],"category":"Symbols","description":"Libra","unicode_version":""},{"emoji":"โ™","aliases":["scorpius"],"tags":[],"category":"Symbols","description":"Scorpio","unicode_version":""},{"emoji":"โ™","aliases":["sagittarius"],"tags":[],"category":"Symbols","description":"Sagittarius","unicode_version":""},{"emoji":"โ™‘","aliases":["capricorn"],"tags":[],"category":"Symbols","description":"Capricorn","unicode_version":""},{"emoji":"โ™’","aliases":["aquarius"],"tags":[],"category":"Symbols","description":"Aquarius","unicode_version":""},{"emoji":"โ™“","aliases":["pisces"],"tags":[],"category":"Symbols","description":"Pisces","unicode_version":""},{"emoji":"โ›Ž","aliases":["ophiuchus"],"tags":[],"category":"Symbols","description":"Ophiuchus","unicode_version":"6.0"},{"emoji":"๐Ÿ”€","aliases":["twisted_rightwards_arrows"],"tags":["shuffle"],"category":"Symbols","description":"shuffle tracks button","unicode_version":"6.0"},{"emoji":"๐Ÿ”","aliases":["repeat"],"tags":["loop"],"category":"Symbols","description":"repeat button","unicode_version":"6.0"},{"emoji":"๐Ÿ”‚","aliases":["repeat_one"],"tags":[],"category":"Symbols","description":"repeat single button","unicode_version":"6.0"},{"emoji":"โ–ถ๏ธ","aliases":["arrow_forward"],"tags":[],"category":"Symbols","description":"play button","unicode_version":""},{"emoji":"โฉ","aliases":["fast_forward"],"tags":[],"category":"Symbols","description":"fast-forward button","unicode_version":"6.0"},{"emoji":"โญ๏ธ","aliases":["next_track_button"],"tags":[],"category":"Symbols","description":"next track button","unicode_version":"6.0"},{"emoji":"โฏ๏ธ","aliases":["play_or_pause_button"],"tags":[],"category":"Symbols","description":"play or pause button","unicode_version":"6.0"},{"emoji":"โ—€๏ธ","aliases":["arrow_backward"],"tags":[],"category":"Symbols","description":"reverse button","unicode_version":""},{"emoji":"โช","aliases":["rewind"],"tags":[],"category":"Symbols","description":"fast reverse button","unicode_version":"6.0"},{"emoji":"โฎ๏ธ","aliases":["previous_track_button"],"tags":[],"category":"Symbols","description":"last track button","unicode_version":"6.0"},{"emoji":"๐Ÿ”ผ","aliases":["arrow_up_small"],"tags":[],"category":"Symbols","description":"upwards button","unicode_version":"6.0"},{"emoji":"โซ","aliases":["arrow_double_up"],"tags":[],"category":"Symbols","description":"fast up button","unicode_version":"6.0"},{"emoji":"๐Ÿ”ฝ","aliases":["arrow_down_small"],"tags":[],"category":"Symbols","description":"downwards button","unicode_version":"6.0"},{"emoji":"โฌ","aliases":["arrow_double_down"],"tags":[],"category":"Symbols","description":"fast down button","unicode_version":"6.0"},{"emoji":"โธ๏ธ","aliases":["pause_button"],"tags":[],"category":"Symbols","description":"pause button","unicode_version":"7.0"},{"emoji":"โน๏ธ","aliases":["stop_button"],"tags":[],"category":"Symbols","description":"stop button","unicode_version":"7.0"},{"emoji":"โบ๏ธ","aliases":["record_button"],"tags":[],"category":"Symbols","description":"record button","unicode_version":"7.0"},{"emoji":"โ๏ธ","aliases":["eject_button"],"tags":[],"category":"Symbols","description":"eject button","unicode_version":"11.0"},{"emoji":"๐ŸŽฆ","aliases":["cinema"],"tags":["film","movie"],"category":"Symbols","description":"cinema","unicode_version":"6.0"},{"emoji":"๐Ÿ”…","aliases":["low_brightness"],"tags":[],"category":"Symbols","description":"dim button","unicode_version":"6.0"},{"emoji":"๐Ÿ”†","aliases":["high_brightness"],"tags":[],"category":"Symbols","description":"bright button","unicode_version":"6.0"},{"emoji":"๐Ÿ“ถ","aliases":["signal_strength"],"tags":["wifi"],"category":"Symbols","description":"antenna bars","unicode_version":"6.0"},{"emoji":"๐Ÿ“ณ","aliases":["vibration_mode"],"tags":[],"category":"Symbols","description":"vibration mode","unicode_version":"6.0"},{"emoji":"๐Ÿ“ด","aliases":["mobile_phone_off"],"tags":["mute","off"],"category":"Symbols","description":"mobile phone off","unicode_version":"6.0"},{"emoji":"โ™€๏ธ","aliases":["female_sign"],"tags":[],"category":"Symbols","description":"female sign","unicode_version":"11.0"},{"emoji":"โ™‚๏ธ","aliases":["male_sign"],"tags":[],"category":"Symbols","description":"male sign","unicode_version":"11.0"},{"emoji":"โšง๏ธ","aliases":["transgender_symbol"],"tags":[],"category":"Symbols","description":"transgender symbol","unicode_version":"13.0"},{"emoji":"โœ–๏ธ","aliases":["heavy_multiplication_x"],"tags":[],"category":"Symbols","description":"multiply","unicode_version":""},{"emoji":"โž•","aliases":["heavy_plus_sign"],"tags":[],"category":"Symbols","description":"plus","unicode_version":"6.0"},{"emoji":"โž–","aliases":["heavy_minus_sign"],"tags":[],"category":"Symbols","description":"minus","unicode_version":"6.0"},{"emoji":"โž—","aliases":["heavy_division_sign"],"tags":[],"category":"Symbols","description":"divide","unicode_version":"6.0"},{"emoji":"โ™พ๏ธ","aliases":["infinity"],"tags":[],"category":"Symbols","description":"infinity","unicode_version":"11.0"},{"emoji":"โ€ผ๏ธ","aliases":["bangbang"],"tags":[],"category":"Symbols","description":"double exclamation mark","unicode_version":""},{"emoji":"โ‰๏ธ","aliases":["interrobang"],"tags":[],"category":"Symbols","description":"exclamation question mark","unicode_version":"3.0"},{"emoji":"โ“","aliases":["question"],"tags":["confused"],"category":"Symbols","description":"red question mark","unicode_version":"6.0"},{"emoji":"โ”","aliases":["grey_question"],"tags":[],"category":"Symbols","description":"white question mark","unicode_version":"6.0"},{"emoji":"โ•","aliases":["grey_exclamation"],"tags":[],"category":"Symbols","description":"white exclamation mark","unicode_version":"6.0"},{"emoji":"โ—","aliases":["exclamation","heavy_exclamation_mark"],"tags":["bang"],"category":"Symbols","description":"red exclamation mark","unicode_version":"5.2"},{"emoji":"ใ€ฐ๏ธ","aliases":["wavy_dash"],"tags":[],"category":"Symbols","description":"wavy dash","unicode_version":""},{"emoji":"๐Ÿ’ฑ","aliases":["currency_exchange"],"tags":[],"category":"Symbols","description":"currency exchange","unicode_version":"6.0"},{"emoji":"๐Ÿ’ฒ","aliases":["heavy_dollar_sign"],"tags":[],"category":"Symbols","description":"heavy dollar sign","unicode_version":"6.0"},{"emoji":"โš•๏ธ","aliases":["medical_symbol"],"tags":[],"category":"Symbols","description":"medical symbol","unicode_version":"11.0"},{"emoji":"โ™ป๏ธ","aliases":["recycle"],"tags":["environment","green"],"category":"Symbols","description":"recycling symbol","unicode_version":"3.2"},{"emoji":"โšœ๏ธ","aliases":["fleur_de_lis"],"tags":[],"category":"Symbols","description":"fleur-de-lis","unicode_version":"4.1"},{"emoji":"๐Ÿ”ฑ","aliases":["trident"],"tags":[],"category":"Symbols","description":"trident emblem","unicode_version":"6.0"},{"emoji":"๐Ÿ“›","aliases":["name_badge"],"tags":[],"category":"Symbols","description":"name badge","unicode_version":"6.0"},{"emoji":"๐Ÿ”ฐ","aliases":["beginner"],"tags":[],"category":"Symbols","description":"Japanese symbol for beginner","unicode_version":"6.0"},{"emoji":"โญ•","aliases":["o"],"tags":[],"category":"Symbols","description":"hollow red circle","unicode_version":"5.2"},{"emoji":"โœ…","aliases":["white_check_mark"],"tags":[],"category":"Symbols","description":"check mark button","unicode_version":"6.0"},{"emoji":"โ˜‘๏ธ","aliases":["ballot_box_with_check"],"tags":[],"category":"Symbols","description":"check box with check","unicode_version":""},{"emoji":"โœ”๏ธ","aliases":["heavy_check_mark"],"tags":[],"category":"Symbols","description":"check mark","unicode_version":""},{"emoji":"โŒ","aliases":["x"],"tags":[],"category":"Symbols","description":"cross mark","unicode_version":"6.0"},{"emoji":"โŽ","aliases":["negative_squared_cross_mark"],"tags":[],"category":"Symbols","description":"cross mark button","unicode_version":"6.0"},{"emoji":"โžฐ","aliases":["curly_loop"],"tags":[],"category":"Symbols","description":"curly loop","unicode_version":"6.0"},{"emoji":"โžฟ","aliases":["loop"],"tags":[],"category":"Symbols","description":"double curly loop","unicode_version":"6.0"},{"emoji":"ใ€ฝ๏ธ","aliases":["part_alternation_mark"],"tags":[],"category":"Symbols","description":"part alternation mark","unicode_version":"3.2"},{"emoji":"โœณ๏ธ","aliases":["eight_spoked_asterisk"],"tags":[],"category":"Symbols","description":"eight-spoked asterisk","unicode_version":""},{"emoji":"โœด๏ธ","aliases":["eight_pointed_black_star"],"tags":[],"category":"Symbols","description":"eight-pointed star","unicode_version":""},{"emoji":"โ‡๏ธ","aliases":["sparkle"],"tags":[],"category":"Symbols","description":"sparkle","unicode_version":""},{"emoji":"ยฉ๏ธ","aliases":["copyright"],"tags":[],"category":"Symbols","description":"copyright","unicode_version":""},{"emoji":"ยฎ๏ธ","aliases":["registered"],"tags":[],"category":"Symbols","description":"registered","unicode_version":""},{"emoji":"โ„ข๏ธ","aliases":["tm"],"tags":["trademark"],"category":"Symbols","description":"trade mark","unicode_version":""},{"emoji":"#๏ธโƒฃ","aliases":["hash"],"tags":["number"],"category":"Symbols","description":"keycap: #","unicode_version":""},{"emoji":"*๏ธโƒฃ","aliases":["asterisk"],"tags":[],"category":"Symbols","description":"keycap: *","unicode_version":""},{"emoji":"0๏ธโƒฃ","aliases":["zero"],"tags":[],"category":"Symbols","description":"keycap: 0","unicode_version":""},{"emoji":"1๏ธโƒฃ","aliases":["one"],"tags":[],"category":"Symbols","description":"keycap: 1","unicode_version":""},{"emoji":"2๏ธโƒฃ","aliases":["two"],"tags":[],"category":"Symbols","description":"keycap: 2","unicode_version":""},{"emoji":"3๏ธโƒฃ","aliases":["three"],"tags":[],"category":"Symbols","description":"keycap: 3","unicode_version":""},{"emoji":"4๏ธโƒฃ","aliases":["four"],"tags":[],"category":"Symbols","description":"keycap: 4","unicode_version":""},{"emoji":"5๏ธโƒฃ","aliases":["five"],"tags":[],"category":"Symbols","description":"keycap: 5","unicode_version":""},{"emoji":"6๏ธโƒฃ","aliases":["six"],"tags":[],"category":"Symbols","description":"keycap: 6","unicode_version":""},{"emoji":"7๏ธโƒฃ","aliases":["seven"],"tags":[],"category":"Symbols","description":"keycap: 7","unicode_version":""},{"emoji":"8๏ธโƒฃ","aliases":["eight"],"tags":[],"category":"Symbols","description":"keycap: 8","unicode_version":""},{"emoji":"9๏ธโƒฃ","aliases":["nine"],"tags":[],"category":"Symbols","description":"keycap: 9","unicode_version":""},{"emoji":"๐Ÿ”Ÿ","aliases":["keycap_ten"],"tags":[],"category":"Symbols","description":"keycap: 10","unicode_version":"6.0"},{"emoji":"๐Ÿ” ","aliases":["capital_abcd"],"tags":["letters"],"category":"Symbols","description":"input latin uppercase","unicode_version":"6.0"},{"emoji":"๐Ÿ”ก","aliases":["abcd"],"tags":[],"category":"Symbols","description":"input latin lowercase","unicode_version":"6.0"},{"emoji":"๐Ÿ”ข","aliases":["1234"],"tags":["numbers"],"category":"Symbols","description":"input numbers","unicode_version":"6.0"},{"emoji":"๐Ÿ”ฃ","aliases":["symbols"],"tags":[],"category":"Symbols","description":"input symbols","unicode_version":"6.0"},{"emoji":"๐Ÿ”ค","aliases":["abc"],"tags":["alphabet"],"category":"Symbols","description":"input latin letters","unicode_version":"6.0"},{"emoji":"๐Ÿ…ฐ๏ธ","aliases":["a"],"tags":[],"category":"Symbols","description":"A button (blood type)","unicode_version":"6.0"},{"emoji":"๐Ÿ†Ž","aliases":["ab"],"tags":[],"category":"Symbols","description":"AB button (blood type)","unicode_version":"6.0"},{"emoji":"๐Ÿ…ฑ๏ธ","aliases":["b"],"tags":[],"category":"Symbols","description":"B button (blood type)","unicode_version":"6.0"},{"emoji":"๐Ÿ†‘","aliases":["cl"],"tags":[],"category":"Symbols","description":"CL button","unicode_version":"6.0"},{"emoji":"๐Ÿ†’","aliases":["cool"],"tags":[],"category":"Symbols","description":"COOL button","unicode_version":"6.0"},{"emoji":"๐Ÿ†“","aliases":["free"],"tags":[],"category":"Symbols","description":"FREE button","unicode_version":"6.0"},{"emoji":"โ„น๏ธ","aliases":["information_source"],"tags":[],"category":"Symbols","description":"information","unicode_version":"3.0"},{"emoji":"๐Ÿ†”","aliases":["id"],"tags":[],"category":"Symbols","description":"ID button","unicode_version":"6.0"},{"emoji":"โ“‚๏ธ","aliases":["m"],"tags":[],"category":"Symbols","description":"circled M","unicode_version":""},{"emoji":"๐Ÿ†•","aliases":["new"],"tags":["fresh"],"category":"Symbols","description":"NEW button","unicode_version":"6.0"},{"emoji":"๐Ÿ†–","aliases":["ng"],"tags":[],"category":"Symbols","description":"NG button","unicode_version":"6.0"},{"emoji":"๐Ÿ…พ๏ธ","aliases":["o2"],"tags":[],"category":"Symbols","description":"O button (blood type)","unicode_version":"6.0"},{"emoji":"๐Ÿ†—","aliases":["ok"],"tags":["yes"],"category":"Symbols","description":"OK button","unicode_version":"6.0"},{"emoji":"๐Ÿ…ฟ๏ธ","aliases":["parking"],"tags":[],"category":"Symbols","description":"P button","unicode_version":"5.2"},{"emoji":"๐Ÿ†˜","aliases":["sos"],"tags":["help","emergency"],"category":"Symbols","description":"SOS button","unicode_version":"6.0"},{"emoji":"๐Ÿ†™","aliases":["up"],"tags":[],"category":"Symbols","description":"UP! button","unicode_version":"6.0"},{"emoji":"๐Ÿ†š","aliases":["vs"],"tags":[],"category":"Symbols","description":"VS button","unicode_version":"6.0"},{"emoji":"๐Ÿˆ","aliases":["koko"],"tags":[],"category":"Symbols","description":"Japanese โ€œhereโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆ‚๏ธ","aliases":["sa"],"tags":[],"category":"Symbols","description":"Japanese โ€œservice chargeโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆท๏ธ","aliases":["u6708"],"tags":[],"category":"Symbols","description":"Japanese โ€œmonthly amountโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆถ","aliases":["u6709"],"tags":[],"category":"Symbols","description":"Japanese โ€œnot free of chargeโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆฏ","aliases":["u6307"],"tags":[],"category":"Symbols","description":"Japanese โ€œreservedโ€ button","unicode_version":""},{"emoji":"๐Ÿ‰","aliases":["ideograph_advantage"],"tags":[],"category":"Symbols","description":"Japanese โ€œbargainโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆน","aliases":["u5272"],"tags":[],"category":"Symbols","description":"Japanese โ€œdiscountโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆš","aliases":["u7121"],"tags":[],"category":"Symbols","description":"Japanese โ€œfree of chargeโ€ button","unicode_version":""},{"emoji":"๐Ÿˆฒ","aliases":["u7981"],"tags":[],"category":"Symbols","description":"Japanese โ€œprohibitedโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿ‰‘","aliases":["accept"],"tags":[],"category":"Symbols","description":"Japanese โ€œacceptableโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆธ","aliases":["u7533"],"tags":[],"category":"Symbols","description":"Japanese โ€œapplicationโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆด","aliases":["u5408"],"tags":[],"category":"Symbols","description":"Japanese โ€œpassing gradeโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆณ","aliases":["u7a7a"],"tags":[],"category":"Symbols","description":"Japanese โ€œvacancyโ€ button","unicode_version":"6.0"},{"emoji":"ใŠ—๏ธ","aliases":["congratulations"],"tags":[],"category":"Symbols","description":"Japanese โ€œcongratulationsโ€ button","unicode_version":""},{"emoji":"ใŠ™๏ธ","aliases":["secret"],"tags":[],"category":"Symbols","description":"Japanese โ€œsecretโ€ button","unicode_version":""},{"emoji":"๐Ÿˆบ","aliases":["u55b6"],"tags":[],"category":"Symbols","description":"Japanese โ€œopen for businessโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿˆต","aliases":["u6e80"],"tags":[],"category":"Symbols","description":"Japanese โ€œno vacancyโ€ button","unicode_version":"6.0"},{"emoji":"๐Ÿ”ด","aliases":["red_circle"],"tags":[],"category":"Symbols","description":"red circle","unicode_version":"6.0"},{"emoji":"๐ŸŸ ","aliases":["orange_circle"],"tags":[],"category":"Symbols","description":"orange circle","unicode_version":"12.0"},{"emoji":"๐ŸŸก","aliases":["yellow_circle"],"tags":[],"category":"Symbols","description":"yellow circle","unicode_version":"12.0"},{"emoji":"๐ŸŸข","aliases":["green_circle"],"tags":[],"category":"Symbols","description":"green circle","unicode_version":"12.0"},{"emoji":"๐Ÿ”ต","aliases":["large_blue_circle"],"tags":[],"category":"Symbols","description":"blue circle","unicode_version":"6.0"},{"emoji":"๐ŸŸฃ","aliases":["purple_circle"],"tags":[],"category":"Symbols","description":"purple circle","unicode_version":"12.0"},{"emoji":"๐ŸŸค","aliases":["brown_circle"],"tags":[],"category":"Symbols","description":"brown circle","unicode_version":"12.0"},{"emoji":"โšซ","aliases":["black_circle"],"tags":[],"category":"Symbols","description":"black circle","unicode_version":"4.1"},{"emoji":"โšช","aliases":["white_circle"],"tags":[],"category":"Symbols","description":"white circle","unicode_version":"4.1"},{"emoji":"๐ŸŸฅ","aliases":["red_square"],"tags":[],"category":"Symbols","description":"red square","unicode_version":"12.0"},{"emoji":"๐ŸŸง","aliases":["orange_square"],"tags":[],"category":"Symbols","description":"orange square","unicode_version":"12.0"},{"emoji":"๐ŸŸจ","aliases":["yellow_square"],"tags":[],"category":"Symbols","description":"yellow square","unicode_version":"12.0"},{"emoji":"๐ŸŸฉ","aliases":["green_square"],"tags":[],"category":"Symbols","description":"green square","unicode_version":"12.0"},{"emoji":"๐ŸŸฆ","aliases":["blue_square"],"tags":[],"category":"Symbols","description":"blue square","unicode_version":"12.0"},{"emoji":"๐ŸŸช","aliases":["purple_square"],"tags":[],"category":"Symbols","description":"purple square","unicode_version":"12.0"},{"emoji":"๐ŸŸซ","aliases":["brown_square"],"tags":[],"category":"Symbols","description":"brown square","unicode_version":"12.0"},{"emoji":"โฌ›","aliases":["black_large_square"],"tags":[],"category":"Symbols","description":"black large square","unicode_version":"5.1"},{"emoji":"โฌœ","aliases":["white_large_square"],"tags":[],"category":"Symbols","description":"white large square","unicode_version":"5.1"},{"emoji":"โ—ผ๏ธ","aliases":["black_medium_square"],"tags":[],"category":"Symbols","description":"black medium square","unicode_version":"3.2"},{"emoji":"โ—ป๏ธ","aliases":["white_medium_square"],"tags":[],"category":"Symbols","description":"white medium square","unicode_version":"3.2"},{"emoji":"โ—พ","aliases":["black_medium_small_square"],"tags":[],"category":"Symbols","description":"black medium-small square","unicode_version":"3.2"},{"emoji":"โ—ฝ","aliases":["white_medium_small_square"],"tags":[],"category":"Symbols","description":"white medium-small square","unicode_version":"3.2"},{"emoji":"โ–ช๏ธ","aliases":["black_small_square"],"tags":[],"category":"Symbols","description":"black small square","unicode_version":""},{"emoji":"โ–ซ๏ธ","aliases":["white_small_square"],"tags":[],"category":"Symbols","description":"white small square","unicode_version":""},{"emoji":"๐Ÿ”ถ","aliases":["large_orange_diamond"],"tags":[],"category":"Symbols","description":"large orange diamond","unicode_version":"6.0"},{"emoji":"๐Ÿ”ท","aliases":["large_blue_diamond"],"tags":[],"category":"Symbols","description":"large blue diamond","unicode_version":"6.0"},{"emoji":"๐Ÿ”ธ","aliases":["small_orange_diamond"],"tags":[],"category":"Symbols","description":"small orange diamond","unicode_version":"6.0"},{"emoji":"๐Ÿ”น","aliases":["small_blue_diamond"],"tags":[],"category":"Symbols","description":"small blue diamond","unicode_version":"6.0"},{"emoji":"๐Ÿ”บ","aliases":["small_red_triangle"],"tags":[],"category":"Symbols","description":"red triangle pointed up","unicode_version":"6.0"},{"emoji":"๐Ÿ”ป","aliases":["small_red_triangle_down"],"tags":[],"category":"Symbols","description":"red triangle pointed down","unicode_version":"6.0"},{"emoji":"๐Ÿ’ ","aliases":["diamond_shape_with_a_dot_inside"],"tags":[],"category":"Symbols","description":"diamond with a dot","unicode_version":"6.0"},{"emoji":"๐Ÿ”˜","aliases":["radio_button"],"tags":[],"category":"Symbols","description":"radio button","unicode_version":"6.0"},{"emoji":"๐Ÿ”ณ","aliases":["white_square_button"],"tags":[],"category":"Symbols","description":"white square button","unicode_version":"6.0"},{"emoji":"๐Ÿ”ฒ","aliases":["black_square_button"],"tags":[],"category":"Symbols","description":"black square button","unicode_version":"6.0"},{"emoji":"๐Ÿ","aliases":["checkered_flag"],"tags":["milestone","finish"],"category":"Flags","description":"chequered flag","unicode_version":"6.0"},{"emoji":"๐Ÿšฉ","aliases":["triangular_flag_on_post"],"tags":[],"category":"Flags","description":"triangular flag","unicode_version":"6.0"},{"emoji":"๐ŸŽŒ","aliases":["crossed_flags"],"tags":[],"category":"Flags","description":"crossed flags","unicode_version":"6.0"},{"emoji":"๐Ÿด","aliases":["black_flag"],"tags":[],"category":"Flags","description":"black flag","unicode_version":"7.0"},{"emoji":"๐Ÿณ๏ธ","aliases":["white_flag"],"tags":[],"category":"Flags","description":"white flag","unicode_version":"7.0"},{"emoji":"๐Ÿณ๏ธโ€๐ŸŒˆ","aliases":["rainbow_flag"],"tags":["pride"],"category":"Flags","description":"rainbow flag","unicode_version":"6.0"},{"emoji":"๐Ÿณ๏ธโ€โšง๏ธ","aliases":["transgender_flag"],"tags":[],"category":"Flags","description":"transgender flag","unicode_version":"13.0"},{"emoji":"๐Ÿดโ€โ˜ ๏ธ","aliases":["pirate_flag"],"tags":[],"category":"Flags","description":"pirate flag","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡จ","aliases":["ascension_island"],"tags":[],"category":"Flags","description":"flag: Ascension Island","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฉ","aliases":["andorra"],"tags":[],"category":"Flags","description":"flag: Andorra","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ช","aliases":["united_arab_emirates"],"tags":[],"category":"Flags","description":"flag: United Arab Emirates","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ซ","aliases":["afghanistan"],"tags":[],"category":"Flags","description":"flag: Afghanistan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฌ","aliases":["antigua_barbuda"],"tags":[],"category":"Flags","description":"flag: Antigua & Barbuda","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฎ","aliases":["anguilla"],"tags":[],"category":"Flags","description":"flag: Anguilla","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฑ","aliases":["albania"],"tags":[],"category":"Flags","description":"flag: Albania","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฒ","aliases":["armenia"],"tags":[],"category":"Flags","description":"flag: Armenia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ด","aliases":["angola"],"tags":[],"category":"Flags","description":"flag: Angola","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ถ","aliases":["antarctica"],"tags":[],"category":"Flags","description":"flag: Antarctica","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ท","aliases":["argentina"],"tags":[],"category":"Flags","description":"flag: Argentina","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ธ","aliases":["american_samoa"],"tags":[],"category":"Flags","description":"flag: American Samoa","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡น","aliases":["austria"],"tags":[],"category":"Flags","description":"flag: Austria","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡บ","aliases":["australia"],"tags":[],"category":"Flags","description":"flag: Australia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ผ","aliases":["aruba"],"tags":[],"category":"Flags","description":"flag: Aruba","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฝ","aliases":["aland_islands"],"tags":[],"category":"Flags","description":"flag: ร…land Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฆ๐Ÿ‡ฟ","aliases":["azerbaijan"],"tags":[],"category":"Flags","description":"flag: Azerbaijan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฆ","aliases":["bosnia_herzegovina"],"tags":[],"category":"Flags","description":"flag: Bosnia & Herzegovina","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ง","aliases":["barbados"],"tags":[],"category":"Flags","description":"flag: Barbados","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฉ","aliases":["bangladesh"],"tags":[],"category":"Flags","description":"flag: Bangladesh","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ช","aliases":["belgium"],"tags":[],"category":"Flags","description":"flag: Belgium","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ซ","aliases":["burkina_faso"],"tags":[],"category":"Flags","description":"flag: Burkina Faso","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฌ","aliases":["bulgaria"],"tags":[],"category":"Flags","description":"flag: Bulgaria","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ญ","aliases":["bahrain"],"tags":[],"category":"Flags","description":"flag: Bahrain","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฎ","aliases":["burundi"],"tags":[],"category":"Flags","description":"flag: Burundi","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฏ","aliases":["benin"],"tags":[],"category":"Flags","description":"flag: Benin","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฑ","aliases":["st_barthelemy"],"tags":[],"category":"Flags","description":"flag: St. Barthรฉlemy","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฒ","aliases":["bermuda"],"tags":[],"category":"Flags","description":"flag: Bermuda","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ณ","aliases":["brunei"],"tags":[],"category":"Flags","description":"flag: Brunei","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ด","aliases":["bolivia"],"tags":[],"category":"Flags","description":"flag: Bolivia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ถ","aliases":["caribbean_netherlands"],"tags":[],"category":"Flags","description":"flag: Caribbean Netherlands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ท","aliases":["brazil"],"tags":[],"category":"Flags","description":"flag: Brazil","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ธ","aliases":["bahamas"],"tags":[],"category":"Flags","description":"flag: Bahamas","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡น","aliases":["bhutan"],"tags":[],"category":"Flags","description":"flag: Bhutan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ป","aliases":["bouvet_island"],"tags":[],"category":"Flags","description":"flag: Bouvet Island","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ผ","aliases":["botswana"],"tags":[],"category":"Flags","description":"flag: Botswana","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡พ","aliases":["belarus"],"tags":[],"category":"Flags","description":"flag: Belarus","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ง๐Ÿ‡ฟ","aliases":["belize"],"tags":[],"category":"Flags","description":"flag: Belize","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฆ","aliases":["canada"],"tags":[],"category":"Flags","description":"flag: Canada","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡จ","aliases":["cocos_islands"],"tags":["keeling"],"category":"Flags","description":"flag: Cocos (Keeling) Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฉ","aliases":["congo_kinshasa"],"tags":[],"category":"Flags","description":"flag: Congo - Kinshasa","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ซ","aliases":["central_african_republic"],"tags":[],"category":"Flags","description":"flag: Central African Republic","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฌ","aliases":["congo_brazzaville"],"tags":[],"category":"Flags","description":"flag: Congo - Brazzaville","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ญ","aliases":["switzerland"],"tags":[],"category":"Flags","description":"flag: Switzerland","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฎ","aliases":["cote_divoire"],"tags":["ivory"],"category":"Flags","description":"flag: Cรดte dโ€™Ivoire","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฐ","aliases":["cook_islands"],"tags":[],"category":"Flags","description":"flag: Cook Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฑ","aliases":["chile"],"tags":[],"category":"Flags","description":"flag: Chile","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฒ","aliases":["cameroon"],"tags":[],"category":"Flags","description":"flag: Cameroon","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ณ","aliases":["cn"],"tags":["china"],"category":"Flags","description":"flag: China","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ด","aliases":["colombia"],"tags":[],"category":"Flags","description":"flag: Colombia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ต","aliases":["clipperton_island"],"tags":[],"category":"Flags","description":"flag: Clipperton Island","unicode_version":"11.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ท","aliases":["costa_rica"],"tags":[],"category":"Flags","description":"flag: Costa Rica","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡บ","aliases":["cuba"],"tags":[],"category":"Flags","description":"flag: Cuba","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ป","aliases":["cape_verde"],"tags":[],"category":"Flags","description":"flag: Cape Verde","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ผ","aliases":["curacao"],"tags":[],"category":"Flags","description":"flag: Curaรงao","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฝ","aliases":["christmas_island"],"tags":[],"category":"Flags","description":"flag: Christmas Island","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡พ","aliases":["cyprus"],"tags":[],"category":"Flags","description":"flag: Cyprus","unicode_version":"6.0"},{"emoji":"๐Ÿ‡จ๐Ÿ‡ฟ","aliases":["czech_republic"],"tags":[],"category":"Flags","description":"flag: Czechia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ช","aliases":["de"],"tags":["flag","germany"],"category":"Flags","description":"flag: Germany","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฌ","aliases":["diego_garcia"],"tags":[],"category":"Flags","description":"flag: Diego Garcia","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฏ","aliases":["djibouti"],"tags":[],"category":"Flags","description":"flag: Djibouti","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฐ","aliases":["denmark"],"tags":[],"category":"Flags","description":"flag: Denmark","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฒ","aliases":["dominica"],"tags":[],"category":"Flags","description":"flag: Dominica","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ด","aliases":["dominican_republic"],"tags":[],"category":"Flags","description":"flag: Dominican Republic","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฉ๐Ÿ‡ฟ","aliases":["algeria"],"tags":[],"category":"Flags","description":"flag: Algeria","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡ฆ","aliases":["ceuta_melilla"],"tags":[],"category":"Flags","description":"flag: Ceuta & Melilla","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡จ","aliases":["ecuador"],"tags":[],"category":"Flags","description":"flag: Ecuador","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡ช","aliases":["estonia"],"tags":[],"category":"Flags","description":"flag: Estonia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡ฌ","aliases":["egypt"],"tags":[],"category":"Flags","description":"flag: Egypt","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡ญ","aliases":["western_sahara"],"tags":[],"category":"Flags","description":"flag: Western Sahara","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡ท","aliases":["eritrea"],"tags":[],"category":"Flags","description":"flag: Eritrea","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡ธ","aliases":["es"],"tags":["spain"],"category":"Flags","description":"flag: Spain","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡น","aliases":["ethiopia"],"tags":[],"category":"Flags","description":"flag: Ethiopia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ช๐Ÿ‡บ","aliases":["eu","european_union"],"tags":[],"category":"Flags","description":"flag: European Union","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฎ","aliases":["finland"],"tags":[],"category":"Flags","description":"flag: Finland","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฏ","aliases":["fiji"],"tags":[],"category":"Flags","description":"flag: Fiji","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฐ","aliases":["falkland_islands"],"tags":[],"category":"Flags","description":"flag: Falkland Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ฒ","aliases":["micronesia"],"tags":[],"category":"Flags","description":"flag: Micronesia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ด","aliases":["faroe_islands"],"tags":[],"category":"Flags","description":"flag: Faroe Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ซ๐Ÿ‡ท","aliases":["fr"],"tags":["france","french"],"category":"Flags","description":"flag: France","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฆ","aliases":["gabon"],"tags":[],"category":"Flags","description":"flag: Gabon","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ง","aliases":["gb","uk"],"tags":["flag","british"],"category":"Flags","description":"flag: United Kingdom","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฉ","aliases":["grenada"],"tags":[],"category":"Flags","description":"flag: Grenada","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ช","aliases":["georgia"],"tags":[],"category":"Flags","description":"flag: Georgia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ซ","aliases":["french_guiana"],"tags":[],"category":"Flags","description":"flag: French Guiana","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฌ","aliases":["guernsey"],"tags":[],"category":"Flags","description":"flag: Guernsey","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ญ","aliases":["ghana"],"tags":[],"category":"Flags","description":"flag: Ghana","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฎ","aliases":["gibraltar"],"tags":[],"category":"Flags","description":"flag: Gibraltar","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฑ","aliases":["greenland"],"tags":[],"category":"Flags","description":"flag: Greenland","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ฒ","aliases":["gambia"],"tags":[],"category":"Flags","description":"flag: Gambia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ณ","aliases":["guinea"],"tags":[],"category":"Flags","description":"flag: Guinea","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ต","aliases":["guadeloupe"],"tags":[],"category":"Flags","description":"flag: Guadeloupe","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ถ","aliases":["equatorial_guinea"],"tags":[],"category":"Flags","description":"flag: Equatorial Guinea","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ท","aliases":["greece"],"tags":[],"category":"Flags","description":"flag: Greece","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ธ","aliases":["south_georgia_south_sandwich_islands"],"tags":[],"category":"Flags","description":"flag: South Georgia & South Sandwich Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡น","aliases":["guatemala"],"tags":[],"category":"Flags","description":"flag: Guatemala","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡บ","aliases":["guam"],"tags":[],"category":"Flags","description":"flag: Guam","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡ผ","aliases":["guinea_bissau"],"tags":[],"category":"Flags","description":"flag: Guinea-Bissau","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฌ๐Ÿ‡พ","aliases":["guyana"],"tags":[],"category":"Flags","description":"flag: Guyana","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ฐ","aliases":["hong_kong"],"tags":[],"category":"Flags","description":"flag: Hong Kong SAR China","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ฒ","aliases":["heard_mcdonald_islands"],"tags":[],"category":"Flags","description":"flag: Heard & McDonald Islands","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ณ","aliases":["honduras"],"tags":[],"category":"Flags","description":"flag: Honduras","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ญ๐Ÿ‡ท","aliases":["croatia"],"tags":[],"category":"Flags","description":"flag: Croatia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ญ๐Ÿ‡น","aliases":["haiti"],"tags":[],"category":"Flags","description":"flag: Haiti","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ญ๐Ÿ‡บ","aliases":["hungary"],"tags":[],"category":"Flags","description":"flag: Hungary","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡จ","aliases":["canary_islands"],"tags":[],"category":"Flags","description":"flag: Canary Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ฉ","aliases":["indonesia"],"tags":[],"category":"Flags","description":"flag: Indonesia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ช","aliases":["ireland"],"tags":[],"category":"Flags","description":"flag: Ireland","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ฑ","aliases":["israel"],"tags":[],"category":"Flags","description":"flag: Israel","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ฒ","aliases":["isle_of_man"],"tags":[],"category":"Flags","description":"flag: Isle of Man","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ณ","aliases":["india"],"tags":[],"category":"Flags","description":"flag: India","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ด","aliases":["british_indian_ocean_territory"],"tags":[],"category":"Flags","description":"flag: British Indian Ocean Territory","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ถ","aliases":["iraq"],"tags":[],"category":"Flags","description":"flag: Iraq","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ท","aliases":["iran"],"tags":[],"category":"Flags","description":"flag: Iran","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡ธ","aliases":["iceland"],"tags":[],"category":"Flags","description":"flag: Iceland","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฎ๐Ÿ‡น","aliases":["it"],"tags":["italy"],"category":"Flags","description":"flag: Italy","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ช","aliases":["jersey"],"tags":[],"category":"Flags","description":"flag: Jersey","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ฒ","aliases":["jamaica"],"tags":[],"category":"Flags","description":"flag: Jamaica","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ด","aliases":["jordan"],"tags":[],"category":"Flags","description":"flag: Jordan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฏ๐Ÿ‡ต","aliases":["jp"],"tags":["japan"],"category":"Flags","description":"flag: Japan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ช","aliases":["kenya"],"tags":[],"category":"Flags","description":"flag: Kenya","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฌ","aliases":["kyrgyzstan"],"tags":[],"category":"Flags","description":"flag: Kyrgyzstan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ญ","aliases":["cambodia"],"tags":[],"category":"Flags","description":"flag: Cambodia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฎ","aliases":["kiribati"],"tags":[],"category":"Flags","description":"flag: Kiribati","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฒ","aliases":["comoros"],"tags":[],"category":"Flags","description":"flag: Comoros","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ณ","aliases":["st_kitts_nevis"],"tags":[],"category":"Flags","description":"flag: St. Kitts & Nevis","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ต","aliases":["north_korea"],"tags":[],"category":"Flags","description":"flag: North Korea","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ท","aliases":["kr"],"tags":["korea"],"category":"Flags","description":"flag: South Korea","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ผ","aliases":["kuwait"],"tags":[],"category":"Flags","description":"flag: Kuwait","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡พ","aliases":["cayman_islands"],"tags":[],"category":"Flags","description":"flag: Cayman Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฐ๐Ÿ‡ฟ","aliases":["kazakhstan"],"tags":[],"category":"Flags","description":"flag: Kazakhstan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ฆ","aliases":["laos"],"tags":[],"category":"Flags","description":"flag: Laos","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ง","aliases":["lebanon"],"tags":[],"category":"Flags","description":"flag: Lebanon","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡จ","aliases":["st_lucia"],"tags":[],"category":"Flags","description":"flag: St. Lucia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ฎ","aliases":["liechtenstein"],"tags":[],"category":"Flags","description":"flag: Liechtenstein","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ฐ","aliases":["sri_lanka"],"tags":[],"category":"Flags","description":"flag: Sri Lanka","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ท","aliases":["liberia"],"tags":[],"category":"Flags","description":"flag: Liberia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ธ","aliases":["lesotho"],"tags":[],"category":"Flags","description":"flag: Lesotho","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡น","aliases":["lithuania"],"tags":[],"category":"Flags","description":"flag: Lithuania","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡บ","aliases":["luxembourg"],"tags":[],"category":"Flags","description":"flag: Luxembourg","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡ป","aliases":["latvia"],"tags":[],"category":"Flags","description":"flag: Latvia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฑ๐Ÿ‡พ","aliases":["libya"],"tags":[],"category":"Flags","description":"flag: Libya","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฆ","aliases":["morocco"],"tags":[],"category":"Flags","description":"flag: Morocco","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡จ","aliases":["monaco"],"tags":[],"category":"Flags","description":"flag: Monaco","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฉ","aliases":["moldova"],"tags":[],"category":"Flags","description":"flag: Moldova","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ช","aliases":["montenegro"],"tags":[],"category":"Flags","description":"flag: Montenegro","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ซ","aliases":["st_martin"],"tags":[],"category":"Flags","description":"flag: St. Martin","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฌ","aliases":["madagascar"],"tags":[],"category":"Flags","description":"flag: Madagascar","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ญ","aliases":["marshall_islands"],"tags":[],"category":"Flags","description":"flag: Marshall Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฐ","aliases":["macedonia"],"tags":[],"category":"Flags","description":"flag: North Macedonia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฑ","aliases":["mali"],"tags":[],"category":"Flags","description":"flag: Mali","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฒ","aliases":["myanmar"],"tags":["burma"],"category":"Flags","description":"flag: Myanmar (Burma)","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ณ","aliases":["mongolia"],"tags":[],"category":"Flags","description":"flag: Mongolia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ด","aliases":["macau"],"tags":[],"category":"Flags","description":"flag: Macao SAR China","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ต","aliases":["northern_mariana_islands"],"tags":[],"category":"Flags","description":"flag: Northern Mariana Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ถ","aliases":["martinique"],"tags":[],"category":"Flags","description":"flag: Martinique","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ท","aliases":["mauritania"],"tags":[],"category":"Flags","description":"flag: Mauritania","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ธ","aliases":["montserrat"],"tags":[],"category":"Flags","description":"flag: Montserrat","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡น","aliases":["malta"],"tags":[],"category":"Flags","description":"flag: Malta","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡บ","aliases":["mauritius"],"tags":[],"category":"Flags","description":"flag: Mauritius","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ป","aliases":["maldives"],"tags":[],"category":"Flags","description":"flag: Maldives","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ผ","aliases":["malawi"],"tags":[],"category":"Flags","description":"flag: Malawi","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฝ","aliases":["mexico"],"tags":[],"category":"Flags","description":"flag: Mexico","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡พ","aliases":["malaysia"],"tags":[],"category":"Flags","description":"flag: Malaysia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฒ๐Ÿ‡ฟ","aliases":["mozambique"],"tags":[],"category":"Flags","description":"flag: Mozambique","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฆ","aliases":["namibia"],"tags":[],"category":"Flags","description":"flag: Namibia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡จ","aliases":["new_caledonia"],"tags":[],"category":"Flags","description":"flag: New Caledonia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ช","aliases":["niger"],"tags":[],"category":"Flags","description":"flag: Niger","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ซ","aliases":["norfolk_island"],"tags":[],"category":"Flags","description":"flag: Norfolk Island","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฌ","aliases":["nigeria"],"tags":[],"category":"Flags","description":"flag: Nigeria","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฎ","aliases":["nicaragua"],"tags":[],"category":"Flags","description":"flag: Nicaragua","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฑ","aliases":["netherlands"],"tags":[],"category":"Flags","description":"flag: Netherlands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ด","aliases":["norway"],"tags":[],"category":"Flags","description":"flag: Norway","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ต","aliases":["nepal"],"tags":[],"category":"Flags","description":"flag: Nepal","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ท","aliases":["nauru"],"tags":[],"category":"Flags","description":"flag: Nauru","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡บ","aliases":["niue"],"tags":[],"category":"Flags","description":"flag: Niue","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ณ๐Ÿ‡ฟ","aliases":["new_zealand"],"tags":[],"category":"Flags","description":"flag: New Zealand","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ด๐Ÿ‡ฒ","aliases":["oman"],"tags":[],"category":"Flags","description":"flag: Oman","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฆ","aliases":["panama"],"tags":[],"category":"Flags","description":"flag: Panama","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ช","aliases":["peru"],"tags":[],"category":"Flags","description":"flag: Peru","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ซ","aliases":["french_polynesia"],"tags":[],"category":"Flags","description":"flag: French Polynesia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฌ","aliases":["papua_new_guinea"],"tags":[],"category":"Flags","description":"flag: Papua New Guinea","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ญ","aliases":["philippines"],"tags":[],"category":"Flags","description":"flag: Philippines","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฐ","aliases":["pakistan"],"tags":[],"category":"Flags","description":"flag: Pakistan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฑ","aliases":["poland"],"tags":[],"category":"Flags","description":"flag: Poland","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ฒ","aliases":["st_pierre_miquelon"],"tags":[],"category":"Flags","description":"flag: St. Pierre & Miquelon","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ณ","aliases":["pitcairn_islands"],"tags":[],"category":"Flags","description":"flag: Pitcairn Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ท","aliases":["puerto_rico"],"tags":[],"category":"Flags","description":"flag: Puerto Rico","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ธ","aliases":["palestinian_territories"],"tags":[],"category":"Flags","description":"flag: Palestinian Territories","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡น","aliases":["portugal"],"tags":[],"category":"Flags","description":"flag: Portugal","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡ผ","aliases":["palau"],"tags":[],"category":"Flags","description":"flag: Palau","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ต๐Ÿ‡พ","aliases":["paraguay"],"tags":[],"category":"Flags","description":"flag: Paraguay","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ถ๐Ÿ‡ฆ","aliases":["qatar"],"tags":[],"category":"Flags","description":"flag: Qatar","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ท๐Ÿ‡ช","aliases":["reunion"],"tags":[],"category":"Flags","description":"flag: Rรฉunion","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ท๐Ÿ‡ด","aliases":["romania"],"tags":[],"category":"Flags","description":"flag: Romania","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ท๐Ÿ‡ธ","aliases":["serbia"],"tags":[],"category":"Flags","description":"flag: Serbia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ท๐Ÿ‡บ","aliases":["ru"],"tags":["russia"],"category":"Flags","description":"flag: Russia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ท๐Ÿ‡ผ","aliases":["rwanda"],"tags":[],"category":"Flags","description":"flag: Rwanda","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฆ","aliases":["saudi_arabia"],"tags":[],"category":"Flags","description":"flag: Saudi Arabia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ง","aliases":["solomon_islands"],"tags":[],"category":"Flags","description":"flag: Solomon Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡จ","aliases":["seychelles"],"tags":[],"category":"Flags","description":"flag: Seychelles","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฉ","aliases":["sudan"],"tags":[],"category":"Flags","description":"flag: Sudan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ช","aliases":["sweden"],"tags":[],"category":"Flags","description":"flag: Sweden","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฌ","aliases":["singapore"],"tags":[],"category":"Flags","description":"flag: Singapore","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ญ","aliases":["st_helena"],"tags":[],"category":"Flags","description":"flag: St. Helena","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฎ","aliases":["slovenia"],"tags":[],"category":"Flags","description":"flag: Slovenia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฏ","aliases":["svalbard_jan_mayen"],"tags":[],"category":"Flags","description":"flag: Svalbard & Jan Mayen","unicode_version":"11.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฐ","aliases":["slovakia"],"tags":[],"category":"Flags","description":"flag: Slovakia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฑ","aliases":["sierra_leone"],"tags":[],"category":"Flags","description":"flag: Sierra Leone","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฒ","aliases":["san_marino"],"tags":[],"category":"Flags","description":"flag: San Marino","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ณ","aliases":["senegal"],"tags":[],"category":"Flags","description":"flag: Senegal","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ด","aliases":["somalia"],"tags":[],"category":"Flags","description":"flag: Somalia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ท","aliases":["suriname"],"tags":[],"category":"Flags","description":"flag: Suriname","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ธ","aliases":["south_sudan"],"tags":[],"category":"Flags","description":"flag: South Sudan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡น","aliases":["sao_tome_principe"],"tags":[],"category":"Flags","description":"flag: Sรฃo Tomรฉ & Prรญncipe","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ป","aliases":["el_salvador"],"tags":[],"category":"Flags","description":"flag: El Salvador","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฝ","aliases":["sint_maarten"],"tags":[],"category":"Flags","description":"flag: Sint Maarten","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡พ","aliases":["syria"],"tags":[],"category":"Flags","description":"flag: Syria","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ธ๐Ÿ‡ฟ","aliases":["swaziland"],"tags":[],"category":"Flags","description":"flag: Eswatini","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฆ","aliases":["tristan_da_cunha"],"tags":[],"category":"Flags","description":"flag: Tristan da Cunha","unicode_version":"11.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡จ","aliases":["turks_caicos_islands"],"tags":[],"category":"Flags","description":"flag: Turks & Caicos Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฉ","aliases":["chad"],"tags":[],"category":"Flags","description":"flag: Chad","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ซ","aliases":["french_southern_territories"],"tags":[],"category":"Flags","description":"flag: French Southern Territories","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฌ","aliases":["togo"],"tags":[],"category":"Flags","description":"flag: Togo","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ญ","aliases":["thailand"],"tags":[],"category":"Flags","description":"flag: Thailand","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฏ","aliases":["tajikistan"],"tags":[],"category":"Flags","description":"flag: Tajikistan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฐ","aliases":["tokelau"],"tags":[],"category":"Flags","description":"flag: Tokelau","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฑ","aliases":["timor_leste"],"tags":[],"category":"Flags","description":"flag: Timor-Leste","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฒ","aliases":["turkmenistan"],"tags":[],"category":"Flags","description":"flag: Turkmenistan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ณ","aliases":["tunisia"],"tags":[],"category":"Flags","description":"flag: Tunisia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ด","aliases":["tonga"],"tags":[],"category":"Flags","description":"flag: Tonga","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ท","aliases":["tr"],"tags":["turkey"],"category":"Flags","description":"flag: Turkey","unicode_version":"8.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡น","aliases":["trinidad_tobago"],"tags":[],"category":"Flags","description":"flag: Trinidad & Tobago","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ป","aliases":["tuvalu"],"tags":[],"category":"Flags","description":"flag: Tuvalu","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ผ","aliases":["taiwan"],"tags":[],"category":"Flags","description":"flag: Taiwan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡น๐Ÿ‡ฟ","aliases":["tanzania"],"tags":[],"category":"Flags","description":"flag: Tanzania","unicode_version":"6.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฆ","aliases":["ukraine"],"tags":[],"category":"Flags","description":"flag: Ukraine","unicode_version":"6.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฌ","aliases":["uganda"],"tags":[],"category":"Flags","description":"flag: Uganda","unicode_version":"6.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฒ","aliases":["us_outlying_islands"],"tags":[],"category":"Flags","description":"flag: U.S. Outlying Islands","unicode_version":"11.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡ณ","aliases":["united_nations"],"tags":[],"category":"Flags","description":"flag: United Nations","unicode_version":"11.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡ธ","aliases":["us"],"tags":["flag","united","america"],"category":"Flags","description":"flag: United States","unicode_version":"6.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡พ","aliases":["uruguay"],"tags":[],"category":"Flags","description":"flag: Uruguay","unicode_version":"6.0"},{"emoji":"๐Ÿ‡บ๐Ÿ‡ฟ","aliases":["uzbekistan"],"tags":[],"category":"Flags","description":"flag: Uzbekistan","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡ฆ","aliases":["vatican_city"],"tags":[],"category":"Flags","description":"flag: Vatican City","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡จ","aliases":["st_vincent_grenadines"],"tags":[],"category":"Flags","description":"flag: St. Vincent & Grenadines","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡ช","aliases":["venezuela"],"tags":[],"category":"Flags","description":"flag: Venezuela","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡ฌ","aliases":["british_virgin_islands"],"tags":[],"category":"Flags","description":"flag: British Virgin Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡ฎ","aliases":["us_virgin_islands"],"tags":[],"category":"Flags","description":"flag: U.S. Virgin Islands","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡ณ","aliases":["vietnam"],"tags":[],"category":"Flags","description":"flag: Vietnam","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ป๐Ÿ‡บ","aliases":["vanuatu"],"tags":[],"category":"Flags","description":"flag: Vanuatu","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ผ๐Ÿ‡ซ","aliases":["wallis_futuna"],"tags":[],"category":"Flags","description":"flag: Wallis & Futuna","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ผ๐Ÿ‡ธ","aliases":["samoa"],"tags":[],"category":"Flags","description":"flag: Samoa","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฝ๐Ÿ‡ฐ","aliases":["kosovo"],"tags":[],"category":"Flags","description":"flag: Kosovo","unicode_version":"6.0"},{"emoji":"๐Ÿ‡พ๐Ÿ‡ช","aliases":["yemen"],"tags":[],"category":"Flags","description":"flag: Yemen","unicode_version":"6.0"},{"emoji":"๐Ÿ‡พ๐Ÿ‡น","aliases":["mayotte"],"tags":[],"category":"Flags","description":"flag: Mayotte","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฟ๐Ÿ‡ฆ","aliases":["south_africa"],"tags":[],"category":"Flags","description":"flag: South Africa","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฟ๐Ÿ‡ฒ","aliases":["zambia"],"tags":[],"category":"Flags","description":"flag: Zambia","unicode_version":"6.0"},{"emoji":"๐Ÿ‡ฟ๐Ÿ‡ผ","aliases":["zimbabwe"],"tags":[],"category":"Flags","description":"flag: Zimbabwe","unicode_version":"6.0"},{"emoji":"๐Ÿด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ","aliases":["england"],"tags":[],"category":"Flags","description":"flag: England","unicode_version":"11.0"},{"emoji":"๐Ÿด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ","aliases":["scotland"],"tags":[],"category":"Flags","description":"flag: Scotland","unicode_version":"11.0"},{"emoji":"๐Ÿด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ","aliases":["wales"],"tags":[],"category":"Flags","description":"flag: Wales","unicode_version":"11.0"}] diff --git a/web/src/app/errors.js b/web/src/app/errors.js index 28f49af..38165a2 100644 --- a/web/src/app/errors.js +++ b/web/src/app/errors.js @@ -1,80 +1,66 @@ -/* eslint-disable max-classes-per-file */ // This is a subset of, and the counterpart to errors.go -const maybeToJson = async (response) => { - try { - return await response.json(); - } catch (e) { - return null; - } +export const fetchOrThrow = async (url, options) => { + const response = await fetch(url, options); + if (response.status !== 200) { + await throwAppError(response); + } + return response; // Promise! }; +export const throwAppError = async (response) => { + if (response.status === 401 || response.status === 403) { + console.log(`[Error] HTTP ${response.status}`, response); + throw new UnauthorizedError(); + } + const error = await maybeToJson(response); + if (error?.code) { + console.log(`[Error] HTTP ${response.status}, ntfy error ${error.code}: ${error.error || ""}`, response); + if (error.code === UserExistsError.CODE) { + throw new UserExistsError(); + } else if (error.code === TopicReservedError.CODE) { + throw new TopicReservedError(); + } else if (error.code === AccountCreateLimitReachedError.CODE) { + throw new AccountCreateLimitReachedError(); + } else if (error.code === IncorrectPasswordError.CODE) { + throw new IncorrectPasswordError(); + } else if (error?.error) { + throw new Error(`Error ${error.code}: ${error.error}`); + } + } + console.log(`[Error] HTTP ${response.status}, not a ntfy error`, response); + throw new Error(`Unexpected response ${response.status}`); +}; + +const maybeToJson = async (response) => { + try { + return await response.json(); + } catch (e) { + return null; + } +} + export class UnauthorizedError extends Error { - constructor() { - super("Unauthorized"); - } + constructor() { super("Unauthorized"); } } export class UserExistsError extends Error { - static CODE = 40901; // errHTTPConflictUserExists - - constructor() { - super("Username already exists"); - } + static CODE = 40901; // errHTTPConflictUserExists + constructor() { super("Username already exists"); } } export class TopicReservedError extends Error { - static CODE = 40902; // errHTTPConflictTopicReserved - - constructor() { - super("Topic already reserved"); - } + static CODE = 40902; // errHTTPConflictTopicReserved + constructor() { super("Topic already reserved"); } } export class AccountCreateLimitReachedError extends Error { - static CODE = 42906; // errHTTPTooManyRequestsLimitAccountCreation - - constructor() { - super("Account creation limit reached"); - } + static CODE = 42906; // errHTTPTooManyRequestsLimitAccountCreation + constructor() { super("Account creation limit reached"); } } export class IncorrectPasswordError extends Error { - static CODE = 40026; // errHTTPBadRequestIncorrectPasswordConfirmation - - constructor() { - super("Password incorrect"); - } + static CODE = 40026; // errHTTPBadRequestIncorrectPasswordConfirmation + constructor() { super("Password incorrect"); } } -export const throwAppError = async (response) => { - if (response.status === 401 || response.status === 403) { - console.log(`[Error] HTTP ${response.status}`, response); - throw new UnauthorizedError(); - } - const error = await maybeToJson(response); - if (error?.code) { - console.log(`[Error] HTTP ${response.status}, ntfy error ${error.code}: ${error.error || ""}`, response); - if (error.code === UserExistsError.CODE) { - throw new UserExistsError(); - } else if (error.code === TopicReservedError.CODE) { - throw new TopicReservedError(); - } else if (error.code === AccountCreateLimitReachedError.CODE) { - throw new AccountCreateLimitReachedError(); - } else if (error.code === IncorrectPasswordError.CODE) { - throw new IncorrectPasswordError(); - } else if (error?.error) { - throw new Error(`Error ${error.code}: ${error.error}`); - } - } - console.log(`[Error] HTTP ${response.status}, not a ntfy error`, response); - throw new Error(`Unexpected response ${response.status}`); -}; - -export const fetchOrThrow = async (url, options) => { - const response = await fetch(url, options); - if (response.status !== 200) { - await throwAppError(response); - } - return response; // Promise! -}; diff --git a/web/src/app/utils.js b/web/src/app/utils.js index ab7551b..6eb4ac5 100644 --- a/web/src/app/utils.js +++ b/web/src/app/utils.js @@ -1,5 +1,4 @@ -import { Base64 } from "js-base64"; -import { rawEmojis } from "./emojis"; +import {rawEmojis} from "./emojis"; import beep from "../sounds/beep.mp3"; import juntos from "../sounds/juntos.mp3"; import pristine from "../sounds/pristine.mp3"; @@ -8,14 +7,12 @@ import dadum from "../sounds/dadum.mp3"; import pop from "../sounds/pop.mp3"; import popSwoosh from "../sounds/pop-swoosh.mp3"; import config from "./config"; +import {Base64} from 'js-base64'; -export const tiersUrl = (baseUrl) => `${baseUrl}/v1/tiers`; -export const shortUrl = (url) => url.replaceAll(/https?:\/\//g, ""); -export const expandUrl = (url) => [`https://${url}`, `http://${url}`]; -export const expandSecureUrl = (url) => `https://${url}`; export const topicUrl = (baseUrl, topic) => `${baseUrl}/${topic}`; -export const topicUrlWs = (baseUrl, topic) => - `${topicUrl(baseUrl, topic)}/ws`.replaceAll("https://", "wss://").replaceAll("http://", "ws://"); +export const topicUrlWs = (baseUrl, topic) => `${topicUrl(baseUrl, topic)}/ws` + .replaceAll("https://", "wss://") + .replaceAll("http://", "ws://"); export const topicUrlJson = (baseUrl, topic) => `${topicUrl(baseUrl, topic)}/json`; export const topicUrlJsonPoll = (baseUrl, topic) => `${topicUrlJson(baseUrl, topic)}?poll=1`; export const topicUrlJsonPollWithSince = (baseUrl, topic, since) => `${topicUrlJson(baseUrl, topic)}?poll=1&since=${since}`; @@ -30,261 +27,276 @@ export const accountReservationUrl = (baseUrl) => `${baseUrl}/v1/account/reserva export const accountReservationSingleUrl = (baseUrl, topic) => `${baseUrl}/v1/account/reservation/${topic}`; export const accountBillingSubscriptionUrl = (baseUrl) => `${baseUrl}/v1/account/billing/subscription`; export const accountBillingPortalUrl = (baseUrl) => `${baseUrl}/v1/account/billing/portal`; -export const accountPhoneUrl = (baseUrl) => `${baseUrl}/v1/account/phone`; -export const accountPhoneVerifyUrl = (baseUrl) => `${baseUrl}/v1/account/phone/verify`; +export const tiersUrl = (baseUrl) => `${baseUrl}/v1/tiers`; +export const shortUrl = (url) => url.replaceAll(/https?:\/\//g, ""); +export const expandUrl = (url) => [`https://${url}`, `http://${url}`]; +export const expandSecureUrl = (url) => `https://${url}`; -export const validUrl = (url) => url.match(/^https?:\/\/.+/); - -export const disallowedTopic = (topic) => config.disallowed_topics.includes(topic); +export const validUrl = (url) => { + return url.match(/^https?:\/\/.+/); +} export const validTopic = (topic) => { - if (disallowedTopic(topic)) { - return false; - } - return topic.match(/^([-_a-zA-Z0-9]{1,64})$/); // Regex must match Go & Android app! -}; + if (disallowedTopic(topic)) { + return false; + } + return topic.match(/^([-_a-zA-Z0-9]{1,64})$/); // Regex must match Go & Android app! +} + +export const disallowedTopic = (topic) => { + return config.disallowed_topics.includes(topic); +} export const topicDisplayName = (subscription) => { - if (subscription.displayName) { - return subscription.displayName; - } - if (subscription.baseUrl === config.base_url) { - return subscription.topic; - } - return topicShortUrl(subscription.baseUrl, subscription.topic); + if (subscription.displayName) { + return subscription.displayName; + } else if (subscription.baseUrl === config.base_url) { + return subscription.topic; + } + return topicShortUrl(subscription.baseUrl, subscription.topic); }; // Format emojis (see emoji.js) const emojis = {}; -rawEmojis.forEach((emoji) => { - emoji.aliases.forEach((alias) => { - emojis[alias] = emoji.emoji; - }); +rawEmojis.forEach(emoji => { + emoji.aliases.forEach(alias => { + emojis[alias] = emoji.emoji; + }); }); const toEmojis = (tags) => { - if (!tags) return []; - return tags.filter((tag) => tag in emojis).map((tag) => emojis[tag]); + if (!tags) return []; + else return tags.filter(tag => tag in emojis).map(tag => emojis[tag]); +} + +export const formatTitleWithDefault = (m, fallback) => { + if (m.title) { + return formatTitle(m); + } + return fallback; }; export const formatTitle = (m) => { - const emojiList = toEmojis(m.tags); - if (emojiList.length > 0) { - return `${emojiList.join(" ")} ${m.title}`; - } - return m.title; -}; - -export const formatTitleWithDefault = (m, fallback) => { - if (m.title) { - return formatTitle(m); - } - return fallback; + const emojiList = toEmojis(m.tags); + if (emojiList.length > 0) { + return `${emojiList.join(" ")} ${m.title}`; + } else { + return m.title; + } }; export const formatMessage = (m) => { - if (m.title) { - return m.message; - } - const emojiList = toEmojis(m.tags); - if (emojiList.length > 0) { - return `${emojiList.join(" ")} ${m.message}`; - } - return m.message; + if (m.title) { + return m.message; + } else { + const emojiList = toEmojis(m.tags); + if (emojiList.length > 0) { + return `${emojiList.join(" ")} ${m.message}`; + } else { + return m.message; + } + } }; export const unmatchedTags = (tags) => { - if (!tags) return []; - return tags.filter((tag) => !(tag in emojis)); -}; - -export const encodeBase64 = (s) => Base64.encode(s); - -export const encodeBase64Url = (s) => Base64.encodeURI(s); - -export const bearerAuth = (token) => `Bearer ${token}`; - -export const basicAuth = (username, password) => `Basic ${encodeBase64(`${username}:${password}`)}`; - -export const withBearerAuth = (headers, token) => ({ ...headers, Authorization: bearerAuth(token) }); - -export const maybeWithBearerAuth = (headers, token) => { - if (token) { - return withBearerAuth(headers, token); - } - return headers; -}; - -export const withBasicAuth = (headers, username, password) => ({ ...headers, Authorization: basicAuth(username, password) }); + if (!tags) return []; + else return tags.filter(tag => !(tag in emojis)); +} export const maybeWithAuth = (headers, user) => { - if (user?.password) { - return withBasicAuth(headers, user.username, user.password); - } - if (user?.token) { - return withBearerAuth(headers, user.token); - } - return headers; -}; + if (user && user.password) { + return withBasicAuth(headers, user.username, user.password); + } else if (user && user.token) { + return withBearerAuth(headers, user.token); + } + return headers; +} + +export const maybeWithBearerAuth = (headers, token) => { + if (token) { + return withBearerAuth(headers, token); + } + return headers; +} + +export const withBasicAuth = (headers, username, password) => { + headers['Authorization'] = basicAuth(username, password); + return headers; +} + +export const basicAuth = (username, password) => { + return `Basic ${encodeBase64(`${username}:${password}`)}`; +} + +export const withBearerAuth = (headers, token) => { + headers['Authorization'] = bearerAuth(token); + return headers; +} + +export const bearerAuth = (token) => { + return `Bearer ${token}`; +} + +export const encodeBase64 = (s) => { + return Base64.encode(s); +} + +export const encodeBase64Url = (s) => { + return Base64.encodeURI(s); +} export const maybeAppendActionErrors = (message, notification) => { - const actionErrors = (notification.actions ?? []) - .map((action) => action.error) - .filter((action) => !!action) - .join("\n"); - if (actionErrors.length === 0) { - return message; - } - return `${message}\n\n${actionErrors}`; -}; + const actionErrors = (notification.actions ?? []) + .map(action => action.error) + .filter(action => !!action) + .join("\n") + if (actionErrors.length === 0) { + return message; + } else { + return `${message}\n\n${actionErrors}`; + } +} export const shuffle = (arr) => { - const returnArr = [...arr]; + let j, x; + for (let index = arr.length - 1; index > 0; index--) { + j = Math.floor(Math.random() * (index + 1)); + x = arr[index]; + arr[index] = arr[j]; + arr[j] = x; + } + return arr; +} - for (let index = returnArr.length - 1; index > 0; index -= 1) { - const j = Math.floor(Math.random() * (index + 1)); - [returnArr[index], returnArr[j]] = [returnArr[j], returnArr[index]]; - } - - return returnArr; -}; - -export const splitNoEmpty = (s, delimiter) => - s - .split(delimiter) - .map((x) => x.trim()) - .filter((x) => x !== ""); +export const splitNoEmpty = (s, delimiter) => { + return s + .split(delimiter) + .map(x => x.trim()) + .filter(x => x !== ""); +} /** Non-cryptographic hash function, see https://stackoverflow.com/a/8831937/1440785 */ export const hashCode = async (s) => { - let hash = 0; - for (let i = 0; i < s.length; i += 1) { - const char = s.charCodeAt(i); - // eslint-disable-next-line no-bitwise - hash = (hash << 5) - hash + char; - // eslint-disable-next-line no-bitwise - hash &= hash; // Convert to 32bit integer - } - return hash; -}; + let hash = 0; + for (let i = 0; i < s.length; i++) { + const char = s.charCodeAt(i); + hash = ((hash<<5)-hash)+char; + hash = hash & hash; // Convert to 32bit integer + } + return hash; +} -export const formatShortDateTime = (timestamp) => - new Intl.DateTimeFormat("default", { - dateStyle: "short", - timeStyle: "short", - }).format(new Date(timestamp * 1000)); +export const formatShortDateTime = (timestamp) => { + return new Intl.DateTimeFormat('default', {dateStyle: 'short', timeStyle: 'short'}) + .format(new Date(timestamp * 1000)); +} -export const formatShortDate = (timestamp) => new Intl.DateTimeFormat("default", { dateStyle: "short" }).format(new Date(timestamp * 1000)); +export const formatShortDate = (timestamp) => { + return new Intl.DateTimeFormat('default', {dateStyle: 'short'}) + .format(new Date(timestamp * 1000)); +} export const formatBytes = (bytes, decimals = 2) => { - if (bytes === 0) return "0 bytes"; - const k = 1024; - const dm = decimals < 0 ? 0 : decimals; - const sizes = ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - const i = Math.floor(Math.log(bytes) / Math.log(k)); - return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`; -}; + if (bytes === 0) return '0 bytes'; + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; +} export const formatNumber = (n) => { - if (n === 0) { + if (n % 1000 === 0) { + return `${n/1000}k`; + } return n; - } - if (n % 1000 === 0) { - return `${n / 1000}k`; - } - return n.toLocaleString(); -}; +} export const formatPrice = (n) => { - if (n % 100 === 0) { - return `$${n / 100}`; - } - return `$${(n / 100).toPrecision(2)}`; -}; + if (n % 100 === 0) { + return `$${n/100}`; + } + return `$${(n/100).toPrecision(2)}`; +} export const openUrl = (url) => { - window.open(url, "_blank", "noopener,noreferrer"); + window.open(url, "_blank", "noopener,noreferrer"); }; export const sounds = { - ding: { - file: ding, - label: "Ding", - }, - juntos: { - file: juntos, - label: "Juntos", - }, - pristine: { - file: pristine, - label: "Pristine", - }, - dadum: { - file: dadum, - label: "Dadum", - }, - pop: { - file: pop, - label: "Pop", - }, - "pop-swoosh": { - file: popSwoosh, - label: "Pop swoosh", - }, - beep: { - file: beep, - label: "Beep", - }, + "ding": { + file: ding, + label: "Ding" + }, + "juntos": { + file: juntos, + label: "Juntos" + }, + "pristine": { + file: pristine, + label: "Pristine" + }, + "dadum": { + file: dadum, + label: "Dadum" + }, + "pop": { + file: pop, + label: "Pop" + }, + "pop-swoosh": { + file: popSwoosh, + label: "Pop swoosh" + }, + "beep": { + file: beep, + label: "Beep" + } }; export const playSound = async (id) => { - const audio = new Audio(sounds[id].file); - return audio.play(); + const audio = new Audio(sounds[id].file); + return audio.play(); }; // From: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch -// eslint-disable-next-line func-style export async function* fetchLinesIterator(fileURL, headers) { - const utf8Decoder = new TextDecoder("utf-8"); - const response = await fetch(fileURL, { - headers, - }); - const reader = response.body.getReader(); - let { value: chunk, done: readerDone } = await reader.read(); - chunk = chunk ? utf8Decoder.decode(chunk) : ""; + const utf8Decoder = new TextDecoder('utf-8'); + const response = await fetch(fileURL, { + headers: headers + }); + const reader = response.body.getReader(); + let { value: chunk, done: readerDone } = await reader.read(); + chunk = chunk ? utf8Decoder.decode(chunk) : ''; - const re = /\n|\r|\r\n/gm; - let startIndex = 0; + const re = /\n|\r|\r\n/gm; + let startIndex = 0; - for (;;) { - const result = re.exec(chunk); - if (!result) { - if (readerDone) { - break; - } - const remainder = chunk.substr(startIndex); - // eslint-disable-next-line no-await-in-loop - ({ value: chunk, done: readerDone } = await reader.read()); - chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : ""); - startIndex = 0; - re.lastIndex = 0; - // eslint-disable-next-line no-continue - continue; + for (;;) { + let result = re.exec(chunk); + if (!result) { + if (readerDone) { + break; + } + let remainder = chunk.substr(startIndex); + ({ value: chunk, done: readerDone } = await reader.read()); + chunk = remainder + (chunk ? utf8Decoder.decode(chunk) : ''); + startIndex = re.lastIndex = 0; + continue; + } + yield chunk.substring(startIndex, result.index); + startIndex = re.lastIndex; + } + if (startIndex < chunk.length) { + yield chunk.substr(startIndex); // last line didn't end in a newline char } - yield chunk.substring(startIndex, result.index); - startIndex = re.lastIndex; - } - if (startIndex < chunk.length) { - yield chunk.substr(startIndex); // last line didn't end in a newline char - } } export const randomAlphanumericString = (len) => { - const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - let id = ""; - for (let i = 0; i < len; i += 1) { - // eslint-disable-next-line no-bitwise - id += alphabet[(Math.random() * alphabet.length) | 0]; - } - return id; -}; + const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + let id = ""; + for (let i = 0; i < len; i++) { + id += alphabet[(Math.random() * alphabet.length) | 0]; + } + return id; +} diff --git a/web/src/components/Account.js b/web/src/components/Account.js new file mode 100644 index 0000000..e5b6007 --- /dev/null +++ b/web/src/components/Account.js @@ -0,0 +1,803 @@ +import * as React from 'react'; +import {useContext, useState} from 'react'; +import { + Alert, + CardActions, + CardContent, + FormControl, + LinearProgress, + Link, + Portal, + Select, + Snackbar, + Stack, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + useMediaQuery +} from "@mui/material"; +import Tooltip from '@mui/material/Tooltip'; +import Typography from "@mui/material/Typography"; +import EditIcon from '@mui/icons-material/Edit'; +import Container from "@mui/material/Container"; +import Card from "@mui/material/Card"; +import Button from "@mui/material/Button"; +import {Trans, useTranslation} from "react-i18next"; +import session from "../app/Session"; +import DeleteOutlineIcon from '@mui/icons-material/DeleteOutline'; +import theme from "./theme"; +import Dialog from "@mui/material/Dialog"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import TextField from "@mui/material/TextField"; +import routes from "./routes"; +import IconButton from "@mui/material/IconButton"; +import {formatBytes, formatShortDate, formatShortDateTime, openUrl} from "../app/utils"; +import accountApi, {LimitBasis, Role, SubscriptionInterval, SubscriptionStatus} from "../app/AccountApi"; +import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined'; +import {Pref, PrefGroup} from "./Pref"; +import db from "../app/db"; +import i18n from "i18next"; +import humanizeDuration from "humanize-duration"; +import UpgradeDialog from "./UpgradeDialog"; +import CelebrationIcon from "@mui/icons-material/Celebration"; +import {AccountContext} from "./App"; +import DialogFooter from "./DialogFooter"; +import {Paragraph} from "./styles"; +import CloseIcon from "@mui/icons-material/Close"; +import {ContentCopy, Public} from "@mui/icons-material"; +import MenuItem from "@mui/material/MenuItem"; +import DialogContentText from "@mui/material/DialogContentText"; +import {IncorrectPasswordError, UnauthorizedError} from "../app/errors"; + +const Account = () => { + if (!session.exists()) { + window.location.href = routes.app; + return <>; + } + return ( + + + + + + + + + ); +}; + +const Basics = () => { + const { t } = useTranslation(); + return ( + + + {t("account_basics_title")} + + + + + + + + ); +}; + +const Username = () => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const labelId = "prefUsername"; + + return ( + +
+ {session.username()} + {account?.role === Role.ADMIN + ? <>{" "}๐Ÿ‘‘ + : ""} +
+
+ ) +}; + +const ChangePassword = () => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + const labelId = "prefChangePassword"; + + const handleDialogOpen = () => { + setDialogKey(prev => prev+1); + setDialogOpen(true); + }; + + const handleDialogClose = () => { + setDialogOpen(false); + }; + + return ( + +
+ โฌคโฌคโฌคโฌคโฌคโฌคโฌคโฌคโฌคโฌค + + + +
+ +
+ ) +}; + +const ChangePasswordDialog = (props) => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [currentPassword, setCurrentPassword] = useState(""); + const [newPassword, setNewPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + const handleDialogSubmit = async () => { + try { + console.debug(`[Account] Changing password`); + await accountApi.changePassword(currentPassword, newPassword); + props.onClose(); + } catch (e) { + console.log(`[Account] Error changing password`, e); + if (e instanceof IncorrectPasswordError) { + setError(t("account_basics_password_dialog_current_password_incorrect")); + } else if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + } + } + }; + + return ( + + {t("account_basics_password_dialog_title")} + + setCurrentPassword(ev.target.value)} + fullWidth + variant="standard" + /> + setNewPassword(ev.target.value)} + fullWidth + variant="standard" + /> + setConfirmPassword(ev.target.value)} + fullWidth + variant="standard" + /> + + + + + + + ); +}; + +const AccountType = () => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const [upgradeDialogKey, setUpgradeDialogKey] = useState(0); + const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false); + const [showPortalError, setShowPortalError] = useState(false); + + if (!account) { + return <>; + } + + const handleUpgradeClick = () => { + setUpgradeDialogKey(k => k + 1); + setUpgradeDialogOpen(true); + } + + const handleManageBilling = async () => { + try { + const response = await accountApi.createBillingPortalSession(); + window.open(response.redirect_url, "billing_portal"); + } catch (e) { + console.log(`[Account] Error opening billing portal`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setShowPortalError(true); + } + } + }; + + let accountType; + if (account.role === Role.ADMIN) { + const tierSuffix = (account.tier) ? t("account_basics_tier_admin_suffix_with_tier", { tier: account.tier.name }) : t("account_basics_tier_admin_suffix_no_tier"); + accountType = `${t("account_basics_tier_admin")} ${tierSuffix}`; + } else if (!account.tier) { + accountType = (config.enable_payments) ? t("account_basics_tier_free") : t("account_basics_tier_basic"); + } else { + accountType = account.tier.name; + if (account.billing?.interval === SubscriptionInterval.MONTH) { + accountType += ` (${t("account_basics_tier_interval_monthly")})`; + } else if (account.billing?.interval === SubscriptionInterval.YEAR) { + accountType += ` (${t("account_basics_tier_interval_yearly")})`; + } + } + + return ( + 0} + title={t("account_basics_tier_title")} + description={t("account_basics_tier_description")} + > +
+ {accountType} + {account.billing?.paid_until && !account.billing?.cancel_at && + + + + } + {config.enable_payments && account.role === Role.USER && !account.billing?.subscription && + + } + {config.enable_payments && account.role === Role.USER && account.billing?.subscription && + + } + {config.enable_payments && account.role === Role.USER && account.billing?.customer && + + } + {config.enable_payments && + setUpgradeDialogOpen(false)} + /> + } +
+ {account.billing?.status === SubscriptionStatus.PAST_DUE && + {t("account_basics_tier_payment_overdue")} + } + {account.billing?.cancel_at > 0 && + {t("account_basics_tier_canceled_subscription", { date: formatShortDate(account.billing.cancel_at) })} + } + + setShowPortalError(false)} + message={t("account_usage_cannot_create_portal_session")} + /> + +
+ ) +}; + +const Stats = () => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + + if (!account) { + return <>; + } + + const normalize = (value, max) => { + return Math.min(value / max * 100, 100); + }; + + return ( + + + {t("account_usage_title")} + + + + {(account.role === Role.ADMIN || account.limits.reservations > 0) && + <> +
+ {account.stats.reservations} + {account.role === Role.USER ? t("account_usage_of_limit", {limit: account.limits.reservations}) : t("account_usage_unlimited")} +
+ 0 ? normalize(account.stats.reservations, account.limits.reservations) : 100} + /> + + } + {account.role === Role.USER && account.limits.reservations === 0 && + {t("account_usage_reservations_none")} + } +
+ + {t("account_usage_messages_title")} + + + }> +
+ {account.stats.messages} + {account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.messages }) : t("account_usage_unlimited")} +
+ +
+ + {t("account_usage_emails_title")} + + + }> +
+ {account.stats.emails} + {account.role === Role.USER ? t("account_usage_of_limit", { limit: account.limits.emails }) : t("account_usage_unlimited")} +
+ +
+ +
+ {formatBytes(account.stats.attachment_total_size)} + {account.role === Role.USER ? t("account_usage_of_limit", { limit: formatBytes(account.limits.attachment_total_size) }) : t("account_usage_unlimited")} +
+ +
+
+ {account.role === Role.USER && account.limits.basis === LimitBasis.IP && + + {t("account_usage_basis_ip_description")} + + } +
+ ); +}; + +const InfoIcon = () => { + return ( + + ); +} + + +const Tokens = () => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + const tokens = account?.tokens || []; + + const handleCreateClick = () => { + setDialogKey(prev => prev+1); + setDialogOpen(true); + }; + + const handleDialogClose = () => { + setDialogOpen(false); + }; + + const handleDialogSubmit = async (user) => { + setDialogOpen(false); + // + }; + return ( + + + + {t("account_tokens_title")} + + + + }} + /> + + {tokens?.length > 0 && } + + + + + + + ); +}; + +const TokensTable = (props) => { + const { t } = useTranslation(); + const [snackOpen, setSnackOpen] = useState(false); + const [upsertDialogKey, setUpsertDialogKey] = useState(0); + const [upsertDialogOpen, setUpsertDialogOpen] = useState(false); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [selectedToken, setSelectedToken] = useState(null); + + const tokens = (props.tokens || []) + .sort( (a, b) => { + if (a.token === session.token()) { + return -1; + } else if (b.token === session.token()) { + return 1; + } + return a.token.localeCompare(b.token); + }); + + const handleEditClick = (token) => { + setUpsertDialogKey(prev => prev+1); + setSelectedToken(token); + setUpsertDialogOpen(true); + }; + + const handleDialogClose = () => { + setUpsertDialogOpen(false); + setDeleteDialogOpen(false); + setSelectedToken(null); + }; + + const handleDeleteClick = async (token) => { + setSelectedToken(token); + setDeleteDialogOpen(true); + }; + + const handleCopy = async (token) => { + await navigator.clipboard.writeText(token); + setSnackOpen(true); + }; + + return ( + + + + {t("account_tokens_table_token_header")} + {t("account_tokens_table_label_header")} + {t("account_tokens_table_expires_header")} + {t("account_tokens_table_last_access_header")} + + + + + {tokens.map(token => ( + + + + {token.token.slice(0, 12)} + ... + + handleCopy(token.token)}> + + + + + {token.token === session.token() && {t("account_tokens_table_current_session")}} + {token.token !== session.token() && (token.label || "-")} + + + {token.expires ? formatShortDateTime(token.expires) : {t("account_tokens_table_never_expires")}} + + +
+ {formatShortDateTime(token.last_access)} + + openUrl(`https://whatismyipaddress.com/ip/${token.last_origin}`)}> + + + +
+
+ + {token.token !== session.token() && + <> + handleEditClick(token)} aria-label={t("account_tokens_dialog_title_edit")}> + + + handleDeleteClick(token)} aria-label={t("account_tokens_dialog_title_delete")}> + + + + } + {token.token === session.token() && + + + + + + + } + +
+ ))} +
+ + setSnackOpen(false)} + message={t("account_tokens_table_copied_to_clipboard")} + /> + + + +
+ ); +}; + +const TokenDialog = (props) => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [label, setLabel] = useState(props.token?.label || ""); + const [expires, setExpires] = useState(props.token ? -1 : 0); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + const editMode = !!props.token; + + const handleSubmit = async () => { + try { + if (editMode) { + await accountApi.updateToken(props.token.token, label, expires); + } else { + await accountApi.createToken(label, expires); + } + props.onClose(); + } catch (e) { + console.log(`[Account] Error creating token`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + } + } + }; + + return ( + + {editMode ? t("account_tokens_dialog_title_edit") : t("account_tokens_dialog_title_create")} + + setLabel(ev.target.value)} + fullWidth + variant="standard" + /> + + + + + + + + + + ); +}; + +const TokenDeleteDialog = (props) => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + + const handleSubmit = async () => { + try { + await accountApi.deleteToken(props.token.token); + props.onClose(); + } catch (e) { + console.log(`[Account] Error deleting token`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + } + } + }; + + return ( + + {t("account_tokens_delete_dialog_title")} + + + + + + + + + + + ); +} + + +const Delete = () => { + const { t } = useTranslation(); + return ( + + + {t("account_delete_title")} + + + + + + ); +}; + +const DeleteAccount = () => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + + const handleDialogOpen = () => { + setDialogKey(prev => prev+1); + setDialogOpen(true); + }; + + const handleDialogClose = () => { + setDialogOpen(false); + }; + + return ( + +
+ +
+ +
+ ) +}; + +const DeleteAccountDialog = (props) => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const [error, setError] = useState(""); + const [password, setPassword] = useState(""); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + const handleSubmit = async () => { + try { + await accountApi.delete(password); + await db.delete(); + console.debug(`[Account] Account deleted`); + session.resetAndRedirect(routes.app); + } catch (e) { + console.log(`[Account] Error deleting account`, e); + if (e instanceof IncorrectPasswordError) { + setError(t("account_basics_password_dialog_current_password_incorrect")); + } else if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + } + } + }; + + return ( + + {t("account_delete_title")} + + + {t("account_delete_dialog_description")} + + setPassword(ev.target.value)} + fullWidth + variant="standard" + /> + {account?.billing?.subscription && + {t("account_delete_dialog_billing_warning")} + } + + + + + + + ); +}; + +export default Account; diff --git a/web/src/components/Account.jsx b/web/src/components/Account.jsx deleted file mode 100644 index 541d4f8..0000000 --- a/web/src/components/Account.jsx +++ /dev/null @@ -1,1128 +0,0 @@ -import * as React from "react"; -import { useContext, useState } from "react"; -import { - Alert, - CardActions, - CardContent, - Chip, - FormControl, - FormControlLabel, - LinearProgress, - Link, - Portal, - Radio, - RadioGroup, - Select, - Snackbar, - Stack, - Table, - TableBody, - TableCell, - TableHead, - TableRow, - useMediaQuery, - Tooltip, - Typography, - Container, - Card, - Button, - Dialog, - DialogTitle, - DialogContent, - TextField, - IconButton, - MenuItem, - DialogContentText, -} from "@mui/material"; -import EditIcon from "@mui/icons-material/Edit"; -import { Trans, useTranslation } from "react-i18next"; -import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; -import i18n from "i18next"; -import humanizeDuration from "humanize-duration"; -import CelebrationIcon from "@mui/icons-material/Celebration"; -import CloseIcon from "@mui/icons-material/Close"; -import { ContentCopy, Public } from "@mui/icons-material"; -import AddIcon from "@mui/icons-material/Add"; -import routes from "./routes"; -import { formatBytes, formatShortDate, formatShortDateTime, openUrl } from "../app/utils"; -import accountApi, { LimitBasis, Role, SubscriptionInterval, SubscriptionStatus } from "../app/AccountApi"; -import { Pref, PrefGroup } from "./Pref"; -import db from "../app/db"; -import UpgradeDialog from "./UpgradeDialog"; -import { AccountContext } from "./App"; -import DialogFooter from "./DialogFooter"; -import { Paragraph } from "./styles"; -import { IncorrectPasswordError, UnauthorizedError } from "../app/errors"; -import { ProChip } from "./SubscriptionPopup"; -import theme from "./theme"; -import session from "../app/Session"; - -const Account = () => { - if (!session.exists()) { - window.location.href = routes.app; - return <>; - } - return ( - - - - - - - - - ); -}; - -const Basics = () => { - const { t } = useTranslation(); - return ( - - - {t("account_basics_title")} - - - - - - - - - ); -}; - -const Username = () => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const labelId = "prefUsername"; - - return ( - -
- {session.username()} - {account?.role === Role.ADMIN ? ( - <> - {" "} - - ๐Ÿ‘‘ - - - ) : ( - "" - )} -
-
- ); -}; - -const ChangePassword = () => { - const { t } = useTranslation(); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - const labelId = "prefChangePassword"; - - const handleDialogOpen = () => { - setDialogKey((prev) => prev + 1); - setDialogOpen(true); - }; - - const handleDialogClose = () => { - setDialogOpen(false); - }; - - return ( - -
- - โฌคโฌคโฌคโฌคโฌคโฌคโฌคโฌคโฌคโฌค - - - - -
- -
- ); -}; - -const ChangePasswordDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [currentPassword, setCurrentPassword] = useState(""); - const [newPassword, setNewPassword] = useState(""); - const [confirmPassword, setConfirmPassword] = useState(""); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const handleDialogSubmit = async () => { - try { - console.debug(`[Account] Changing password`); - await accountApi.changePassword(currentPassword, newPassword); - props.onClose(); - } catch (e) { - console.log(`[Account] Error changing password`, e); - if (e instanceof IncorrectPasswordError) { - setError(t("account_basics_password_dialog_current_password_incorrect")); - } else if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } - }; - - return ( - - {t("account_basics_password_dialog_title")} - - setCurrentPassword(ev.target.value)} - fullWidth - variant="standard" - /> - setNewPassword(ev.target.value)} - fullWidth - variant="standard" - /> - setConfirmPassword(ev.target.value)} - fullWidth - variant="standard" - /> - - - - - - - ); -}; - -const AccountType = () => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [upgradeDialogKey, setUpgradeDialogKey] = useState(0); - const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false); - const [showPortalError, setShowPortalError] = useState(false); - - if (!account) { - return <>; - } - - const handleUpgradeClick = () => { - setUpgradeDialogKey((k) => k + 1); - setUpgradeDialogOpen(true); - }; - - const handleManageBilling = async () => { - try { - const response = await accountApi.createBillingPortalSession(); - window.open(response.redirect_url, "billing_portal"); - } catch (e) { - console.log(`[Account] Error opening billing portal`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setShowPortalError(true); - } - } - }; - - let accountType; - if (account.role === Role.ADMIN) { - const tierSuffix = account.tier - ? t("account_basics_tier_admin_suffix_with_tier", { - tier: account.tier.name, - }) - : t("account_basics_tier_admin_suffix_no_tier"); - accountType = `${t("account_basics_tier_admin")} ${tierSuffix}`; - } else if (!account.tier) { - accountType = config.enable_payments ? t("account_basics_tier_free") : t("account_basics_tier_basic"); - } else { - accountType = account.tier.name; - if (account.billing?.interval === SubscriptionInterval.MONTH) { - accountType += ` (${t("account_basics_tier_interval_monthly")})`; - } else if (account.billing?.interval === SubscriptionInterval.YEAR) { - accountType += ` (${t("account_basics_tier_interval_yearly")})`; - } - } - - return ( - 0} - title={t("account_basics_tier_title")} - description={t("account_basics_tier_description")} - > -
- {accountType} - {account.billing?.paid_until && !account.billing?.cancel_at && ( - - - - - - )} - {config.enable_payments && account.role === Role.USER && !account.billing?.subscription && ( - - )} - {config.enable_payments && account.role === Role.USER && account.billing?.subscription && ( - - )} - {config.enable_payments && account.role === Role.USER && account.billing?.customer && ( - - )} - {config.enable_payments && ( - setUpgradeDialogOpen(false)} - /> - )} -
- {account.billing?.status === SubscriptionStatus.PAST_DUE && ( - - {t("account_basics_tier_payment_overdue")} - - )} - {account.billing?.cancel_at > 0 && ( - - {t("account_basics_tier_canceled_subscription", { - date: formatShortDate(account.billing.cancel_at), - })} - - )} - - setShowPortalError(false)} - message={t("account_usage_cannot_create_portal_session")} - /> - -
- ); -}; - -const PhoneNumbers = () => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - const [snackOpen, setSnackOpen] = useState(false); - const labelId = "prefPhoneNumbers"; - - const handleDialogOpen = () => { - setDialogKey((prev) => prev + 1); - setDialogOpen(true); - }; - - const handleDialogClose = () => { - setDialogOpen(false); - }; - - const handleCopy = (phoneNumber) => { - navigator.clipboard.writeText(phoneNumber); - setSnackOpen(true); - }; - - const handleDelete = async (phoneNumber) => { - try { - await accountApi.deletePhoneNumber(phoneNumber); - } catch (e) { - console.log(`[Account] Error deleting phone number`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } - } - }; - - if (!config.enable_calls) { - return null; - } - - if (account?.limits.calls === 0) { - return ( - - {t("account_basics_phone_numbers_title")} - {config.enable_payments && } - - } - description={t("account_basics_phone_numbers_description")} - > - {t("account_usage_calls_none")} - - ); - } - - return ( - -
- {account?.phone_numbers?.map((phoneNumber) => ( - - {phoneNumber} - - } - variant="outlined" - onClick={() => handleCopy(phoneNumber)} - onDelete={() => handleDelete(phoneNumber)} - /> - ))} - {!account?.phone_numbers && {t("account_basics_phone_numbers_no_phone_numbers_yet")}} - - - -
- - - setSnackOpen(false)} - message={t("account_basics_phone_numbers_copied_to_clipboard")} - /> - -
- ); -}; - -const AddPhoneNumberDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [phoneNumber, setPhoneNumber] = useState(""); - const [channel, setChannel] = useState("sms"); - const [code, setCode] = useState(""); - const [sending, setSending] = useState(false); - const [verificationCodeSent, setVerificationCodeSent] = useState(false); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const verifyPhone = async () => { - try { - setSending(true); - await accountApi.verifyPhoneNumber(phoneNumber, channel); - setVerificationCodeSent(true); - } catch (e) { - console.log(`[Account] Error sending verification`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } finally { - setSending(false); - } - }; - - const checkVerifyPhone = async () => { - try { - setSending(true); - await accountApi.addPhoneNumber(phoneNumber, code); - props.onClose(); - } catch (e) { - console.log(`[Account] Error confirming verification`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } finally { - setSending(false); - } - }; - - const handleDialogSubmit = async () => { - if (!verificationCodeSent) { - await verifyPhone(); - } else { - await checkVerifyPhone(); - } - }; - - const handleCancel = () => { - if (verificationCodeSent) { - setVerificationCodeSent(false); - setCode(""); - } else { - props.onClose(); - } - }; - - return ( - - {t("account_basics_phone_numbers_dialog_title")} - - {t("account_basics_phone_numbers_dialog_description")} - {!verificationCodeSent && ( -
- setPhoneNumber(ev.target.value)} - inputProps={{ inputMode: "tel", pattern: "+[0-9]*" }} - variant="standard" - sx={{ flexGrow: 1 }} - /> - - - setChannel(e.target.value)} />} - label={t("account_basics_phone_numbers_dialog_channel_sms")} - /> - setChannel(e.target.value)} />} - label={t("account_basics_phone_numbers_dialog_channel_call")} - sx={{ marginRight: 0 }} - /> - - -
- )} - {verificationCodeSent && ( - setCode(ev.target.value)} - fullWidth - inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }} - variant="standard" - /> - )} -
- - - - -
- ); -}; - -const Stats = () => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - - if (!account) { - return <>; - } - - const normalize = (value, max) => Math.min((value / max) * 100, 100); - - return ( - - - {t("account_usage_title")} - - - {(account.role === Role.ADMIN || account.limits.reservations > 0) && ( - -
- - {account.stats.reservations.toLocaleString()} - - - {account.role === Role.USER - ? t("account_usage_of_limit", { - limit: account.limits.reservations.toLocaleString(), - }) - : t("account_usage_unlimited")} - -
- 0 - ? normalize(account.stats.reservations, account.limits.reservations) - : 100 - } - /> -
- )} - - {t("account_usage_messages_title")} - - - - - - - } - > -
- - {account.stats.messages.toLocaleString()} - - - {account.role === Role.USER - ? t("account_usage_of_limit", { - limit: account.limits.messages.toLocaleString(), - }) - : t("account_usage_unlimited")} - -
- -
- {config.enable_emails && ( - - {t("account_usage_emails_title")} - - - - - - - } - > -
- - {account.stats.emails.toLocaleString()} - - - {account.role === Role.USER - ? t("account_usage_of_limit", { - limit: account.limits.emails.toLocaleString(), - }) - : t("account_usage_unlimited")} - -
- -
- )} - {config.enable_calls && (account.role === Role.ADMIN || account.limits.calls > 0) && ( - - {t("account_usage_calls_title")} - - - - - - - } - > -
- - {account.stats.calls.toLocaleString()} - - - {account.role === Role.USER - ? t("account_usage_of_limit", { - limit: account.limits.calls.toLocaleString(), - }) - : t("account_usage_unlimited")} - -
- 0 ? normalize(account.stats.calls, account.limits.calls) : 100} - /> -
- )} - -
- - {formatBytes(account.stats.attachment_total_size)} - - - {account.role === Role.USER - ? t("account_usage_of_limit", { - limit: formatBytes(account.limits.attachment_total_size), - }) - : t("account_usage_unlimited")} - -
- -
- {config.enable_reservations && account.role === Role.USER && account.limits.reservations === 0 && ( - - {t("account_usage_reservations_title")} - {config.enable_payments && } - - } - > - {t("account_usage_reservations_none")} - - )} - {config.enable_calls && account.role === Role.USER && account.limits.calls === 0 && ( - - {t("account_usage_calls_title")} - {config.enable_payments && } - - } - > - {t("account_usage_calls_none")} - - )} -
- {account.role === Role.USER && account.limits.basis === LimitBasis.IP && ( - {t("account_usage_basis_ip_description")} - )} -
- ); -}; - -const InfoIcon = () => ( - -); - -const Tokens = () => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - const tokens = account?.tokens || []; - - const handleCreateClick = () => { - setDialogKey((prev) => prev + 1); - setDialogOpen(true); - }; - - const handleDialogClose = () => { - setDialogOpen(false); - }; - - return ( - - - - {t("account_tokens_title")} - - - , - }} - /> - - {tokens?.length > 0 && } - - - - - - - ); -}; - -const TokensTable = (props) => { - const { t } = useTranslation(); - const [snackOpen, setSnackOpen] = useState(false); - const [upsertDialogKey, setUpsertDialogKey] = useState(0); - const [upsertDialogOpen, setUpsertDialogOpen] = useState(false); - const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); - const [selectedToken, setSelectedToken] = useState(null); - - const tokens = (props.tokens || []).sort((a, b) => { - if (a.token === session.token()) { - return -1; - } - if (b.token === session.token()) { - return 1; - } - return a.token.localeCompare(b.token); - }); - - const handleEditClick = (token) => { - setUpsertDialogKey((prev) => prev + 1); - setSelectedToken(token); - setUpsertDialogOpen(true); - }; - - const handleDialogClose = () => { - setUpsertDialogOpen(false); - setDeleteDialogOpen(false); - setSelectedToken(null); - }; - - const handleDeleteClick = async (token) => { - setSelectedToken(token); - setDeleteDialogOpen(true); - }; - - const handleCopy = async (token) => { - await navigator.clipboard.writeText(token); - setSnackOpen(true); - }; - - return ( - - - - {t("account_tokens_table_token_header")} - {t("account_tokens_table_label_header")} - {t("account_tokens_table_expires_header")} - {t("account_tokens_table_last_access_header")} - - - - - {tokens.map((token) => ( - - - - {token.token.slice(0, 12)} - ... - - handleCopy(token.token)}> - - - - - - - {token.token === session.token() && {t("account_tokens_table_current_session")}} - {token.token !== session.token() && (token.label || "-")} - - - {token.expires ? formatShortDateTime(token.expires) : {t("account_tokens_table_never_expires")}} - - -
- {formatShortDateTime(token.last_access)} - - openUrl(`https://whatismyipaddress.com/ip/${token.last_origin}`)}> - - - -
-
- - {token.token !== session.token() && ( - <> - handleEditClick(token)} aria-label={t("account_tokens_dialog_title_edit")}> - - - handleDeleteClick(token)} aria-label={t("account_tokens_dialog_title_delete")}> - - - - )} - {token.token === session.token() && ( - - - - - - - - - - - )} - -
- ))} -
- - setSnackOpen(false)} - message={t("account_tokens_table_copied_to_clipboard")} - /> - - - -
- ); -}; - -const TokenDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [label, setLabel] = useState(props.token?.label || ""); - const [expires, setExpires] = useState(props.token ? -1 : 0); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - const editMode = !!props.token; - - const handleSubmit = async () => { - try { - if (editMode) { - await accountApi.updateToken(props.token.token, label, expires); - } else { - await accountApi.createToken(label, expires); - } - props.onClose(); - } catch (e) { - console.log(`[Account] Error creating token`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } - }; - - return ( - - {editMode ? t("account_tokens_dialog_title_edit") : t("account_tokens_dialog_title_create")} - - setLabel(ev.target.value)} - fullWidth - variant="standard" - /> - - - - - - - - - - ); -}; - -const TokenDeleteDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - - const handleSubmit = async () => { - try { - await accountApi.deleteToken(props.token.token); - props.onClose(); - } catch (e) { - console.log(`[Account] Error deleting token`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } - }; - - return ( - - {t("account_tokens_delete_dialog_title")} - - - - - - - - - - - ); -}; - -const Delete = () => { - const { t } = useTranslation(); - return ( - - - {t("account_delete_title")} - - - - - - ); -}; - -const DeleteAccount = () => { - const { t } = useTranslation(); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - - const handleDialogOpen = () => { - setDialogKey((prev) => prev + 1); - setDialogOpen(true); - }; - - const handleDialogClose = () => { - setDialogOpen(false); - }; - - return ( - -
- -
- -
- ); -}; - -const DeleteAccountDialog = (props) => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [error, setError] = useState(""); - const [password, setPassword] = useState(""); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const handleSubmit = async () => { - try { - await accountApi.delete(password); - await db.delete(); - console.debug(`[Account] Account deleted`); - session.resetAndRedirect(routes.app); - } catch (e) { - console.log(`[Account] Error deleting account`, e); - if (e instanceof IncorrectPasswordError) { - setError(t("account_basics_password_dialog_current_password_incorrect")); - } else if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } - }; - - return ( - - {t("account_delete_title")} - - {t("account_delete_dialog_description")} - setPassword(ev.target.value)} - fullWidth - variant="standard" - /> - {account?.billing?.subscription && ( - - {t("account_delete_dialog_billing_warning")} - - )} - - - - - - - ); -}; - -export default Account; diff --git a/web/src/components/ActionBar.js b/web/src/components/ActionBar.js new file mode 100644 index 0000000..189ae1c --- /dev/null +++ b/web/src/components/ActionBar.js @@ -0,0 +1,183 @@ +import AppBar from "@mui/material/AppBar"; +import Navigation from "./Navigation"; +import Toolbar from "@mui/material/Toolbar"; +import IconButton from "@mui/material/IconButton"; +import MenuIcon from "@mui/icons-material/Menu"; +import Typography from "@mui/material/Typography"; +import * as React from "react"; +import {useState} from "react"; +import Box from "@mui/material/Box"; +import {topicDisplayName} from "../app/utils"; +import db from "../app/db"; +import {useLocation, useNavigate} from "react-router-dom"; +import MenuItem from '@mui/material/MenuItem'; +import MoreVertIcon from "@mui/icons-material/MoreVert"; +import NotificationsIcon from '@mui/icons-material/Notifications'; +import NotificationsOffIcon from '@mui/icons-material/NotificationsOff'; +import routes from "./routes"; +import subscriptionManager from "../app/SubscriptionManager"; +import logo from "../img/ntfy.svg"; +import {useTranslation} from "react-i18next"; +import session from "../app/Session"; +import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +import Button from "@mui/material/Button"; +import Divider from "@mui/material/Divider"; +import {Logout, Person, Settings} from "@mui/icons-material"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import accountApi from "../app/AccountApi"; +import PopupMenu from "./PopupMenu"; +import { SubscriptionPopup } from "./SubscriptionPopup"; + +const ActionBar = (props) => { + const { t } = useTranslation(); + const location = useLocation(); + let title = "ntfy"; + if (props.selected) { + title = topicDisplayName(props.selected); + } else if (location.pathname === routes.settings) { + title = t("action_bar_settings"); + } else if (location.pathname === routes.account) { + title = t("action_bar_account"); + } + return ( + Navigation (1200), but < Dialog (1300) + ml: { sm: `${Navigation.width}px` } + }}> + + + + + + + {title} + + {props.selected && + } + + + + ); +}; + +const SettingsIcons = (props) => { + const { t } = useTranslation(); + const [anchorEl, setAnchorEl] = useState(null); + const subscription = props.subscription; + + const handleToggleMute = async () => { + const mutedUntil = (subscription.mutedUntil) ? 0 : 1; // Make this a timestamp in the future + await subscriptionManager.setMutedUntil(subscription.id, mutedUntil); + } + + return ( + <> + + {subscription.mutedUntil ? : } + + setAnchorEl(ev.currentTarget)} aria-label={t("action_bar_toggle_action_menu")}> + + + setAnchorEl(null)} + /> + + ); +}; + +const ProfileIcon = () => { + const { t } = useTranslation(); + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + const navigate = useNavigate(); + + const handleClick = (event) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const handleLogout = async () => { + try { + await accountApi.logout(); + await db.delete(); + } finally { + session.resetAndRedirect(routes.app); + } + }; + + return ( + <> + {session.exists() && + + + + } + {!session.exists() && config.enable_login && + + } + {!session.exists() && config.enable_signup && + + } + + navigate(routes.account)}> + + + + {session.username()} + + + navigate(routes.settings)}> + + + + {t("action_bar_profile_settings")} + + + + + + {t("action_bar_profile_logout")} + + + + ); +}; + +export default ActionBar; diff --git a/web/src/components/ActionBar.jsx b/web/src/components/ActionBar.jsx deleted file mode 100644 index 798efb4..0000000 --- a/web/src/components/ActionBar.jsx +++ /dev/null @@ -1,172 +0,0 @@ -import { AppBar, Toolbar, IconButton, Typography, Box, MenuItem, Button, Divider, ListItemIcon } from "@mui/material"; -import MenuIcon from "@mui/icons-material/Menu"; -import * as React from "react"; -import { useState } from "react"; -import { useLocation, useNavigate } from "react-router-dom"; -import MoreVertIcon from "@mui/icons-material/MoreVert"; -import NotificationsIcon from "@mui/icons-material/Notifications"; -import NotificationsOffIcon from "@mui/icons-material/NotificationsOff"; -import { useTranslation } from "react-i18next"; -import AccountCircleIcon from "@mui/icons-material/AccountCircle"; -import { Logout, Person, Settings } from "@mui/icons-material"; -import session from "../app/Session"; -import logo from "../img/ntfy.svg"; -import subscriptionManager from "../app/SubscriptionManager"; -import routes from "./routes"; -import db from "../app/db"; -import { topicDisplayName } from "../app/utils"; -import Navigation from "./Navigation"; -import accountApi from "../app/AccountApi"; -import PopupMenu from "./PopupMenu"; -import { SubscriptionPopup } from "./SubscriptionPopup"; - -const ActionBar = (props) => { - const { t } = useTranslation(); - const location = useLocation(); - let title = "ntfy"; - if (props.selected) { - title = topicDisplayName(props.selected); - } else if (location.pathname === routes.settings) { - title = t("action_bar_settings"); - } else if (location.pathname === routes.account) { - title = t("action_bar_account"); - } - return ( - Navigation (1200), but < Dialog (1300) - ml: { sm: `${Navigation.width}px` }, - }} - > - - - - - - - {title} - - {props.selected && } - - - - ); -}; - -const SettingsIcons = (props) => { - const { t } = useTranslation(); - const [anchorEl, setAnchorEl] = useState(null); - const { subscription } = props; - - const handleToggleMute = async () => { - const mutedUntil = subscription.mutedUntil ? 0 : 1; // Make this a timestamp in the future - await subscriptionManager.setMutedUntil(subscription.id, mutedUntil); - }; - - return ( - <> - - {subscription.mutedUntil ? : } - - setAnchorEl(ev.currentTarget)} - aria-label={t("action_bar_toggle_action_menu")} - > - - - setAnchorEl(null)} /> - - ); -}; - -const ProfileIcon = () => { - const { t } = useTranslation(); - const [anchorEl, setAnchorEl] = useState(null); - const open = Boolean(anchorEl); - const navigate = useNavigate(); - - const handleClick = (event) => { - setAnchorEl(event.currentTarget); - }; - - const handleClose = () => { - setAnchorEl(null); - }; - - const handleLogout = async () => { - try { - await accountApi.logout(); - await db.delete(); - } finally { - session.resetAndRedirect(routes.app); - } - }; - - return ( - <> - {session.exists() && ( - - - - )} - {!session.exists() && config.enable_login && ( - - )} - {!session.exists() && config.enable_signup && ( - - )} - - navigate(routes.account)}> - - - - {session.username()} - - - navigate(routes.settings)}> - - - - {t("action_bar_profile_settings")} - - - - - - {t("action_bar_profile_logout")} - - - - ); -}; - -export default ActionBar; diff --git a/web/src/components/App.js b/web/src/components/App.js new file mode 100644 index 0000000..861a370 --- /dev/null +++ b/web/src/components/App.js @@ -0,0 +1,147 @@ +import * as React from 'react'; +import {createContext, Suspense, useContext, useEffect, useState} from 'react'; +import Box from '@mui/material/Box'; +import {ThemeProvider} from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; +import Toolbar from '@mui/material/Toolbar'; +import {AllSubscriptions, SingleSubscription} from "./Notifications"; +import theme from "./theme"; +import Navigation from "./Navigation"; +import ActionBar from "./ActionBar"; +import notifier from "../app/Notifier"; +import Preferences from "./Preferences"; +import {useLiveQuery} from "dexie-react-hooks"; +import subscriptionManager from "../app/SubscriptionManager"; +import userManager from "../app/UserManager"; +import {BrowserRouter, Outlet, Route, Routes, useParams} from "react-router-dom"; +import {expandUrl} from "../app/utils"; +import ErrorBoundary from "./ErrorBoundary"; +import routes from "./routes"; +import {useAccountListener, useBackgroundProcesses, useConnectionListeners} from "./hooks"; +import PublishDialog from "./PublishDialog"; +import Messaging from "./Messaging"; +import "./i18n"; // Translations! +import {Backdrop, CircularProgress} from "@mui/material"; +import Login from "./Login"; +import Signup from "./Signup"; +import Account from "./Account"; + +export const AccountContext = createContext(null); + +const App = () => { + const [account, setAccount] = useState(null); + return ( + }> + + + + + + + }/> + }/> + }> + }/> + }/> + }/> + }/> + }/> + + + + + + + + ); +} + +const Layout = () => { + const params = useParams(); + const { account, setAccount } = useContext(AccountContext); + const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false); + const [notificationsGranted, setNotificationsGranted] = useState(notifier.granted()); + const [sendDialogOpenMode, setSendDialogOpenMode] = useState(""); + const users = useLiveQuery(() => userManager.all()); + const subscriptions = useLiveQuery(() => subscriptionManager.all()); + const subscriptionsWithoutInternal = subscriptions?.filter(s => !s.internal); + const newNotificationsCount = subscriptionsWithoutInternal?.reduce((prev, cur) => prev + cur.new, 0) || 0; + const [selected] = (subscriptionsWithoutInternal || []).filter(s => { + return (params.baseUrl && expandUrl(params.baseUrl).includes(s.baseUrl) && params.topic === s.topic) + || (config.base_url === s.baseUrl && params.topic === s.topic) + }); + + useConnectionListeners(account, subscriptions, users); + useAccountListener(setAccount) + useBackgroundProcesses(); + useEffect(() => updateTitle(newNotificationsCount), [newNotificationsCount]); + + return ( + + setMobileDrawerOpen(!mobileDrawerOpen)} + /> + setMobileDrawerOpen(!mobileDrawerOpen)} + onNotificationGranted={setNotificationsGranted} + onPublishMessageClick={() => setSendDialogOpenMode(PublishDialog.OPEN_MODE_DEFAULT)} + /> +
+ + +
+ +
+ ); +} + +const Main = (props) => { + return ( + theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900] + }} + > + {props.children} + + ); +}; + +const Loader = () => ( + theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900] + }} + > + + +); + +const updateTitle = (newNotificationsCount) => { + document.title = (newNotificationsCount > 0) ? `(${newNotificationsCount}) ntfy` : "ntfy"; +} + +export default App; diff --git a/web/src/components/App.jsx b/web/src/components/App.jsx deleted file mode 100644 index 189235b..0000000 --- a/web/src/components/App.jsx +++ /dev/null @@ -1,140 +0,0 @@ -import * as React from "react"; -import { createContext, Suspense, useContext, useEffect, useState, useMemo } from "react"; -import { Box, Toolbar, CssBaseline, Backdrop, CircularProgress } from "@mui/material"; -import { ThemeProvider } from "@mui/material/styles"; -import { useLiveQuery } from "dexie-react-hooks"; -import { BrowserRouter, Outlet, Route, Routes, useParams } from "react-router-dom"; -import { AllSubscriptions, SingleSubscription } from "./Notifications"; -import theme from "./theme"; -import Navigation from "./Navigation"; -import ActionBar from "./ActionBar"; -import notifier from "../app/Notifier"; -import Preferences from "./Preferences"; -import subscriptionManager from "../app/SubscriptionManager"; -import userManager from "../app/UserManager"; -import { expandUrl } from "../app/utils"; -import ErrorBoundary from "./ErrorBoundary"; -import routes from "./routes"; -import { useAccountListener, useBackgroundProcesses, useConnectionListeners } from "./hooks"; -import PublishDialog from "./PublishDialog"; -import Messaging from "./Messaging"; -import "./i18n"; // Translations! -import Login from "./Login"; -import Signup from "./Signup"; -import Account from "./Account"; - -export const AccountContext = createContext(null); - -const App = () => { - const [account, setAccount] = useState(null); - const accountMemo = useMemo(() => ({ account, setAccount }), [account, setAccount]); - - return ( - }> - - - - - - - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - - - - - - - - ); -}; - -const updateTitle = (newNotificationsCount) => { - document.title = newNotificationsCount > 0 ? `(${newNotificationsCount}) ntfy` : "ntfy"; -}; - -const Layout = () => { - const params = useParams(); - const { account, setAccount } = useContext(AccountContext); - const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false); - const [notificationsGranted, setNotificationsGranted] = useState(notifier.granted()); - const [sendDialogOpenMode, setSendDialogOpenMode] = useState(""); - const users = useLiveQuery(() => userManager.all()); - const subscriptions = useLiveQuery(() => subscriptionManager.all()); - const subscriptionsWithoutInternal = subscriptions?.filter((s) => !s.internal); - const newNotificationsCount = subscriptionsWithoutInternal?.reduce((prev, cur) => prev + cur.new, 0) || 0; - const [selected] = (subscriptionsWithoutInternal || []).filter( - (s) => - (params.baseUrl && expandUrl(params.baseUrl).includes(s.baseUrl) && params.topic === s.topic) || - (config.base_url === s.baseUrl && params.topic === s.topic) - ); - - useConnectionListeners(account, subscriptions, users); - useAccountListener(setAccount); - useBackgroundProcesses(); - useEffect(() => updateTitle(newNotificationsCount), [newNotificationsCount]); - - return ( - - setMobileDrawerOpen(!mobileDrawerOpen)} /> - setMobileDrawerOpen(!mobileDrawerOpen)} - onNotificationGranted={setNotificationsGranted} - onPublishMessageClick={() => setSendDialogOpenMode(PublishDialog.OPEN_MODE_DEFAULT)} - /> -
- - -
- -
- ); -}; - -const Main = (props) => ( - (palette.mode === "light" ? palette.grey[100] : palette.grey[900]), - }} - > - {props.children} - -); - -const Loader = () => ( - (palette.mode === "light" ? palette.grey[100] : palette.grey[900]), - }} - > - - -); - -export default App; diff --git a/web/src/components/AttachmentIcon.js b/web/src/components/AttachmentIcon.js new file mode 100644 index 0000000..337760b --- /dev/null +++ b/web/src/components/AttachmentIcon.js @@ -0,0 +1,47 @@ +import * as React from "react"; +import Box from "@mui/material/Box"; +import fileDocument from "../img/file-document.svg"; +import fileImage from "../img/file-image.svg"; +import fileVideo from "../img/file-video.svg"; +import fileAudio from "../img/file-audio.svg"; +import fileApp from "../img/file-app.svg"; +import {useTranslation} from "react-i18next"; + +const AttachmentIcon = (props) => { + const { t } = useTranslation(); + const type = props.type; + let imageFile, imageLabel; + if (!type) { + imageFile = fileDocument; + imageLabel = t("notifications_attachment_file_image"); + } else if (type.startsWith('image/')) { + imageFile = fileImage; + imageLabel = t("notifications_attachment_file_video"); + } else if (type.startsWith('video/')) { + imageFile = fileVideo; + imageLabel = t("notifications_attachment_file_video"); + } else if (type.startsWith('audio/')) { + imageFile = fileAudio; + imageLabel = t("notifications_attachment_file_audio"); + } else if (type === "application/vnd.android.package-archive") { + imageFile = fileApp; + imageLabel = t("notifications_attachment_file_app"); + } else { + imageFile = fileDocument; + imageLabel = t("notifications_attachment_file_document"); + } + return ( + + ); +} + +export default AttachmentIcon; diff --git a/web/src/components/AttachmentIcon.jsx b/web/src/components/AttachmentIcon.jsx deleted file mode 100644 index 9a2581e..0000000 --- a/web/src/components/AttachmentIcon.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import * as React from "react"; -import { Box } from "@mui/material"; -import { useTranslation } from "react-i18next"; -import fileDocument from "../img/file-document.svg"; -import fileImage from "../img/file-image.svg"; -import fileVideo from "../img/file-video.svg"; -import fileAudio from "../img/file-audio.svg"; -import fileApp from "../img/file-app.svg"; - -const AttachmentIcon = (props) => { - const { t } = useTranslation(); - const { type } = props; - let imageFile; - let imageLabel; - if (!type) { - imageFile = fileDocument; - imageLabel = t("notifications_attachment_file_image"); - } else if (type.startsWith("image/")) { - imageFile = fileImage; - imageLabel = t("notifications_attachment_file_video"); - } else if (type.startsWith("video/")) { - imageFile = fileVideo; - imageLabel = t("notifications_attachment_file_video"); - } else if (type.startsWith("audio/")) { - imageFile = fileAudio; - imageLabel = t("notifications_attachment_file_audio"); - } else if (type === "application/vnd.android.package-archive") { - imageFile = fileApp; - imageLabel = t("notifications_attachment_file_app"); - } else { - imageFile = fileDocument; - imageLabel = t("notifications_attachment_file_document"); - } - return ( - - ); -}; - -export default AttachmentIcon; diff --git a/web/src/components/AvatarBox.js b/web/src/components/AvatarBox.js new file mode 100644 index 0000000..2278f60 --- /dev/null +++ b/web/src/components/AvatarBox.js @@ -0,0 +1,29 @@ +import * as React from 'react'; +import {Avatar} from "@mui/material"; +import Box from "@mui/material/Box"; +import logo from "../img/ntfy-filled.svg"; + +const AvatarBox = (props) => { + return ( + + + {props.children} + + ); +} + +export default AvatarBox; diff --git a/web/src/components/AvatarBox.jsx b/web/src/components/AvatarBox.jsx deleted file mode 100644 index 1037868..0000000 --- a/web/src/components/AvatarBox.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from "react"; -import { Avatar, Box } from "@mui/material"; -import logo from "../img/ntfy-filled.svg"; - -const AvatarBox = (props) => ( - - - {props.children} - -); - -export default AvatarBox; diff --git a/web/src/components/DialogFooter.js b/web/src/components/DialogFooter.js new file mode 100644 index 0000000..68d17c7 --- /dev/null +++ b/web/src/components/DialogFooter.js @@ -0,0 +1,33 @@ +import * as React from "react"; +import Box from "@mui/material/Box"; +import DialogContentText from "@mui/material/DialogContentText"; +import DialogActions from "@mui/material/DialogActions"; + +const DialogFooter = (props) => { + return ( + + + {props.status} + + + {props.children} + + + ); +}; + +export default DialogFooter; diff --git a/web/src/components/DialogFooter.jsx b/web/src/components/DialogFooter.jsx deleted file mode 100644 index bcaf4cf..0000000 --- a/web/src/components/DialogFooter.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from "react"; -import { Box, DialogContentText, DialogActions } from "@mui/material"; - -const DialogFooter = (props) => ( - - - {props.status} - - {props.children} - -); - -export default DialogFooter; diff --git a/web/src/components/EmojiPicker.js b/web/src/components/EmojiPicker.js new file mode 100644 index 0000000..9b29e8f --- /dev/null +++ b/web/src/components/EmojiPicker.js @@ -0,0 +1,179 @@ +import * as React from 'react'; +import {useRef, useState} from 'react'; +import Typography from '@mui/material/Typography'; +import {rawEmojis} from '../app/emojis'; +import Box from "@mui/material/Box"; +import TextField from "@mui/material/TextField"; +import {ClickAwayListener, Fade, InputAdornment, styled} from "@mui/material"; +import IconButton from "@mui/material/IconButton"; +import {Close} from "@mui/icons-material"; +import Popper from "@mui/material/Popper"; +import {splitNoEmpty} from "../app/utils"; +import {useTranslation} from "react-i18next"; + +// Create emoji list by category and create a search base (string with all search words) +// +// This also filters emojis that are not supported by Desktop Chrome. +// This is a hack, but on Ubuntu 18.04, with Chrome 99, only Emoji <= 11 are supported. + +const emojisByCategory = {}; +const isDesktopChrome = /Chrome/.test(navigator.userAgent) && !/Mobile/.test(navigator.userAgent); +const maxSupportedVersionForDesktopChrome = 11; +rawEmojis.forEach(emoji => { + if (!emojisByCategory[emoji.category]) { + emojisByCategory[emoji.category] = []; + } + try { + const unicodeVersion = parseFloat(emoji.unicode_version); + const supportedEmoji = unicodeVersion <= maxSupportedVersionForDesktopChrome || !isDesktopChrome; + if (supportedEmoji) { + const searchBase = `${emoji.description.toLowerCase()} ${emoji.aliases.join(" ")} ${emoji.tags.join(" ")}`; + const emojiWithSearchBase = { ...emoji, searchBase: searchBase }; + emojisByCategory[emoji.category].push(emojiWithSearchBase); + } + } catch (e) { + // Nothing. Ignore. + } +}); + +const EmojiPicker = (props) => { + const { t } = useTranslation(); + const open = Boolean(props.anchorEl); + const [search, setSearch] = useState(""); + const searchRef = useRef(null); + const searchFields = splitNoEmpty(search.toLowerCase(), " "); + + const handleSearchClear = () => { + setSearch(""); + searchRef.current?.focus(); + }; + + return ( + + {({ TransitionProps }) => ( + + + + setSearch(ev.target.value)} + type="text" + variant="standard" + fullWidth + sx={{ marginTop: 0, marginBottom: "12px", paddingRight: 2 }} + inputProps={{ + role: "searchbox", + "aria-label": t("emoji_picker_search_placeholder") + }} + InputProps={{ + endAdornment: + + + + + + }} + /> + + {Object.keys(emojisByCategory).map(category => + + )} + + + + + )} + + ); +}; + +const Category = (props) => { + const showTitle = props.search.length === 0; + return ( + <> + {showTitle && + + {props.title} + + } + {props.emojis.map(emoji => + props.onPick(emoji.aliases[0])} + /> + )} + + ); +}; + +const Emoji = (props) => { + const emoji = props.emoji; + const matches = emojiMatches(emoji, props.search); + const title = `${emoji.description} (${emoji.aliases[0]})`; + return ( + + {props.emoji.emoji} + + ); +}; + +const EmojiDiv = styled("div")({ + fontSize: "30px", + width: "30px", + height: "30px", + marginTop: "8px", + marginBottom: "8px", + marginRight: "8px", + lineHeight: "30px", + cursor: "pointer", + opacity: 0.85, + "&:hover": { + opacity: 1 + } +}); + +const emojiMatches = (emoji, words) => { + if (words.length === 0) { + return true; + } + for (const word of words) { + if (emoji.searchBase.indexOf(word) === -1) { + return false; + } + } + return true; +} + +export default EmojiPicker; diff --git a/web/src/components/EmojiPicker.jsx b/web/src/components/EmojiPicker.jsx deleted file mode 100644 index d1fb170..0000000 --- a/web/src/components/EmojiPicker.jsx +++ /dev/null @@ -1,158 +0,0 @@ -import * as React from "react"; -import { useRef, useState } from "react"; -import { Typography, Box, TextField, ClickAwayListener, Fade, InputAdornment, styled, IconButton, Popper } from "@mui/material"; -import { Close } from "@mui/icons-material"; -import { useTranslation } from "react-i18next"; -import { splitNoEmpty } from "../app/utils"; -import { rawEmojis } from "../app/emojis"; - -// Create emoji list by category and create a search base (string with all search words) -// -// This also filters emojis that are not supported by Desktop Chrome. -// This is a hack, but on Ubuntu 18.04, with Chrome 99, only Emoji <= 11 are supported. - -const emojisByCategory = {}; -const isDesktopChrome = /Chrome/.test(navigator.userAgent) && !/Mobile/.test(navigator.userAgent); -const maxSupportedVersionForDesktopChrome = 11; -rawEmojis.forEach((emoji) => { - if (!emojisByCategory[emoji.category]) { - emojisByCategory[emoji.category] = []; - } - try { - const unicodeVersion = parseFloat(emoji.unicode_version); - const supportedEmoji = unicodeVersion <= maxSupportedVersionForDesktopChrome || !isDesktopChrome; - if (supportedEmoji) { - const searchBase = `${emoji.description.toLowerCase()} ${emoji.aliases.join(" ")} ${emoji.tags.join(" ")}`; - const emojiWithSearchBase = { ...emoji, searchBase }; - emojisByCategory[emoji.category].push(emojiWithSearchBase); - } - } catch (e) { - // Nothing. Ignore. - } -}); - -const EmojiPicker = (props) => { - const { t } = useTranslation(); - const open = Boolean(props.anchorEl); - const [search, setSearch] = useState(""); - const searchRef = useRef(null); - const searchFields = splitNoEmpty(search.toLowerCase(), " "); - - const handleSearchClear = () => { - setSearch(""); - searchRef.current?.focus(); - }; - - return ( - - {({ TransitionProps }) => ( - - - - setSearch(ev.target.value)} - type="text" - variant="standard" - fullWidth - sx={{ marginTop: 0, marginBottom: "12px", paddingRight: 2 }} - inputProps={{ - role: "searchbox", - "aria-label": t("emoji_picker_search_placeholder"), - }} - InputProps={{ - endAdornment: ( - - - - - - ), - }} - /> - - {Object.keys(emojisByCategory).map((category) => ( - - ))} - - - - - )} - - ); -}; - -const Category = (props) => { - const showTitle = props.search.length === 0; - return ( - <> - {showTitle && ( - - {props.title} - - )} - {props.emojis.map((emoji) => ( - props.onPick(emoji.aliases[0])} /> - ))} - - ); -}; - -const emojiMatches = (emoji, words) => words.length === 0 || words.some((word) => emoji.searchBase.includes(word)); - -const Emoji = (props) => { - const { emoji } = props; - const matches = emojiMatches(emoji, props.search); - const title = `${emoji.description} (${emoji.aliases[0]})`; - return ( - - {props.emoji.emoji} - - ); -}; - -const EmojiDiv = styled("div")({ - fontSize: "30px", - width: "30px", - height: "30px", - marginTop: "8px", - marginBottom: "8px", - marginRight: "8px", - lineHeight: "30px", - cursor: "pointer", - opacity: 0.85, - "&:hover": { - opacity: 1, - }, -}); - -export default EmojiPicker; diff --git a/web/src/components/ErrorBoundary.js b/web/src/components/ErrorBoundary.js new file mode 100644 index 0000000..c6d789a --- /dev/null +++ b/web/src/components/ErrorBoundary.js @@ -0,0 +1,129 @@ +import * as React from "react"; +import StackTrace from "stacktrace-js"; +import {CircularProgress, Link} from "@mui/material"; +import Button from "@mui/material/Button"; +import {Trans, withTranslation} from "react-i18next"; + +class ErrorBoundaryImpl extends React.Component { + constructor(props) { + super(props); + this.state = { + error: false, + originalStack: null, + niceStack: null, + unsupportedIndexedDB: false + }; + } + + componentDidCatch(error, info) { + console.error("[ErrorBoundary] Error caught", error, info); + + // Special case for unsupported IndexedDB in Private Browsing mode (Firefox, Safari), see + // - https://github.com/dexie/Dexie.js/issues/312 + // - https://bugzilla.mozilla.org/show_bug.cgi?id=781982 + const isUnsupportedIndexedDB = error?.name === "InvalidStateError" || + (error?.name === "DatabaseClosedError" && error?.message?.indexOf("InvalidStateError") !== -1); + + if (isUnsupportedIndexedDB) { + this.handleUnsupportedIndexedDB(); + } else { + this.handleError(error, info); + } + } + + handleError(error, info) { + // Immediately render original stack trace + const prettierOriginalStack = info.componentStack + .trim() + .split("\n") + .map(line => ` at ${line}`) + .join("\n"); + this.setState({ + error: true, + originalStack: `${error.toString()}\n${prettierOriginalStack}` + }); + + // Fetch additional info and a better stack trace + StackTrace.fromError(error).then(stack => { + console.error("[ErrorBoundary] Stacktrace fetched", stack); + const niceStack = `${error.toString()}\n` + stack.map( el => ` at ${el.functionName} (${el.fileName}:${el.columnNumber}:${el.lineNumber})`).join("\n"); + this.setState({ niceStack }); + }); + } + + handleUnsupportedIndexedDB() { + this.setState({ + error: true, + unsupportedIndexedDB: true + }); + } + + copyStack() { + let stack = ""; + if (this.state.niceStack) { + stack += `${this.state.niceStack}\n\n`; + } + stack += `${this.state.originalStack}\n`; + navigator.clipboard.writeText(stack); + } + + render() { + if (this.state.error) { + if (this.state.unsupportedIndexedDB) { + return this.renderUnsupportedIndexedDB(); + } else { + return this.renderError(); + } + } + return this.props.children; + } + + renderUnsupportedIndexedDB() { + const { t } = this.props; + return ( +
+

{t("error_boundary_unsupported_indexeddb_title")} ๐Ÿ˜ฎ

+

+ , + discordLink: , + matrixLink: + }} + /> +

+
+ ); + } + + renderError() { + const { t } = this.props; + return ( +
+

{t("error_boundary_title")} ๐Ÿ˜ฎ

+

+ , + discordLink: , + matrixLink: + }} + /> +

+

+ +

+

{t("error_boundary_stack_trace")}

+ {this.state.niceStack + ?
{this.state.niceStack}
+ : <> {t("error_boundary_gathering_info")}} +
{this.state.originalStack}
+
+ ); + } +} + +const ErrorBoundary = withTranslation()(ErrorBoundaryImpl); // Adds props.t +export default ErrorBoundary; diff --git a/web/src/components/ErrorBoundary.jsx b/web/src/components/ErrorBoundary.jsx deleted file mode 100644 index 9715c0c..0000000 --- a/web/src/components/ErrorBoundary.jsx +++ /dev/null @@ -1,134 +0,0 @@ -import * as React from "react"; -import StackTrace from "stacktrace-js"; -import { CircularProgress, Link, Button } from "@mui/material"; -import { Trans, withTranslation } from "react-i18next"; - -class ErrorBoundaryImpl extends React.Component { - constructor(props) { - super(props); - this.state = { - error: false, - originalStack: null, - niceStack: null, - unsupportedIndexedDB: false, - }; - } - - componentDidCatch(error, info) { - console.error("[ErrorBoundary] Error caught", error, info); - - // Special case for unsupported IndexedDB in Private Browsing mode (Firefox, Safari), see - // - https://github.com/dexie/Dexie.js/issues/312 - // - https://bugzilla.mozilla.org/show_bug.cgi?id=781982 - const isUnsupportedIndexedDB = - error?.name === "InvalidStateError" || (error?.name === "DatabaseClosedError" && error?.message?.indexOf("InvalidStateError") !== -1); - - if (isUnsupportedIndexedDB) { - this.handleUnsupportedIndexedDB(); - } else { - this.handleError(error, info); - } - } - - handleError(error, info) { - // Immediately render original stack trace - const prettierOriginalStack = info.componentStack - .trim() - .split("\n") - .map((line) => ` at ${line}`) - .join("\n"); - this.setState({ - error: true, - originalStack: `${error.toString()}\n${prettierOriginalStack}`, - }); - - // Fetch additional info and a better stack trace - StackTrace.fromError(error).then((stack) => { - console.error("[ErrorBoundary] Stacktrace fetched", stack); - const stackString = stack.map((el) => ` at ${el.functionName} (${el.fileName}:${el.columnNumber}:${el.lineNumber})`).join("\n"); - const niceStack = `${error.toString()}\n${stackString}`; - this.setState({ niceStack }); - }); - } - - handleUnsupportedIndexedDB() { - this.setState({ - error: true, - unsupportedIndexedDB: true, - }); - } - - copyStack() { - let stack = ""; - if (this.state.niceStack) { - stack += `${this.state.niceStack}\n\n`; - } - stack += `${this.state.originalStack}\n`; - navigator.clipboard.writeText(stack); - } - - renderUnsupportedIndexedDB() { - const { t } = this.props; - return ( -
-

{t("error_boundary_unsupported_indexeddb_title")} ๐Ÿ˜ฎ

-

- , - discordLink: , - matrixLink: , - }} - /> -

-
- ); - } - - renderError() { - const { t } = this.props; - return ( -
-

{t("error_boundary_title")} ๐Ÿ˜ฎ

-

- , - discordLink: , - matrixLink: , - }} - /> -

-

- -

-

{t("error_boundary_stack_trace")}

- {this.state.niceStack ? ( -
{this.state.niceStack}
- ) : ( - <> - {t("error_boundary_gathering_info")} - - )} -
{this.state.originalStack}
-
- ); - } - - render() { - if (this.state.error) { - if (this.state.unsupportedIndexedDB) { - return this.renderUnsupportedIndexedDB(); - } - return this.renderError(); - } - return this.props.children; - } -} - -const ErrorBoundary = withTranslation()(ErrorBoundaryImpl); // Adds props.t -export default ErrorBoundary; diff --git a/web/src/components/Login.js b/web/src/components/Login.js new file mode 100644 index 0000000..8b14c53 --- /dev/null +++ b/web/src/components/Login.js @@ -0,0 +1,122 @@ +import * as React from 'react'; +import {useState} from 'react'; +import Typography from "@mui/material/Typography"; +import WarningAmberIcon from '@mui/icons-material/WarningAmber'; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; +import routes from "./routes"; +import session from "../app/Session"; +import {NavLink} from "react-router-dom"; +import AvatarBox from "./AvatarBox"; +import {useTranslation} from "react-i18next"; +import accountApi from "../app/AccountApi"; +import IconButton from "@mui/material/IconButton"; +import {InputAdornment} from "@mui/material"; +import {Visibility, VisibilityOff} from "@mui/icons-material"; +import {UnauthorizedError} from "../app/errors"; + +const Login = () => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + + const handleSubmit = async (event) => { + event.preventDefault(); + const user = { username, password }; + try { + const token = await accountApi.login(user); + console.log(`[Login] User auth for user ${user.username} successful, token is ${token}`); + session.store(user.username, token); + window.location.href = routes.app; + } catch (e) { + console.log(`[Login] User auth for user ${user.username} failed`, e); + if (e instanceof UnauthorizedError) { + setError(t("Login failed: Invalid username or password")); + } else { + setError(e.message); + } + } + }; + if (!config.enable_login) { + return ( + + {t("login_disabled")} + + ); + } + return ( + + + {t("login_title")} + + + setUsername(ev.target.value.trim())} + autoFocus + /> + setPassword(ev.target.value.trim())} + autoComplete="current-password" + InputProps={{ + endAdornment: ( + + setShowPassword(!showPassword)} + onMouseDown={(ev) => ev.preventDefault()} + edge="end" + > + {showPassword ? : } + + + ) + }} + /> + + {error && + + + {error} + + } + + {/* This is where the password reset link would go */} + {config.enable_signup &&
{t("login_link_signup")}
} +
+
+
+ ); +} + +export default Login; diff --git a/web/src/components/Login.jsx b/web/src/components/Login.jsx deleted file mode 100644 index 489eee0..0000000 --- a/web/src/components/Login.jsx +++ /dev/null @@ -1,117 +0,0 @@ -import * as React from "react"; -import { useState } from "react"; -import { Typography, TextField, Button, Box, IconButton, InputAdornment } from "@mui/material"; -import WarningAmberIcon from "@mui/icons-material/WarningAmber"; -import { NavLink } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import { Visibility, VisibilityOff } from "@mui/icons-material"; -import accountApi from "../app/AccountApi"; -import AvatarBox from "./AvatarBox"; -import session from "../app/Session"; -import routes from "./routes"; -import { UnauthorizedError } from "../app/errors"; - -const Login = () => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [showPassword, setShowPassword] = useState(false); - - const handleSubmit = async (event) => { - event.preventDefault(); - const user = { username, password }; - try { - const token = await accountApi.login(user); - console.log(`[Login] User auth for user ${user.username} successful, token is ${token}`); - session.store(user.username, token); - window.location.href = routes.app; - } catch (e) { - console.log(`[Login] User auth for user ${user.username} failed`, e); - if (e instanceof UnauthorizedError) { - setError(t("Login failed: Invalid username or password")); - } else { - setError(e.message); - } - } - }; - if (!config.enable_login) { - return ( - - {t("login_disabled")} - - ); - } - return ( - - {t("login_title")} - - setUsername(ev.target.value.trim())} - autoFocus - /> - setPassword(ev.target.value.trim())} - autoComplete="current-password" - InputProps={{ - endAdornment: ( - - setShowPassword(!showPassword)} - onMouseDown={(ev) => ev.preventDefault()} - edge="end" - > - {showPassword ? : } - - - ), - }} - /> - - {error && ( - - - {error} - - )} - - {/* This is where the password reset link would go */} - {config.enable_signup && ( -
- - {t("login_link_signup")} - -
- )} -
-
-
- ); -}; - -export default Login; diff --git a/web/src/components/Messaging.js b/web/src/components/Messaging.js new file mode 100644 index 0000000..b1f11a9 --- /dev/null +++ b/web/src/components/Messaging.js @@ -0,0 +1,114 @@ +import * as React from 'react'; +import {useState} from 'react'; +import Navigation from "./Navigation"; +import Paper from "@mui/material/Paper"; +import IconButton from "@mui/material/IconButton"; +import TextField from "@mui/material/TextField"; +import SendIcon from "@mui/icons-material/Send"; +import api from "../app/Api"; +import PublishDialog from "./PublishDialog"; +import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; +import {Portal, Snackbar} from "@mui/material"; +import {useTranslation} from "react-i18next"; + +const Messaging = (props) => { + const [message, setMessage] = useState(""); + const [dialogKey, setDialogKey] = useState(0); + + const dialogOpenMode = props.dialogOpenMode; + const subscription = props.selected; + + const handleOpenDialogClick = () => { + props.onDialogOpenModeChange(PublishDialog.OPEN_MODE_DEFAULT); + }; + + const handleDialogClose = () => { + props.onDialogOpenModeChange(""); + setDialogKey(prev => prev+1); + }; + + return ( + <> + {subscription && } + props.onDialogOpenModeChange(prev => (prev) ? prev : PublishDialog.OPEN_MODE_DRAG)} // Only update if not already open + onResetOpenMode={() => props.onDialogOpenModeChange(PublishDialog.OPEN_MODE_DEFAULT)} + /> + + ); +} + +const MessageBar = (props) => { + const { t } = useTranslation(); + const subscription = props.subscription; + const [snackOpen, setSnackOpen] = useState(false); + const handleSendClick = async () => { + try { + await api.publish(subscription.baseUrl, subscription.topic, props.message); + } catch (e) { + console.log(`[MessageBar] Error publishing message`, e); + setSnackOpen(true); + } + props.onMessageChange(""); + }; + return ( + theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.grey[900] + }} + > + + + + props.onMessageChange(ev.target.value)} + onKeyPress={(ev) => { + if (ev.key === 'Enter') { + ev.preventDefault(); + handleSendClick(); + } + }} + /> + + + + + setSnackOpen(false)} + message={t("message_bar_error_publishing")} + /> + + + ); +}; + +export default Messaging; diff --git a/web/src/components/Messaging.jsx b/web/src/components/Messaging.jsx deleted file mode 100644 index 27e08dc..0000000 --- a/web/src/components/Messaging.jsx +++ /dev/null @@ -1,108 +0,0 @@ -import * as React from "react"; -import { useState } from "react"; -import { Paper, IconButton, TextField, Portal, Snackbar } from "@mui/material"; -import SendIcon from "@mui/icons-material/Send"; -import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; -import { useTranslation } from "react-i18next"; -import PublishDialog from "./PublishDialog"; -import api from "../app/Api"; -import Navigation from "./Navigation"; - -const Messaging = (props) => { - const [message, setMessage] = useState(""); - const [dialogKey, setDialogKey] = useState(0); - - const { dialogOpenMode } = props; - const subscription = props.selected; - - const handleOpenDialogClick = () => { - props.onDialogOpenModeChange(PublishDialog.OPEN_MODE_DEFAULT); - }; - - const handleDialogClose = () => { - props.onDialogOpenModeChange(""); - setDialogKey((prev) => prev + 1); - }; - - return ( - <> - {subscription && ( - - )} - props.onDialogOpenModeChange((prev) => prev || PublishDialog.OPEN_MODE_DRAG)} // Only update if not already open - onResetOpenMode={() => props.onDialogOpenModeChange(PublishDialog.OPEN_MODE_DEFAULT)} - /> - - ); -}; - -const MessageBar = (props) => { - const { t } = useTranslation(); - const { subscription } = props; - const [snackOpen, setSnackOpen] = useState(false); - const handleSendClick = async () => { - try { - await api.publish(subscription.baseUrl, subscription.topic, props.message); - } catch (e) { - console.log(`[MessageBar] Error publishing message`, e); - setSnackOpen(true); - } - props.onMessageChange(""); - }; - return ( - (theme.palette.mode === "light" ? theme.palette.grey[100] : theme.palette.grey[900]), - }} - > - - - - props.onMessageChange(ev.target.value)} - onKeyPress={(ev) => { - if (ev.key === "Enter") { - ev.preventDefault(); - handleSendClick(); - } - }} - /> - - - - - setSnackOpen(false)} - message={t("message_bar_error_publishing")} - /> - - - ); -}; - -export default Messaging; diff --git a/web/src/components/Navigation.js b/web/src/components/Navigation.js new file mode 100644 index 0000000..a7d0da0 --- /dev/null +++ b/web/src/components/Navigation.js @@ -0,0 +1,371 @@ +import Drawer from "@mui/material/Drawer"; +import * as React from "react"; +import {useContext, useState} from "react"; +import ListItemButton from "@mui/material/ListItemButton"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline"; +import Person from "@mui/icons-material/Person"; +import ListItemText from "@mui/material/ListItemText"; +import Toolbar from "@mui/material/Toolbar"; +import Divider from "@mui/material/Divider"; +import List from "@mui/material/List"; +import SettingsIcon from "@mui/icons-material/Settings"; +import AddIcon from "@mui/icons-material/Add"; +import SubscribeDialog from "./SubscribeDialog"; +import {Alert, AlertTitle, Badge, CircularProgress, Link, ListSubheader, Portal, Tooltip} from "@mui/material"; +import Button from "@mui/material/Button"; +import Typography from "@mui/material/Typography"; +import {openUrl, topicDisplayName, topicUrl} from "../app/utils"; +import routes from "./routes"; +import {ConnectionState} from "../app/Connection"; +import {useLocation, useNavigate} from "react-router-dom"; +import subscriptionManager from "../app/SubscriptionManager"; +import {ChatBubble, MoreVert, NotificationsOffOutlined, Send} from "@mui/icons-material"; +import Box from "@mui/material/Box"; +import notifier from "../app/Notifier"; +import config from "../app/config"; +import ArticleIcon from '@mui/icons-material/Article'; +import {Trans, useTranslation} from "react-i18next"; +import session from "../app/Session"; +import accountApi, {Permission, Role} from "../app/AccountApi"; +import CelebrationIcon from '@mui/icons-material/Celebration'; +import UpgradeDialog from "./UpgradeDialog"; +import {AccountContext} from "./App"; +import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons"; +import IconButton from "@mui/material/IconButton"; +import { SubscriptionPopup } from "./SubscriptionPopup"; + +const navWidth = 280; + +const Navigation = (props) => { + const navigationList = ; + return ( + + {/* Mobile drawer; only shown if menu icon clicked (mobile open) and display is small */} + + {navigationList} + + {/* Big screen drawer; persistent, shown if screen is big */} + + {navigationList} + + + ); +}; +Navigation.width = navWidth; + +const NavList = (props) => { + const { t } = useTranslation(); + const navigate = useNavigate(); + const location = useLocation(); + const { account } = useContext(AccountContext); + const [subscribeDialogKey, setSubscribeDialogKey] = useState(0); + const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false); + + const handleSubscribeReset = () => { + setSubscribeDialogOpen(false); + setSubscribeDialogKey(prev => prev+1); + } + + const handleSubscribeSubmit = (subscription) => { + console.log(`[Navigation] New subscription: ${subscription.id}`, subscription); + handleSubscribeReset(); + navigate(routes.forSubscription(subscription)); + handleRequestNotificationPermission(); + } + + const handleRequestNotificationPermission = () => { + notifier.maybeRequestPermission(granted => props.onNotificationGranted(granted)) + }; + + const handleAccountClick = () => { + accountApi.sync(); // Dangle! + navigate(routes.account); + }; + + const isAdmin = account?.role === Role.ADMIN; + const isPaid = account?.billing?.subscription; + const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid; + const showSubscriptionsList = props.subscriptions?.length > 0; + const showNotificationBrowserNotSupportedBox = !notifier.browserSupported(); + const showNotificationContextNotSupportedBox = notifier.browserSupported() && !notifier.contextSupported(); // Only show if notifications are generally supported in the browser + const showNotificationGrantBox = notifier.supported() && props.subscriptions?.length > 0 && !props.notificationsGranted; + const navListPadding = (showNotificationGrantBox || showNotificationBrowserNotSupportedBox || showNotificationContextNotSupportedBox) ? '0' : ''; + + return ( + <> + + + {showNotificationBrowserNotSupportedBox && } + {showNotificationContextNotSupportedBox && } + {showNotificationGrantBox && } + {!showSubscriptionsList && + navigate(routes.app)} selected={location.pathname === config.app_root}> + + + } + {showSubscriptionsList && + <> + {t("nav_topics_title")} + navigate(routes.app)} selected={location.pathname === config.app_root}> + + + + + + } + {session.exists() && + + + + + } + navigate(routes.settings)} selected={location.pathname === routes.settings}> + + + + openUrl("/docs")}> + + + + props.onPublishMessageClick()}> + + + + setSubscribeDialogOpen(true)}> + + + + {showUpgradeBanner && + + } + + + + ); +}; + +const UpgradeBanner = () => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + + const handleClick = () => { + setDialogKey(k => k + 1); + setDialogOpen(true); + }; + + return ( + + + + + + + setDialogOpen(false)} + /> + + ); +}; + +const SubscriptionList = (props) => { + const sortedSubscriptions = props.subscriptions + .filter(s => !s.internal) + .sort((a, b) => { + return (topicUrl(a.baseUrl, a.topic) < topicUrl(b.baseUrl, b.topic)) ? -1 : 1; + }); + return ( + <> + {sortedSubscriptions.map(subscription => + )} + + ); +} + +const SubscriptionItem = (props) => { + const { t } = useTranslation(); + const navigate = useNavigate(); + const [menuAnchorEl, setMenuAnchorEl] = useState(null); + + const subscription = props.subscription; + const iconBadge = (subscription.new <= 99) ? subscription.new : "99+"; + const displayName = topicDisplayName(subscription); + const ariaLabel = (subscription.state === ConnectionState.Connecting) + ? `${displayName} (${t("nav_button_connecting")})` + : displayName; + const icon = (subscription.state === ConnectionState.Connecting) + ? + : ; + + const handleClick = async () => { + navigate(routes.forSubscription(subscription)); + await subscriptionManager.markNotificationsRead(subscription.id); + }; + + return ( + <> + + {icon} + + {subscription.reservation?.everyone && + + {subscription.reservation?.everyone === Permission.READ_WRITE && + + } + {subscription.reservation?.everyone === Permission.READ_ONLY && + + } + {subscription.reservation?.everyone === Permission.WRITE_ONLY && + + } + {subscription.reservation?.everyone === Permission.DENY_ALL && + + } + + } + {subscription.mutedUntil > 0 && + + + + } + + e.stopPropagation()} + onClick={(e) => { + e.stopPropagation(); + setMenuAnchorEl(e.currentTarget); + }} + > + + + + + + setMenuAnchorEl(null)} + /> + + + ); +}; + +const NotificationGrantAlert = (props) => { + const { t } = useTranslation(); + return ( + <> + + {t("alert_grant_title")} + {t("alert_grant_description")} + + + + + ); +}; + +const NotificationBrowserNotSupportedAlert = () => { + const { t } = useTranslation(); + return ( + <> + + {t("alert_not_supported_title")} + {t("alert_not_supported_description")} + + + + ); +}; + +const NotificationContextNotSupportedAlert = () => { + const { t } = useTranslation(); + return ( + <> + + {t("alert_not_supported_title")} + + + }} + /> + + + + + ); +}; + +export default Navigation; diff --git a/web/src/components/Navigation.jsx b/web/src/components/Navigation.jsx deleted file mode 100644 index 8cbefec..0000000 --- a/web/src/components/Navigation.jsx +++ /dev/null @@ -1,396 +0,0 @@ -import { - Drawer, - ListItemButton, - ListItemIcon, - ListItemText, - Toolbar, - Divider, - List, - Alert, - AlertTitle, - Badge, - CircularProgress, - Link, - ListSubheader, - Portal, - Tooltip, - Button, - Typography, - Box, - IconButton, -} from "@mui/material"; -import * as React from "react"; -import { useContext, useState } from "react"; -import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline"; -import Person from "@mui/icons-material/Person"; -import SettingsIcon from "@mui/icons-material/Settings"; -import AddIcon from "@mui/icons-material/Add"; -import { useLocation, useNavigate } from "react-router-dom"; -import { ChatBubble, MoreVert, NotificationsOffOutlined, Send } from "@mui/icons-material"; -import ArticleIcon from "@mui/icons-material/Article"; -import { Trans, useTranslation } from "react-i18next"; -import CelebrationIcon from "@mui/icons-material/Celebration"; -import SubscribeDialog from "./SubscribeDialog"; -import { openUrl, topicDisplayName, topicUrl } from "../app/utils"; -import routes from "./routes"; -import { ConnectionState } from "../app/Connection"; -import subscriptionManager from "../app/SubscriptionManager"; -import notifier from "../app/Notifier"; -import config from "../app/config"; -import session from "../app/Session"; -import accountApi, { Permission, Role } from "../app/AccountApi"; -import UpgradeDialog from "./UpgradeDialog"; -import { AccountContext } from "./App"; -import { PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite } from "./ReserveIcons"; -import { SubscriptionPopup } from "./SubscriptionPopup"; - -const navWidth = 280; - -const Navigation = (props) => { - const navigationList = ; - return ( - - {/* Mobile drawer; only shown if menu icon clicked (mobile open) and display is small */} - - {navigationList} - - {/* Big screen drawer; persistent, shown if screen is big */} - - {navigationList} - - - ); -}; -Navigation.width = navWidth; - -const NavList = (props) => { - const { t } = useTranslation(); - const navigate = useNavigate(); - const location = useLocation(); - const { account } = useContext(AccountContext); - const [subscribeDialogKey, setSubscribeDialogKey] = useState(0); - const [subscribeDialogOpen, setSubscribeDialogOpen] = useState(false); - - const handleSubscribeReset = () => { - setSubscribeDialogOpen(false); - setSubscribeDialogKey((prev) => prev + 1); - }; - - const handleRequestNotificationPermission = () => { - notifier.maybeRequestPermission((granted) => props.onNotificationGranted(granted)); - }; - - const handleSubscribeSubmit = (subscription) => { - console.log(`[Navigation] New subscription: ${subscription.id}`, subscription); - handleSubscribeReset(); - navigate(routes.forSubscription(subscription)); - handleRequestNotificationPermission(); - }; - - const handleAccountClick = () => { - accountApi.sync(); // Dangle! - navigate(routes.account); - }; - - const isAdmin = account?.role === Role.ADMIN; - const isPaid = account?.billing?.subscription; - const showUpgradeBanner = config.enable_payments && !isAdmin && !isPaid; - const showSubscriptionsList = props.subscriptions?.length > 0; - const showNotificationBrowserNotSupportedBox = !notifier.browserSupported(); - const showNotificationContextNotSupportedBox = notifier.browserSupported() && !notifier.contextSupported(); // Only show if notifications are generally supported in the browser - const showNotificationGrantBox = notifier.supported() && props.subscriptions?.length > 0 && !props.notificationsGranted; - const navListPadding = - showNotificationGrantBox || showNotificationBrowserNotSupportedBox || showNotificationContextNotSupportedBox ? "0" : ""; - - return ( - <> - - - {showNotificationBrowserNotSupportedBox && } - {showNotificationContextNotSupportedBox && } - {showNotificationGrantBox && } - {!showSubscriptionsList && ( - navigate(routes.app)} selected={location.pathname === config.app_root}> - - - - - - )} - {showSubscriptionsList && ( - <> - {t("nav_topics_title")} - navigate(routes.app)} selected={location.pathname === config.app_root}> - - - - - - - - - )} - {session.exists() && ( - - - - - - - )} - navigate(routes.settings)} selected={location.pathname === routes.settings}> - - - - - - openUrl("/docs")}> - - - - - - props.onPublishMessageClick()}> - - - - - - setSubscribeDialogOpen(true)}> - - - - - - {showUpgradeBanner && } - - - - ); -}; - -const UpgradeBanner = () => { - const { t } = useTranslation(); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - - const handleClick = () => { - setDialogKey((k) => k + 1); - setDialogOpen(true); - }; - - return ( - - - - - - - - - setDialogOpen(false)} /> - - ); -}; - -const SubscriptionList = (props) => { - const sortedSubscriptions = props.subscriptions - .filter((s) => !s.internal) - .sort((a, b) => (topicUrl(a.baseUrl, a.topic) < topicUrl(b.baseUrl, b.topic) ? -1 : 1)); - return ( - <> - {sortedSubscriptions.map((subscription) => ( - - ))} - - ); -}; - -const SubscriptionItem = (props) => { - const { t } = useTranslation(); - const navigate = useNavigate(); - const [menuAnchorEl, setMenuAnchorEl] = useState(null); - - const { subscription } = props; - const iconBadge = subscription.new <= 99 ? subscription.new : "99+"; - const displayName = topicDisplayName(subscription); - const ariaLabel = subscription.state === ConnectionState.Connecting ? `${displayName} (${t("nav_button_connecting")})` : displayName; - const icon = - subscription.state === ConnectionState.Connecting ? ( - - ) : ( - - - - ); - - const handleClick = async () => { - navigate(routes.forSubscription(subscription)); - await subscriptionManager.markNotificationsRead(subscription.id); - }; - - return ( - <> - - {icon} - - {subscription.reservation?.everyone && ( - - {subscription.reservation?.everyone === Permission.READ_WRITE && ( - - - - )} - {subscription.reservation?.everyone === Permission.READ_ONLY && ( - - - - )} - {subscription.reservation?.everyone === Permission.WRITE_ONLY && ( - - - - )} - {subscription.reservation?.everyone === Permission.DENY_ALL && ( - - - - )} - - )} - {subscription.mutedUntil > 0 && ( - - - - - - )} - - e.stopPropagation()} - onClick={(e) => { - e.stopPropagation(); - setMenuAnchorEl(e.currentTarget); - }} - > - - - - - - setMenuAnchorEl(null)} /> - - - ); -}; - -const NotificationGrantAlert = (props) => { - const { t } = useTranslation(); - return ( - <> - - {t("alert_grant_title")} - {t("alert_grant_description")} - - - - - ); -}; - -const NotificationBrowserNotSupportedAlert = () => { - const { t } = useTranslation(); - return ( - <> - - {t("alert_not_supported_title")} - {t("alert_not_supported_description")} - - - - ); -}; - -const NotificationContextNotSupportedAlert = () => { - const { t } = useTranslation(); - return ( - <> - - {t("alert_not_supported_title")} - - , - }} - /> - - - - - ); -}; - -export default Navigation; diff --git a/web/src/components/Notifications.js b/web/src/components/Notifications.js new file mode 100644 index 0000000..10bcad8 --- /dev/null +++ b/web/src/components/Notifications.js @@ -0,0 +1,548 @@ +import Container from "@mui/material/Container"; +import { + ButtonBase, + CardActions, + CardContent, + CircularProgress, + Fade, + Link, + Modal, + Snackbar, + Stack, + Tooltip +} from "@mui/material"; +import Card from "@mui/material/Card"; +import Typography from "@mui/material/Typography"; +import * as React from "react"; +import {useEffect, useState} from "react"; +import { + formatBytes, + formatMessage, + formatShortDateTime, + formatTitle, + maybeAppendActionErrors, + openUrl, + shortUrl, + topicShortUrl, + unmatchedTags +} from "../app/utils"; +import IconButton from "@mui/material/IconButton"; +import CheckIcon from '@mui/icons-material/Check'; +import CloseIcon from '@mui/icons-material/Close'; +import {LightboxBackdrop, Paragraph, VerticallyCenteredContainer} from "./styles"; +import {useLiveQuery} from "dexie-react-hooks"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import subscriptionManager from "../app/SubscriptionManager"; +import InfiniteScroll from "react-infinite-scroll-component"; +import priority1 from "../img/priority-1.svg"; +import priority2 from "../img/priority-2.svg"; +import priority4 from "../img/priority-4.svg"; +import priority5 from "../img/priority-5.svg"; +import logoOutline from "../img/ntfy-outline.svg"; +import AttachmentIcon from "./AttachmentIcon"; +import {Trans, useTranslation} from "react-i18next"; +import {useOutletContext} from "react-router-dom"; +import {useAutoSubscribe} from "./hooks"; + +export const AllSubscriptions = () => { + const { subscriptions } = useOutletContext(); + if (!subscriptions) { + return ; + } + return ; +}; + +export const SingleSubscription = () => { + const { subscriptions, selected } = useOutletContext(); + useAutoSubscribe(subscriptions, selected); + if (!selected) { + return ; + } + return ; +}; + +const AllSubscriptionsList = (props) => { + const subscriptions = props.subscriptions; + const notifications = useLiveQuery(() => subscriptionManager.getAllNotifications(), []); + if (notifications === null || notifications === undefined) { + return ; + } else if (subscriptions.length === 0) { + return ; + } else if (notifications.length === 0) { + return ; + } + return ; +} + +const SingleSubscriptionList = (props) => { + const subscription = props.subscription; + const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]); + if (notifications === null || notifications === undefined) { + return ; + } else if (notifications.length === 0) { + return ; + } + return ; +} + +const NotificationList = (props) => { + const { t } = useTranslation(); + const pageSize = 20; + const notifications = props.notifications; + const [snackOpen, setSnackOpen] = useState(false); + const [maxCount, setMaxCount] = useState(pageSize); + const count = Math.min(notifications.length, maxCount); + + useEffect(() => { + return () => { + setMaxCount(pageSize); + const main = document.getElementById("main"); + if (main) { + main.scrollTo(0, 0); + } + } + }, [props.id]); + + return ( + setMaxCount(prev => prev + pageSize)} + hasMore={count < notifications.length} + loader={<>Loading ...} + scrollThreshold={0.7} + scrollableTarget="main" + > + + + {notifications.slice(0, count).map(notification => + setSnackOpen(true)} + />)} + setSnackOpen(false)} + message={t("notifications_copied_to_clipboard")} + /> + + + + ); +} + +const NotificationItem = (props) => { + const { t } = useTranslation(); + const notification = props.notification; + const attachment = notification.attachment; + const date = formatShortDateTime(notification.time); + const otherTags = unmatchedTags(notification.tags); + const tags = (otherTags.length > 0) ? otherTags.join(', ') : null; + const handleDelete = async () => { + console.log(`[Notifications] Deleting notification ${notification.id}`); + await subscriptionManager.deleteNotification(notification.id) + } + const handleMarkRead = async () => { + console.log(`[Notifications] Marking notification ${notification.id} as read`); + await subscriptionManager.markNotificationRead(notification.id) + } + const handleCopy = (s) => { + navigator.clipboard.writeText(s); + props.onShowSnack(); + }; + const expired = attachment && attachment.expires && attachment.expires < Date.now()/1000; + const hasAttachmentActions = attachment && !expired; + const hasClickAction = notification.click; + const hasUserActions = notification.actions && notification.actions.length > 0; + const showActions = hasAttachmentActions || hasClickAction || hasUserActions; + return ( + + + + + + + + {notification.new === 1 && + + + + + } + + {date} + {[1,2,4,5].includes(notification.priority) && + {t("notifications_priority_x",} + {notification.new === 1 && + + + } + + {notification.title && {formatTitle(notification)}} + + {autolink(maybeAppendActionErrors(formatMessage(notification), notification))} + + {attachment && } + {tags && {t("notifications_tags")}: {tags}} + + {showActions && + + {hasAttachmentActions && <> + + + + + + + } + {hasClickAction && <> + + + + + + + } + {hasUserActions && } + } + + ); +} + +/** + * Replace links with components; this is a combination of the genius function + * in [1] and the regex in [2]. + * + * [1] https://github.com/facebook/react/issues/3386#issuecomment-78605760 + * [2] https://github.com/bryanwoods/autolink-js/blob/master/autolink.js#L9 + */ +const autolink = (s) => { + const parts = s.split(/(\bhttps?:\/\/[\-A-Z0-9+\u0026\u2019@#\/%?=()~_|!:,.;]*[\-A-Z0-9+\u0026@#\/%=~()_|]\b)/gi); + for (let i = 1; i < parts.length; i += 2) { + parts[i] = {shortUrl(parts[i])}; + } + return <>{parts}; +}; + +const priorityFiles = { + 1: priority1, + 2: priority2, + 4: priority4, + 5: priority5 +}; + +const Attachment = (props) => { + const { t } = useTranslation(); + const attachment = props.attachment; + const expired = attachment.expires && attachment.expires < Date.now()/1000; + const expires = attachment.expires && attachment.expires > Date.now()/1000; + const displayableImage = !expired && attachment.type && attachment.type.startsWith("image/"); + + // Unexpired image + if (displayableImage) { + return ; + } + + // Anything else: Show box + const infos = []; + if (attachment.size) { + infos.push(formatBytes(attachment.size)); + } + if (expires) { + infos.push(t("notifications_attachment_link_expires", { date: formatShortDateTime(attachment.expires) })); + } + if (expired) { + infos.push(t("notifications_attachment_link_expired")); + } + const maybeInfoText = (infos.length > 0) ? <>
{infos.join(", ")} : null; + + // If expired, just show infos without click target + if (expired) { + return ( + + + + {attachment.name} + {maybeInfoText} + + + ); + } + + // Not expired + return ( + + + + + {attachment.name} + {maybeInfoText} + + + + ); +}; + +const Image = (props) => { + const { t } = useTranslation(); + const [open, setOpen] = useState(false); + return ( + <> + setOpen(true)} + sx={{ + marginTop: 2, + borderRadius: '4px', + boxShadow: 2, + width: 1, + maxHeight: '400px', + objectFit: 'cover', + cursor: 'pointer' + }} + /> + setOpen(false)} + BackdropComponent={LightboxBackdrop} + > + + + + + + ); +} + +const UserActions = (props) => { + return ( + <>{props.notification.actions.map(action => + )} + ); +}; + +const UserAction = (props) => { + const { t } = useTranslation(); + const notification = props.notification; + const action = props.action; + if (action.action === "broadcast") { + return ( + + + + ); + } else if (action.action === "view") { + return ( + + + + ); + } else if (action.action === "http") { + const method = action.method ?? "POST"; + const label = action.label + (ACTION_LABEL_SUFFIX[action.progress ?? 0] ?? ""); + return ( + + + + ); + } + return null; // Others +}; + +const performHttpAction = async (notification, action) => { + console.log(`[Notifications] Performing HTTP user action`, action); + try { + updateActionStatus(notification, action, ACTION_PROGRESS_ONGOING, null); + const response = await fetch(action.url, { + method: action.method ?? "POST", + headers: action.headers ?? {}, + // This must not null-coalesce to a non nullish value. Otherwise, the fetch API + // will reject it for "having a body" + body: action.body + }); + console.log(`[Notifications] HTTP user action response`, response); + const success = response.status >= 200 && response.status <= 299; + if (success) { + updateActionStatus(notification, action, ACTION_PROGRESS_SUCCESS, null); + } else { + updateActionStatus(notification, action, ACTION_PROGRESS_FAILED, `${action.label}: Unexpected response HTTP ${response.status}`); + } + } catch (e) { + console.log(`[Notifications] HTTP action failed`, e); + updateActionStatus(notification, action, ACTION_PROGRESS_FAILED, `${action.label}: ${e} Check developer console for details.`); + } +}; + +const updateActionStatus = (notification, action, progress, error) => { + notification.actions = notification.actions.map(a => { + if (a.id !== action.id) { + return a; + } + return { ...a, progress: progress, error: error }; + }); + subscriptionManager.updateNotification(notification); +} + +const ACTION_PROGRESS_ONGOING = 1; +const ACTION_PROGRESS_SUCCESS = 2; +const ACTION_PROGRESS_FAILED = 3; + +const ACTION_LABEL_SUFFIX = { + [ACTION_PROGRESS_ONGOING]: " โ€ฆ", + [ACTION_PROGRESS_SUCCESS]: " โœ”", + [ACTION_PROGRESS_FAILED]: " โŒ" +}; + +const NoNotifications = (props) => { + const { t } = useTranslation(); + const shortUrl = topicShortUrl(props.subscription.baseUrl, props.subscription.topic); + return ( + + + {t("action_bar_logo_alt")}/
+ {t("notifications_none_for_topic_title")} +
+ + {t("notifications_none_for_topic_description")} + + + {t("notifications_example")}:
+ + $ curl -d "Hi" {shortUrl} + +
+ + + +
+ ); +}; + +const NoNotificationsWithoutSubscription = (props) => { + const { t } = useTranslation(); + const subscription = props.subscriptions[0]; + const shortUrl = topicShortUrl(subscription.baseUrl, subscription.topic); + return ( + + + {t("action_bar_logo_alt")}/
+ {t("notifications_none_for_any_title")} +
+ + {t("notifications_none_for_any_description")} + + + {t("notifications_example")}:
+ + $ curl -d "Hi" {shortUrl} + +
+ + + +
+ ); +}; + +const NoSubscriptions = () => { + const { t } = useTranslation(); + return ( + + + {t("action_bar_logo_alt")}/
+ {t("notifications_no_subscriptions_title")} +
+ + {t("notifications_no_subscriptions_description", { + linktext: t("nav_button_subscribe") + })} + + + + +
+ ); +}; + +const ForMoreDetails = () => { + return ( + , + docsLink: + }} + /> + ); +}; + +const Loading = () => { + const { t } = useTranslation(); + return ( + + +
+ {t("notifications_loading")} +
+
+ ); +}; diff --git a/web/src/components/Notifications.jsx b/web/src/components/Notifications.jsx deleted file mode 100644 index 2faf2fd..0000000 --- a/web/src/components/Notifications.jsx +++ /dev/null @@ -1,616 +0,0 @@ -import { - Container, - ButtonBase, - CardActions, - CardContent, - CircularProgress, - Fade, - Link, - Modal, - Snackbar, - Stack, - Tooltip, - Card, - Typography, - IconButton, - Box, - Button, -} from "@mui/material"; -import * as React from "react"; -import { useEffect, useState } from "react"; -import CheckIcon from "@mui/icons-material/Check"; -import CloseIcon from "@mui/icons-material/Close"; -import { useLiveQuery } from "dexie-react-hooks"; -import InfiniteScroll from "react-infinite-scroll-component"; -import { Trans, useTranslation } from "react-i18next"; -import { useOutletContext } from "react-router-dom"; -import { - formatBytes, - formatMessage, - formatShortDateTime, - formatTitle, - maybeAppendActionErrors, - openUrl, - shortUrl, - topicShortUrl, - unmatchedTags, -} from "../app/utils"; -import { LightboxBackdrop, Paragraph, VerticallyCenteredContainer } from "./styles"; -import subscriptionManager from "../app/SubscriptionManager"; -import priority1 from "../img/priority-1.svg"; -import priority2 from "../img/priority-2.svg"; -import priority4 from "../img/priority-4.svg"; -import priority5 from "../img/priority-5.svg"; -import logoOutline from "../img/ntfy-outline.svg"; -import AttachmentIcon from "./AttachmentIcon"; -import { useAutoSubscribe } from "./hooks"; - -const priorityFiles = { - 1: priority1, - 2: priority2, - 4: priority4, - 5: priority5, -}; - -export const AllSubscriptions = () => { - const { subscriptions } = useOutletContext(); - if (!subscriptions) { - return ; - } - return ; -}; - -export const SingleSubscription = () => { - const { subscriptions, selected } = useOutletContext(); - useAutoSubscribe(subscriptions, selected); - if (!selected) { - return ; - } - return ; -}; - -const AllSubscriptionsList = (props) => { - const { subscriptions } = props; - const notifications = useLiveQuery(() => subscriptionManager.getAllNotifications(), []); - if (notifications === null || notifications === undefined) { - return ; - } - if (subscriptions.length === 0) { - return ; - } - if (notifications.length === 0) { - return ; - } - return ; -}; - -const SingleSubscriptionList = (props) => { - const { subscription } = props; - const notifications = useLiveQuery(() => subscriptionManager.getNotifications(subscription.id), [subscription]); - if (notifications === null || notifications === undefined) { - return ; - } - if (notifications.length === 0) { - return ; - } - return ; -}; - -const NotificationList = (props) => { - const { t } = useTranslation(); - const pageSize = 20; - const { notifications } = props; - const [snackOpen, setSnackOpen] = useState(false); - const [maxCount, setMaxCount] = useState(pageSize); - const count = Math.min(notifications.length, maxCount); - - useEffect( - () => () => { - setMaxCount(pageSize); - const main = document.getElementById("main"); - if (main) { - main.scrollTo(0, 0); - } - }, - [props.id] - ); - - return ( - setMaxCount((prev) => prev + pageSize)} - hasMore={count < notifications.length} - loader={<>Loading ...} - scrollThreshold={0.7} - scrollableTarget="main" - > - - - {notifications.slice(0, count).map((notification) => ( - setSnackOpen(true)} /> - ))} - setSnackOpen(false)} - message={t("notifications_copied_to_clipboard")} - /> - - - - ); -}; - -/** - * Replace links with components; this is a combination of the genius function - * in [1] and the regex in [2]. - * - * [1] https://github.com/facebook/react/issues/3386#issuecomment-78605760 - * [2] https://github.com/bryanwoods/autolink-js/blob/master/autolink.js#L9 - */ -const autolink = (s) => { - const parts = s.split(/(\bhttps?:\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|]\b)/gi); - for (let i = 1; i < parts.length; i += 2) { - parts[i] = ( - - {shortUrl(parts[i])} - - ); - } - return <>{parts}; -}; - -const NotificationItem = (props) => { - const { t } = useTranslation(); - const { notification } = props; - const { attachment } = notification; - const date = formatShortDateTime(notification.time); - const otherTags = unmatchedTags(notification.tags); - const tags = otherTags.length > 0 ? otherTags.join(", ") : null; - const handleDelete = async () => { - console.log(`[Notifications] Deleting notification ${notification.id}`); - await subscriptionManager.deleteNotification(notification.id); - }; - const handleMarkRead = async () => { - console.log(`[Notifications] Marking notification ${notification.id} as read`); - await subscriptionManager.markNotificationRead(notification.id); - }; - const handleCopy = (s) => { - navigator.clipboard.writeText(s); - props.onShowSnack(); - }; - const expired = attachment && attachment.expires && attachment.expires < Date.now() / 1000; - const hasAttachmentActions = attachment && !expired; - const hasClickAction = notification.click; - const hasUserActions = notification.actions && notification.actions.length > 0; - const showActions = hasAttachmentActions || hasClickAction || hasUserActions; - return ( - - - - - - - - {notification.new === 1 && ( - - - - - - )} - - {date} - {[1, 2, 4, 5].includes(notification.priority) && ( - {t("notifications_priority_x", - )} - {notification.new === 1 && ( - - - - )} - - {notification.title && ( - - {formatTitle(notification)} - - )} - - {autolink(maybeAppendActionErrors(formatMessage(notification), notification))} - - {attachment && } - {tags && ( - - {t("notifications_tags")}: {tags} - - )} - - {showActions && ( - - {hasAttachmentActions && ( - <> - - - - - - - - )} - {hasClickAction && ( - <> - - - - - - - - )} - {hasUserActions && } - - )} - - ); -}; - -const Attachment = (props) => { - const { t } = useTranslation(); - const { attachment } = props; - const expired = attachment.expires && attachment.expires < Date.now() / 1000; - const expires = attachment.expires && attachment.expires > Date.now() / 1000; - const displayableImage = !expired && attachment.type && attachment.type.startsWith("image/"); - - // Unexpired image - if (displayableImage) { - return ; - } - - // Anything else: Show box - const infos = []; - if (attachment.size) { - infos.push(formatBytes(attachment.size)); - } - if (expires) { - infos.push( - t("notifications_attachment_link_expires", { - date: formatShortDateTime(attachment.expires), - }) - ); - } - if (expired) { - infos.push(t("notifications_attachment_link_expired")); - } - const maybeInfoText = - infos.length > 0 ? ( - <> -
- {infos.join(", ")} - - ) : null; - - // If expired, just show infos without click target - if (expired) { - return ( - - - - {attachment.name} - {maybeInfoText} - - - ); - } - - // Not expired - return ( - - - - - {attachment.name} - {maybeInfoText} - - - - ); -}; - -const Image = (props) => { - const { t } = useTranslation(); - const [open, setOpen] = useState(false); - return ( - <> - setOpen(true)} - sx={{ - marginTop: 2, - borderRadius: "4px", - boxShadow: 2, - width: 1, - maxHeight: "400px", - objectFit: "cover", - cursor: "pointer", - }} - /> - setOpen(false)} BackdropComponent={LightboxBackdrop}> - - - - - - ); -}; - -const UserActions = (props) => ( - <> - {props.notification.actions.map((action) => ( - - ))} - -); - -const ACTION_PROGRESS_ONGOING = 1; -const ACTION_PROGRESS_SUCCESS = 2; -const ACTION_PROGRESS_FAILED = 3; - -const ACTION_LABEL_SUFFIX = { - [ACTION_PROGRESS_ONGOING]: " โ€ฆ", - [ACTION_PROGRESS_SUCCESS]: " โœ”", - [ACTION_PROGRESS_FAILED]: " โŒ", -}; - -const updateActionStatus = (notification, action, progress, error) => { - subscriptionManager.updateNotification({ - ...notification, - actions: notification.actions.map((a) => (a.id === action.id ? { ...a, progress, error } : a)), - }); -}; - -const performHttpAction = async (notification, action) => { - console.log(`[Notifications] Performing HTTP user action`, action); - try { - updateActionStatus(notification, action, ACTION_PROGRESS_ONGOING, null); - const response = await fetch(action.url, { - method: action.method ?? "POST", - headers: action.headers ?? {}, - // This must not null-coalesce to a non nullish value. Otherwise, the fetch API - // will reject it for "having a body" - body: action.body, - }); - console.log(`[Notifications] HTTP user action response`, response); - const success = response.status >= 200 && response.status <= 299; - if (success) { - updateActionStatus(notification, action, ACTION_PROGRESS_SUCCESS, null); - } else { - updateActionStatus(notification, action, ACTION_PROGRESS_FAILED, `${action.label}: Unexpected response HTTP ${response.status}`); - } - } catch (e) { - console.log(`[Notifications] HTTP action failed`, e); - updateActionStatus(notification, action, ACTION_PROGRESS_FAILED, `${action.label}: ${e} Check developer console for details.`); - } -}; - -const UserAction = (props) => { - const { t } = useTranslation(); - const { notification } = props; - const { action } = props; - if (action.action === "broadcast") { - return ( - - - - - - ); - } - if (action.action === "view") { - return ( - - - - ); - } - if (action.action === "http") { - const method = action.method ?? "POST"; - const label = action.label + (ACTION_LABEL_SUFFIX[action.progress ?? 0] ?? ""); - return ( - - - - ); - } - return null; // Others -}; - -const NoNotifications = (props) => { - const { t } = useTranslation(); - const topicShortUrlResolved = topicShortUrl(props.subscription.baseUrl, props.subscription.topic); - return ( - - - {t("action_bar_logo_alt")} -
- {t("notifications_none_for_topic_title")} -
- {t("notifications_none_for_topic_description")} - - {t("notifications_example")}:
- - {'$ curl -d "Hi" '} - {topicShortUrlResolved} - -
- - - -
- ); -}; - -const NoNotificationsWithoutSubscription = (props) => { - const { t } = useTranslation(); - const subscription = props.subscriptions[0]; - const topicShortUrlResolved = topicShortUrl(subscription.baseUrl, subscription.topic); - return ( - - - {t("action_bar_logo_alt")} -
- {t("notifications_none_for_any_title")} -
- {t("notifications_none_for_any_description")} - - {t("notifications_example")}:
- - {'$ curl -d "Hi" '} - {topicShortUrlResolved} - -
- - - -
- ); -}; - -const NoSubscriptions = () => { - const { t } = useTranslation(); - return ( - - - {t("action_bar_logo_alt")} -
- {t("notifications_no_subscriptions_title")} -
- - {t("notifications_no_subscriptions_description", { - linktext: t("nav_button_subscribe"), - })} - - - - -
- ); -}; - -const ForMoreDetails = () => ( - , - docsLink: , - }} - /> -); - -const Loading = () => { - const { t } = useTranslation(); - return ( - - - -
- {t("notifications_loading")} -
-
- ); -}; diff --git a/web/src/components/PopupMenu.js b/web/src/components/PopupMenu.js new file mode 100644 index 0000000..4d22398 --- /dev/null +++ b/web/src/components/PopupMenu.js @@ -0,0 +1,48 @@ +import {Fade, Menu} from "@mui/material"; +import * as React from "react"; + +const PopupMenu = (props) => { + const horizontal = props.horizontal ?? "left"; + const arrow = (horizontal === "right") ? { right: 19 } : { left: 19 }; + return ( + + {props.children} + + ); +}; + +export default PopupMenu; diff --git a/web/src/components/PopupMenu.jsx b/web/src/components/PopupMenu.jsx deleted file mode 100644 index 89b2011..0000000 --- a/web/src/components/PopupMenu.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import { Fade, Menu } from "@mui/material"; -import * as React from "react"; - -const PopupMenu = (props) => { - const horizontal = props.horizontal ?? "left"; - const arrow = horizontal === "right" ? { right: 19 } : { left: 19 }; - return ( - - {props.children} - - ); -}; - -export default PopupMenu; diff --git a/web/src/components/Pref.js b/web/src/components/Pref.js new file mode 100644 index 0000000..622d9bb --- /dev/null +++ b/web/src/components/Pref.js @@ -0,0 +1,51 @@ +import * as React from "react"; + +export const PrefGroup = (props) => { + return ( +
+ {props.children} +
+ ) +}; + +export const Pref = (props) => { + const justifyContent = (props.alignTop) ? "normal" : "center"; + return ( +
+
+
{props.title}{props.subtitle && ({props.subtitle})}
+ {props.description &&
{props.description}
} +
+
+ {props.children} +
+
+ ); +}; diff --git a/web/src/components/Pref.jsx b/web/src/components/Pref.jsx deleted file mode 100644 index a725d11..0000000 --- a/web/src/components/Pref.jsx +++ /dev/null @@ -1,52 +0,0 @@ -import * as React from "react"; - -export const PrefGroup = (props) =>
{props.children}
; - -export const Pref = (props) => { - const justifyContent = props.alignTop ? "normal" : "center"; - return ( -
-
-
- {props.title} - {props.subtitle && ({props.subtitle})} -
- {props.description && ( -
- {props.description} -
- )} -
-
- {props.children} -
-
- ); -}; diff --git a/web/src/components/Preferences.js b/web/src/components/Preferences.js new file mode 100644 index 0000000..3f6c1b3 --- /dev/null +++ b/web/src/components/Preferences.js @@ -0,0 +1,646 @@ +import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; +import { + Alert, + CardActions, + CardContent, + Chip, + FormControl, + Select, + Stack, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Tooltip, + useMediaQuery +} from "@mui/material"; +import Typography from "@mui/material/Typography"; +import prefs from "../app/Prefs"; +import {Paragraph} from "./styles"; +import EditIcon from '@mui/icons-material/Edit'; +import CloseIcon from "@mui/icons-material/Close"; +import IconButton from "@mui/material/IconButton"; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; +import Container from "@mui/material/Container"; +import TextField from "@mui/material/TextField"; +import MenuItem from "@mui/material/MenuItem"; +import Card from "@mui/material/Card"; +import Button from "@mui/material/Button"; +import {useLiveQuery} from "dexie-react-hooks"; +import theme from "./theme"; +import Dialog from "@mui/material/Dialog"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import DialogActions from "@mui/material/DialogActions"; +import userManager from "../app/UserManager"; +import {playSound, shuffle, sounds, validUrl} from "../app/utils"; +import {useTranslation} from "react-i18next"; +import session from "../app/Session"; +import routes from "./routes"; +import accountApi, {Permission, Role} from "../app/AccountApi"; +import {Pref, PrefGroup} from "./Pref"; +import {Info} from "@mui/icons-material"; +import {AccountContext} from "./App"; +import {useOutletContext} from "react-router-dom"; +import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons"; +import {ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog} from "./ReserveDialogs"; +import {UnauthorizedError} from "../app/errors"; +import subscriptionManager from "../app/SubscriptionManager"; +import {subscribeTopic} from "./SubscribeDialog"; + +const Preferences = () => { + return ( + + + + + + + + + ); +}; + +const Notifications = () => { + const { t } = useTranslation(); + return ( + + + {t("prefs_notifications_title")} + + + + + + + + ); +}; + +const Sound = () => { + const { t } = useTranslation(); + const labelId = "prefSound"; + const sound = useLiveQuery(async () => prefs.sound()); + const handleChange = async (ev) => { + await prefs.setSound(ev.target.value); + await maybeUpdateAccountSettings({ + notification: { + sound: ev.target.value + } + }); + } + if (!sound) { + return null; // While loading + } + let description; + if (sound === "none") { + description = t("prefs_notifications_sound_description_none"); + } else { + description = t("prefs_notifications_sound_description_some", { sound: sounds[sound].label }); + } + return ( + +
+ + + + playSound(sound)} disabled={sound === "none"} aria-label={t("prefs_notifications_sound_play")}> + + +
+
+ ) +}; + +const MinPriority = () => { + const { t } = useTranslation(); + const labelId = "prefMinPriority"; + const minPriority = useLiveQuery(async () => prefs.minPriority()); + const handleChange = async (ev) => { + await prefs.setMinPriority(ev.target.value); + await maybeUpdateAccountSettings({ + notification: { + min_priority: ev.target.value + } + }); + } + if (!minPriority) { + return null; // While loading + } + const priorities = { + 1: t("priority_min"), + 2: t("priority_low"), + 3: t("priority_default"), + 4: t("priority_high"), + 5: t("priority_max") + } + let description; + if (minPriority === 1) { + description = t("prefs_notifications_min_priority_description_any"); + } else if (minPriority === 5) { + description = t("prefs_notifications_min_priority_description_max"); + } else { + description = t("prefs_notifications_min_priority_description_x_or_higher", { + number: minPriority, + name: priorities[minPriority] + }); + } + return ( + + + + + + ) +}; + +const DeleteAfter = () => { + const { t } = useTranslation(); + const labelId = "prefDeleteAfter"; + const deleteAfter = useLiveQuery(async () => prefs.deleteAfter()); + const handleChange = async (ev) => { + await prefs.setDeleteAfter(ev.target.value); + await maybeUpdateAccountSettings({ + notification: { + delete_after: ev.target.value + } + }); + } + if (deleteAfter === null || deleteAfter === undefined) { // !deleteAfter will not work with "0" + return null; // While loading + } + const description = (() => { + switch (deleteAfter) { + case 0: return t("prefs_notifications_delete_after_never_description"); + case 10800: return t("prefs_notifications_delete_after_three_hours_description"); + case 86400: return t("prefs_notifications_delete_after_one_day_description"); + case 604800: return t("prefs_notifications_delete_after_one_week_description"); + case 2592000: return t("prefs_notifications_delete_after_one_month_description"); + } + })(); + return ( + + + + + + ) +}; + +const Users = () => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + const users = useLiveQuery(() => userManager.all()); + const handleAddClick = () => { + setDialogKey(prev => prev+1); + setDialogOpen(true); + }; + const handleDialogCancel = () => { + setDialogOpen(false); + }; + const handleDialogSubmit = async (user) => { + setDialogOpen(false); + try { + await userManager.save(user); + console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} added`); + } catch (e) { + console.log(`[Preferences] Error adding user.`, e); + } + }; + return ( + + + + {t("prefs_users_title")} + + + {t("prefs_users_description")} + {session.exists() && <>{" " + t("prefs_users_description_no_sync")}} + + {users?.length > 0 && } + + + + + + + ); +}; + +const UserTable = (props) => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + const [dialogUser, setDialogUser] = useState(null); + + const handleEditClick = (user) => { + setDialogKey(prev => prev+1); + setDialogUser(user); + setDialogOpen(true); + }; + + const handleDialogCancel = () => { + setDialogOpen(false); + }; + + const handleDialogSubmit = async (user) => { + setDialogOpen(false); + try { + await userManager.save(user); + console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} updated`); + } catch (e) { + console.log(`[Preferences] Error updating user.`, e); + } + }; + + const handleDeleteClick = async (user) => { + try { + await userManager.delete(user.baseUrl); + console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} deleted`); + } catch (e) { + console.error(`[Preferences] Error deleting user for ${user.baseUrl}`, e); + } + }; + + return ( + + + + {t("prefs_users_table_user_header")} + {t("prefs_users_table_base_url_header")} + + + + + {props.users?.map(user => ( + + {user.username} + {user.baseUrl} + + {(!session.exists() || user.baseUrl !== config.base_url) && + <> + handleEditClick(user)} aria-label={t("prefs_users_edit_button")}> + + + handleDeleteClick(user)} aria-label={t("prefs_users_delete_button")}> + + + + } + {session.exists() && user.baseUrl === config.base_url && + + + + + + + } + + + ))} + + +
+ ); +}; + +const UserDialog = (props) => { + const { t } = useTranslation(); + const [baseUrl, setBaseUrl] = useState(""); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + const editMode = props.user !== null; + const addButtonEnabled = (() => { + if (editMode) { + return username.length > 0 && password.length > 0; + } + const baseUrlValid = validUrl(baseUrl); + const baseUrlExists = props.users?.map(user => user.baseUrl).includes(baseUrl); + return baseUrlValid + && !baseUrlExists + && username.length > 0 + && password.length > 0; + })(); + const handleSubmit = async () => { + props.onSubmit({ + baseUrl: baseUrl, + username: username, + password: password + }) + }; + useEffect(() => { + if (editMode) { + setBaseUrl(props.user.baseUrl); + setUsername(props.user.username); + setPassword(props.user.password); + } + }, [editMode, props.user]); + return ( + + {editMode ? t("prefs_users_dialog_title_edit") : t("prefs_users_dialog_title_add")} + + {!editMode && setBaseUrl(ev.target.value)} + type="url" + fullWidth + variant="standard" + />} + setUsername(ev.target.value)} + type="text" + fullWidth + variant="standard" + /> + setPassword(ev.target.value)} + fullWidth + variant="standard" + /> + + + + + + + ); +}; + +const Appearance = () => { + const { t } = useTranslation(); + return ( + + + {t("prefs_appearance_title")} + + + + + + ); +}; + +const Language = () => { + const { t, i18n } = useTranslation(); + const labelId = "prefLanguage"; + const randomFlags = shuffle(["๐Ÿ‡ฌ๐Ÿ‡ง", "๐Ÿ‡บ๐Ÿ‡ธ", "๐Ÿ‡ช๐Ÿ‡ธ", "๐Ÿ‡ซ๐Ÿ‡ท", "๐Ÿ‡ง๐Ÿ‡ฌ", "๐Ÿ‡จ๐Ÿ‡ฟ", "๐Ÿ‡ฉ๐Ÿ‡ช", "๐Ÿ‡ต๐Ÿ‡ฑ", "๐Ÿ‡บ๐Ÿ‡ฆ", "๐Ÿ‡จ๐Ÿ‡ณ", "๐Ÿ‡ฎ๐Ÿ‡น", "๐Ÿ‡ญ๐Ÿ‡บ", "๐Ÿ‡ง๐Ÿ‡ท", "๐Ÿ‡ณ๐Ÿ‡ฑ", "๐Ÿ‡ฎ๐Ÿ‡ฉ", "๐Ÿ‡ฏ๐Ÿ‡ต", "๐Ÿ‡ท๐Ÿ‡บ", "๐Ÿ‡น๐Ÿ‡ท"]).slice(0, 3); + const title = t("prefs_appearance_language_title") + " " + randomFlags.join(" "); + const lang = i18n.language ?? "en"; + + const handleChange = async (ev) => { + await i18n.changeLanguage(ev.target.value); + await maybeUpdateAccountSettings({ + language: ev.target.value + }); + }; + + // Remember: Flags are not languages. Don't put flags next to the language in the list. + // Languages names from: https://www.omniglot.com/language/names.htm + // Better: Sidebar in Wikipedia: https://en.wikipedia.org/wiki/Bokm%C3%A5l + + return ( + + + + + + ) +}; + +const Reservations = () => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const [dialogKey, setDialogKey] = useState(0); + const [dialogOpen, setDialogOpen] = useState(false); + + if (!config.enable_reservations || !session.exists() || !account) { + return <>; + } + const reservations = account.reservations || []; + const limitReached = account.role === Role.USER && account.stats.reservations_remaining === 0; + + const handleAddClick = () => { + setDialogKey(prev => prev+1); + setDialogOpen(true); + }; + + return ( + + + + {t("prefs_reservations_title")} + + + {t("prefs_reservations_description")} + + {reservations.length > 0 && } + {limitReached && {t("prefs_reservations_limit_reached")}} + + + + setDialogOpen(false)} + /> + + + ); +}; + +const ReservationsTable = (props) => { + const { t } = useTranslation(); + const [dialogKey, setDialogKey] = useState(0); + const [dialogReservation, setDialogReservation] = useState(null); + const [editDialogOpen, setEditDialogOpen] = useState(false); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const { subscriptions } = useOutletContext(); + const localSubscriptions = (subscriptions?.length > 0) + ? Object.assign(...subscriptions.filter(s => s.baseUrl === config.base_url).map(s => ({[s.topic]: s}))) + : []; + + const handleEditClick = (reservation) => { + setDialogKey(prev => prev+1); + setDialogReservation(reservation); + setEditDialogOpen(true); + }; + + const handleDeleteClick = async (reservation) => { + setDialogKey(prev => prev+1); + setDialogReservation(reservation); + setDeleteDialogOpen(true); + }; + + const handleSubscribeClick = async (reservation) => { + await subscribeTopic(config.base_url, reservation.topic); + }; + + return ( + + + + {t("prefs_reservations_table_topic_header")} + {t("prefs_reservations_table_access_header")} + + + + + {props.reservations.map(reservation => ( + + + {reservation.topic} + + + {reservation.everyone === Permission.READ_WRITE && + <> + + {t("prefs_reservations_table_everyone_read_write")} + + } + {reservation.everyone === Permission.READ_ONLY && + <> + + {t("prefs_reservations_table_everyone_read_only")} + + } + {reservation.everyone === Permission.WRITE_ONLY && + <> + + {t("prefs_reservations_table_everyone_write_only")} + + } + {reservation.everyone === Permission.DENY_ALL && + <> + + {t("prefs_reservations_table_everyone_deny_all")} + + } + + + {!localSubscriptions[reservation.topic] && + + } onClick={() => handleSubscribeClick(reservation)} label={t("prefs_reservations_table_not_subscribed")} color="primary" variant="outlined"/> + + } + handleEditClick(reservation)} aria-label={t("prefs_reservations_edit_button")}> + + + handleDeleteClick(reservation)} aria-label={t("prefs_reservations_delete_button")}> + + + + + ))} + + setEditDialogOpen(false)} + /> + setDeleteDialogOpen(false)} + /> +
+ ); +}; + +const maybeUpdateAccountSettings = async (payload) => { + if (!session.exists()) { + return; + } + try { + await accountApi.updateSettings(payload); + } catch (e) { + console.log(`[Preferences] Error updating account settings`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } + } +}; + +export default Preferences; diff --git a/web/src/components/Preferences.jsx b/web/src/components/Preferences.jsx deleted file mode 100644 index 4afc0f8..0000000 --- a/web/src/components/Preferences.jsx +++ /dev/null @@ -1,695 +0,0 @@ -import * as React from "react"; -import { useContext, useEffect, useState } from "react"; -import { - Alert, - CardActions, - CardContent, - Chip, - FormControl, - Select, - Stack, - Table, - TableBody, - TableCell, - TableHead, - TableRow, - Tooltip, - useMediaQuery, - Typography, - IconButton, - Container, - TextField, - MenuItem, - Card, - Button, - Dialog, - DialogTitle, - DialogContent, - DialogActions, -} from "@mui/material"; -import EditIcon from "@mui/icons-material/Edit"; -import CloseIcon from "@mui/icons-material/Close"; -import PlayArrowIcon from "@mui/icons-material/PlayArrow"; -import { useLiveQuery } from "dexie-react-hooks"; -import { useTranslation } from "react-i18next"; -import { Info } from "@mui/icons-material"; -import { useOutletContext } from "react-router-dom"; -import theme from "./theme"; -import userManager from "../app/UserManager"; -import { playSound, shuffle, sounds, validUrl } from "../app/utils"; -import session from "../app/Session"; -import routes from "./routes"; -import accountApi, { Permission, Role } from "../app/AccountApi"; -import { Pref, PrefGroup } from "./Pref"; -import { AccountContext } from "./App"; -import { Paragraph } from "./styles"; -import prefs from "../app/Prefs"; -import { PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite } from "./ReserveIcons"; -import { ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog } from "./ReserveDialogs"; -import { UnauthorizedError } from "../app/errors"; -import { subscribeTopic } from "./SubscribeDialog"; - -const maybeUpdateAccountSettings = async (payload) => { - if (!session.exists()) { - return; - } - try { - await accountApi.updateSettings(payload); - } catch (e) { - console.log(`[Preferences] Error updating account settings`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } - } -}; - -const Preferences = () => ( - - - - - - - - -); - -const Notifications = () => { - const { t } = useTranslation(); - return ( - - - {t("prefs_notifications_title")} - - - - - - - - ); -}; - -const Sound = () => { - const { t } = useTranslation(); - const labelId = "prefSound"; - const sound = useLiveQuery(async () => prefs.sound()); - const handleChange = async (ev) => { - await prefs.setSound(ev.target.value); - await maybeUpdateAccountSettings({ - notification: { - sound: ev.target.value, - }, - }); - }; - if (!sound) { - return null; // While loading - } - let description; - if (sound === "none") { - description = t("prefs_notifications_sound_description_none"); - } else { - description = t("prefs_notifications_sound_description_some", { - sound: sounds[sound].label, - }); - } - return ( - -
- - - - playSound(sound)} disabled={sound === "none"} aria-label={t("prefs_notifications_sound_play")}> - - -
-
- ); -}; - -const MinPriority = () => { - const { t } = useTranslation(); - const labelId = "prefMinPriority"; - const minPriority = useLiveQuery(async () => prefs.minPriority()); - const handleChange = async (ev) => { - await prefs.setMinPriority(ev.target.value); - await maybeUpdateAccountSettings({ - notification: { - min_priority: ev.target.value, - }, - }); - }; - if (!minPriority) { - return null; // While loading - } - const priorities = { - 1: t("priority_min"), - 2: t("priority_low"), - 3: t("priority_default"), - 4: t("priority_high"), - 5: t("priority_max"), - }; - let description; - if (minPriority === 1) { - description = t("prefs_notifications_min_priority_description_any"); - } else if (minPriority === 5) { - description = t("prefs_notifications_min_priority_description_max"); - } else { - description = t("prefs_notifications_min_priority_description_x_or_higher", { - number: minPriority, - name: priorities[minPriority], - }); - } - return ( - - - - - - ); -}; - -const DeleteAfter = () => { - const { t } = useTranslation(); - const labelId = "prefDeleteAfter"; - const deleteAfter = useLiveQuery(async () => prefs.deleteAfter()); - const handleChange = async (ev) => { - await prefs.setDeleteAfter(ev.target.value); - await maybeUpdateAccountSettings({ - notification: { - delete_after: ev.target.value, - }, - }); - }; - - if (deleteAfter === null || deleteAfter === undefined) { - // !deleteAfter will not work with "0" - return null; // While loading - } - - const description = (() => { - switch (deleteAfter) { - case 0: - return t("prefs_notifications_delete_after_never_description"); - case 10800: - return t("prefs_notifications_delete_after_three_hours_description"); - case 86400: - return t("prefs_notifications_delete_after_one_day_description"); - case 604800: - return t("prefs_notifications_delete_after_one_week_description"); - case 2592000: - return t("prefs_notifications_delete_after_one_month_description"); - default: - return ""; - } - })(); - - return ( - - - - - - ); -}; - -const Users = () => { - const { t } = useTranslation(); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - const users = useLiveQuery(() => userManager.all()); - const handleAddClick = () => { - setDialogKey((prev) => prev + 1); - setDialogOpen(true); - }; - const handleDialogCancel = () => { - setDialogOpen(false); - }; - const handleDialogSubmit = async (user) => { - setDialogOpen(false); - try { - await userManager.save(user); - console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} added`); - } catch (e) { - console.log(`[Preferences] Error adding user.`, e); - } - }; - return ( - - - - {t("prefs_users_title")} - - - {t("prefs_users_description")} - {session.exists() && <>{` ${t("prefs_users_description_no_sync")}`}} - - {users?.length > 0 && } - - - - - - - ); -}; - -const UserTable = (props) => { - const { t } = useTranslation(); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - const [dialogUser, setDialogUser] = useState(null); - - const handleEditClick = (user) => { - setDialogKey((prev) => prev + 1); - setDialogUser(user); - setDialogOpen(true); - }; - - const handleDialogCancel = () => { - setDialogOpen(false); - }; - - const handleDialogSubmit = async (user) => { - setDialogOpen(false); - try { - await userManager.save(user); - console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} updated`); - } catch (e) { - console.log(`[Preferences] Error updating user.`, e); - } - }; - - const handleDeleteClick = async (user) => { - try { - await userManager.delete(user.baseUrl); - console.debug(`[Preferences] User ${user.username} for ${user.baseUrl} deleted`); - } catch (e) { - console.error(`[Preferences] Error deleting user for ${user.baseUrl}`, e); - } - }; - - return ( - - - - {t("prefs_users_table_user_header")} - {t("prefs_users_table_base_url_header")} - - - - - {props.users?.map((user) => ( - - - {user.username} - - {user.baseUrl} - - {(!session.exists() || user.baseUrl !== config.base_url) && ( - <> - handleEditClick(user)} aria-label={t("prefs_users_edit_button")}> - - - handleDeleteClick(user)} aria-label={t("prefs_users_delete_button")}> - - - - )} - {session.exists() && user.baseUrl === config.base_url && ( - - - - - - - - - - - )} - - - ))} - - -
- ); -}; - -const UserDialog = (props) => { - const { t } = useTranslation(); - const [baseUrl, setBaseUrl] = useState(""); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - const editMode = props.user !== null; - const addButtonEnabled = (() => { - if (editMode) { - return username.length > 0 && password.length > 0; - } - const baseUrlValid = validUrl(baseUrl); - const baseUrlExists = props.users?.map((user) => user.baseUrl).includes(baseUrl); - return baseUrlValid && !baseUrlExists && username.length > 0 && password.length > 0; - })(); - const handleSubmit = async () => { - props.onSubmit({ - baseUrl, - username, - password, - }); - }; - useEffect(() => { - if (editMode) { - setBaseUrl(props.user.baseUrl); - setUsername(props.user.username); - setPassword(props.user.password); - } - }, [editMode, props.user]); - return ( - - {editMode ? t("prefs_users_dialog_title_edit") : t("prefs_users_dialog_title_add")} - - {!editMode && ( - setBaseUrl(ev.target.value)} - type="url" - fullWidth - variant="standard" - /> - )} - setUsername(ev.target.value)} - type="text" - fullWidth - variant="standard" - /> - setPassword(ev.target.value)} - fullWidth - variant="standard" - /> - - - - - - - ); -}; - -const Appearance = () => { - const { t } = useTranslation(); - return ( - - - {t("prefs_appearance_title")} - - - - - - ); -}; - -const Language = () => { - const { t, i18n } = useTranslation(); - const labelId = "prefLanguage"; - const lang = i18n.resolvedLanguage ?? "en"; - - // Country flags are displayed using emoji. Emoji rendering is handled by platform fonts. - // Windows in particular does not yet play nicely with flag emoji so for now, hide flags on Windows. - const randomFlags = shuffle([ - "๐Ÿ‡ฌ๐Ÿ‡ง", - "๐Ÿ‡บ๐Ÿ‡ธ", - "๐Ÿ‡ช๐Ÿ‡ธ", - "๐Ÿ‡ซ๐Ÿ‡ท", - "๐Ÿ‡ง๐Ÿ‡ฌ", - "๐Ÿ‡จ๐Ÿ‡ฟ", - "๐Ÿ‡ฉ๐Ÿ‡ช", - "๐Ÿ‡ต๐Ÿ‡ฑ", - "๐Ÿ‡บ๐Ÿ‡ฆ", - "๐Ÿ‡จ๐Ÿ‡ณ", - "๐Ÿ‡ฎ๐Ÿ‡น", - "๐Ÿ‡ญ๐Ÿ‡บ", - "๐Ÿ‡ง๐Ÿ‡ท", - "๐Ÿ‡ณ๐Ÿ‡ฑ", - "๐Ÿ‡ฎ๐Ÿ‡ฉ", - "๐Ÿ‡ฏ๐Ÿ‡ต", - "๐Ÿ‡ท๐Ÿ‡บ", - "๐Ÿ‡น๐Ÿ‡ท", - ]).slice(0, 3); - const showFlags = !navigator.userAgent.includes("Windows"); - let title = t("prefs_appearance_language_title"); - if (showFlags) { - title += ` ${randomFlags.join(" ")}`; - } - - const handleChange = async (ev) => { - await i18n.changeLanguage(ev.target.value); - await maybeUpdateAccountSettings({ - language: ev.target.value, - }); - }; - - // Remember: Flags are not languages. Don't put flags next to the language in the list. - // Languages names from: https://www.omniglot.com/language/names.htm - // Better: Sidebar in Wikipedia: https://en.wikipedia.org/wiki/Bokm%C3%A5l - - return ( - - - - - - ); -}; - -const Reservations = () => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [dialogKey, setDialogKey] = useState(0); - const [dialogOpen, setDialogOpen] = useState(false); - - if (!config.enable_reservations || !session.exists() || !account) { - return <>; - } - const reservations = account.reservations || []; - const limitReached = account.role === Role.USER && account.stats.reservations_remaining === 0; - - const handleAddClick = () => { - setDialogKey((prev) => prev + 1); - setDialogOpen(true); - }; - - return ( - - - - {t("prefs_reservations_title")} - - {t("prefs_reservations_description")} - {reservations.length > 0 && } - {limitReached && {t("prefs_reservations_limit_reached")}} - - - - setDialogOpen(false)} - /> - - - ); -}; - -const ReservationsTable = (props) => { - const { t } = useTranslation(); - const [dialogKey, setDialogKey] = useState(0); - const [dialogReservation, setDialogReservation] = useState(null); - const [editDialogOpen, setEditDialogOpen] = useState(false); - const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); - const { subscriptions } = useOutletContext(); - const localSubscriptions = - subscriptions?.length > 0 - ? Object.assign({}, ...subscriptions.filter((s) => s.baseUrl === config.base_url).map((s) => ({ [s.topic]: s }))) - : {}; - - const handleEditClick = (reservation) => { - setDialogKey((prev) => prev + 1); - setDialogReservation(reservation); - setEditDialogOpen(true); - }; - - const handleDeleteClick = async (reservation) => { - setDialogKey((prev) => prev + 1); - setDialogReservation(reservation); - setDeleteDialogOpen(true); - }; - - const handleSubscribeClick = async (reservation) => { - await subscribeTopic(config.base_url, reservation.topic); - }; - - return ( - - - - {t("prefs_reservations_table_topic_header")} - {t("prefs_reservations_table_access_header")} - - - - - {props.reservations.map((reservation) => ( - - - {reservation.topic} - - - {reservation.everyone === Permission.READ_WRITE && ( - <> - - {t("prefs_reservations_table_everyone_read_write")} - - )} - {reservation.everyone === Permission.READ_ONLY && ( - <> - - {t("prefs_reservations_table_everyone_read_only")} - - )} - {reservation.everyone === Permission.WRITE_ONLY && ( - <> - - {t("prefs_reservations_table_everyone_write_only")} - - )} - {reservation.everyone === Permission.DENY_ALL && ( - <> - - {t("prefs_reservations_table_everyone_deny_all")} - - )} - - - {!localSubscriptions[reservation.topic] && ( - - } - onClick={() => handleSubscribeClick(reservation)} - label={t("prefs_reservations_table_not_subscribed")} - color="primary" - variant="outlined" - /> - - )} - handleEditClick(reservation)} aria-label={t("prefs_reservations_edit_button")}> - - - handleDeleteClick(reservation)} aria-label={t("prefs_reservations_delete_button")}> - - - - - ))} - - setEditDialogOpen(false)} - /> - setDeleteDialogOpen(false)} - /> -
- ); -}; - -export default Preferences; diff --git a/web/src/components/PublishDialog.js b/web/src/components/PublishDialog.js new file mode 100644 index 0000000..bdf6fb6 --- /dev/null +++ b/web/src/components/PublishDialog.js @@ -0,0 +1,740 @@ +import * as React from 'react'; +import {useEffect, useRef, useState} from 'react'; +import theme from "./theme"; +import {Checkbox, Chip, FormControl, FormControlLabel, InputLabel, Link, Select, useMediaQuery} from "@mui/material"; +import TextField from "@mui/material/TextField"; +import priority1 from "../img/priority-1.svg"; +import priority2 from "../img/priority-2.svg"; +import priority3 from "../img/priority-3.svg"; +import priority4 from "../img/priority-4.svg"; +import priority5 from "../img/priority-5.svg"; +import Dialog from "@mui/material/Dialog"; +import DialogTitle from "@mui/material/DialogTitle"; +import DialogContent from "@mui/material/DialogContent"; +import Button from "@mui/material/Button"; +import Typography from "@mui/material/Typography"; +import IconButton from "@mui/material/IconButton"; +import InsertEmoticonIcon from '@mui/icons-material/InsertEmoticon'; +import {Close} from "@mui/icons-material"; +import MenuItem from "@mui/material/MenuItem"; +import {formatBytes, maybeWithAuth, topicShortUrl, topicUrl, validTopic, validUrl} from "../app/utils"; +import Box from "@mui/material/Box"; +import AttachmentIcon from "./AttachmentIcon"; +import DialogFooter from "./DialogFooter"; +import api from "../app/Api"; +import userManager from "../app/UserManager"; +import EmojiPicker from "./EmojiPicker"; +import {Trans, useTranslation} from "react-i18next"; +import session from "../app/Session"; +import routes from "./routes"; +import accountApi from "../app/AccountApi"; +import {UnauthorizedError} from "../app/errors"; + +const PublishDialog = (props) => { + const { t } = useTranslation(); + const [baseUrl, setBaseUrl] = useState(""); + const [topic, setTopic] = useState(""); + const [message, setMessage] = useState(""); + const [messageFocused, setMessageFocused] = useState(true); + const [title, setTitle] = useState(""); + const [tags, setTags] = useState(""); + const [priority, setPriority] = useState(3); + const [clickUrl, setClickUrl] = useState(""); + const [attachUrl, setAttachUrl] = useState(""); + const [attachFile, setAttachFile] = useState(null); + const [filename, setFilename] = useState(""); + const [filenameEdited, setFilenameEdited] = useState(false); + const [email, setEmail] = useState(""); + const [delay, setDelay] = useState(""); + const [publishAnother, setPublishAnother] = useState(false); + + const [showTopicUrl, setShowTopicUrl] = useState(""); + const [showClickUrl, setShowClickUrl] = useState(false); + const [showAttachUrl, setShowAttachUrl] = useState(false); + const [showEmail, setShowEmail] = useState(false); + const [showDelay, setShowDelay] = useState(false); + + const showAttachFile = !!attachFile && !showAttachUrl; + const attachFileInput = useRef(); + const [attachFileError, setAttachFileError] = useState(""); + + const [activeRequest, setActiveRequest] = useState(null); + const [status, setStatus] = useState(""); + const disabled = !!activeRequest; + + const [emojiPickerAnchorEl, setEmojiPickerAnchorEl] = useState(null); + + const [dropZone, setDropZone] = useState(false); + const [sendButtonEnabled, setSendButtonEnabled] = useState(true); + + const open = !!props.openMode; + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + useEffect(() => { + window.addEventListener('dragenter', () => { + props.onDragEnter(); + setDropZone(true); + }); + }, []); + + useEffect(() => { + setBaseUrl(props.baseUrl); + setTopic(props.topic); + setShowTopicUrl(!props.baseUrl || !props.topic); + setMessageFocused(!!props.topic); // Focus message only if topic is set + }, [props.baseUrl, props.topic]); + + useEffect(() => { + const valid = validUrl(baseUrl) && validTopic(topic) && !attachFileError; + setSendButtonEnabled(valid); + }, [baseUrl, topic, attachFileError]); + + useEffect(() => { + setMessage(props.message); + }, [props.message]); + + const updateBaseUrl = (newVal) => { + if (validUrl(newVal)) { + setBaseUrl(newVal.replace(/\/$/, '')); // strip traililng slash after https?:// + } else { + setBaseUrl(newVal); + } + }; + + const handleSubmit = async () => { + const url = new URL(topicUrl(baseUrl, topic)); + if (title.trim()) { + url.searchParams.append("title", title.trim()); + } + if (tags.trim()) { + url.searchParams.append("tags", tags.trim()); + } + if (priority && priority !== 3) { + url.searchParams.append("priority", priority.toString()); + } + if (clickUrl.trim()) { + url.searchParams.append("click", clickUrl.trim()); + } + if (attachUrl.trim()) { + url.searchParams.append("attach", attachUrl.trim()); + } + if (filename.trim()) { + url.searchParams.append("filename", filename.trim()); + } + if (email.trim()) { + url.searchParams.append("email", email.trim()); + } + if (delay.trim()) { + url.searchParams.append("delay", delay.trim()); + } + if (attachFile && message.trim()) { + url.searchParams.append("message", message.replaceAll("\n", "\\n").trim()); + } + const body = (attachFile) ? attachFile : message; + try { + const user = await userManager.get(baseUrl); + const headers = maybeWithAuth({}, user); + const progressFn = (ev) => { + if (ev.loaded > 0 && ev.total > 0) { + setStatus(t("publish_dialog_progress_uploading_detail", { + loaded: formatBytes(ev.loaded), + total: formatBytes(ev.total), + percent: Math.round(ev.loaded * 100.0 / ev.total) + })); + } else { + setStatus(t("publish_dialog_progress_uploading")); + } + }; + const request = api.publishXHR(url, body, headers, progressFn); + setActiveRequest(request); + await request; + if (!publishAnother) { + props.onClose(); + } else { + setStatus(t("publish_dialog_message_published")); + setActiveRequest(null); + } + } catch (e) { + setStatus({e}); + setActiveRequest(null); + } + }; + + const checkAttachmentLimits = async (file) => { + try { + const account = await accountApi.get(); + const fileSizeLimit = account.limits.attachment_file_size ?? 0; + const remainingBytes = account.stats.attachment_total_size_remaining; + const fileSizeLimitReached = fileSizeLimit > 0 && file.size > fileSizeLimit; + const quotaReached = remainingBytes > 0 && file.size > remainingBytes; + if (fileSizeLimitReached && quotaReached) { + return setAttachFileError(t("publish_dialog_attachment_limits_file_and_quota_reached", { + fileSizeLimit: formatBytes(fileSizeLimit), + remainingBytes: formatBytes(remainingBytes) + })); + } else if (fileSizeLimitReached) { + return setAttachFileError(t("publish_dialog_attachment_limits_file_reached", { fileSizeLimit: formatBytes(fileSizeLimit) })); + } else if (quotaReached) { + return setAttachFileError(t("publish_dialog_attachment_limits_quota_reached", { remainingBytes: formatBytes(remainingBytes) })); + } + setAttachFileError(""); + } catch (e) { + console.log(`[PublishDialog] Retrieving attachment limits failed`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setAttachFileError(""); // Reset error (rely on server-side checking) + } + } + }; + + const handleAttachFileClick = () => { + attachFileInput.current.click(); + }; + + const handleAttachFileChanged = async (ev) => { + await updateAttachFile(ev.target.files[0]); + }; + + const handleAttachFileDrop = async (ev) => { + ev.preventDefault(); + setDropZone(false); + await updateAttachFile(ev.dataTransfer.files[0]); + }; + + const updateAttachFile = async (file) => { + setAttachFile(file); + setFilename(file.name); + props.onResetOpenMode(); + await checkAttachmentLimits(file); + }; + + const handleAttachFileDragLeave = () => { + setDropZone(false); + if (props.openMode === PublishDialog.OPEN_MODE_DRAG) { + props.onClose(); // Only close dialog if it was not open before dragging file in + } + }; + + const handleEmojiClick = (ev) => { + setEmojiPickerAnchorEl(ev.currentTarget); + }; + + const handleEmojiPick = (emoji) => { + setTags(tags => (tags.trim()) ? `${tags.trim()}, ${emoji}` : emoji); + }; + + const handleEmojiClose = () => { + setEmojiPickerAnchorEl(null); + }; + + const priorities = { + 1: { label: t("publish_dialog_priority_min"), file: priority1 }, + 2: { label: t("publish_dialog_priority_low"), file: priority2 }, + 3: { label: t("publish_dialog_priority_default"), file: priority3 }, + 4: { label: t("publish_dialog_priority_high"), file: priority4 }, + 5: { label: t("publish_dialog_priority_max"), file: priority5 } + }; + + return ( + <> + {dropZone && + } + + {(baseUrl && topic) ? t("publish_dialog_title_topic", { topic: topicShortUrl(baseUrl, topic) }) : t("publish_dialog_title_no_topic")} + + {dropZone && } + {showTopicUrl && + { + setBaseUrl(props.baseUrl); + setTopic(props.topic); + setShowTopicUrl(false); + }}> + updateBaseUrl(ev.target.value)} + disabled={disabled} + type="url" + variant="standard" + sx={{flexGrow: 1, marginRight: 1}} + inputProps={{ + "aria-label": t("publish_dialog_base_url_label") + }} + /> + setTopic(ev.target.value)} + disabled={disabled} + type="text" + variant="standard" + autoFocus={!messageFocused} + sx={{flexGrow: 1}} + inputProps={{ + "aria-label": t("publish_dialog_topic_label") + }} + /> + + } + setTitle(ev.target.value)} + disabled={disabled} + type="text" + fullWidth + variant="standard" + inputProps={{ + "aria-label": t("publish_dialog_title_label") + }} + /> + setMessage(ev.target.value)} + disabled={disabled} + type="text" + variant="standard" + rows={5} + autoFocus={messageFocused} + fullWidth + multiline + inputProps={{ + "aria-label": t("publish_dialog_message_label") + }} + /> +
+ + + + + setTags(ev.target.value)} + disabled={disabled} + type="text" + variant="standard" + sx={{flexGrow: 1, marginRight: 1}} + inputProps={{ + "aria-label": t("publish_dialog_tags_label") + }} + /> + + + + +
+ {showClickUrl && + { + setClickUrl(""); + setShowClickUrl(false); + }}> + setClickUrl(ev.target.value)} + disabled={disabled} + type="url" + fullWidth + variant="standard" + inputProps={{ + "aria-label": t("publish_dialog_click_label") + }} + /> + + } + {showEmail && + { + setEmail(""); + setShowEmail(false); + }}> + setEmail(ev.target.value)} + disabled={disabled} + type="email" + variant="standard" + fullWidth + inputProps={{ + "aria-label": t("publish_dialog_email_label") + }} + /> + + } + {showAttachUrl && + { + setAttachUrl(""); + setFilename(""); + setFilenameEdited(false); + setShowAttachUrl(false); + }}> + { + const url = ev.target.value; + setAttachUrl(url); + if (!filenameEdited) { + try { + const u = new URL(url); + const parts = u.pathname.split("/"); + if (parts.length > 0) { + setFilename(parts[parts.length-1]); + } + } catch (e) { + // Do nothing + } + } + }} + disabled={disabled} + type="url" + variant="standard" + sx={{flexGrow: 5, marginRight: 1}} + inputProps={{ + "aria-label": t("publish_dialog_attach_label") + }} + /> + { + setFilename(ev.target.value); + setFilenameEdited(true); + }} + disabled={disabled} + type="text" + variant="standard" + sx={{flexGrow: 1}} + inputProps={{ + "aria-label": t("publish_dialog_filename_label") + }} + /> + + } + + {showAttachFile && setFilename(f)} + onClose={() => { + setAttachFile(null); + setAttachFileError(""); + setFilename(""); + }} + />} + {showDelay && + { + setDelay(""); + setShowDelay(false); + }}> + setDelay(ev.target.value)} + disabled={disabled} + type="text" + variant="standard" + fullWidth + inputProps={{ + "aria-label": t("publish_dialog_delay_label") + }} + /> + + } + + {t("publish_dialog_other_features")} + +
+ {!showClickUrl && setShowClickUrl(true)} sx={{marginRight: 1, marginBottom: 1}}/>} + {!showEmail && setShowEmail(true)} sx={{marginRight: 1, marginBottom: 1}}/>} + {!showAttachUrl && !showAttachFile && setShowAttachUrl(true)} sx={{marginRight: 1, marginBottom: 1}}/>} + {!showAttachFile && !showAttachUrl && handleAttachFileClick()} sx={{marginRight: 1, marginBottom: 1}}/>} + {!showDelay && setShowDelay(true)} sx={{marginRight: 1, marginBottom: 1}}/>} + {!showTopicUrl && setShowTopicUrl(true)} sx={{marginRight: 1, marginBottom: 1}}/>} +
+ + + }} + /> + +
+ + {activeRequest && } + {!activeRequest && + <> + setPublishAnother(ev.target.checked)} + inputProps={{ + "aria-label": t("publish_dialog_checkbox_publish_another") + }} /> + } /> + + + + } + +
+ + ); +}; + +const Row = (props) => { + return ( +
+ {props.children} +
+ ); +}; + +const ClosableRow = (props) => { + const closable = (props.hasOwnProperty("closable")) ? props.closable : true; + return ( + + {props.children} + {closable && + + + + } + + ); +}; + +const DialogIconButton = (props) => { + const sx = props.sx || {}; + return ( + + {props.children} + + ); +}; + +const AttachmentBox = (props) => { + const { t } = useTranslation(); + const file = props.file; + return ( + <> + + {t("publish_dialog_attached_file_title")} + + + + + props.onChangeFilename(ev.target.value)} + disabled={props.disabled} + /> +
+ + {formatBytes(file.size)} + {props.error && + + {" "}({props.error}) + + } + +
+ + + +
+ + ); +}; + +const ExpandingTextField = (props) => { + const invisibleFieldRef = useRef(); + const [textWidth, setTextWidth] = useState(props.minWidth); + const determineTextWidth = () => { + const boundingRect = invisibleFieldRef?.current?.getBoundingClientRect(); + if (!boundingRect) { + return props.minWidth; + } + return (boundingRect.width >= props.minWidth) ? Math.round(boundingRect.width) : props.minWidth; + }; + useEffect(() => { + setTextWidth(determineTextWidth() + 5); + }, [props.value]); + return ( + <> + + {props.value} + + + + ) +}; + +const DropArea = (props) => { + const allowDrag = (ev) => { + // This is where we could disallow certain files to be dragged in. + // For now we allow all files. + + ev.dataTransfer.dropEffect = 'copy'; + ev.preventDefault(); + }; + + return ( + + ); +}; + +const DropBox = () => { + const { t } = useTranslation(); + return ( + + + {t("publish_dialog_drop_file_here")} + + + ); +} + +PublishDialog.OPEN_MODE_DEFAULT = "default"; +PublishDialog.OPEN_MODE_DRAG = "drag"; + +export default PublishDialog; diff --git a/web/src/components/PublishDialog.jsx b/web/src/components/PublishDialog.jsx deleted file mode 100644 index eb0af0d..0000000 --- a/web/src/components/PublishDialog.jsx +++ /dev/null @@ -1,913 +0,0 @@ -import * as React from "react"; -import { useContext, useEffect, useRef, useState } from "react"; -import { - Checkbox, - Chip, - FormControl, - FormControlLabel, - InputLabel, - Link, - Select, - Tooltip, - useMediaQuery, - TextField, - Dialog, - DialogTitle, - DialogContent, - Button, - Typography, - IconButton, - MenuItem, - Box, -} from "@mui/material"; -import InsertEmoticonIcon from "@mui/icons-material/InsertEmoticon"; -import { Close } from "@mui/icons-material"; -import { Trans, useTranslation } from "react-i18next"; -import priority1 from "../img/priority-1.svg"; -import priority2 from "../img/priority-2.svg"; -import priority3 from "../img/priority-3.svg"; -import priority4 from "../img/priority-4.svg"; -import priority5 from "../img/priority-5.svg"; -import { formatBytes, maybeWithAuth, topicShortUrl, topicUrl, validTopic, validUrl } from "../app/utils"; -import AttachmentIcon from "./AttachmentIcon"; -import DialogFooter from "./DialogFooter"; -import api from "../app/Api"; -import userManager from "../app/UserManager"; -import EmojiPicker from "./EmojiPicker"; -import theme from "./theme"; -import session from "../app/Session"; -import routes from "./routes"; -import accountApi from "../app/AccountApi"; -import { UnauthorizedError } from "../app/errors"; -import { AccountContext } from "./App"; - -const PublishDialog = (props) => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [baseUrl, setBaseUrl] = useState(""); - const [topic, setTopic] = useState(""); - const [message, setMessage] = useState(""); - const [messageFocused, setMessageFocused] = useState(true); - const [title, setTitle] = useState(""); - const [tags, setTags] = useState(""); - const [priority, setPriority] = useState(3); - const [clickUrl, setClickUrl] = useState(""); - const [attachUrl, setAttachUrl] = useState(""); - const [attachFile, setAttachFile] = useState(null); - const [filename, setFilename] = useState(""); - const [filenameEdited, setFilenameEdited] = useState(false); - const [email, setEmail] = useState(""); - const [call, setCall] = useState(""); - const [delay, setDelay] = useState(""); - const [publishAnother, setPublishAnother] = useState(false); - - const [showTopicUrl, setShowTopicUrl] = useState(""); - const [showClickUrl, setShowClickUrl] = useState(false); - const [showAttachUrl, setShowAttachUrl] = useState(false); - const [showEmail, setShowEmail] = useState(false); - const [showCall, setShowCall] = useState(false); - const [showDelay, setShowDelay] = useState(false); - - const showAttachFile = !!attachFile && !showAttachUrl; - const attachFileInput = useRef(); - const [attachFileError, setAttachFileError] = useState(""); - - const [activeRequest, setActiveRequest] = useState(null); - const [status, setStatus] = useState(""); - const disabled = !!activeRequest; - - const [emojiPickerAnchorEl, setEmojiPickerAnchorEl] = useState(null); - - const [dropZone, setDropZone] = useState(false); - const [sendButtonEnabled, setSendButtonEnabled] = useState(true); - - const open = !!props.openMode; - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - useEffect(() => { - window.addEventListener("dragenter", () => { - props.onDragEnter(); - setDropZone(true); - }); - }, []); - - useEffect(() => { - setBaseUrl(props.baseUrl); - setTopic(props.topic); - setShowTopicUrl(!props.baseUrl || !props.topic); - setMessageFocused(!!props.topic); // Focus message only if topic is set - }, [props.baseUrl, props.topic]); - - useEffect(() => { - const valid = validUrl(baseUrl) && validTopic(topic) && !attachFileError; - setSendButtonEnabled(valid); - }, [baseUrl, topic, attachFileError]); - - useEffect(() => { - setMessage(props.message); - }, [props.message]); - - const updateBaseUrl = (newVal) => { - if (validUrl(newVal)) { - setBaseUrl(newVal.replace(/\/$/, "")); // strip traililng slash after https?:// - } else { - setBaseUrl(newVal); - } - }; - - const handleSubmit = async () => { - const url = new URL(topicUrl(baseUrl, topic)); - if (title.trim()) { - url.searchParams.append("title", title.trim()); - } - if (tags.trim()) { - url.searchParams.append("tags", tags.trim()); - } - if (priority && priority !== 3) { - url.searchParams.append("priority", priority.toString()); - } - if (clickUrl.trim()) { - url.searchParams.append("click", clickUrl.trim()); - } - if (attachUrl.trim()) { - url.searchParams.append("attach", attachUrl.trim()); - } - if (filename.trim()) { - url.searchParams.append("filename", filename.trim()); - } - if (email.trim()) { - url.searchParams.append("email", email.trim()); - } - if (call.trim()) { - url.searchParams.append("call", call.trim()); - } - if (delay.trim()) { - url.searchParams.append("delay", delay.trim()); - } - if (attachFile && message.trim()) { - url.searchParams.append("message", message.replaceAll("\n", "\\n").trim()); - } - const body = attachFile || message; - try { - const user = await userManager.get(baseUrl); - const headers = maybeWithAuth({}, user); - const progressFn = (ev) => { - if (ev.loaded > 0 && ev.total > 0) { - setStatus( - t("publish_dialog_progress_uploading_detail", { - loaded: formatBytes(ev.loaded), - total: formatBytes(ev.total), - percent: Math.round((ev.loaded * 100.0) / ev.total), - }) - ); - } else { - setStatus(t("publish_dialog_progress_uploading")); - } - }; - const request = api.publishXHR(url, body, headers, progressFn); - setActiveRequest(request); - await request; - if (!publishAnother) { - props.onClose(); - } else { - setStatus(t("publish_dialog_message_published")); - setActiveRequest(null); - } - } catch (e) { - setStatus({e}); - setActiveRequest(null); - } - }; - - const checkAttachmentLimits = async (file) => { - try { - const apiAccount = await accountApi.get(); - const fileSizeLimit = apiAccount.limits.attachment_file_size ?? 0; - const remainingBytes = apiAccount.stats.attachment_total_size_remaining; - const fileSizeLimitReached = fileSizeLimit > 0 && file.size > fileSizeLimit; - const quotaReached = remainingBytes > 0 && file.size > remainingBytes; - if (fileSizeLimitReached && quotaReached) { - setAttachFileError( - t("publish_dialog_attachment_limits_file_and_quota_reached", { - fileSizeLimit: formatBytes(fileSizeLimit), - remainingBytes: formatBytes(remainingBytes), - }) - ); - } else if (fileSizeLimitReached) { - setAttachFileError( - t("publish_dialog_attachment_limits_file_reached", { - fileSizeLimit: formatBytes(fileSizeLimit), - }) - ); - } else if (quotaReached) { - setAttachFileError( - t("publish_dialog_attachment_limits_quota_reached", { - remainingBytes: formatBytes(remainingBytes), - }) - ); - } else { - setAttachFileError(""); - } - } catch (e) { - console.log(`[PublishDialog] Retrieving attachment limits failed`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setAttachFileError(""); // Reset error (rely on server-side checking) - } - } - }; - - const handleAttachFileClick = () => { - attachFileInput.current.click(); - }; - - const updateAttachFile = async (file) => { - setAttachFile(file); - setFilename(file.name); - props.onResetOpenMode(); - await checkAttachmentLimits(file); - }; - - const handleAttachFileChanged = async (ev) => { - await updateAttachFile(ev.target.files[0]); - }; - - const handleAttachFileDrop = async (ev) => { - ev.preventDefault(); - setDropZone(false); - await updateAttachFile(ev.dataTransfer.files[0]); - }; - - const handleAttachFileDragLeave = () => { - setDropZone(false); - if (props.openMode === PublishDialog.OPEN_MODE_DRAG) { - props.onClose(); // Only close dialog if it was not open before dragging file in - } - }; - - const handleEmojiClick = (ev) => { - setEmojiPickerAnchorEl(ev.currentTarget); - }; - - const handleEmojiPick = (emoji) => { - setTags((prevTags) => (prevTags.trim() ? `${prevTags.trim()}, ${emoji}` : emoji)); - }; - - const handleEmojiClose = () => { - setEmojiPickerAnchorEl(null); - }; - - const priorities = { - 1: { label: t("publish_dialog_priority_min"), file: priority1 }, - 2: { label: t("publish_dialog_priority_low"), file: priority2 }, - 3: { label: t("publish_dialog_priority_default"), file: priority3 }, - 4: { label: t("publish_dialog_priority_high"), file: priority4 }, - 5: { label: t("publish_dialog_priority_max"), file: priority5 }, - }; - - return ( - <> - {dropZone && } - - - {baseUrl && topic - ? t("publish_dialog_title_topic", { - topic: topicShortUrl(baseUrl, topic), - }) - : t("publish_dialog_title_no_topic")} - - - {dropZone && } - {showTopicUrl && ( - { - setBaseUrl(props.baseUrl); - setTopic(props.topic); - setShowTopicUrl(false); - }} - > - updateBaseUrl(ev.target.value)} - disabled={disabled} - type="url" - variant="standard" - sx={{ flexGrow: 1, marginRight: 1 }} - inputProps={{ - "aria-label": t("publish_dialog_base_url_label"), - }} - /> - setTopic(ev.target.value)} - disabled={disabled} - type="text" - variant="standard" - autoFocus={!messageFocused} - sx={{ flexGrow: 1 }} - inputProps={{ - "aria-label": t("publish_dialog_topic_label"), - }} - /> - - )} - setTitle(ev.target.value)} - disabled={disabled} - type="text" - fullWidth - variant="standard" - inputProps={{ - "aria-label": t("publish_dialog_title_label"), - }} - /> - setMessage(ev.target.value)} - disabled={disabled} - type="text" - variant="standard" - rows={5} - autoFocus={messageFocused} - fullWidth - multiline - inputProps={{ - "aria-label": t("publish_dialog_message_label"), - }} - /> -
- - - - - setTags(ev.target.value)} - disabled={disabled} - type="text" - variant="standard" - sx={{ flexGrow: 1, marginRight: 1 }} - inputProps={{ - "aria-label": t("publish_dialog_tags_label"), - }} - /> - - - - -
- {showClickUrl && ( - { - setClickUrl(""); - setShowClickUrl(false); - }} - > - setClickUrl(ev.target.value)} - disabled={disabled} - type="url" - fullWidth - variant="standard" - inputProps={{ - "aria-label": t("publish_dialog_click_label"), - }} - /> - - )} - {showEmail && ( - { - setEmail(""); - setShowEmail(false); - }} - > - setEmail(ev.target.value)} - disabled={disabled} - type="email" - variant="standard" - fullWidth - inputProps={{ - "aria-label": t("publish_dialog_email_label"), - }} - /> - - )} - {showCall && ( - { - setCall(""); - setShowCall(false); - }} - > - - - - - - )} - {showAttachUrl && ( - { - setAttachUrl(""); - setFilename(""); - setFilenameEdited(false); - setShowAttachUrl(false); - }} - > - { - const url = ev.target.value; - setAttachUrl(url); - if (!filenameEdited) { - try { - const u = new URL(url); - const parts = u.pathname.split("/"); - if (parts.length > 0) { - setFilename(parts[parts.length - 1]); - } - } catch (e) { - // Do nothing - } - } - }} - disabled={disabled} - type="url" - variant="standard" - sx={{ flexGrow: 5, marginRight: 1 }} - inputProps={{ - "aria-label": t("publish_dialog_attach_label"), - }} - /> - { - setFilename(ev.target.value); - setFilenameEdited(true); - }} - disabled={disabled} - type="text" - variant="standard" - sx={{ flexGrow: 1 }} - inputProps={{ - "aria-label": t("publish_dialog_filename_label"), - }} - /> - - )} - - {showAttachFile && ( - setFilename(f)} - onClose={() => { - setAttachFile(null); - setAttachFileError(""); - setFilename(""); - }} - /> - )} - {showDelay && ( - { - setDelay(""); - setShowDelay(false); - }} - > - setDelay(ev.target.value)} - disabled={disabled} - type="text" - variant="standard" - fullWidth - inputProps={{ - "aria-label": t("publish_dialog_delay_label"), - }} - /> - - )} - - {t("publish_dialog_other_features")} - -
- {!showClickUrl && ( - setShowClickUrl(true)} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {!showEmail && ( - setShowEmail(true)} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {account?.phone_numbers?.length > 0 && !showCall && ( - { - setShowCall(true); - setCall(account.phone_numbers[0]); - }} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {!showAttachUrl && !showAttachFile && ( - setShowAttachUrl(true)} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {!showAttachFile && !showAttachUrl && ( - handleAttachFileClick()} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {!showDelay && ( - setShowDelay(true)} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {!showTopicUrl && ( - setShowTopicUrl(true)} - sx={{ marginRight: 1, marginBottom: 1 }} - /> - )} - {account && !account?.phone_numbers && ( - - - - - - )} -
- - , - }} - /> - -
- - {activeRequest && } - {!activeRequest && ( - <> - setPublishAnother(ev.target.checked)} - inputProps={{ - "aria-label": t("publish_dialog_checkbox_publish_another"), - }} - /> - } - /> - - - - )} - -
- - ); -}; - -const Row = (props) => ( -
- {props.children} -
-); - -const ClosableRow = (props) => { - const closable = props.closable !== undefined ? props.closable : true; - return ( - - {props.children} - {closable && ( - - - - )} - - ); -}; - -const DialogIconButton = (props) => { - const sx = props.sx || {}; - return ( - - {props.children} - - ); -}; - -const AttachmentBox = (props) => { - const { t } = useTranslation(); - const { file } = props; - return ( - <> - - {t("publish_dialog_attached_file_title")} - - - - - props.onChangeFilename(ev.target.value)} - disabled={props.disabled} - /> -
- - {formatBytes(file.size)} - {props.error && ( - - {" "} - ({props.error}) - - )} - -
- - - -
- - ); -}; - -const ExpandingTextField = (props) => { - const invisibleFieldRef = useRef(); - const [textWidth, setTextWidth] = useState(props.minWidth); - const determineTextWidth = () => { - const boundingRect = invisibleFieldRef?.current?.getBoundingClientRect(); - if (!boundingRect) { - return props.minWidth; - } - return boundingRect.width >= props.minWidth ? Math.round(boundingRect.width) : props.minWidth; - }; - useEffect(() => { - setTextWidth(determineTextWidth() + 5); - }, [props.value]); - return ( - <> - - {props.value} - - - - ); -}; - -const DropArea = (props) => { - const allowDrag = (ev) => { - // This is where we could disallow certain files to be dragged in. - // For now we allow all files. - - // eslint-disable-next-line no-param-reassign - ev.dataTransfer.dropEffect = "copy"; - ev.preventDefault(); - }; - - return ( - - ); -}; - -const DropBox = () => { - const { t } = useTranslation(); - return ( - - - {t("publish_dialog_drop_file_here")} - - - ); -}; - -PublishDialog.OPEN_MODE_DEFAULT = "default"; -PublishDialog.OPEN_MODE_DRAG = "drag"; - -export default PublishDialog; diff --git a/web/src/components/ReserveDialogs.js b/web/src/components/ReserveDialogs.js new file mode 100644 index 0000000..7a6a044 --- /dev/null +++ b/web/src/components/ReserveDialogs.js @@ -0,0 +1,199 @@ +import * as React from 'react'; +import {useState} from 'react'; +import Button from '@mui/material/Button'; +import TextField from '@mui/material/TextField'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import {Alert, FormControl, Select, useMediaQuery} from "@mui/material"; +import theme from "./theme"; +import {validTopic} from "../app/utils"; +import DialogFooter from "./DialogFooter"; +import {useTranslation} from "react-i18next"; +import session from "../app/Session"; +import routes from "./routes"; +import accountApi, {Permission} from "../app/AccountApi"; +import ReserveTopicSelect from "./ReserveTopicSelect"; +import MenuItem from "@mui/material/MenuItem"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; +import {Check, DeleteForever} from "@mui/icons-material"; +import {TopicReservedError, UnauthorizedError} from "../app/errors"; + +export const ReserveAddDialog = (props) => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [topic, setTopic] = useState(props.topic || ""); + const [everyone, setEveryone] = useState(Permission.DENY_ALL); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + const allowTopicEdit = !props.topic; + const alreadyReserved = props.reservations.filter(r => r.topic === topic).length > 0; + const submitButtonEnabled = validTopic(topic) && !alreadyReserved; + + const handleSubmit = async () => { + try { + await accountApi.upsertReservation(topic, everyone); + console.debug(`[ReserveAddDialog] Added reservation for topic ${t}: ${everyone}`); + } catch (e) { + console.log(`[ReserveAddDialog] Error adding topic reservation.`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else if (e instanceof TopicReservedError) { + setError(t("subscribe_dialog_error_topic_already_reserved")); + return; + } else { + setError(e.message); + return; + } + } + props.onClose(); + }; + + return ( + + {t("prefs_reservations_dialog_title_add")} + + + {t("prefs_reservations_dialog_description")} + + {allowTopicEdit && setTopic(ev.target.value)} + type="url" + fullWidth + variant="standard" + />} + + + + + + + + ); +}; + +export const ReserveEditDialog = (props) => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [everyone, setEveryone] = useState(props.reservation?.everyone || Permission.DENY_ALL); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + const handleSubmit = async () => { + try { + await accountApi.upsertReservation(props.reservation.topic, everyone); + console.debug(`[ReserveEditDialog] Updated reservation for topic ${t}: ${everyone}`); + } catch (e) { + console.log(`[ReserveEditDialog] Error updating topic reservation.`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + return; + } + } + props.onClose(); + }; + + return ( + + {t("prefs_reservations_dialog_title_edit")} + + + {t("prefs_reservations_dialog_description")} + + + + + + + + + ); +}; + +export const ReserveDeleteDialog = (props) => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [deleteMessages, setDeleteMessages] = useState(false); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + const handleSubmit = async () => { + try { + await accountApi.deleteReservation(props.topic, deleteMessages); + console.debug(`[ReserveDeleteDialog] Deleted reservation for topic ${props.topic}`); + } catch (e) { + console.log(`[ReserveDeleteDialog] Error deleting topic reservation.`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + return; + } + } + props.onClose(); + }; + + return ( + + {t("prefs_reservations_dialog_title_delete")} + + + {t("reservation_delete_dialog_description")} + + + + + {!deleteMessages && + + {t("reservation_delete_dialog_action_keep_description")} + + } + {deleteMessages && + + {t("reservation_delete_dialog_action_delete_description")} + + } + + + + + + + ); +}; + diff --git a/web/src/components/ReserveDialogs.jsx b/web/src/components/ReserveDialogs.jsx deleted file mode 100644 index 3dc370e..0000000 --- a/web/src/components/ReserveDialogs.jsx +++ /dev/null @@ -1,199 +0,0 @@ -import * as React from "react"; -import { useState } from "react"; -import { - Button, - TextField, - Dialog, - DialogContent, - DialogContentText, - DialogTitle, - Alert, - FormControl, - Select, - useMediaQuery, - MenuItem, - ListItemIcon, - ListItemText, -} from "@mui/material"; -import { useTranslation } from "react-i18next"; -import { Check, DeleteForever } from "@mui/icons-material"; -import theme from "./theme"; -import { validTopic } from "../app/utils"; -import DialogFooter from "./DialogFooter"; -import session from "../app/Session"; -import routes from "./routes"; -import accountApi, { Permission } from "../app/AccountApi"; -import ReserveTopicSelect from "./ReserveTopicSelect"; -import { TopicReservedError, UnauthorizedError } from "../app/errors"; - -export const ReserveAddDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [topic, setTopic] = useState(props.topic || ""); - const [everyone, setEveryone] = useState(Permission.DENY_ALL); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - const allowTopicEdit = !props.topic; - const alreadyReserved = props.reservations.filter((r) => r.topic === topic).length > 0; - const submitButtonEnabled = validTopic(topic) && !alreadyReserved; - - const handleSubmit = async () => { - try { - await accountApi.upsertReservation(topic, everyone); - console.debug(`[ReserveAddDialog] Added reservation for topic ${topic}: ${everyone}`); - } catch (e) { - console.log(`[ReserveAddDialog] Error adding topic reservation.`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else if (e instanceof TopicReservedError) { - setError(t("subscribe_dialog_error_topic_already_reserved")); - return; - } else { - setError(e.message); - return; - } - } - props.onClose(); - }; - - return ( - - {t("prefs_reservations_dialog_title_add")} - - {t("prefs_reservations_dialog_description")} - {allowTopicEdit && ( - setTopic(ev.target.value)} - type="url" - fullWidth - variant="standard" - /> - )} - - - - - - - - ); -}; - -export const ReserveEditDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [everyone, setEveryone] = useState(props.reservation?.everyone || Permission.DENY_ALL); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const handleSubmit = async () => { - try { - await accountApi.upsertReservation(props.reservation.topic, everyone); - console.debug(`[ReserveEditDialog] Updated reservation for topic ${t}: ${everyone}`); - } catch (e) { - console.log(`[ReserveEditDialog] Error updating topic reservation.`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - return; - } - } - props.onClose(); - }; - - return ( - - {t("prefs_reservations_dialog_title_edit")} - - {t("prefs_reservations_dialog_description")} - - - - - - - - ); -}; - -export const ReserveDeleteDialog = (props) => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [deleteMessages, setDeleteMessages] = useState(false); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const handleSubmit = async () => { - try { - await accountApi.deleteReservation(props.topic, deleteMessages); - console.debug(`[ReserveDeleteDialog] Deleted reservation for topic ${props.topic}`); - } catch (e) { - console.log(`[ReserveDeleteDialog] Error deleting topic reservation.`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - return; - } - } - props.onClose(); - }; - - return ( - - {t("prefs_reservations_dialog_title_delete")} - - {t("reservation_delete_dialog_description")} - - - - {!deleteMessages && ( - - {t("reservation_delete_dialog_action_keep_description")} - - )} - {deleteMessages && ( - - {t("reservation_delete_dialog_action_delete_description")} - - )} - - - - - - - ); -}; diff --git a/web/src/components/ReserveIcons.js b/web/src/components/ReserveIcons.js new file mode 100644 index 0000000..0d7b05b --- /dev/null +++ b/web/src/components/ReserveIcons.js @@ -0,0 +1,46 @@ +import * as React from 'react'; +import {Lock, Public} from "@mui/icons-material"; +import Box from "@mui/material/Box"; + +export const PermissionReadWrite = React.forwardRef((props, ref) => { + return ; +}); + +export const PermissionDenyAll = React.forwardRef((props, ref) => { + return ; +}); + +export const PermissionRead = React.forwardRef((props, ref) => { + return ; +}); + +export const PermissionWrite = React.forwardRef((props, ref) => { + return ; +}); + +const PermissionInternal = React.forwardRef((props, ref) => { + const size = props.size ?? "medium"; + const Icon = props.icon; + return ( + + + {props.text && + + {props.text} + + } + + ); +}); diff --git a/web/src/components/ReserveIcons.jsx b/web/src/components/ReserveIcons.jsx deleted file mode 100644 index 95f6f47..0000000 --- a/web/src/components/ReserveIcons.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from "react"; -import { Lock, Public } from "@mui/icons-material"; -import { Box } from "@mui/material"; - -export const PermissionReadWrite = React.forwardRef((props, ref) => ); - -export const PermissionDenyAll = React.forwardRef((props, ref) => ); - -export const PermissionRead = React.forwardRef((props, ref) => ); - -export const PermissionWrite = React.forwardRef((props, ref) => ); - -const PermissionInternal = React.forwardRef((props, ref) => { - const size = props.size ?? "medium"; - const Icon = props.icon; - return ( - - - {props.text && ( - - {props.text} - - )} - - ); -}); diff --git a/web/src/components/ReserveTopicSelect.js b/web/src/components/ReserveTopicSelect.js new file mode 100644 index 0000000..e5daf69 --- /dev/null +++ b/web/src/components/ReserveTopicSelect.js @@ -0,0 +1,49 @@ +import * as React from 'react'; +import {FormControl, Select} from "@mui/material"; +import {useTranslation} from "react-i18next"; +import MenuItem from "@mui/material/MenuItem"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; +import {PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite} from "./ReserveIcons"; +import {Permission} from "../app/AccountApi"; + +const ReserveTopicSelect = (props) => { + const { t } = useTranslation(); + const sx = props.sx || {}; + return ( + + + + ); +}; + +export default ReserveTopicSelect; diff --git a/web/src/components/ReserveTopicSelect.jsx b/web/src/components/ReserveTopicSelect.jsx deleted file mode 100644 index 39ae5df..0000000 --- a/web/src/components/ReserveTopicSelect.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import * as React from "react"; -import { FormControl, Select, MenuItem, ListItemIcon, ListItemText } from "@mui/material"; -import { useTranslation } from "react-i18next"; -import { PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite } from "./ReserveIcons"; -import { Permission } from "../app/AccountApi"; - -const ReserveTopicSelect = (props) => { - const { t } = useTranslation(); - const sx = props.sx || {}; - return ( - - - - ); -}; - -export default ReserveTopicSelect; diff --git a/web/src/components/Signup.js b/web/src/components/Signup.js new file mode 100644 index 0000000..856ce8f --- /dev/null +++ b/web/src/components/Signup.js @@ -0,0 +1,158 @@ +import * as React from 'react'; +import {useState} from 'react'; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; +import routes from "./routes"; +import session from "../app/Session"; +import Typography from "@mui/material/Typography"; +import {NavLink} from "react-router-dom"; +import AvatarBox from "./AvatarBox"; +import {useTranslation} from "react-i18next"; +import WarningAmberIcon from "@mui/icons-material/WarningAmber"; +import accountApi from "../app/AccountApi"; +import {InputAdornment} from "@mui/material"; +import IconButton from "@mui/material/IconButton"; +import {Visibility, VisibilityOff} from "@mui/icons-material"; +import {AccountCreateLimitReachedError, UserExistsError} from "../app/errors"; + +const Signup = () => { + const { t } = useTranslation(); + const [error, setError] = useState(""); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [confirm, setConfirm] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [showConfirm, setShowConfirm] = useState(false); + + const handleSubmit = async (event) => { + event.preventDefault(); + const user = { username, password }; + try { + await accountApi.create(user.username, user.password); + const token = await accountApi.login(user); + console.log(`[Signup] User signup for user ${user.username} successful, token is ${token}`); + session.store(user.username, token); + window.location.href = routes.app; + } catch (e) { + console.log(`[Signup] Signup for user ${user.username} failed`, e); + if (e instanceof UserExistsError) { + setError(t("signup_error_username_taken", { username: e.username })); + } else if ((e instanceof AccountCreateLimitReachedError)) { + setError(t("signup_error_creation_limit_reached")); + } else { + setError(e.message); + } + } + }; + + if (!config.enable_signup) { + return ( + + {t("signup_disabled")} + + ); + } + + return ( + + + {t("signup_title")} + + + setUsername(ev.target.value.trim())} + autoFocus + /> + setPassword(ev.target.value.trim())} + InputProps={{ + endAdornment: ( + + setShowPassword(!showPassword)} + onMouseDown={(ev) => ev.preventDefault()} + edge="end" + > + {showPassword ? : } + + + ) + }} + /> + setConfirm(ev.target.value.trim())} + InputProps={{ + endAdornment: ( + + setShowConfirm(!showConfirm)} + onMouseDown={(ev) => ev.preventDefault()} + edge="end" + > + {showConfirm ? : } + + + ) + }} + /> + + {error && + + + {error} + + } + + {config.enable_login && + + + {t("signup_already_have_account")} + + + } + + ); +} + +export default Signup; diff --git a/web/src/components/Signup.jsx b/web/src/components/Signup.jsx deleted file mode 100644 index 3b82cd6..0000000 --- a/web/src/components/Signup.jsx +++ /dev/null @@ -1,153 +0,0 @@ -import * as React from "react"; -import { useState } from "react"; -import { TextField, Button, Box, Typography, InputAdornment, IconButton } from "@mui/material"; -import { NavLink } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import WarningAmberIcon from "@mui/icons-material/WarningAmber"; -import { Visibility, VisibilityOff } from "@mui/icons-material"; -import accountApi from "../app/AccountApi"; -import AvatarBox from "./AvatarBox"; -import session from "../app/Session"; -import routes from "./routes"; -import { AccountCreateLimitReachedError, UserExistsError } from "../app/errors"; - -const Signup = () => { - const { t } = useTranslation(); - const [error, setError] = useState(""); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [confirm, setConfirm] = useState(""); - const [showPassword, setShowPassword] = useState(false); - const [showConfirm, setShowConfirm] = useState(false); - - const handleSubmit = async (event) => { - event.preventDefault(); - const user = { username, password }; - try { - await accountApi.create(user.username, user.password); - const token = await accountApi.login(user); - console.log(`[Signup] User signup for user ${user.username} successful, token is ${token}`); - session.store(user.username, token); - window.location.href = routes.app; - } catch (e) { - console.log(`[Signup] Signup for user ${user.username} failed`, e); - if (e instanceof UserExistsError) { - setError(t("signup_error_username_taken", { username: e.username })); - } else if (e instanceof AccountCreateLimitReachedError) { - setError(t("signup_error_creation_limit_reached")); - } else { - setError(e.message); - } - } - }; - - if (!config.enable_signup) { - return ( - - {t("signup_disabled")} - - ); - } - - return ( - - {t("signup_title")} - - setUsername(ev.target.value.trim())} - autoFocus - /> - setPassword(ev.target.value.trim())} - InputProps={{ - endAdornment: ( - - setShowPassword(!showPassword)} - onMouseDown={(ev) => ev.preventDefault()} - edge="end" - > - {showPassword ? : } - - - ), - }} - /> - setConfirm(ev.target.value.trim())} - InputProps={{ - endAdornment: ( - - setShowConfirm(!showConfirm)} - onMouseDown={(ev) => ev.preventDefault()} - edge="end" - > - {showConfirm ? : } - - - ), - }} - /> - - {error && ( - - - {error} - - )} - - {config.enable_login && ( - - - {t("signup_already_have_account")} - - - )} - - ); -}; - -export default Signup; diff --git a/web/src/components/SubscribeDialog.js b/web/src/components/SubscribeDialog.js new file mode 100644 index 0000000..4fd4f8c --- /dev/null +++ b/web/src/components/SubscribeDialog.js @@ -0,0 +1,313 @@ +import * as React from 'react'; +import {useContext, useState} from 'react'; +import Button from '@mui/material/Button'; +import TextField from '@mui/material/TextField'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import {Autocomplete, Checkbox, FormControlLabel, FormGroup, useMediaQuery} from "@mui/material"; +import theme from "./theme"; +import api from "../app/Api"; +import {randomAlphanumericString, topicUrl, validTopic, validUrl} from "../app/utils"; +import userManager from "../app/UserManager"; +import subscriptionManager from "../app/SubscriptionManager"; +import poller from "../app/Poller"; +import DialogFooter from "./DialogFooter"; +import {useTranslation} from "react-i18next"; +import session from "../app/Session"; +import routes from "./routes"; +import accountApi, {Permission, Role} from "../app/AccountApi"; +import ReserveTopicSelect from "./ReserveTopicSelect"; +import {AccountContext} from "./App"; +import {TopicReservedError, UnauthorizedError} from "../app/errors"; +import {ReserveLimitChip} from "./SubscriptionPopup"; + +const publicBaseUrl = "https://ntfy.sh"; + +const SubscribeDialog = (props) => { + const [baseUrl, setBaseUrl] = useState(""); + const [topic, setTopic] = useState(""); + const [showLoginPage, setShowLoginPage] = useState(false); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + const handleSuccess = async () => { + console.log(`[SubscribeDialog] Subscribing to topic ${topic}`); + const actualBaseUrl = (baseUrl) ? baseUrl : config.base_url; + const subscription = await subscribeTopic(actualBaseUrl, topic); + poller.pollInBackground(subscription); // Dangle! + props.onSuccess(subscription); + } + + return ( + + {!showLoginPage && setShowLoginPage(true)} + onSuccess={handleSuccess} + />} + {showLoginPage && setShowLoginPage(false)} + onSuccess={handleSuccess} + />} + + ); +}; + +const SubscribePage = (props) => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const [error, setError] = useState(""); + const [reserveTopicVisible, setReserveTopicVisible] = useState(false); + const [anotherServerVisible, setAnotherServerVisible] = useState(false); + const [everyone, setEveryone] = useState(Permission.DENY_ALL); + const baseUrl = (anotherServerVisible) ? props.baseUrl : config.base_url; + const topic = props.topic; + const existingTopicUrls = props.subscriptions.map(s => topicUrl(s.baseUrl, s.topic)); + const existingBaseUrls = Array + .from(new Set([publicBaseUrl, ...props.subscriptions.map(s => s.baseUrl)])) + .filter(s => s !== config.base_url); + const showReserveTopicCheckbox = config.enable_reservations && !anotherServerVisible && (config.enable_payments || account); + const reserveTopicEnabled = session.exists() && (account?.role === Role.ADMIN || (account?.role === Role.USER && (account?.stats.reservations_remaining || 0) > 0)); + + const handleSubscribe = async () => { + const user = await userManager.get(baseUrl); // May be undefined + const username = (user) ? user.username : t("subscribe_dialog_error_user_anonymous"); + + // Check read access to topic + const success = await api.topicAuth(baseUrl, topic, user); + if (!success) { + console.log(`[SubscribeDialog] Login to ${topicUrl(baseUrl, topic)} failed for user ${username}`); + if (user) { + setError(t("subscribe_dialog_error_user_not_authorized", { username: username })); + return; + } else { + props.onNeedsLogin(); + return; + } + } + + // Reserve topic (if requested) + if (session.exists() && baseUrl === config.base_url && reserveTopicVisible) { + console.log(`[SubscribeDialog] Reserving topic ${topic} with everyone access ${everyone}`); + try { + await accountApi.upsertReservation(topic, everyone); + } catch (e) { + console.log(`[SubscribeDialog] Error reserving topic`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else if (e instanceof TopicReservedError) { + setError(t("subscribe_dialog_error_topic_already_reserved")); + return; + } + } + } + + console.log(`[SubscribeDialog] Successful login to ${topicUrl(baseUrl, topic)} for user ${username}`); + props.onSuccess(); + }; + + const handleUseAnotherChanged = (e) => { + props.setBaseUrl(""); + setAnotherServerVisible(e.target.checked); + }; + + const subscribeButtonEnabled = (() => { + if (anotherServerVisible) { + const isExistingTopicUrl = existingTopicUrls.includes(topicUrl(baseUrl, topic)); + return validTopic(topic) && validUrl(baseUrl) && !isExistingTopicUrl; + } else { + const isExistingTopicUrl = existingTopicUrls.includes(topicUrl(config.base_url, topic)); + return validTopic(topic) && !isExistingTopicUrl; + } + })(); + + const updateBaseUrl = (ev, newVal) => { + if (validUrl(newVal)) { + props.setBaseUrl(newVal.replace(/\/$/, '')); // strip trailing slash after https?:// + } else { + props.setBaseUrl(newVal); + } + }; + + return ( + <> + {t("subscribe_dialog_subscribe_title")} + + + {t("subscribe_dialog_subscribe_description")} + +
+ props.setTopic(ev.target.value)} + type="text" + fullWidth + variant="standard" + inputProps={{ + maxLength: 64, + "aria-label": t("subscribe_dialog_subscribe_topic_placeholder") + }} + /> + +
+ {showReserveTopicCheckbox && + + setReserveTopicVisible(ev.target.checked)} + inputProps={{ + "aria-label": t("reserve_dialog_checkbox_label") + }} + /> + } + label={ + <> + {t("reserve_dialog_checkbox_label")} + + + } + /> + {reserveTopicVisible && + + } + + } + {!reserveTopicVisible && + + + } + label={t("subscribe_dialog_subscribe_use_another_label")}/> + {anotherServerVisible && + + } + />} + + } +
+ + + + + + ); +}; + +const LoginPage = (props) => { + const { t } = useTranslation(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [error, setError] = useState(""); + const baseUrl = (props.baseUrl) ? props.baseUrl : config.base_url; + const topic = props.topic; + + const handleLogin = async () => { + const user = {baseUrl, username, password}; + const success = await api.topicAuth(baseUrl, topic, user); + if (!success) { + console.log(`[SubscribeDialog] Login to ${topicUrl(baseUrl, topic)} failed for user ${username}`); + setError(t("subscribe_dialog_error_user_not_authorized", { username: username })); + return; + } + console.log(`[SubscribeDialog] Successful login to ${topicUrl(baseUrl, topic)} for user ${username}`); + await userManager.save(user); + props.onSuccess(); + }; + + return ( + <> + {t("subscribe_dialog_login_title")} + + + {t("subscribe_dialog_login_description")} + + setUsername(ev.target.value)} + type="text" + fullWidth + variant="standard" + inputProps={{ + "aria-label": t("subscribe_dialog_login_username_label") + }} + /> + setPassword(ev.target.value)} + fullWidth + variant="standard" + inputProps={{ + "aria-label": t("subscribe_dialog_login_password_label") + }} + /> + + + + + + + ); +}; + +export const subscribeTopic = async (baseUrl, topic) => { + const subscription = await subscriptionManager.add(baseUrl, topic); + if (session.exists()) { + try { + await accountApi.addSubscription(baseUrl, topic); + } catch (e) { + console.log(`[SubscribeDialog] Subscribing to topic ${topic} failed`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } + } + } + return subscription; +}; + +export default SubscribeDialog; diff --git a/web/src/components/SubscribeDialog.jsx b/web/src/components/SubscribeDialog.jsx deleted file mode 100644 index 0f1cec1..0000000 --- a/web/src/components/SubscribeDialog.jsx +++ /dev/null @@ -1,320 +0,0 @@ -import * as React from "react"; -import { useContext, useState } from "react"; -import { - Button, - TextField, - Dialog, - DialogContent, - DialogContentText, - DialogTitle, - Autocomplete, - Checkbox, - FormControlLabel, - FormGroup, - useMediaQuery, -} from "@mui/material"; -import { useTranslation } from "react-i18next"; -import theme from "./theme"; -import api from "../app/Api"; -import { randomAlphanumericString, topicUrl, validTopic, validUrl } from "../app/utils"; -import userManager from "../app/UserManager"; -import subscriptionManager from "../app/SubscriptionManager"; -import poller from "../app/Poller"; -import DialogFooter from "./DialogFooter"; -import session from "../app/Session"; -import routes from "./routes"; -import accountApi, { Permission, Role } from "../app/AccountApi"; -import ReserveTopicSelect from "./ReserveTopicSelect"; -import { AccountContext } from "./App"; -import { TopicReservedError, UnauthorizedError } from "../app/errors"; -import { ReserveLimitChip } from "./SubscriptionPopup"; - -const publicBaseUrl = "https://ntfy.sh"; - -export const subscribeTopic = async (baseUrl, topic) => { - const subscription = await subscriptionManager.add(baseUrl, topic); - if (session.exists()) { - try { - await accountApi.addSubscription(baseUrl, topic); - } catch (e) { - console.log(`[SubscribeDialog] Subscribing to topic ${topic} failed`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } - } - } - return subscription; -}; - -const SubscribeDialog = (props) => { - const [baseUrl, setBaseUrl] = useState(""); - const [topic, setTopic] = useState(""); - const [showLoginPage, setShowLoginPage] = useState(false); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const handleSuccess = async () => { - console.log(`[SubscribeDialog] Subscribing to topic ${topic}`); - const actualBaseUrl = baseUrl || config.base_url; - const subscription = await subscribeTopic(actualBaseUrl, topic); - poller.pollInBackground(subscription); // Dangle! - props.onSuccess(subscription); - }; - - return ( - - {!showLoginPage && ( - setShowLoginPage(true)} - onSuccess={handleSuccess} - /> - )} - {showLoginPage && setShowLoginPage(false)} onSuccess={handleSuccess} />} - - ); -}; - -const SubscribePage = (props) => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const [error, setError] = useState(""); - const [reserveTopicVisible, setReserveTopicVisible] = useState(false); - const [anotherServerVisible, setAnotherServerVisible] = useState(false); - const [everyone, setEveryone] = useState(Permission.DENY_ALL); - const baseUrl = anotherServerVisible ? props.baseUrl : config.base_url; - const { topic } = props; - const existingTopicUrls = props.subscriptions.map((s) => topicUrl(s.baseUrl, s.topic)); - const existingBaseUrls = Array.from(new Set([publicBaseUrl, ...props.subscriptions.map((s) => s.baseUrl)])).filter( - (s) => s !== config.base_url - ); - const showReserveTopicCheckbox = config.enable_reservations && !anotherServerVisible && (config.enable_payments || account); - const reserveTopicEnabled = - session.exists() && (account?.role === Role.ADMIN || (account?.role === Role.USER && (account?.stats.reservations_remaining || 0) > 0)); - - const handleSubscribe = async () => { - const user = await userManager.get(baseUrl); // May be undefined - const username = user ? user.username : t("subscribe_dialog_error_user_anonymous"); - - // Check read access to topic - const success = await api.topicAuth(baseUrl, topic, user); - if (!success) { - console.log(`[SubscribeDialog] Login to ${topicUrl(baseUrl, topic)} failed for user ${username}`); - if (user) { - setError( - t("subscribe_dialog_error_user_not_authorized", { - username, - }) - ); - return; - } - props.onNeedsLogin(); - return; - } - - // Reserve topic (if requested) - if (session.exists() && baseUrl === config.base_url && reserveTopicVisible) { - console.log(`[SubscribeDialog] Reserving topic ${topic} with everyone access ${everyone}`); - try { - await accountApi.upsertReservation(topic, everyone); - } catch (e) { - console.log(`[SubscribeDialog] Error reserving topic`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else if (e instanceof TopicReservedError) { - setError(t("subscribe_dialog_error_topic_already_reserved")); - return; - } - } - } - - console.log(`[SubscribeDialog] Successful login to ${topicUrl(baseUrl, topic)} for user ${username}`); - props.onSuccess(); - }; - - const handleUseAnotherChanged = (e) => { - props.setBaseUrl(""); - setAnotherServerVisible(e.target.checked); - }; - - const subscribeButtonEnabled = (() => { - if (anotherServerVisible) { - const isExistingTopicUrl = existingTopicUrls.includes(topicUrl(baseUrl, topic)); - return validTopic(topic) && validUrl(baseUrl) && !isExistingTopicUrl; - } - const isExistingTopicUrl = existingTopicUrls.includes(topicUrl(config.base_url, topic)); - return validTopic(topic) && !isExistingTopicUrl; - })(); - - const updateBaseUrl = (ev, newVal) => { - if (validUrl(newVal)) { - props.setBaseUrl(newVal.replace(/\/$/, "")); // strip trailing slash after https?:// - } else { - props.setBaseUrl(newVal); - } - }; - - return ( - <> - {t("subscribe_dialog_subscribe_title")} - - {t("subscribe_dialog_subscribe_description")} -
- props.setTopic(ev.target.value)} - type="text" - fullWidth - variant="standard" - inputProps={{ - maxLength: 64, - "aria-label": t("subscribe_dialog_subscribe_topic_placeholder"), - }} - /> - -
- {showReserveTopicCheckbox && ( - - setReserveTopicVisible(ev.target.checked)} - inputProps={{ - "aria-label": t("reserve_dialog_checkbox_label"), - }} - /> - } - label={ - <> - {t("reserve_dialog_checkbox_label")} - - - } - /> - {reserveTopicVisible && } - - )} - {!reserveTopicVisible && ( - - - } - label={t("subscribe_dialog_subscribe_use_another_label")} - /> - {anotherServerVisible && ( - ( - - )} - /> - )} - - )} -
- - - - - - ); -}; - -const LoginPage = (props) => { - const { t } = useTranslation(); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [error, setError] = useState(""); - const baseUrl = props.baseUrl ? props.baseUrl : config.base_url; - const { topic } = props; - - const handleLogin = async () => { - const user = { baseUrl, username, password }; - const success = await api.topicAuth(baseUrl, topic, user); - if (!success) { - console.log(`[SubscribeDialog] Login to ${topicUrl(baseUrl, topic)} failed for user ${username}`); - setError(t("subscribe_dialog_error_user_not_authorized", { username })); - return; - } - console.log(`[SubscribeDialog] Successful login to ${topicUrl(baseUrl, topic)} for user ${username}`); - await userManager.save(user); - props.onSuccess(); - }; - - return ( - <> - {t("subscribe_dialog_login_title")} - - {t("subscribe_dialog_login_description")} - setUsername(ev.target.value)} - type="text" - fullWidth - variant="standard" - inputProps={{ - "aria-label": t("subscribe_dialog_login_username_label"), - }} - /> - setPassword(ev.target.value)} - fullWidth - variant="standard" - inputProps={{ - "aria-label": t("subscribe_dialog_login_password_label"), - }} - /> - - - - - - - ); -}; - -export default SubscribeDialog; diff --git a/web/src/components/SubscriptionPopup.js b/web/src/components/SubscriptionPopup.js new file mode 100644 index 0000000..7655605 --- /dev/null +++ b/web/src/components/SubscriptionPopup.js @@ -0,0 +1,292 @@ +import * as React from 'react'; +import {useContext, useState} from 'react'; +import Button from '@mui/material/Button'; +import TextField from '@mui/material/TextField'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import {Chip, InputAdornment, Portal, Snackbar, useMediaQuery} from "@mui/material"; +import theme from "./theme"; +import subscriptionManager from "../app/SubscriptionManager"; +import DialogFooter from "./DialogFooter"; +import {useTranslation} from "react-i18next"; +import accountApi, {Role} from "../app/AccountApi"; +import session from "../app/Session"; +import routes from "./routes"; +import MenuItem from "@mui/material/MenuItem"; +import PopupMenu from "./PopupMenu"; +import {formatShortDateTime, shuffle} from "../app/utils"; +import api from "../app/Api"; +import {useNavigate} from "react-router-dom"; +import IconButton from "@mui/material/IconButton"; +import {Clear} from "@mui/icons-material"; +import {AccountContext} from "./App"; +import {ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog} from "./ReserveDialogs"; +import {UnauthorizedError} from "../app/errors"; + +export const SubscriptionPopup = (props) => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); + const navigate = useNavigate(); + const [displayNameDialogOpen, setDisplayNameDialogOpen] = useState(false); + const [reserveAddDialogOpen, setReserveAddDialogOpen] = useState(false); + const [reserveEditDialogOpen, setReserveEditDialogOpen] = useState(false); + const [reserveDeleteDialogOpen, setReserveDeleteDialogOpen] = useState(false); + const [showPublishError, setShowPublishError] = useState(false); + const subscription = props.subscription; + const placement = props.placement ?? "left"; + const reservations = account?.reservations || []; + + const showReservationAdd = config.enable_reservations && !subscription?.reservation && account?.stats.reservations_remaining > 0; + const showReservationAddDisabled = !showReservationAdd && config.enable_reservations && !subscription?.reservation && (config.enable_payments || account?.stats.reservations_remaining === 0); + const showReservationEdit = config.enable_reservations && !!subscription?.reservation; + const showReservationDelete = config.enable_reservations && !!subscription?.reservation; + + const handleChangeDisplayName = async () => { + setDisplayNameDialogOpen(true); + } + + const handleReserveAdd = async () => { + setReserveAddDialogOpen(true); + } + + const handleReserveEdit = async () => { + setReserveEditDialogOpen(true); + } + + const handleReserveDelete = async () => { + setReserveDeleteDialogOpen(true); + } + + const handleSendTestMessage = async () => { + const baseUrl = props.subscription.baseUrl; + const topic = props.subscription.topic; + const tags = shuffle([ + "grinning", "octopus", "upside_down_face", "palm_tree", "maple_leaf", "apple", "skull", "warning", "jack_o_lantern", + "de-server-1", "backups", "cron-script", "script-error", "phils-automation", "mouse", "go-rocks", "hi-ben"]) + .slice(0, Math.round(Math.random() * 4)); + const priority = shuffle([1, 2, 3, 4, 5])[0]; + const title = shuffle([ + "", + "", + "", // Higher chance of no title + "Oh my, another test message?", + "Titles are optional, did you know that?", + "ntfy is open source, and will always be free. Cool, right?", + "I don't really like apples", + "My favorite TV show is The Wire. You should watch it!", + "You can attach files and URLs to messages too", + "You can delay messages up to 3 days" + ])[0]; + const nowSeconds = Math.round(Date.now()/1000); + const message = shuffle([ + `Hello friend, this is a test notification from ntfy web. It's ${formatShortDateTime(nowSeconds)} right now. Is that early or late?`, + `So I heard you like ntfy? If that's true, go to GitHub and star it, or to the Play store and rate it. Thanks! Oh yeah, this is a test notification.`, + `It's almost like you want to hear what I have to say. I'm not even a machine. I'm just a sentence that Phil typed on a random Thursday.`, + `Alright then, it's ${formatShortDateTime(nowSeconds)} already. Boy oh boy, where did the time go? I hope you're alright, friend.`, + `There are nine million bicycles in Beijing That's a fact; It's a thing we can't deny. I wonder if that's true ...`, + `I'm really excited that you're trying out ntfy. Did you know that there are a few public topics, such as ntfy.sh/stats and ntfy.sh/announcements.`, + `It's interesting to hear what people use ntfy for. I've heard people talk about using it for so many cool things. What do you use it for?` + ])[0]; + try { + await api.publish(baseUrl, topic, message, { + title: title, + priority: priority, + tags: tags + }); + } catch (e) { + console.log(`[SubscriptionPopup] Error publishing message`, e); + setShowPublishError(true); + } + } + + const handleClearAll = async () => { + console.log(`[SubscriptionPopup] Deleting all notifications from ${props.subscription.id}`); + await subscriptionManager.deleteNotifications(props.subscription.id); + }; + + const handleUnsubscribe = async () => { + console.log(`[SubscriptionPopup] Unsubscribing from ${props.subscription.id}`, props.subscription); + await subscriptionManager.remove(props.subscription.id); + if (session.exists() && !subscription.internal) { + try { + await accountApi.deleteSubscription(props.subscription.baseUrl, props.subscription.topic); + } catch (e) { + console.log(`[SubscriptionPopup] Error unsubscribing`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } + } + } + const newSelected = await subscriptionManager.first(); // May be undefined + if (newSelected && !newSelected.internal) { + navigate(routes.forSubscription(newSelected)); + } else { + navigate(routes.app); + } + }; + + return ( + <> + + {t("action_bar_change_display_name")} + {showReservationAdd && {t("action_bar_reservation_add")}} + {showReservationAddDisabled && + + {t("action_bar_reservation_add")} + + + } + {showReservationEdit && {t("action_bar_reservation_edit")}} + {showReservationDelete && {t("action_bar_reservation_delete")}} + {t("action_bar_send_test_notification")} + {t("action_bar_clear_notifications")} + {t("action_bar_unsubscribe")} + + + setShowPublishError(false)} + message={t("message_bar_error_publishing")} + /> + setDisplayNameDialogOpen(false)} + /> + {showReservationAdd && + setReserveAddDialogOpen(false)} + /> + } + {showReservationEdit && + setReserveEditDialogOpen(false)} + /> + } + {showReservationDelete && + setReserveDeleteDialogOpen(false)} + /> + } + + + ); +}; + +const DisplayNameDialog = (props) => { + const { t } = useTranslation(); + const subscription = props.subscription; + const [error, setError] = useState(""); + const [displayName, setDisplayName] = useState(subscription.displayName ?? ""); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + const handleSave = async () => { + await subscriptionManager.setDisplayName(subscription.id, displayName); + if (session.exists() && !subscription.internal) { + try { + console.log(`[SubscriptionSettingsDialog] Updating subscription display name to ${displayName}`); + await accountApi.updateSubscription(subscription.baseUrl, subscription.topic, { display_name: displayName }); + } catch (e) { + console.log(`[SubscriptionSettingsDialog] Error updating subscription`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + return; + } + } + } + props.onClose(); + } + + return ( + + {t("display_name_dialog_title")} + + + {t("display_name_dialog_description")} + + setDisplayName(ev.target.value)} + type="text" + fullWidth + variant="standard" + inputProps={{ + maxLength: 64, + "aria-label": t("display_name_dialog_placeholder") + }} + InputProps={{ + endAdornment: ( + + setDisplayName("")} edge="end"> + + + + ) + }} + /> + + + + + + + ); +}; + +export const ReserveLimitChip = () => { + const { account } = useContext(AccountContext); + if (account?.role === Role.ADMIN || account?.stats.reservations_remaining > 0) { + return <>; + } else if (config.enable_payments) { + return (account?.limits.reservations > 0) ? : ; + } else if (account) { + return ; + } + return <>; +}; + +const LimitReachedChip = () => { + const { t } = useTranslation(); + return ( + + ); +}; + +const ProChip = () => { + const { t } = useTranslation(); + return ( + + ); +}; + + diff --git a/web/src/components/SubscriptionPopup.jsx b/web/src/components/SubscriptionPopup.jsx deleted file mode 100644 index ee83a11..0000000 --- a/web/src/components/SubscriptionPopup.jsx +++ /dev/null @@ -1,314 +0,0 @@ -import * as React from "react"; -import { useContext, useState } from "react"; -import { - Button, - TextField, - Dialog, - DialogContent, - DialogContentText, - DialogTitle, - Chip, - InputAdornment, - Portal, - Snackbar, - useMediaQuery, - MenuItem, - IconButton, -} from "@mui/material"; -import { useTranslation } from "react-i18next"; -import { useNavigate } from "react-router-dom"; -import { Clear } from "@mui/icons-material"; -import theme from "./theme"; -import subscriptionManager from "../app/SubscriptionManager"; -import DialogFooter from "./DialogFooter"; -import accountApi, { Role } from "../app/AccountApi"; -import session from "../app/Session"; -import routes from "./routes"; -import PopupMenu from "./PopupMenu"; -import { formatShortDateTime, shuffle } from "../app/utils"; -import api from "../app/Api"; -import { AccountContext } from "./App"; -import { ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog } from "./ReserveDialogs"; -import { UnauthorizedError } from "../app/errors"; - -export const SubscriptionPopup = (props) => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); - const navigate = useNavigate(); - const [displayNameDialogOpen, setDisplayNameDialogOpen] = useState(false); - const [reserveAddDialogOpen, setReserveAddDialogOpen] = useState(false); - const [reserveEditDialogOpen, setReserveEditDialogOpen] = useState(false); - const [reserveDeleteDialogOpen, setReserveDeleteDialogOpen] = useState(false); - const [showPublishError, setShowPublishError] = useState(false); - const { subscription } = props; - const placement = props.placement ?? "left"; - const reservations = account?.reservations || []; - - const showReservationAdd = config.enable_reservations && !subscription?.reservation && account?.stats.reservations_remaining > 0; - const showReservationAddDisabled = - !showReservationAdd && - config.enable_reservations && - !subscription?.reservation && - (config.enable_payments || account?.stats.reservations_remaining === 0); - const showReservationEdit = config.enable_reservations && !!subscription?.reservation; - const showReservationDelete = config.enable_reservations && !!subscription?.reservation; - - const handleChangeDisplayName = async () => { - setDisplayNameDialogOpen(true); - }; - - const handleReserveAdd = async () => { - setReserveAddDialogOpen(true); - }; - - const handleReserveEdit = async () => { - setReserveEditDialogOpen(true); - }; - - const handleReserveDelete = async () => { - setReserveDeleteDialogOpen(true); - }; - - const handleSendTestMessage = async () => { - const { baseUrl } = props.subscription; - const { topic } = props.subscription; - const tags = shuffle([ - "grinning", - "octopus", - "upside_down_face", - "palm_tree", - "maple_leaf", - "apple", - "skull", - "warning", - "jack_o_lantern", - "de-server-1", - "backups", - "cron-script", - "script-error", - "phils-automation", - "mouse", - "go-rocks", - "hi-ben", - ]).slice(0, Math.round(Math.random() * 4)); - const priority = shuffle([1, 2, 3, 4, 5])[0]; - const title = shuffle([ - "", - "", - "", // Higher chance of no title - "Oh my, another test message?", - "Titles are optional, did you know that?", - "ntfy is open source, and will always be free. Cool, right?", - "I don't really like apples", - "My favorite TV show is The Wire. You should watch it!", - "You can attach files and URLs to messages too", - "You can delay messages up to 3 days", - ])[0]; - const nowSeconds = Math.round(Date.now() / 1000); - const message = shuffle([ - `Hello friend, this is a test notification from ntfy web. It's ${formatShortDateTime(nowSeconds)} right now. Is that early or late?`, - `So I heard you like ntfy? If that's true, go to GitHub and star it, or to the Play store and rate it. Thanks! Oh yeah, this is a test notification.`, - `It's almost like you want to hear what I have to say. I'm not even a machine. I'm just a sentence that Phil typed on a random Thursday.`, - `Alright then, it's ${formatShortDateTime(nowSeconds)} already. Boy oh boy, where did the time go? I hope you're alright, friend.`, - `There are nine million bicycles in Beijing That's a fact; It's a thing we can't deny. I wonder if that's true ...`, - `I'm really excited that you're trying out ntfy. Did you know that there are a few public topics, such as ntfy.sh/stats and ntfy.sh/announcements.`, - `It's interesting to hear what people use ntfy for. I've heard people talk about using it for so many cool things. What do you use it for?`, - ])[0]; - try { - await api.publish(baseUrl, topic, message, { - title, - priority, - tags, - }); - } catch (e) { - console.log(`[SubscriptionPopup] Error publishing message`, e); - setShowPublishError(true); - } - }; - - const handleClearAll = async () => { - console.log(`[SubscriptionPopup] Deleting all notifications from ${props.subscription.id}`); - await subscriptionManager.deleteNotifications(props.subscription.id); - }; - - const handleUnsubscribe = async () => { - console.log(`[SubscriptionPopup] Unsubscribing from ${props.subscription.id}`, props.subscription); - await subscriptionManager.remove(props.subscription.id); - if (session.exists() && !subscription.internal) { - try { - await accountApi.deleteSubscription(props.subscription.baseUrl, props.subscription.topic); - } catch (e) { - console.log(`[SubscriptionPopup] Error unsubscribing`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } - } - } - const newSelected = await subscriptionManager.first(); // May be undefined - if (newSelected && !newSelected.internal) { - navigate(routes.forSubscription(newSelected)); - } else { - navigate(routes.app); - } - }; - - return ( - <> - - {t("action_bar_change_display_name")} - {showReservationAdd && {t("action_bar_reservation_add")}} - {showReservationAddDisabled && ( - - {t("action_bar_reservation_add")} - - - )} - {showReservationEdit && {t("action_bar_reservation_edit")}} - {showReservationDelete && {t("action_bar_reservation_delete")}} - {t("action_bar_send_test_notification")} - {t("action_bar_clear_notifications")} - {t("action_bar_unsubscribe")} - - - setShowPublishError(false)} - message={t("message_bar_error_publishing")} - /> - setDisplayNameDialogOpen(false)} /> - {showReservationAdd && ( - setReserveAddDialogOpen(false)} - /> - )} - {showReservationEdit && ( - setReserveEditDialogOpen(false)} - /> - )} - {showReservationDelete && ( - setReserveDeleteDialogOpen(false)} - /> - )} - - - ); -}; - -const DisplayNameDialog = (props) => { - const { t } = useTranslation(); - const { subscription } = props; - const [error, setError] = useState(""); - const [displayName, setDisplayName] = useState(subscription.displayName ?? ""); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - const handleSave = async () => { - await subscriptionManager.setDisplayName(subscription.id, displayName); - if (session.exists() && !subscription.internal) { - try { - console.log(`[SubscriptionSettingsDialog] Updating subscription display name to ${displayName}`); - await accountApi.updateSubscription(subscription.baseUrl, subscription.topic, { display_name: displayName }); - } catch (e) { - console.log(`[SubscriptionSettingsDialog] Error updating subscription`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - return; - } - } - } - props.onClose(); - }; - - return ( - - {t("display_name_dialog_title")} - - {t("display_name_dialog_description")} - setDisplayName(ev.target.value)} - type="text" - fullWidth - variant="standard" - inputProps={{ - maxLength: 64, - "aria-label": t("display_name_dialog_placeholder"), - }} - InputProps={{ - endAdornment: ( - - setDisplayName("")} edge="end"> - - - - ), - }} - /> - - - - - - - ); -}; - -export const ReserveLimitChip = () => { - const { account } = useContext(AccountContext); - if (account?.role === Role.ADMIN || account?.stats.reservations_remaining > 0) { - return <>; - } - if (config.enable_payments) { - return account?.limits.reservations > 0 ? : ; - } - if (account) { - return ; - } - return <>; -}; - -const LimitReachedChip = () => { - const { t } = useTranslation(); - return ( - - ); -}; - -export const ProChip = () => ( - -); diff --git a/web/src/components/UpgradeDialog.js b/web/src/components/UpgradeDialog.js new file mode 100644 index 0000000..43be16f --- /dev/null +++ b/web/src/components/UpgradeDialog.js @@ -0,0 +1,366 @@ +import * as React from 'react'; +import {useContext, useEffect, useState} from 'react'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import DialogTitle from '@mui/material/DialogTitle'; +import {Alert, CardActionArea, CardContent, Chip, Link, ListItem, Switch, useMediaQuery} from "@mui/material"; +import theme from "./theme"; +import Button from "@mui/material/Button"; +import accountApi, {SubscriptionInterval} from "../app/AccountApi"; +import session from "../app/Session"; +import routes from "./routes"; +import Card from "@mui/material/Card"; +import Typography from "@mui/material/Typography"; +import {AccountContext} from "./App"; +import {formatBytes, formatNumber, formatPrice, formatShortDate} from "../app/utils"; +import {Trans, useTranslation} from "react-i18next"; +import List from "@mui/material/List"; +import {Check, Close} from "@mui/icons-material"; +import ListItemIcon from "@mui/material/ListItemIcon"; +import ListItemText from "@mui/material/ListItemText"; +import Box from "@mui/material/Box"; +import {NavLink} from "react-router-dom"; +import {UnauthorizedError} from "../app/errors"; +import DialogContentText from "@mui/material/DialogContentText"; +import DialogActions from "@mui/material/DialogActions"; + +const UpgradeDialog = (props) => { + const { t } = useTranslation(); + const { account } = useContext(AccountContext); // May be undefined! + const [error, setError] = useState(""); + const [tiers, setTiers] = useState(null); + const [interval, setInterval] = useState(account?.billing?.interval || SubscriptionInterval.YEAR); + const [newTierCode, setNewTierCode] = useState(account?.tier?.code); // May be undefined + const [loading, setLoading] = useState(false); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); + + useEffect(() => { + const fetchTiers = async () => { + setTiers(await accountApi.billingTiers()); + } + fetchTiers(); // Dangle + }, []); + + if (!tiers) { + return <>; + } + + const tiersMap = Object.assign(...tiers.map(tier => ({[tier.code]: tier}))); + const newTier = tiersMap[newTierCode]; // May be undefined + const currentTier = account?.tier; // May be undefined + const currentInterval = account?.billing?.interval; // May be undefined + const currentTierCode = currentTier?.code; // May be undefined + + // Figure out buttons, labels and the submit action + let submitAction, submitButtonLabel, banner; + if (!account) { + submitButtonLabel = t("account_upgrade_dialog_button_redirect_signup"); + submitAction = Action.REDIRECT_SIGNUP; + banner = null; + } else if (currentTierCode === newTierCode && (currentInterval === undefined || currentInterval === interval)) { + submitButtonLabel = t("account_upgrade_dialog_button_update_subscription"); + submitAction = null; + banner = (currentTierCode) ? Banner.PRORATION_INFO : null; + } else if (!currentTierCode) { + submitButtonLabel = t("account_upgrade_dialog_button_pay_now"); + submitAction = Action.CREATE_SUBSCRIPTION; + banner = null; + } else if (!newTierCode) { + submitButtonLabel = t("account_upgrade_dialog_button_cancel_subscription"); + submitAction = Action.CANCEL_SUBSCRIPTION; + banner = Banner.CANCEL_WARNING; + } else { + submitButtonLabel = t("account_upgrade_dialog_button_update_subscription"); + submitAction = Action.UPDATE_SUBSCRIPTION; + banner = Banner.PRORATION_INFO; + } + + // Exceptional conditions + if (loading) { + submitAction = null; + } else if (newTier?.code && account?.reservations?.length > newTier?.limits?.reservations) { + submitAction = null; + banner = Banner.RESERVATIONS_WARNING; + } + + const handleSubmit = async () => { + if (submitAction === Action.REDIRECT_SIGNUP) { + window.location.href = routes.signup; + return; + } + try { + setLoading(true); + if (submitAction === Action.CREATE_SUBSCRIPTION) { + const response = await accountApi.createBillingSubscription(newTierCode, interval); + window.location.href = response.redirect_url; + } else if (submitAction === Action.UPDATE_SUBSCRIPTION) { + await accountApi.updateBillingSubscription(newTierCode, interval); + } else if (submitAction === Action.CANCEL_SUBSCRIPTION) { + await accountApi.deleteBillingSubscription(); + } + props.onCancel(); + } catch (e) { + console.log(`[UpgradeDialog] Error changing billing subscription`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } else { + setError(e.message); + } + } finally { + setLoading(false); + } + } + + // Figure out discount + let discount = 0, upto = false; + if (newTier?.prices) { + discount = Math.round(((newTier.prices.month*12/newTier.prices.year)-1)*100); + } else { + let n = 0; + for (const t of tiers) { + if (t.prices) { + const tierDiscount = Math.round(((t.prices.month*12/t.prices.year)-1)*100); + if (tierDiscount > discount) { + discount = tierDiscount; + n++; + } + } + } + upto = n > 1; + } + + return ( + + +
+
{t("account_upgrade_dialog_title")}
+
+ {t("account_upgrade_dialog_interval_monthly")} + setInterval(ev.target.checked ? SubscriptionInterval.YEAR : SubscriptionInterval.MONTH)} + /> + {t("account_upgrade_dialog_interval_yearly")} + {discount > 0 && + + } +
+
+
+ +
+ {tiers.map(tier => + setNewTierCode(tier.code)} // tier.code may be undefined! + /> + )} +
+ {banner === Banner.CANCEL_WARNING && + + + + } + {banner === Banner.PRORATION_INFO && + + + + } + {banner === Banner.RESERVATIONS_WARNING && + + , + }} + /> + + } +
+ + + {config.billing_contact.indexOf('@') !== -1 && + <> }}/>{" "} + } + {config.billing_contact.match(`^http?s://`) && + <> }}/>{" "} + } + {error} + + + + + + +
+ ); +}; + +const TierCard = (props) => { + const { t } = useTranslation(); + const tier = props.tier; + + let cardStyle, labelStyle, labelText; + if (props.selected) { + cardStyle = { background: "#eee", border: "3px solid #338574" }; + labelStyle = { background: "#338574", color: "white" }; + labelText = t("account_upgrade_dialog_tier_selected_label"); + } else if (props.current) { + cardStyle = { border: "3px solid #eee" }; + labelStyle = { background: "#eee", color: "black" }; + labelText = t("account_upgrade_dialog_tier_current_label"); + } else { + cardStyle = { border: "3px solid transparent" }; + } + + let monthlyPrice; + if (!tier.prices) { + monthlyPrice = 0; + } else if (props.interval === SubscriptionInterval.YEAR) { + monthlyPrice = tier.prices.year/12; + } else if (props.interval === SubscriptionInterval.MONTH) { + monthlyPrice = tier.prices.month; + } + + return ( + + + + + {labelStyle && +
{labelText}
+ } + + {tier.name || t("account_basics_tier_free")} + +
+ {formatPrice(monthlyPrice)} + {monthlyPrice > 0 && <>/ {t("account_upgrade_dialog_tier_price_per_month")}} +
+ + {tier.limits.reservations > 0 && {t("account_upgrade_dialog_tier_features_reservations", { reservations: tier.limits.reservations })}} + {tier.limits.reservations === 0 && {t("account_upgrade_dialog_tier_features_no_reservations")}} + {t("account_upgrade_dialog_tier_features_messages", { messages: formatNumber(tier.limits.messages) })} + {t("account_upgrade_dialog_tier_features_emails", { emails: formatNumber(tier.limits.emails) })} + {t("account_upgrade_dialog_tier_features_attachment_file_size", { filesize: formatBytes(tier.limits.attachment_file_size, 0) })} + {t("account_upgrade_dialog_tier_features_attachment_total_size", { totalsize: formatBytes(tier.limits.attachment_total_size, 0) })} + + {tier.prices && props.interval === SubscriptionInterval.MONTH && + + {t("account_upgrade_dialog_tier_price_billed_monthly", { price: formatPrice(tier.prices.month*12) })} + + } + {tier.prices && props.interval === SubscriptionInterval.YEAR && + + {t("account_upgrade_dialog_tier_price_billed_yearly", { price: formatPrice(tier.prices.year), save: formatPrice(tier.prices.month*12-tier.prices.year) })} + + } +
+
+
+
+ + ); +} + +const Feature = (props) => { + return {props.children}; +} + +const NoFeature = (props) => { + return {props.children}; +} + +const FeatureItem = (props) => { + return ( + + + {props.feature && } + {!props.feature && } + + + {props.children} + + } + /> + + + ); +}; + +const Action = { + REDIRECT_SIGNUP: 1, + CREATE_SUBSCRIPTION: 2, + UPDATE_SUBSCRIPTION: 3, + CANCEL_SUBSCRIPTION: 4 +}; + +const Banner = { + CANCEL_WARNING: 1, + PRORATION_INFO: 2, + RESERVATIONS_WARNING: 3 +}; + +export default UpgradeDialog; diff --git a/web/src/components/UpgradeDialog.jsx b/web/src/components/UpgradeDialog.jsx deleted file mode 100644 index a554f1f..0000000 --- a/web/src/components/UpgradeDialog.jsx +++ /dev/null @@ -1,435 +0,0 @@ -import * as React from "react"; -import { useContext, useEffect, useState } from "react"; -import { - Dialog, - DialogContent, - DialogTitle, - Alert, - CardActionArea, - CardContent, - Chip, - Link, - ListItem, - Switch, - useMediaQuery, - Button, - Card, - Typography, - List, - ListItemIcon, - ListItemText, - Box, - DialogContentText, - DialogActions, -} from "@mui/material"; -import { Trans, useTranslation } from "react-i18next"; -import { Check, Close } from "@mui/icons-material"; -import { NavLink } from "react-router-dom"; -import { UnauthorizedError } from "../app/errors"; -import { formatBytes, formatNumber, formatPrice, formatShortDate } from "../app/utils"; -import { AccountContext } from "./App"; -import routes from "./routes"; -import session from "../app/Session"; -import accountApi, { SubscriptionInterval } from "../app/AccountApi"; -import theme from "./theme"; - -const Feature = (props) => {props.children}; - -const NoFeature = (props) => {props.children}; - -const FeatureItem = (props) => ( - - - {props.feature && } - {!props.feature && } - - {props.children}} /> - -); - -const Action = { - REDIRECT_SIGNUP: 1, - CREATE_SUBSCRIPTION: 2, - UPDATE_SUBSCRIPTION: 3, - CANCEL_SUBSCRIPTION: 4, -}; - -const Banner = { - CANCEL_WARNING: 1, - PRORATION_INFO: 2, - RESERVATIONS_WARNING: 3, -}; - -const UpgradeDialog = (props) => { - const { t } = useTranslation(); - const { account } = useContext(AccountContext); // May be undefined! - const [error, setError] = useState(""); - const [tiers, setTiers] = useState(null); - const [interval, setInterval] = useState(account?.billing?.interval || SubscriptionInterval.YEAR); - const [newTierCode, setNewTierCode] = useState(account?.tier?.code); // May be undefined - const [loading, setLoading] = useState(false); - const fullScreen = useMediaQuery(theme.breakpoints.down("sm")); - - useEffect(() => { - const fetchTiers = async () => { - setTiers(await accountApi.billingTiers()); - }; - fetchTiers(); // Dangle - }, []); - - if (!tiers) { - return <>; - } - - const tiersMap = Object.assign(...tiers.map((tier) => ({ [tier.code]: tier }))); - const newTier = tiersMap[newTierCode]; // May be undefined - const currentTier = account?.tier; // May be undefined - const currentInterval = account?.billing?.interval; // May be undefined - const currentTierCode = currentTier?.code; // May be undefined - - // Figure out buttons, labels and the submit action - let submitAction; - let submitButtonLabel; - let banner; - if (!account) { - submitButtonLabel = t("account_upgrade_dialog_button_redirect_signup"); - submitAction = Action.REDIRECT_SIGNUP; - banner = null; - } else if (currentTierCode === newTierCode && (currentInterval === undefined || currentInterval === interval)) { - submitButtonLabel = t("account_upgrade_dialog_button_update_subscription"); - submitAction = null; - banner = currentTierCode ? Banner.PRORATION_INFO : null; - } else if (!currentTierCode) { - submitButtonLabel = t("account_upgrade_dialog_button_pay_now"); - submitAction = Action.CREATE_SUBSCRIPTION; - banner = null; - } else if (!newTierCode) { - submitButtonLabel = t("account_upgrade_dialog_button_cancel_subscription"); - submitAction = Action.CANCEL_SUBSCRIPTION; - banner = Banner.CANCEL_WARNING; - } else { - submitButtonLabel = t("account_upgrade_dialog_button_update_subscription"); - submitAction = Action.UPDATE_SUBSCRIPTION; - banner = Banner.PRORATION_INFO; - } - - // Exceptional conditions - if (loading) { - submitAction = null; - } else if (newTier?.code && account?.reservations?.length > newTier?.limits?.reservations) { - submitAction = null; - banner = Banner.RESERVATIONS_WARNING; - } - - const handleSubmit = async () => { - if (submitAction === Action.REDIRECT_SIGNUP) { - window.location.href = routes.signup; - return; - } - try { - setLoading(true); - if (submitAction === Action.CREATE_SUBSCRIPTION) { - const response = await accountApi.createBillingSubscription(newTierCode, interval); - window.location.href = response.redirect_url; - } else if (submitAction === Action.UPDATE_SUBSCRIPTION) { - await accountApi.updateBillingSubscription(newTierCode, interval); - } else if (submitAction === Action.CANCEL_SUBSCRIPTION) { - await accountApi.deleteBillingSubscription(); - } - props.onCancel(); - } catch (e) { - console.log(`[UpgradeDialog] Error changing billing subscription`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } else { - setError(e.message); - } - } finally { - setLoading(false); - } - }; - - // Figure out discount - let discount = 0; - let upto = false; - if (newTier?.prices) { - discount = Math.round(((newTier.prices.month * 12) / newTier.prices.year - 1) * 100); - } else { - let n = 0; - for (const tier of tiers) { - if (tier.prices) { - const tierDiscount = Math.round(((tier.prices.month * 12) / tier.prices.year - 1) * 100); - if (tierDiscount > discount) { - discount = tierDiscount; - n += 1; - } - } - } - upto = n > 1; - } - - return ( - - -
-
{t("account_upgrade_dialog_title")}
-
- - {t("account_upgrade_dialog_interval_monthly")} - - setInterval(ev.target.checked ? SubscriptionInterval.YEAR : SubscriptionInterval.MONTH)} - /> - - {t("account_upgrade_dialog_interval_yearly")} - - {discount > 0 && ( - - )} -
-
-
- -
- {tiers.map((tier) => ( - setNewTierCode(tier.code)} // tier.code may be undefined! - /> - ))} -
- {banner === Banner.CANCEL_WARNING && ( - - - - )} - {banner === Banner.PRORATION_INFO && ( - - - - )} - {banner === Banner.RESERVATIONS_WARNING && ( - - , - }} - /> - - )} -
- - - {config.billing_contact.indexOf("@") !== -1 && ( - <> - , - }} - />{" "} - - )} - {config.billing_contact.match(`^http?s://`) && ( - <> - , - }} - />{" "} - - )} - {error} - - - - - - -
- ); -}; - -const TierCard = (props) => { - const { t } = useTranslation(); - const { tier } = props; - - let cardStyle; - let labelStyle; - let labelText; - if (props.selected) { - cardStyle = { background: "#eee", border: "3px solid #338574" }; - labelStyle = { background: "#338574", color: "white" }; - labelText = t("account_upgrade_dialog_tier_selected_label"); - } else if (props.current) { - cardStyle = { border: "3px solid #eee" }; - labelStyle = { background: "#eee", color: "black" }; - labelText = t("account_upgrade_dialog_tier_current_label"); - } else { - cardStyle = { border: "3px solid transparent" }; - } - - let monthlyPrice; - if (!tier.prices) { - monthlyPrice = 0; - } else if (props.interval === SubscriptionInterval.YEAR) { - monthlyPrice = tier.prices.year / 12; - } else if (props.interval === SubscriptionInterval.MONTH) { - monthlyPrice = tier.prices.month; - } - - return ( - - - - - {labelStyle && ( -
- {labelText} -
- )} - - {tier.name || t("account_basics_tier_free")} - -
- - {formatPrice(monthlyPrice)} - - {monthlyPrice > 0 && <>/ {t("account_upgrade_dialog_tier_price_per_month")}} -
- - {tier.limits.reservations > 0 && ( - - {t("account_upgrade_dialog_tier_features_reservations", { - reservations: tier.limits.reservations, - count: tier.limits.reservations, - })} - - )} - - {t("account_upgrade_dialog_tier_features_messages", { - messages: formatNumber(tier.limits.messages), - count: tier.limits.messages, - })} - - - {t("account_upgrade_dialog_tier_features_emails", { - emails: formatNumber(tier.limits.emails), - count: tier.limits.emails, - })} - - {tier.limits.calls > 0 && ( - - {t("account_upgrade_dialog_tier_features_calls", { - calls: formatNumber(tier.limits.calls), - count: tier.limits.calls, - })} - - )} - - {t("account_upgrade_dialog_tier_features_attachment_file_size", { - filesize: formatBytes(tier.limits.attachment_file_size, 0), - })} - - {tier.limits.reservations === 0 && {t("account_upgrade_dialog_tier_features_no_reservations")}} - {tier.limits.calls === 0 && {t("account_upgrade_dialog_tier_features_no_calls")}} - - {tier.prices && props.interval === SubscriptionInterval.MONTH && ( - - {t("account_upgrade_dialog_tier_price_billed_monthly", { - price: formatPrice(tier.prices.month * 12), - })} - - )} - {tier.prices && props.interval === SubscriptionInterval.YEAR && ( - - {t("account_upgrade_dialog_tier_price_billed_yearly", { - price: formatPrice(tier.prices.year), - save: formatPrice(tier.prices.month * 12 - tier.prices.year), - })} - - )} -
-
-
-
- ); -}; - -export default UpgradeDialog; diff --git a/web/src/components/hooks.js b/web/src/components/hooks.js index 6b68188..b1ce8ff 100644 --- a/web/src/components/hooks.js +++ b/web/src/components/hooks.js @@ -1,7 +1,7 @@ -import { useNavigate, useParams } from "react-router-dom"; -import { useEffect, useState } from "react"; +import {useNavigate, useParams} from "react-router-dom"; +import {useEffect, useState} from "react"; import subscriptionManager from "../app/SubscriptionManager"; -import { disallowedTopic, expandSecureUrl, topicUrl } from "../app/utils"; +import {disallowedTopic, expandSecureUrl, topicUrl} from "../app/utils"; import notifier from "../app/Notifier"; import routes from "./routes"; import connectionManager from "../app/ConnectionManager"; @@ -9,7 +9,7 @@ import poller from "../app/Poller"; import pruner from "../app/Pruner"; import session from "../app/Session"; import accountApi from "../app/AccountApi"; -import { UnauthorizedError } from "../app/errors"; +import {UnauthorizedError} from "../app/errors"; /** * Wire connectionManager and subscriptionManager so that subscriptions are updated when the connection @@ -17,75 +17,65 @@ import { UnauthorizedError } from "../app/errors"; * to the connection being re-established). */ export const useConnectionListeners = (account, subscriptions, users) => { - const navigate = useNavigate(); + const navigate = useNavigate(); - // Register listeners for incoming messages, and connection state changes - useEffect( - () => { - const handleInternalMessage = async (message) => { - console.log(`[ConnectionListener] Received message on sync topic`, message.message); - try { - const data = JSON.parse(message.message); - if (data.event === "sync") { - console.log(`[ConnectionListener] Triggering account sync`); - await accountApi.sync(); - } else { - console.log(`[ConnectionListener] Unknown message type. Doing nothing.`); - } - } catch (e) { - console.log(`[ConnectionListener] Error parsing sync topic message`, e); + // Register listeners for incoming messages, and connection state changes + useEffect(() => { + const handleMessage = async (subscriptionId, message) => { + const subscription = await subscriptionManager.get(subscriptionId); + if (subscription.internal) { + await handleInternalMessage(message); + } else { + await handleNotification(subscriptionId, message); + } + }; + + const handleInternalMessage = async (message) => { + console.log(`[ConnectionListener] Received message on sync topic`, message.message); + try { + const data = JSON.parse(message.message); + if (data.event === "sync") { + console.log(`[ConnectionListener] Triggering account sync`); + await accountApi.sync(); + } else { + console.log(`[ConnectionListener] Unknown message type. Doing nothing.`); + } + } catch (e) { + console.log(`[ConnectionListener] Error parsing sync topic message`, e); + } + }; + + const handleNotification = async (subscriptionId, notification) => { + const added = await subscriptionManager.addNotification(subscriptionId, notification); + if (added) { + const defaultClickAction = (subscription) => navigate(routes.forSubscription(subscription)); + await notifier.notify(subscriptionId, notification, defaultClickAction) + } + }; + connectionManager.registerStateListener(subscriptionManager.updateState); + connectionManager.registerMessageListener(handleMessage); + return () => { + connectionManager.resetStateListener(); + connectionManager.resetMessageListener(); + } + }, + // We have to disable dep checking for "navigate". This is fine, it never changes. + // eslint-disable-next-line + [] + ); + + // Sync topic listener: For accounts with sync_topic, subscribe to an internal topic + useEffect(() => { + if (!account || !account.sync_topic) { + return; } - }; + subscriptionManager.add(config.base_url, account.sync_topic, true); // Dangle! + }, [account]); - const handleNotification = async (subscriptionId, notification) => { - const added = await subscriptionManager.addNotification(subscriptionId, notification); - if (added) { - const defaultClickAction = (subscription) => navigate(routes.forSubscription(subscription)); - await notifier.notify(subscriptionId, notification, defaultClickAction); - } - }; - - const handleMessage = async (subscriptionId, message) => { - const subscription = await subscriptionManager.get(subscriptionId); - - // Race condition: sometimes the subscription is already unsubscribed from account - // sync before the message is handled - if (!subscription) { - return; - } - - if (subscription.internal) { - await handleInternalMessage(message); - } else { - await handleNotification(subscriptionId, message); - } - }; - - connectionManager.registerStateListener(subscriptionManager.updateState); - connectionManager.registerMessageListener(handleMessage); - - return () => { - connectionManager.resetStateListener(); - connectionManager.resetMessageListener(); - }; - }, - // We have to disable dep checking for "navigate". This is fine, it never changes. - - [] - ); - - // Sync topic listener: For accounts with sync_topic, subscribe to an internal topic - useEffect(() => { - if (!account || !account.sync_topic) { - return; - } - subscriptionManager.add(config.base_url, account.sync_topic, true); // Dangle! - }, [account]); - - // When subscriptions or users change, refresh the connections - useEffect(() => { - connectionManager.refresh(subscriptions, users); // Dangle - }, [subscriptions, users]); + // When subscriptions or users change, refresh the connections + useEffect(() => { + connectionManager.refresh(subscriptions, users); // Dangle + }, [subscriptions, users]); }; /** @@ -93,35 +83,35 @@ export const useConnectionListeners = (account, subscriptions, users) => { * This will only be run once after the initial page load. */ export const useAutoSubscribe = (subscriptions, selected) => { - const [hasRun, setHasRun] = useState(false); - const params = useParams(); + const [hasRun, setHasRun] = useState(false); + const params = useParams(); - useEffect(() => { - const loaded = subscriptions !== null && subscriptions !== undefined; - if (!loaded || hasRun) { - return; - } - setHasRun(true); - const eligible = params.topic && !selected && !disallowedTopic(params.topic); - if (eligible) { - const baseUrl = params.baseUrl ? expandSecureUrl(params.baseUrl) : config.base_url; - console.log(`[Hooks] Auto-subscribing to ${topicUrl(baseUrl, params.topic)}`); - (async () => { - const subscription = await subscriptionManager.add(baseUrl, params.topic); - if (session.exists()) { - try { - await accountApi.addSubscription(baseUrl, params.topic); - } catch (e) { - console.log(`[Hooks] Auto-subscribing failed`, e); - if (e instanceof UnauthorizedError) { - session.resetAndRedirect(routes.login); - } - } + useEffect(() => { + const loaded = subscriptions !== null && subscriptions !== undefined; + if (!loaded || hasRun) { + return; } - poller.pollInBackground(subscription); // Dangle! - })(); - } - }, [params, subscriptions, selected, hasRun]); + setHasRun(true); + const eligible = params.topic && !selected && !disallowedTopic(params.topic); + if (eligible) { + const baseUrl = (params.baseUrl) ? expandSecureUrl(params.baseUrl) : config.base_url; + console.log(`[Hooks] Auto-subscribing to ${topicUrl(baseUrl, params.topic)}`); + (async () => { + const subscription = await subscriptionManager.add(baseUrl, params.topic); + if (session.exists()) { + try { + await accountApi.addSubscription(baseUrl, params.topic); + } catch (e) { + console.log(`[Hooks] Auto-subscribing failed`, e); + if (e instanceof UnauthorizedError) { + session.resetAndRedirect(routes.login); + } + } + } + poller.pollInBackground(subscription); // Dangle! + })(); + } + }, [params, subscriptions, selected, hasRun]); }; /** @@ -130,19 +120,19 @@ export const useAutoSubscribe = (subscriptions, selected) => { * up "unused" imports. See https://github.com/binwiederhier/ntfy/issues/186. */ export const useBackgroundProcesses = () => { - useEffect(() => { - poller.startWorker(); - pruner.startWorker(); - accountApi.startWorker(); - }, []); -}; + useEffect(() => { + poller.startWorker(); + pruner.startWorker(); + accountApi.startWorker(); + }, []); +} export const useAccountListener = (setAccount) => { - useEffect(() => { - accountApi.registerListener(setAccount); - accountApi.sync(); // Dangle - return () => { - accountApi.resetListener(); - }; - }, []); -}; + useEffect(() => { + accountApi.registerListener(setAccount); + accountApi.sync(); // Dangle + return () => { + accountApi.resetListener(); + } + }, []); +} diff --git a/web/src/components/i18n.js b/web/src/components/i18n.js new file mode 100644 index 0000000..42eb572 --- /dev/null +++ b/web/src/components/i18n.js @@ -0,0 +1,29 @@ +import i18n from 'i18next'; +import Backend from 'i18next-http-backend'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; + +// Translations using i18next +// - Options: https://www.i18next.com/overview/configuration-options +// - Browser Language Detector: https://github.com/i18next/i18next-browser-languageDetector +// - HTTP Backend (load files via fetch): https://github.com/i18next/i18next-http-backend +// +// See example project here: +// https://github.com/i18next/react-i18next/tree/master/example/react + +i18n + .use(Backend) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + fallbackLng: 'en', + debug: true, + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + backend: { + loadPath: '/static/langs/{{lng}}.json', + } + }); + +export default i18n; diff --git a/web/src/components/i18n.jsx b/web/src/components/i18n.jsx deleted file mode 100644 index 2bc315c..0000000 --- a/web/src/components/i18n.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import i18n from "i18next"; -import Backend from "i18next-http-backend"; -import LanguageDetector from "i18next-browser-languagedetector"; -import { initReactI18next } from "react-i18next"; - -// Translations using i18next -// - Options: https://www.i18next.com/overview/configuration-options -// - Browser Language Detector: https://github.com/i18next/i18next-browser-languageDetector -// - HTTP Backend (load files via fetch): https://github.com/i18next/i18next-http-backend -// -// See example project here: -// https://github.com/i18next/react-i18next/tree/master/example/react - -i18n - .use(Backend) - .use(LanguageDetector) - .use(initReactI18next) - .init({ - fallbackLng: "en", - debug: true, - interpolation: { - escapeValue: false, // not needed for react as it escapes by default - }, - backend: { - loadPath: "/static/langs/{{lng}}.json", - }, - }); - -export default i18n; diff --git a/web/src/components/routes.js b/web/src/components/routes.js index 17e0eac..d1db160 100644 --- a/web/src/components/routes.js +++ b/web/src/components/routes.js @@ -1,20 +1,20 @@ import config from "../app/config"; -import { shortUrl } from "../app/utils"; +import {shortUrl} from "../app/utils"; const routes = { - login: "/login", - signup: "/signup", - app: config.app_root, - account: "/account", - settings: "/settings", - subscription: "/:topic", - subscriptionExternal: "/:baseUrl/:topic", - forSubscription: (subscription) => { - if (subscription.baseUrl !== config.base_url) { - return `/${shortUrl(subscription.baseUrl)}/${subscription.topic}`; + login: "/login", + signup: "/signup", + app: config.app_root, + account: "/account", + settings: "/settings", + subscription: "/:topic", + subscriptionExternal: "/:baseUrl/:topic", + forSubscription: (subscription) => { + if (subscription.baseUrl !== config.base_url) { + return `/${shortUrl(subscription.baseUrl)}/${subscription.topic}`; + } + return `/${subscription.topic}`; } - return `/${subscription.topic}`; - }, }; export default routes; diff --git a/web/src/components/styles.js b/web/src/components/styles.js index edcfb46..d612794 100644 --- a/web/src/components/styles.js +++ b/web/src/components/styles.js @@ -1,5 +1,7 @@ -import { Typography, Container, Backdrop, styled } from "@mui/material"; +import Typography from "@mui/material/Typography"; import theme from "./theme"; +import Container from "@mui/material/Container"; +import {Backdrop, styled} from "@mui/material"; export const Paragraph = styled(Typography)({ paddingTop: 8, @@ -7,14 +9,14 @@ export const Paragraph = styled(Typography)({ }); export const VerticallyCenteredContainer = styled(Container)({ - display: "flex", + display: 'flex', flexGrow: 1, - flexDirection: "column", - justifyContent: "center", - alignContent: "center", - color: theme.palette.text.primary, + flexDirection: 'column', + justifyContent: 'center', + alignContent: 'center', + color: theme.palette.text.primary }); export const LightboxBackdrop = styled(Backdrop)({ - backgroundColor: "rgba(0, 0, 0, 0.8)", // was: 0.5 + backgroundColor: 'rgba(0, 0, 0, 0.8)' // was: 0.5 }); diff --git a/web/src/components/theme.js b/web/src/components/theme.js index ca77cdc..3fdafae 100644 --- a/web/src/components/theme.js +++ b/web/src/components/theme.js @@ -1,13 +1,13 @@ -import { red } from "@mui/material/colors"; -import { createTheme } from "@mui/material/styles"; +import { red } from '@mui/material/colors'; +import { createTheme } from '@mui/material/styles'; const theme = createTheme({ palette: { primary: { - main: "#338574", + main: '#338574', }, secondary: { - main: "#6cead0", + main: '#6cead0', }, error: { main: red.A400, @@ -17,19 +17,19 @@ const theme = createTheme({ MuiListItemIcon: { styleOverrides: { root: { - minWidth: "36px", + minWidth: '36px', }, }, }, MuiCardContent: { styleOverrides: { root: { - ":last-child": { - paddingBottom: "16px", - }, - }, - }, - }, + ':last-child': { + paddingBottom: '16px' + } + } + } + } }, }); diff --git a/web/src/index.js b/web/src/index.js new file mode 100644 index 0000000..659bcb8 --- /dev/null +++ b/web/src/index.js @@ -0,0 +1,6 @@ +import * as React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './components/App'; + +const root = createRoot(document.querySelector('#root')); +root.render(); diff --git a/web/src/index.jsx b/web/src/index.jsx deleted file mode 100644 index d60c05a..0000000 --- a/web/src/index.jsx +++ /dev/null @@ -1,6 +0,0 @@ -import * as React from "react"; -import { createRoot } from "react-dom/client"; -import App from "./components/App"; - -const root = createRoot(document.querySelector("#root")); -root.render(); diff --git a/web/vite.config.js b/web/vite.config.js deleted file mode 100644 index ffc80ab..0000000 --- a/web/vite.config.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; - -export default defineConfig(() => ({ - build: { - outDir: "build", - assetsDir: "static/media", - }, - server: { - port: 3000, - }, - plugins: [react()], -}));