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..b0c2d33 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ dist/ -dev-dist/ build/ .idea/ .vscode/ 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..76f46a8 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,14 +137,6 @@ 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 @@ -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)') diff --git a/README.md b/README.md index cebf55b..7cf41fe 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/) | @@ -133,14 +130,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..95e6379 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -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"}), @@ -149,7 +144,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 +151,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") @@ -205,6 +195,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 +211,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 +293,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 +302,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,6 +317,7 @@ 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 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..3955ff7 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.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", + "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", "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.3", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.21.2", + "@babel/helpers": "^7.21.0", + "@babel/parser": "^7.21.3", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", + "@babel/traverse": "^7.21.3", + "@babel/types": "^7.21.3", "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.21.3", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz", + "integrity": "sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==", "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.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", + "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "dependencies": { + "@babel/types": "^7.21.3", "@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.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", + "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", "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,914 @@ "@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.21.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz", + "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==", + "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.21.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz", + "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==", + "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.21.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz", + "integrity": "sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ==", + "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.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz", + "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==", + "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-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 +1817,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.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", + "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", "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.3", + "@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.3", + "@babel/types": "^7.21.3", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -375,11 +1850,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.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", + "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", "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 +1862,341 @@ "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.2.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", + "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "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,385 +2248,32 @@ } }, "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" - } + "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-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" }, @@ -888,23 +2285,21 @@ } }, "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, + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "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.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.5.1", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -919,11 +2314,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 +2333,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.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -947,7 +2367,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 +2380,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 +2391,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 +3080,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,42 +3088,60 @@ "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.123", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.123.tgz", + "integrity": "sha512-pxzcAfET3I6jvWqS4kijiLMn1OmdMw+mGmDa0SqmDZo3bXXdvLhpCCPqCkULG3UykhvFCOcU5HclOX3JCA+Zhg==", "dependencies": { "@babel/runtime": "^7.21.0", - "@emotion/is-prop-valid": "^1.2.1", - "@mui/types": "^7.2.4", - "@mui/utils": "^5.13.1", + "@emotion/is-prop-valid": "^1.2.0", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", "@popperjs/core": "^2.11.7", "clsx": "^1.2.1", "prop-types": "^15.8.1", @@ -1063,18 +3166,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.15", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.15.tgz", + "integrity": "sha512-Q0e2oBsjHyIWWj1wLzl14btunvBYC0yl+px7zL9R69tF87uenj6q72ieS369BJ6jxYpJwvXfR6/f+TC+ZUsKKg==", "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 +3200,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.15", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.15.tgz", + "integrity": "sha512-E5RbLq9/OvRKmGyeZawdnmFBCvhKkI/Zqgr0xFqW27TGwKLxObq/BreJc6Uu5Sbv8Fjj34vEAbRx6otfOyxn5w==", "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.123", + "@mui/core-downloads-tracker": "^5.11.15", + "@mui/system": "^5.11.15", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", + "@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 +3244,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.13", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.13.tgz", + "integrity": "sha512-PJnYNKzW5LIx3R+Zsp6WZVPs6w5sEKJ7mgLNnUXuYB1zo5aX71FVLtV7geyPXRcaN2tsoRNK7h444ED0t7cIjA==", "dependencies": { "@babel/runtime": "^7.21.0", - "@mui/utils": "^5.13.1", + "@mui/utils": "^5.11.13", "prop-types": "^15.8.1" }, "engines": { @@ -1167,13 +3270,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 +3301,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.15", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.15.tgz", + "integrity": "sha512-vCatoWCTnAPquoNifHbqMCMnOElEbLosVUeW0FQDyjCq+8yMABD9E6iY0s14O7iq1wD+qqU7rFAuDIVvJ/AzzA==", "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.13", + "@mui/styled-engine": "^5.11.11", + "@mui/types": "^7.2.3", + "@mui/utils": "^5.11.13", "clsx": "^1.2.1", - "csstype": "^3.1.2", + "csstype": "^3.1.1", "prop-types": "^15.8.1" }, "engines": { @@ -1237,9 +3340,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 +3353,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.13", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.13.tgz", + "integrity": "sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA==", "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 +3374,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 +3418,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 +3426,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,6 +3434,63 @@ "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", @@ -1316,33 +3501,558 @@ } }, "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.5.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz", + "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==", "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.37.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "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.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" }, "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.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.31.tgz", + "integrity": "sha512-EEG67of7DsvRDU6BLLI0p+k1GojDLz9+lZsnCpCRTa/lOokvyPBvp8S5x+A24hME3yyQuIipcP70KJ6H7Qupww==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -1350,49 +4060,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/resolve": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", + "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "dependencies": { + "@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.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/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": { - "@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/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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz", + "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/type-utils": "5.57.0", + "@typescript-eslint/utils": "5.57.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.57.0.tgz", + "integrity": "sha512-0RnrwGQ7MmgtOSnzB/rSGYr2iXENi6L+CtPzX3g5ovo0HlruLukSEKcc4s+q0IEc+DLTDc7Edan0Y4WSQ/bFhw==", + "dependencies": { + "@typescript-eslint/utils": "5.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz", + "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz", + "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==", + "dependencies": { + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz", + "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.57.0", + "@typescript-eslint/utils": "5.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz", + "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==", + "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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz", + "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==", + "dependencies": { + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz", + "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "eslint-scope": "^5.1.1", + "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.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz", + "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==", + "dependencies": { + "@typescript-eslint/types": "5.57.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 +4541,85 @@ "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-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 +4631,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,17 +4719,40 @@ "node": ">=4" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "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" } @@ -1464,7 +4761,6 @@ "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" @@ -1473,11 +4769,15 @@ "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 +4792,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 +4821,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 +4834,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 +4864,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.14", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", + "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.5", + "caniuse-lite": "^1.0.30001464", + "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 +4936,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 +4947,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 +5114,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.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz", + "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==", + "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 +5399,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 +5451,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.30001473", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001473.tgz", + "integrity": "sha512-ewDad7+D2vlyy+E4UJuVfiBsU69IL+8oVmTuZnH5Q6CIUbxNfI50uVpRHbUPDD6SUaN2o0Lh4DhTrvLG/Tn1yg==", "funding": [ { "type": "opencollective", @@ -1676,6 +5509,14 @@ } ] }, + "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 +5538,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 +5652,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 +5692,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.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.1.tgz", + "integrity": "sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.29.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.29.1.tgz", + "integrity": "sha512-QmchCua884D8wWskMX8tW5ydINzd8oSJVx38lx/pVkFGqztxt73GYre3pm/hyYq8bPf+MW5In4I/uRShFDsbrA==", + "dependencies": { + "browserslist": "^4.21.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.29.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.29.1.tgz", + "integrity": "sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg==", + "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 +5904,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 +5913,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.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", + "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", + "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.5.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.5.2.tgz", + "integrity": "sha512-Xpu7Bf5Vlw+G7ikA2Lg/lVCRTSY8D5M5qFUgGNFyS4pa8ufGLyCBxIX/3if3krHlF1SKSfVPI/YsAWLDVEbocw==", + "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 +6363,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 +6390,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 +6403,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.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "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 +6447,73 @@ "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/dexie": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/dexie/-/dexie-3.2.3.tgz", @@ -1869,11 +6532,55 @@ "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.5.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.5.0.tgz", + "integrity": "sha512-USawdAUzRkV6xrqTjiAEp6M9YagZEzWcSUaZTcIFAiyQWW1SoI6KyId8y2+/71wbgHKQAKd+iupLv4YvEwYWvA==", + "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 +6588,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 +6605,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.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "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.347", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.347.tgz", + "integrity": "sha512-LNi3+/9nV0vT6Bz1OsSoZ/w7IgNuWdefZ7mjKNjZxyRlI/ag6uMXxsxAy5Etvuixq3Q26exw2fc4bNYvYQqXSw==" + }, + "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", @@ -1922,7 +6798,6 @@ "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, "dependencies": { "array-buffer-byte-length": "^1.0.0", "available-typed-arrays": "^1.0.5", @@ -1966,11 +6841,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 +6865,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 +6887,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 +6895,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 +6907,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 +6931,92 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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": { + "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.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", - "dev": true, + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2102,9 +7026,9 @@ "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-visitor-keys": "^3.4.0", + "espree": "^9.5.1", "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", @@ -2139,63 +7064,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 +7105,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 +7129,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 +7182,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 +7190,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 +7197,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 +7257,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 +7297,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 +7308,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 +7319,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,27 +7331,45 @@ "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" - }, - "funding": { - "url": "https://opencollective.com/eslint" } }, "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.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -2415,11 +7377,117 @@ "url": "https://opencollective.com/eslint" } }, + "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": { + "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 +7498,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 +7522,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 +7532,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 +7552,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 +7578,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.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^3.4.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2517,11 +7605,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 +7632,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 +7643,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 +7863,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 +7983,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 +7998,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 +8009,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.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "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 +8280,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 +8297,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 +8305,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 +8373,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 +8392,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 +8399,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 +8451,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 +8461,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 +8491,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.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "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 +8540,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 +8556,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 +8567,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 +8578,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 +8589,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 +8599,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 +8620,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 +8720,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 +8897,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.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "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 +8967,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 +8997,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 +9005,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 +9025,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 +9052,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 +9070,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 +9077,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 +9107,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 +9115,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 +9129,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 +9139,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 +9192,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 +9212,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 +9234,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 +9281,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 +9309,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 +9316,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 +9345,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 +9359,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 +9373,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 +9390,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 +9401,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 +9409,2188 @@ "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.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "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/jiti": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", + "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "bin": { + "jiti": "bin/jiti.js" + } }, "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.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "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 +11603,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 +11629,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 +11660,64 @@ "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/launch-editor": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", + "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.7.3" + } + }, + "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 +11726,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 +11774,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 +11815,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.5", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz", + "integrity": "sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ==", + "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,22 +12056,52 @@ "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/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } }, "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", @@ -3516,8 +12118,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 +12166,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 +12246,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 +12266,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 +12281,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 +12289,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 +12306,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 +12319,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 +12331,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 +12364,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 +12376,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 +12458,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 +12472,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 +12482,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 +12539,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 +12573,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 +12581,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 +12590,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 +12603,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 +12778,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 +12789,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 +14030,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 +14110,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 +14189,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 +14323,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 +14366,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.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz", + "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==", "dependencies": { - "@remix-run/router": "1.6.2" + "@remix-run/router": "1.5.0" }, "engines": { "node": ">=14" @@ -3975,12 +14388,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.10.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz", + "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==", "dependencies": { - "@remix-run/router": "1.6.2", - "react-router": "6.11.2" + "@remix-run/router": "1.5.0", + "react-router": "6.10.0" }, "engines": { "node": ">=14" @@ -3990,6 +14403,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 +14490,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.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "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 +14583,88 @@ "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/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "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 +14675,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 +14702,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 +14787,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 +14798,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 +14888,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 +14920,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 +14991,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 +15207,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 +15232,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 +15277,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 +15371,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 +15422,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 +15441,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", @@ -4273,7 +15506,6 @@ "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", @@ -4290,7 +15522,6 @@ "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 +15535,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 +15544,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 +15569,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 +15603,87 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-loader": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.2.tgz", + "integrity": "sha512-RHs/vcrKdQK8wZliteNK4NKzxvLBzpuHMqYmUVWeKa6MkaIQ97ZTOS0b+zapZhy6GcrgWnvWYCMHRirC3FsUmw==", + "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/sucrase": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.31.0.tgz", + "integrity": "sha512-6QsHnkqyVEzYcaiHsOKkzOtOgdJcb8i54x6AV2hDwyZcY9ZyykGZVw6L/YN98xC0evwTP6utsWWrKRaa8QlfEQ==", + "dependencies": { + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/supports-color": { "version": "5.5.0", @@ -4363,6 +15696,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 +15738,297 @@ "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.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz", + "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==", + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.17.2", + "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", + "sucrase": "^3.29.0" + }, + "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.8", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.8.tgz", + "integrity": "sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA==", + "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.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "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/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "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 +16038,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 +16056,66 @@ "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/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, "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 +16127,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 +16134,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 +16177,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 +16196,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 +16221,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 +16256,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 +16345,6 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -4502,7 +16352,7 @@ "picocolors": "^1.0.0" }, "bin": { - "update-browserslist-db": "cli.js" + "browserslist-lint": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -4512,57 +16362,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 +16452,423 @@ "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.77.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.77.0.tgz", + "integrity": "sha512-sbGNjBr5Ya5ss91yzjeJTLKyfiwo5C628AFjEa6WSXcZa4E+F57om3Cc8xLb1Jh0b243AWuSYRf3dn7HVeFQ9Q==", + "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.13.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.1.tgz", + "integrity": "sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA==", + "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", + "launch-editor": "^2.6.0", + "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.13.0" + }, + "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": { + "optional": true + }, + "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.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "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 +16879,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 +16902,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 +16917,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 +16931,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 +16950,408 @@ "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/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 +17361,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..a3919ff 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": "ุงู„ุฃูˆู„ูˆูŠุฉ ุงู„ู‚ุตูˆู‰ ูู‚ุท", @@ -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}}ุŒ ุงู†ู‚ุฑ ู„ู„ุจุญุซ", diff --git a/web/public/static/langs/bg.json b/web/public/static/langs/bg.json index a040b01..6952303 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": "ะะฑะพะฝะธั€ะฐะฝะต", @@ -278,14 +278,5 @@ "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_payment_overdue": "ะ˜ะผะฐั‚ะต ะฟั€ะพัั€ะพั‡ะตะฝะพ ะทะฐะดัŠะปะถะตะฝะธะต. ะžะฑะฝะพะฒะตั‚ะต ะฝะฐั‡ะธะฝะฐ ะฝะฐ ะฟะปะฐั‰ะฐะฝะต, ะทะฐั‰ะพั‚ะพ ะฒ ะฟั€ะพั‚ะธะฒะตะฝ ัะปัƒั‡ะฐะน ัะบะพั€ะพ ะฟั€ะพั„ะธะปัŠั‚ ะฒะธ ั‰ะต ะทะฐะณัƒะฑะธ ะฟั€ะตะดะธะผัั‚ะฒะฐั‚ะฐ ะฝะฐ ะฐะฑะพะฝะฐะผะตะฝั‚ะฐ." } diff --git a/web/public/static/langs/cs.json b/web/public/static/langs/cs.json index 6b967c8..423259a 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ฤ›", @@ -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..d60c56c 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", @@ -209,7 +209,7 @@ "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_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", diff --git a/web/public/static/langs/de.json b/web/public/static/langs/de.json index 6343dee..0aee271 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", @@ -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..8760eb3 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", @@ -255,9 +232,6 @@ "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_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 +254,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..16fe2cd 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", @@ -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..a24ece0 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", @@ -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", @@ -352,24 +352,5 @@ "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" + "account_upgrade_dialog_billing_contact_email": "Pour des questions concernant la facturation, merci de nous contacter directement." } 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..b442a22 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", @@ -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..87ea04a 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", @@ -256,8 +256,5 @@ "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 โค" + "account_usage_emails_title": "Email inviate" } diff --git a/web/public/static/langs/ja.json b/web/public/static/langs/ja.json index 9c68679..65a1598 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": "ๅ„ชๅ…ˆๅบฆๆœ€้ซ˜ใฎใฟ", @@ -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": "ใ‚ขใ‚ฏใ‚ปใ‚นใƒˆใƒผใ‚ฏใƒณใ‚’็”Ÿๆˆ", @@ -352,9 +352,5 @@ "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": "้›ป่ฉฑ" + "account_upgrade_dialog_billing_contact_website": "ๆ”ฏๆ‰•ใ„ใซ้–ขใ™ใ‚‹่ณชๅ•ใฏใ€ใ‚ฆใ‚งใƒ–ใ‚ตใ‚คใƒˆใ‚’ๅ‚็…งใ—ใฆไธ‹ใ•ใ„ใ€‚" } 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..5e6bcbe 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", diff --git a/web/public/static/langs/pt.json b/web/public/static/langs/pt.json index 57d5656..196baf4 100644 --- a/web/public/static/langs/pt.json +++ b/web/public/static/langs/pt.json @@ -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..42025e4 100644 --- a/web/public/static/langs/ru.json +++ b/web/public/static/langs/ru.json @@ -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": "ะฐะฝะพะฝะธะผะฝั‹ะน ะฟะพะปัŒะทะพะฒะฐั‚ะตะปัŒ", @@ -206,7 +206,7 @@ "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}} ะดะฝะตะน", 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..bb88cc7 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", @@ -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..4da4328 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": "ๅŒฟๅ", @@ -333,7 +333,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": "ๅˆ›ๅปบ่ฎฟ้—ฎไปค็‰Œ", 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..c62560a --- /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, count: 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), count: tier.limits.messages })} + {t("account_upgrade_dialog_tier_features_emails", { emails: formatNumber(tier.limits.emails), count: 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()], -}));