From 32d7bd74f275261c22668506d3b5fc6529cb4b85 Mon Sep 17 00:00:00 2001 From: Thomas Marcon Date: Tue, 12 Nov 2024 10:53:09 +0100 Subject: [PATCH] Rebase from origin repo (#1) * Fix typo in `Welcome Message` section (#1111) * fix: make linter happy again * chore: update playwright to fix build * more subdomain restrictions * feature: send welcome email on signup * fix: unencrypted smtp login * send welcome email * skip email on self hosted * update readme * typo * fix: postgres encoding error doing searches * fix: use hostname for powered by link * update to go 1.19 and node 18.x (#1118) * fix: disallow external url during oauth login * fix: use non-breaking spaces for assertions * dont write to body when method is head * Scrollbars would always be visible in the `VotesModal` component (#1134) * enhancement: add overflow-auto utility class * fix: auto remove scrollbars if there not necessary Before with overflow-scroll there where always two scrollbars, now it will change depending on the content of the container * fix error on cname lookup * use jwt to prevent redirect_uri changes * npm ci --maxsockets 1 * better validation for redirect * Update go to 1.22 * Node 18 -> 22 * Fix build script. * csrf middleware * Added migration to create missing posts.user_id index * Show email on the member listing * Only include email when listing the members. * lint fix. * fix: added an empty view query params checker and setting it to 'all' * Update golint-ci * More time for lint-server * feat: migrated form/Select class component to functional component (based this off of the form/Input component), changed the version in go.mod to 1.22 * Update FUNDING.yml Changed funding options * fix: added back 1.22.0 to go.mod * feat: add Arabic locales * Also publish on tag pushes. * chore(deps): bump ws Bumps and [ws](https://github.com/websockets/ws). These dependencies needed to be updated together. Updates `ws` from 8.4.2 to 8.18.0 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.4.2...8.18.0) Updates `ws` from 7.5.7 to 8.18.0 - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.4.2...8.18.0) --- updated-dependencies: - dependency-name: ws dependency-type: indirect - dependency-name: ws dependency-type: indirect ... Signed-off-by: dependabot[bot] * chore(deps-dev): bump @babel/traverse from 7.17.10 to 7.25.4 Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.17.10 to 7.25.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.25.4/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] * Another way to trigger on tag/releases. * Wasn't picking up the tag name properly * Trigger a build when we push to stable too. * chore(deps-dev): bump webpack from 5.72.0 to 5.94.0 Bumps [webpack](https://github.com/webpack/webpack) from 5.72.0 to 5.94.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.72.0...v5.94.0) --- updated-dependencies: - dependency-name: webpack dependency-type: direct:development ... Signed-off-by: dependabot[bot] * Userlist integration added - new signup will create company and user in userlist.com * Updating a user feeds into userlist * Updating the billing status in userlist. * Add test for the changes to billing lock function * Integration with user actions. * Lint and test fixes * Moved the action struct to a dto. * Updated the version of upload artifact * Updated the download-artifact too. * Tag the docker image correctly. * Go mod tidy * Ignorne pem files * chore(deps): bump golang.org/x/image Bumps [golang.org/x/image](https://github.com/golang/image) from 0.0.0-20211028202545-6944b10bf410 to 0.18.0. - [Commits](https://github.com/golang/image/commits/v0.18.0) --- updated-dependencies: - dependency-name: golang.org/x/image dependency-type: indirect ... Signed-off-by: dependabot[bot] * chore(deps): bump json5 Bumps and [json5](https://github.com/json5/json5). These dependencies needed to be updated together. Updates `json5` from 2.2.1 to 2.2.3 - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3) Updates `json5` from 1.0.1 to 2.2.3 - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] * refactor: Update Contributing doc * refactor: Update broken link in Makefile * feature: add ability to copy comment link * fix(migration): Looks for pending migrations * refactor: Rewrite versions string * refactor: Get pending versions using slices * refactor: Copy versions slice to local variable * fix: Use pq.Array as SQL query param * fix: Close connection using defer statement * fix: Handle errors during version scan * test: Ensure migration will be executed even with past timestamp * lint: Fix typo in sql request in tests * test: Check error while fetching versions * lint: Light refactor * feat: Copy versions array to local var Co-authored-by: Matt Roberts * Fixes #1156 * Fix: No webhook message when post deleted with no comment. * Fixed tests, added one for no-comment-delete of post. * First set of proposed UI tweaks. * Fixing tests * Added missing description * Fixed tests for google font * Settings tweaks * My settings UI tweaks * More webhooks tweaks * No duplicate emails on the "show votes" * Fixed lint issue * WIP notifications modal. * Remove the paddle webhooks from CSRF checks. * Revert "Merge pull request #1203 from Quentinchampenois/fix/pending_migrations" This reverts commit 42c9a98c921c087709a7eb61cf630ba533bf7721, reversing changes made to a9c05c5c8d7d3faddb9e8e6427dfcc30678406ef. * Fix: Can't access tenant from context in paddle webhook logic (but don't need to anyway) * Billing status should be forced to string * No need to log this * Changing to use matrix strategy for parallel builds * Notifications dropdown * Username component shouldn't show email unless explicitly requested * Formatting. * Revert "Changing to use matrix strategy for parallel builds" This reverts commit 55dfbc9bc4bd89ff2f3da622578954833c6464fe. * Missing route * Margin bottom fixes * Some minor changes to the styles * Localised notifications modal * Locale files updated * Moved the userlist logic so it runs for social signups too. * Fixed previous userlist change. * Changed the email details for welcome emails. * No notifications improvements. * Console.logs removed * Formatting * More notification spacing tweaks * More styling, plus "mark all as read" * Borders in the notifications modal * Show posts mobile view. * Small tweaks to the powered by link * Changed how google fonts are included. * Order notifications by date desc * Messing about with reactions * Working reactions UI and backend * Lint checks * Viewing reactions for anonymous users * Sort the reactions by count * Make comments stand out more Techincally this is part of the UI stuff, but it stands out when you have the reactions in there so adding it here. * More tests * Validate that the reaction is one of the allowed emoji responses. * Update Dockerfile to Debian Bookworm and NodeJS 22 * Update gomarkdown/markdown dependency * Changed some bits on the main readme. --------- Signed-off-by: dependabot[bot] Co-authored-by: Matthew Yarmolinsky Co-authored-by: goenning Co-authored-by: Ik <113038466+Ik1497@users.noreply.github.com> Co-authored-by: Matt Roberts Co-authored-by: mway-niels <53857383+mway-niels@users.noreply.github.com> Co-authored-by: Brian Pham Co-authored-by: Dinh Nguyen Pham <63203684+npham49@users.noreply.github.com> Co-authored-by: Maher El Gamil Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: quentinchampenois <26109239+Quentinchampenois@users.noreply.github.com> Co-authored-by: indyteo Co-authored-by: Kim Tiago Baptista --- .github/FUNDING.yml | 2 +- .github/workflows/build.yml | 33 +- .github/workflows/publish.yml | 18 +- .gitignore | 3 +- .nvmrc | 2 +- .test.env | 5 +- CONTRIBUTING.md | 8 +- Dockerfile | 8 +- Makefile | 4 +- README.md | 61 +- app/actions/post.go | 32 + app/cmd/routes.go | 31 +- app/cmd/server.go | 5 +- app/handlers/admin.go | 22 +- app/handlers/admin_test.go | 4 +- app/handlers/apiv1/post.go | 39 +- app/handlers/apiv1/post_test.go | 141 +- app/handlers/common.go | 20 +- app/handlers/common_test.go | 8 +- app/handlers/images.go | 12 +- app/handlers/images_test.go | 6 +- app/handlers/notification.go | 13 +- app/handlers/oauth.go | 15 +- app/handlers/oauth_test.go | 105 +- app/handlers/settings.go | 20 + app/handlers/signup.go | 19 +- app/handlers/signup_test.go | 12 + app/handlers/webhooks/paddle.go | 18 + app/jobs/lock_expired_tenants_job.go | 13 + app/jobs/trial_reminder_job.go | 4 +- app/middlewares/compress_test.go | 4 +- app/middlewares/security.go | 13 + app/models/cmd/billing.go | 1 + app/models/cmd/reaction.go | 10 + app/models/cmd/userlist.go | 32 + app/models/dto/userlist.go | 9 + app/models/entity/comment.go | 23 +- app/models/entity/notification.go | 21 +- app/models/entity/reaction.go | 12 + app/models/entity/user.go | 28 +- app/models/entity/user_test.go | 55 + app/pkg/csv/csv_test.go | 8 +- app/pkg/dbx/dbx.go | 10 +- app/pkg/dbx/dbx_test.go | 3 +- app/pkg/dbx/migrate.go | 3 +- app/pkg/dbx/setup.sql | 12 + app/pkg/env/env.go | 4 + app/pkg/i18n/i18n.go | 4 +- app/pkg/jwt/jwt.go | 17 + app/pkg/log/parse.go | 2 +- app/pkg/mock/server.go | 4 +- app/pkg/validate/subdomain.go | 6 +- app/pkg/validate/upload_test.go | 10 +- app/pkg/web/binder_test.go | 6 +- app/pkg/web/context.go | 81 +- app/pkg/web/engine.go | 48 +- app/pkg/web/engine_test.go | 4 +- app/pkg/web/renderer.go | 8 +- app/pkg/web/renderer_test.go | 6 +- app/pkg/web/request.go | 8 +- app/pkg/web/ssl.go | 14 +- app/pkg/web/testdata/basic.html | 3 + app/pkg/web/testdata/canonical.html | 3 + app/pkg/web/testdata/chunk.html | 3 + app/pkg/web/testdata/home.html | 3 + app/pkg/web/testdata/home_ssr.html | 3 + app/pkg/web/testdata/oauth.html | 3 + app/pkg/web/testdata/tenant.html | 3 + app/pkg/web/testdata/user.html | 3 + app/services/blob/blob_test.go | 9 +- app/services/blob/fs/fs.go | 5 +- app/services/blob/s3/s3.go | 6 +- app/services/email/mailgun/sendmail_test.go | 6 +- app/services/email/smtp/auth.go | 39 +- app/services/httpclient/httpclient.go | 4 +- app/services/oauth/oauth.go | 13 +- app/services/oauth/oauth_test.go | 36 +- app/services/sqlstore/postgres/billing.go | 1 + .../sqlstore/postgres/billing_test.go | 24 + app/services/sqlstore/postgres/comment.go | 86 +- app/services/sqlstore/postgres/common.go | 6 + .../sqlstore/postgres/notification.go | 17 +- app/services/sqlstore/postgres/post.go | 2 +- app/services/sqlstore/postgres/post_test.go | 81 +- app/services/sqlstore/postgres/postgres.go | 1 + app/services/sqlstore/postgres/user_test.go | 2 +- .../userlist/mocks/mockUserQueryService.go | 41 + app/services/userlist/userlist.go | 227 +++ app/services/userlist/userlist_test.go | 226 +++ app/tasks/delete_post.go | 47 +- app/tasks/delete_post_test.go | 87 +- app/tasks/signup.go | 32 +- app/tasks/userlist.go | 82 + e2e/features/server/ssr.feature | 4 +- etc/browserstack.png | Bin 18073 -> 4845 bytes go.mod | 278 +-- go.sum | 1114 ++++------ locale/ar/client.json | 153 ++ locale/ar/server.json | 62 + locale/de/client.json | 7 + locale/el/client.json | 7 + locale/en/client.json | 7 + locale/en/server.json | 1 + locale/es-ES/client.json | 7 + locale/fr/client.json | 7 + locale/locales.ts | 3 + locale/nl/client.json | 7 + locale/pl/client.json | 7 + locale/pt-BR/client.json | 7 + locale/ru/client.json | 7 + locale/sk/client.json | 7 + locale/sv-SE/client.json | 7 + locale/tr/client.json | 7 + .../202406111146_add_posts_user_id_index.sql | 1 + .../202410122105_create_reactions_up.sql | 11 + package-lock.json | 1788 ++++++----------- package.json | 8 +- public/assets/images/reaction-add.svg | 6 + public/assets/styles/reset.scss | 2 +- public/assets/styles/utility/display.scss | 25 + public/assets/styles/utility/page.scss | 2 +- public/assets/styles/utility/text.scss | 20 +- public/assets/styles/variables/_text.scss | 2 +- public/components/Header.tsx | 6 +- public/components/NotificationIndicator.scss | 8 + public/components/NotificationIndicator.tsx | 123 +- public/components/Reactions.scss | 20 + public/components/Reactions.tsx | 86 + public/components/common/Dropdown.scss | 13 + public/components/common/Dropdown.tsx | 16 +- public/components/common/PoweredByFider.scss | 4 +- public/components/common/PoweredByFider.tsx | 7 +- public/components/common/UserName.scss | 7 + public/components/common/UserName.tsx | 4 + public/components/common/form/Form.scss | 6 +- public/components/common/form/Select.tsx | 97 +- public/components/index.tsx | 1 + public/components/layout/Stack.tsx | 2 +- public/models/identity.ts | 1 + public/models/notification.ts | 2 + public/models/post.ts | 7 + .../components/AdminBasePage.scss | 2 +- .../Administration/components/SideMenu.scss | 2 +- .../Administration/components/SideMenu.tsx | 2 +- .../components/webhook/WebhookForm.tsx | 6 +- .../components/webhook/WebhookListItem.tsx | 20 +- .../pages/GeneralSettings.page.tsx | 25 +- .../pages/ManageMembers.page.tsx | 13 +- .../pages/ManageWebhooks.page.tsx | 23 +- public/pages/Home/Home.page.scss | 19 +- public/pages/Home/Home.page.tsx | 6 +- public/pages/Home/components/TagsFilter.tsx | 4 +- .../components/NotificationSettings.tsx | 2 +- public/pages/ShowPost/ShowPost.page.scss | 31 +- public/pages/ShowPost/ShowPost.page.tsx | 212 +- .../ShowPost/components/DiscussionPanel.tsx | 5 +- .../pages/ShowPost/components/ShowComment.tsx | 183 +- .../pages/ShowPost/components/VotesModal.tsx | 2 +- public/services/actions/notification.ts | 5 + public/services/actions/post.ts | 7 + public/services/utils.spec.ts | 32 +- public/services/utils.ts | 29 + views/base.html | 3 + views/email/welcome_email.html | 24 + 164 files changed, 4232 insertions(+), 2652 deletions(-) create mode 100644 app/models/cmd/reaction.go create mode 100644 app/models/cmd/userlist.go create mode 100644 app/models/dto/userlist.go create mode 100644 app/models/entity/reaction.go create mode 100644 app/models/entity/user_test.go create mode 100644 app/services/sqlstore/postgres/billing_test.go create mode 100644 app/services/userlist/mocks/mockUserQueryService.go create mode 100644 app/services/userlist/userlist.go create mode 100644 app/services/userlist/userlist_test.go create mode 100644 app/tasks/userlist.go create mode 100644 locale/ar/client.json create mode 100644 locale/ar/server.json create mode 100644 migrations/202406111146_add_posts_user_id_index.sql create mode 100644 migrations/202410122105_create_reactions_up.sql create mode 100644 public/assets/images/reaction-add.svg create mode 100644 public/components/Reactions.scss create mode 100644 public/components/Reactions.tsx create mode 100644 views/email/welcome_email.html diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 31f7721c3..847503b37 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,6 @@ # These are supported funding model platforms -github: [goenning] +github: patreon: # Replace with a single Patreon username open_collective: fider ko_fi: # Replace with a single Ko-fi username diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 85b48ba8c..047630f47 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,9 +1,12 @@ name: build on: + release: + types: [created] push: branches: - main + - stable pull_request: branches: - main @@ -14,10 +17,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Use Node.js 16.x + - name: Use Node.js 22.x uses: actions/setup-node@v1 with: - node-version: 16.x + node-version: 22.x - run: npm ci - run: make lint-ui - run: make test-ui @@ -49,17 +52,17 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Use Go 1.18 + - name: Use Go 1.22 uses: actions/setup-go@v2 with: - go-version: 1.18 - - name: Use Node.js 16.x + go-version: 1.22 + - name: Use Node.js 22.x uses: actions/setup-node@v1 with: - node-version: 16.x + node-version: 22.x - run: npm ci # required for esbuild - name: install golangci-lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.45.0 + run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.59.1 - name: install godotenv run: go install github.com/joho/godotenv/cmd/godotenv - run: make lint-server @@ -84,6 +87,8 @@ jobs: echo sha7=${GITHUB_SHA::7} id: vars + + - run: docker build -t fider-image . - run: mkdir -p ./out @@ -95,7 +100,7 @@ jobs: - run: echo ${{ steps.vars.outputs.sha7 }} > ./out/sha7 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: fider-image path: out/ @@ -124,11 +129,11 @@ jobs: browser: ["chromium", "webkit", "firefox"] steps: - uses: actions/checkout@v2 - - name: Use Node.js 16.x + - name: Use Node.js 22.x uses: actions/setup-node@v1 with: - node-version: 16.x - - uses: actions/download-artifact@v2 + node-version: 22.x + - uses: actions/download-artifact@v4 with: name: fider-image path: ./out @@ -178,11 +183,11 @@ jobs: options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - uses: actions/checkout@v2 - - name: Use Node.js 16.x + - name: Use Node.js 22.x uses: actions/setup-node@v1 with: - node-version: 16.x - - uses: actions/download-artifact@v2 + node-version: 22.x + - uses: actions/download-artifact@v4 with: name: fider-image path: ./out diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 4b973bb74..4c27c3a84 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -45,7 +45,7 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max - - name: build and push docker image (push) + - name: build and push docker image (push branch) if: ${{ github.event.workflow_run.event == 'push' }} uses: docker/build-push-action@v3 with: @@ -53,6 +53,20 @@ jobs: context: . build-args: COMMITHASH=${{ github.event.workflow_run.head_sha }} platforms: linux/amd64,linux/arm64/v8 - tags: getfider/fider:SHA_${{ github.event.workflow_run.head_sha }},getfider/fider:main + tags: | + getfider/fider:SHA_${{ github.event.workflow_run.head_sha }} + getfider/fider:${{ github.event.workflow_run.head_branch == 'main' && 'main' || 'stable' }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: build and push docker image (push tag) + if: ${{ github.event.workflow_run.event == 'release' }} + uses: docker/build-push-action@v3 + with: + push: true + context: . + build-args: COMMITHASH=${{ github.event.workflow_run.head_sha }} + platforms: linux/amd64,linux/arm64/v8 + tags: getfider/fider:${{ github.event.workflow_run.display_title }} cache-from: type=gha cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 3d908313a..cb09769c8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ debug.test .DS_Store cover.out coverage.tmp -tsconfig.tsbuildinfo \ No newline at end of file +tsconfig.tsbuildinfo +etc/*.pem diff --git a/.nvmrc b/.nvmrc index 96d7ddff6..1fba266e9 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.* +v22.* diff --git a/.test.env b/.test.env index a2236fb91..f1e0a7123 100644 --- a/.test.env +++ b/.test.env @@ -34,4 +34,7 @@ EMAIL_SMTP_USERNAME=us3r EMAIL_SMTP_PASSWORD=p4ss EMAIL_MAILGUN_API=mys3cr3tk3y -EMAIL_MAILGUN_DOMAIN=mydomain.com \ No newline at end of file +EMAIL_MAILGUN_DOMAIN=mydomain.com + +USER_LIST_ENABLED=true +USER_LIST_APIKEY=abcdefg \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f31d69a08..acfe6f791 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,8 +21,8 @@ If you know these technologies or would like to learn them, lucky you! This is t | Software | How to install | What is it used for | | ----------- | -------------------------------------------------------------- | --------------------------------------------------------- | -| Go 1.18+ | https://golang.org/ | To compile server side code | -| Node.js 16+ | https://nodejs.org/ or run `nvm use` if you have nvm installed | To compile TypeScript and bundle all the client side code | +| Go 1.22+ | https://golang.org/ | To compile server side code | +| Node.js 22+ | https://nodejs.org/ or run `nvm use` if you have nvm installed | To compile TypeScript and bundle all the client side code | | Docker | https://www.docker.com/ | To start local PostgreSQL instances | #### 2. To setup your development workspace: @@ -31,9 +31,9 @@ If you know these technologies or would like to learn them, lucky you! This is t 2. navigate into the cloned repository. 3. run `go install github.com/cosmtrek/air` to install air, a cli tool for live reload, when you change the code, it automatically recompiles the application. 4. run `go install github.com/joho/godotenv/cmd/godotenv` to install godotenv, a cli tool to load environment variables from a `.env` so that you don't have to change your machine environment variables. -5. run `go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.45.0` to install golangci-lint, a linter for Go apps. +5. run `go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.59.1` to install golangci-lint, a linter for Go apps. 6. run `npm install` to install client side packages. -7. run `docker-compose up -d` to start a local PostgreSQL database and Local SMTP (with [MailHog](https://github.com/mailhog/MailHog)) on Docker. +7. run `docker compose up -d` to start a local PostgreSQL database and Local SMTP (with [MailHog](https://github.com/mailhog/MailHog)) on Docker. 8. run `cp .example.env .env` to create a local environment configuration file. - **Important:** Fider has a strong dependency on an email delivery service. For easier local development, the docker-compose file already provides diff --git a/Dockerfile b/Dockerfile index c613e21db..dcd2faf95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ ##################### ### Server Build Step ##################### -FROM --platform=${TARGETPLATFORM:-linux/amd64} golang:1.18-buster AS server-builder +FROM --platform=${TARGETPLATFORM:-linux/amd64} golang:1.22-bookworm AS server-builder RUN mkdir /server @@ -18,12 +18,12 @@ RUN COMMITHASH=${COMMITHASH} GOOS=${TARGETOS} GOARCH=${TARGETARCH} make build-se ################# ### UI Build Step ################# -FROM --platform=${TARGETPLATFORM:-linux/amd64} node:16-buster AS ui-builder +FROM --platform=${TARGETPLATFORM:-linux/amd64} node:22-bookworm AS ui-builder WORKDIR /ui COPY package.json package-lock.json ./ -RUN npm ci +RUN npm ci --maxsockets 1 COPY . . RUN make build-ssr @@ -32,7 +32,7 @@ RUN make build-ui ################ ### Runtime Step ################ -FROM --platform=${TARGETPLATFORM:-linux/amd64} debian:buster-slim +FROM --platform=${TARGETPLATFORM:-linux/amd64} debian:bookworm-slim RUN apt-get update RUN apt-get install -y ca-certificates diff --git a/Makefile b/Makefile index f8a5a24db..ed69180ed 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ ## This is a self-documented Makefile. For usage information, run `make help`: ## -## For more information, refer to https://suva.sh/posts/well-documented-makefiles/ +## For more information, refer to https://www.thapaliya.com/en/writings/well-documented-makefiles/ LDFLAGS += -X github.com/getfider/fider/app/pkg/env.commithash=${COMMITHASH} @@ -78,7 +78,7 @@ watch-ui: ## Build and run server in watch mode lint: lint-server lint-ui ## Lint server and ui lint-server: ## Lint server code - golangci-lint run --timeout 2m + golangci-lint run --timeout 3m lint-ui: ## Lint ui code npx eslint . diff --git a/README.md b/README.md index 0fff4a377..663a6cd24 100644 --- a/README.md +++ b/README.md @@ -7,63 +7,64 @@

- Fider is a feedback portal to help you build better products. + Fider is a feedback portal for feature requests and suggestions.
Give your customers a voice and let them tell you what they need. Spend less time guessing and more time building the right product.

- Built with ❤️ by Guilherme Oenning and contributors + Created with ❤️ by Guilherme Oenning, now maintained by Matt Roberts and supported by contributors
-
+
+
-## Get Started +# Getting Started -- **Fider Cloud**: The easiest and quickest way to get started. A fully managed services by the creators of Fider to help you get started in minutes. Forget about managing software updates and patches, we do it all for you! [Sign up now](https://fider.io/#get-started) +## ☁️ **Fider Cloud** -- **Self-Hosted**: You can also install Fider yourelf. It's free, but you are responsible for managing it. [Learn how](https://fider.io/docs/hosting-instance) +The easiest and quickest way to get started. A fully managed services by the creators of Fider to help you get started in minutes. Forget about managing software updates and patches, we do it all for you! [Sign up now](https://fider.io/#get-started) -## Contributors +## 🏢 **Self-Hosted** -This project exists thanks to all the people who contribute. +You can also install Fider yourself. It's free, but you are responsible for managing it. [Learn how](https://fider.io/docs/hosting-instance) - +
+
-Read our [CONTRIBUTING](CONTRIBUTING.md) guide to learn how you can contribute to Fider. +# Sponsors -## Sponsors + + + -Does your organization use Fider? [Become a sponsor](https://opencollective.com/fider) and your logo will show up here with a link to your website. +
+
- - - - - +> Does your organization use Fider? [Become a sponsor](https://opencollective.com/fider) and get your logo and link on our README! -## Backers +
+
-Thank you to all our backers! 🙏 +# Contributors - - - +This project exists thanks to all the amazing people who contribute! -Thanks to [BrowserStack](https://browserstack.com/) for providing us with free cross-browser testing for Fider. + - - - +Read our [CONTRIBUTING](CONTRIBUTING.md) guide to learn how you can contribute to Fider. + +
+
diff --git a/app/actions/post.go b/app/actions/post.go index fa7ba65a7..89314a8dd 100644 --- a/app/actions/post.go +++ b/app/actions/post.go @@ -133,6 +133,38 @@ func (action *UpdatePost) Validate(ctx context.Context, user *entity.User) *vali return result } +type ToggleCommentReaction struct { + Number int `route:"number"` + Comment int `route:"id"` + Reaction string `route:"reaction"` +} + +// IsAuthorized returns true if current user is authorized to perform this action +func (action *ToggleCommentReaction) IsAuthorized(ctx context.Context, user *entity.User) bool { + return user != nil +} + +// Validate if current model is valid +func (action *ToggleCommentReaction) Validate(ctx context.Context, user *entity.User) *validate.Result { + + result := validate.Success() + + allowedEmojis := []string{"👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"} + isAllowed := false + for _, emoji := range allowedEmojis { + if action.Reaction == emoji { + isAllowed = true + break + } + } + + if !isAllowed { + result.AddFieldFailure("reaction", i18n.T(ctx, "validation.custom.invalidemoji")) + } + + return result +} + // AddNewComment represents a new comment to be added type AddNewComment struct { Number int `route:"number"` diff --git a/app/cmd/routes.go b/app/cmd/routes.go index 49bd7bfd3..4406917e2 100644 --- a/app/cmd/routes.go +++ b/app/cmd/routes.go @@ -55,13 +55,6 @@ func routes(r *web.Engine) *web.Engine { r.Use(middlewares.User()) r.Get("/privacy", handlers.LegalPage("Privacy Policy", "privacy.md")) - r.Get("/terms", handlers.LegalPage("Terms of Service", "terms.md")) - - r.Post("/_api/tenants", handlers.CreateTenant()) - r.Get("/_api/tenants/:subdomain/availability", handlers.CheckAvailability()) - r.Get("/signup", handlers.SignUp()) - r.Get("/oauth/:provider", handlers.SignInByOAuth()) - r.Get("/oauth/:provider/callback", handlers.OAuthCallback()) if env.IsBillingEnabled() { wh := r.Group() @@ -70,7 +63,17 @@ func routes(r *web.Engine) *web.Engine { } } - //Starting from this step, a Tenant is required + r.Use(middlewares.CSRF()) + + r.Get("/terms", handlers.LegalPage("Terms of Service", "terms.md")) + + r.Post("/_api/tenants", handlers.CreateTenant()) + r.Get("/_api/tenants/:subdomain/availability", handlers.CheckAvailability()) + r.Get("/signup", handlers.SignUp()) + r.Get("/oauth/:provider", handlers.SignInByOAuth()) + r.Get("/oauth/:provider/callback", handlers.OAuthCallback()) + + // Starting from this step, a Tenant is required r.Use(middlewares.RequireTenant()) r.Get("/sitemap.xml", handlers.Sitemap()) @@ -79,7 +82,7 @@ func routes(r *web.Engine) *web.Engine { { tenantAssets.Use(middlewares.ClientCache(5 * 24 * time.Hour)) tenantAssets.Get("/static/avatars/letter/:id/:name", handlers.LetterAvatar()) - tenantAssets.Get("/static/avatars/gravatar/:id/:name", handlers.Gravatar()) + tenantAssets.Get("/static/avatars/gravatar/:id/*name", handlers.Gravatar()) tenantAssets.Use(middlewares.ClientCache(30 * 24 * time.Hour)) tenantAssets.Get("/static/favicon/*bkey", handlers.Favicon()) @@ -95,7 +98,7 @@ func routes(r *web.Engine) *web.Engine { r.Get("/oauth/:provider/token", handlers.OAuthToken()) r.Get("/oauth/:provider/echo", handlers.OAuthEcho()) - //If tenant is pending, block it from using any other route + // If tenant is pending, block it from using any other route r.Use(middlewares.BlockPendingTenants()) r.Get("/signin", handlers.SignInPage()) @@ -105,7 +108,7 @@ func routes(r *web.Engine) *web.Engine { r.Post("/_api/signin/complete", handlers.CompleteSignInProfile()) r.Post("/_api/signin", handlers.SignInByEmail()) - //Block if it's private tenant with unauthenticated user + // Block if it's private tenant with unauthenticated user r.Use(middlewares.CheckTenantPrivacy()) r.Get("/", handlers.Index()) @@ -114,12 +117,13 @@ func routes(r *web.Engine) *web.Engine { ui := r.Group() { - //From this step, a User is required + // From this step, a User is required ui.Use(middlewares.IsAuthenticated()) ui.Get("/settings", handlers.UserSettings()) ui.Get("/notifications", handlers.Notifications()) ui.Get("/notifications/:id", handlers.ReadNotification()) + ui.Get("/_api/notifications/unread", handlers.GetAllNotifications()) ui.Get("/change-email/verify", handlers.VerifyChangeEmailKey()) ui.Delete("/_api/user", handlers.DeleteUser()) @@ -145,7 +149,7 @@ func routes(r *web.Engine) *web.Engine { ui.Get("/admin/authentication", handlers.ManageAuthentication()) ui.Get("/_api/admin/oauth/:provider", handlers.GetOAuthConfig()) - //From this step, only Administrators are allowed + // From this step, only Administrators are allowed ui.Use(middlewares.IsAuthorized(enum.RoleAdministrator)) ui.Get("/admin/export", handlers.Page("Export · Site Settings", "", "Administration/pages/Export.page")) @@ -193,6 +197,7 @@ func routes(r *web.Engine) *web.Engine { membersApi.Post("/api/v1/posts", apiv1.CreatePost()) membersApi.Put("/api/v1/posts/:number", apiv1.UpdatePost()) + membersApi.Post("/api/v1/posts/:number/comments/:id/reactions/:reaction", apiv1.ToggleReaction()) membersApi.Post("/api/v1/posts/:number/comments", apiv1.PostComment()) membersApi.Put("/api/v1/posts/:number/comments/:id", apiv1.UpdateComment()) membersApi.Delete("/api/v1/posts/:number/comments/:id", apiv1.DeleteComment()) diff --git a/app/cmd/server.go b/app/cmd/server.go index 23125f048..fcfbeec20 100644 --- a/app/cmd/server.go +++ b/app/cmd/server.go @@ -30,11 +30,12 @@ import ( _ "github.com/getfider/fider/app/services/log/sql" _ "github.com/getfider/fider/app/services/oauth" _ "github.com/getfider/fider/app/services/sqlstore/postgres" + _ "github.com/getfider/fider/app/services/userlist" _ "github.com/getfider/fider/app/services/webhook" ) -//RunServer starts the Fider Server -//Returns an exitcode, 0 for OK and 1 for ERROR +// RunServer starts the Fider Server +// Returns an exitcode, 0 for OK and 1 for ERROR func RunServer() int { svcs := bus.Init() ctx := log.WithProperty(context.Background(), log.PropertyKeyTag, "BOOTSTRAP") diff --git a/app/handlers/admin.go b/app/handlers/admin.go index 9bdae3174..030809209 100644 --- a/app/handlers/admin.go +++ b/app/handlers/admin.go @@ -5,9 +5,13 @@ import ( "github.com/getfider/fider/app/actions" "github.com/getfider/fider/app/models/cmd" + "github.com/getfider/fider/app/models/dto" + "github.com/getfider/fider/app/models/entity" "github.com/getfider/fider/app/models/query" "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/pkg/web" + "github.com/getfider/fider/app/tasks" ) // GeneralSettingsPage is the general settings page @@ -58,6 +62,14 @@ func UpdateSettings() web.HandlerFunc { return c.Failure(err) } + // Handle userlist. + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListUpdateCompany(&dto.UserListUpdateCompany{ + TenantID: c.Tenant().ID, + Name: action.Title, + })) + } + return c.Ok(web.Map{}) } } @@ -126,11 +138,19 @@ func ManageMembers() web.HandlerFunc { return c.Failure(err) } + // Create an array of UserWithEmail structs from the allUsers.Result + allUsersWithEmail := make([]entity.UserWithEmail, len(allUsers.Result)) + for i, user := range allUsers.Result { + allUsersWithEmail[i] = entity.UserWithEmail{ + User: user, + } + } + return c.Page(http.StatusOK, web.Props{ Page: "Administration/pages/ManageMembers.page", Title: "Manage Members · Site Settings", Data: web.Map{ - "users": allUsers.Result, + "users": allUsersWithEmail, }, }) } diff --git a/app/handlers/admin_test.go b/app/handlers/admin_test.go index 6617c9cb0..3275da679 100644 --- a/app/handlers/admin_test.go +++ b/app/handlers/admin_test.go @@ -3,8 +3,8 @@ package handlers_test import ( "context" "encoding/base64" - "io/ioutil" "net/http" + "os" "testing" "github.com/getfider/fider/app/models/cmd" @@ -69,7 +69,7 @@ func TestUpdateSettingsHandler_NewLogo(t *testing.T) { return nil }) - logoBytes, _ := ioutil.ReadFile(env.Etc("logo.png")) + logoBytes, _ := os.ReadFile(env.Etc("logo.png")) logoB64 := base64.StdEncoding.EncodeToString(logoBytes) server := mock.NewServer() diff --git a/app/handlers/apiv1/post.go b/app/handlers/apiv1/post.go index 7d4f41d4f..3718315ff 100644 --- a/app/handlers/apiv1/post.go +++ b/app/handlers/apiv1/post.go @@ -15,9 +15,13 @@ import ( // SearchPosts return existing posts based on search criteria func SearchPosts() web.HandlerFunc { return func(c *web.Context) error { + viewQueryParams := c.QueryParam("view") + if viewQueryParams == "" { + viewQueryParams = "all" // Set default value to "all" if not provided + } searchPosts := &query.SearchPosts{ Query: c.QueryParam("query"), - View: c.QueryParam("view"), + View: viewQueryParams, Limit: c.QueryParam("limit"), Tags: c.QueryParamAsArray("tags"), } @@ -169,10 +173,7 @@ func DeletePost() web.HandlerFunc { return c.Failure(err) } - if action.Text != "" { - // Only send notification if user wrote a comment. - c.Enqueue(tasks.NotifyAboutDeletedPost(action.Post)) - } + c.Enqueue(tasks.NotifyAboutDeletedPost(action.Post, action.Text != "")) return c.Ok(web.Map{}) } @@ -217,6 +218,34 @@ func GetComment() web.HandlerFunc { } } +// ToggleReaction adds or removes a reaction on a comment +func ToggleReaction() web.HandlerFunc { + return func(c *web.Context) error { + action := new(actions.ToggleCommentReaction) + if result := c.BindTo(action); !result.Ok { + return c.HandleValidation(result) + } + + getComment := &query.GetCommentByID{CommentID: action.Comment} + if err := bus.Dispatch(c, getComment); err != nil { + return c.Failure(err) + } + + toggleReaction := &cmd.ToggleCommentReaction{ + Comment: getComment.Result, + Emoji: action.Reaction, + User: c.User(), + } + if err := bus.Dispatch(c, toggleReaction); err != nil { + return c.Failure(err) + } + + return c.Ok(web.Map{ + "added": toggleReaction.Result, + }) + } +} + // PostComment creates a new comment on given post func PostComment() web.HandlerFunc { return func(c *web.Context) error { diff --git a/app/handlers/apiv1/post_test.go b/app/handlers/apiv1/post_test.go index 72e9c9572..1bb77621e 100644 --- a/app/handlers/apiv1/post_test.go +++ b/app/handlers/apiv1/post_test.go @@ -124,11 +124,11 @@ func TestUpdatePostHandler_NonAuthorized(t *testing.T) { RegisterT(t) post := &entity.Post{ - ID: 5, - Number: 5, - Title: "My First Post", + ID: 5, + Number: 5, + Title: "My First Post", Description: "Such an amazing description", - User: mock.JonSnow, + User: mock.JonSnow, } bus.AddHandler(func(ctx context.Context, q *query.GetPostByNumber) error { if q.Number == post.Number { @@ -151,12 +151,12 @@ func TestUpdatePostHandler_IsOwner_AfterGracePeriod(t *testing.T) { RegisterT(t) post := &entity.Post{ - ID: 5, - Number: 5, - Title: "My First Post", + ID: 5, + Number: 5, + Title: "My First Post", Description: "Such an amazing description", - User: mock.AryaStark, - CreatedAt: time.Now().UTC().Add(-2 * time.Hour), + User: mock.AryaStark, + CreatedAt: time.Now().UTC().Add(-2 * time.Hour), } bus.AddHandler(func(ctx context.Context, q *query.GetPostByNumber) error { if q.Number == post.Number { @@ -175,17 +175,16 @@ func TestUpdatePostHandler_IsOwner_AfterGracePeriod(t *testing.T) { Expect(code).Equals(http.StatusForbidden) } - func TestUpdatePostHandler_IsOwner_WithinGracePeriod(t *testing.T) { RegisterT(t) post := &entity.Post{ - ID: 5, - Number: 5, - Title: "My First Post", + ID: 5, + Number: 5, + Title: "My First Post", Description: "Such an amazing description", - User: mock.AryaStark, - CreatedAt: time.Now().UTC(), + User: mock.AryaStark, + CreatedAt: time.Now().UTC(), } bus.AddHandler(func(ctx context.Context, q *query.GetPostByNumber) error { if q.Number == post.Number { @@ -654,3 +653,115 @@ func TestListCommentHandler(t *testing.T) { Expect(query.IsArray()).IsTrue() Expect(query.ArrayLength()).Equals(2) } + +func TestCommentReactionToggleHandler(t *testing.T) { + RegisterT(t) + + comment := &entity.Comment{ID: 5, Content: "Old comment text", User: mock.AryaStark} + + bus.AddHandler(func(ctx context.Context, q *query.GetCommentByID) error { + q.Result = comment + return nil + }) + + testCases := []struct { + name string + user *entity.User + reaction string + }{ + {"JonSnow reacts with like", mock.JonSnow, "👍"}, + {"AryaStark reacts with smile", mock.AryaStark, "👍"}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var toggleReaction *cmd.ToggleCommentReaction + bus.AddHandler(func(ctx context.Context, c *cmd.ToggleCommentReaction) error { + toggleReaction = c + return nil + }) + + code, _ := mock.NewServer(). + OnTenant(mock.DemoTenant). + AsUser(tc.user). + AddParam("number", 1). + AddParam("id", comment.ID). + AddParam("reaction", tc.reaction). + ExecutePost(apiv1.ToggleReaction(), ``) + + Expect(code).Equals(http.StatusOK) + Expect(toggleReaction.Emoji).Equals(tc.reaction) + Expect(toggleReaction.Comment).Equals(comment) + Expect(toggleReaction.User).Equals(tc.user) + }) + } +} + +func TestCommentReactionToggleHandler_InvalidEmoji(t *testing.T) { + RegisterT(t) + + comment := &entity.Comment{ID: 5, Content: "Old comment text", User: mock.AryaStark} + bus.AddHandler(func(ctx context.Context, q *query.GetCommentByID) error { + q.Result = comment + return nil + }) + + bus.AddHandler(func(ctx context.Context, c *cmd.ToggleCommentReaction) error { + return nil + }) + + code, _ := mock.NewServer(). + OnTenant(mock.DemoTenant). + AsUser(mock.AryaStark). + AddParam("number", 1). + AddParam("id", comment.ID). + AddParam("reaction", "like"). + ExecutePost(apiv1.ToggleReaction(), ``) + + Expect(code).Equals(http.StatusBadRequest) +} + +func TestCommentReactionToggleHandler_UnAuthorised(t *testing.T) { + RegisterT(t) + + comment := &entity.Comment{ID: 5, Content: "Old comment text", User: mock.AryaStark} + bus.AddHandler(func(ctx context.Context, q *query.GetCommentByID) error { + q.Result = comment + return nil + }) + + bus.AddHandler(func(ctx context.Context, c *cmd.ToggleCommentReaction) error { + return nil + }) + + code, _ := mock.NewServer(). + OnTenant(mock.DemoTenant). + AddParam("number", 1). + AddParam("id", comment.ID). + AddParam("reaction", "👍"). + ExecutePost(apiv1.ToggleReaction(), ``) + + Expect(code).Equals(http.StatusForbidden) +} + +func TestCommentReactionToggleHandler_MismatchingTenantAndComment(t *testing.T) { + RegisterT(t) + + bus.AddHandler(func(ctx context.Context, q *query.GetCommentByID) error { + return app.ErrNotFound + }) + + bus.AddHandler(func(ctx context.Context, c *cmd.ToggleCommentReaction) error { + return nil + }) + + code, _ := mock.NewServer(). + OnTenant(mock.DemoTenant). + AsUser(mock.JonSnow). + AddParam("number", 1). + AddParam("id", 1). + AddParam("reaction", "👍"). + ExecutePost(apiv1.ToggleReaction(), ``) + + Expect(code).Equals(http.StatusNotFound) +} diff --git a/app/handlers/common.go b/app/handlers/common.go index dafcc33cf..6b4b5d0ee 100644 --- a/app/handlers/common.go +++ b/app/handlers/common.go @@ -2,8 +2,8 @@ package handlers import ( "fmt" - "io/ioutil" "net/http" + "os" "strings" "time" @@ -23,7 +23,7 @@ import ( "github.com/getfider/fider/app/pkg/web" ) -//Health always returns OK +// Health always returns OK func Health() web.HandlerFunc { return func(c *web.Context) error { err := dbx.Ping() @@ -34,10 +34,10 @@ func Health() web.HandlerFunc { } } -//LegalPage returns a legal page with content from a file +// LegalPage returns a legal page with content from a file func LegalPage(title, file string) web.HandlerFunc { return func(c *web.Context) error { - bytes, err := ioutil.ReadFile(env.Etc(file)) + bytes, err := os.ReadFile(env.Etc(file)) if err != nil { return c.NotFound() } @@ -52,7 +52,7 @@ func LegalPage(title, file string) web.HandlerFunc { } } -//Sitemap returns the sitemap.xml of current site +// Sitemap returns the sitemap.xml of current site func Sitemap() web.HandlerFunc { return func(c *web.Context) error { if c.Tenant().IsPrivate { @@ -79,10 +79,10 @@ func Sitemap() web.HandlerFunc { } } -//RobotsTXT return content of robots.txt file +// RobotsTXT return content of robots.txt file func RobotsTXT() web.HandlerFunc { return func(c *web.Context) error { - bytes, err := ioutil.ReadFile(env.Path("./robots.txt")) + bytes, err := os.ReadFile(env.Path("./robots.txt")) if err != nil { return c.NotFound() } @@ -92,7 +92,7 @@ func RobotsTXT() web.HandlerFunc { } } -//Page returns a page without properties +// Page returns a page without properties func Page(title, description, page string) web.HandlerFunc { return func(c *web.Context) error { return c.Page(http.StatusOK, web.Props{ @@ -103,13 +103,13 @@ func Page(title, description, page string) web.HandlerFunc { } } -//NewLogError is the input model for UI errors +// NewLogError is the input model for UI errors type NewLogError struct { Message string `json:"message"` Data any `json:"data"` } -//LogError logs an error coming from the UI +// LogError logs an error coming from the UI func LogError() web.HandlerFunc { return func(c *web.Context) error { action := new(NewLogError) diff --git a/app/handlers/common_test.go b/app/handlers/common_test.go index 0e076538c..6130264c2 100644 --- a/app/handlers/common_test.go +++ b/app/handlers/common_test.go @@ -2,7 +2,7 @@ package handlers_test import ( "context" - "io/ioutil" + "io" "net/http" "testing" @@ -62,7 +62,7 @@ func TestRobotsTXT(t *testing.T) { code, response := server. WithURL("https://demo.test.fider.io/robots.txt"). Execute(handlers.RobotsTXT()) - content, _ := ioutil.ReadAll(response.Body) + content, _ := io.ReadAll(response.Body) Expect(code).Equals(http.StatusOK) Expect(string(content)).Equals(`User-agent: * Disallow: /_api/ @@ -89,7 +89,7 @@ func TestSitemap(t *testing.T) { WithURL("http://demo.test.fider.io:3000/sitemap.xml"). Execute(handlers.Sitemap()) - bytes, _ := ioutil.ReadAll(response.Body) + bytes, _ := io.ReadAll(response.Body) Expect(code).Equals(http.StatusOK) Expect(string(bytes)).Equals(` http://demo.test.fider.io:3000 `) } @@ -112,7 +112,7 @@ func TestSitemap_WithPosts(t *testing.T) { WithURL("http://demo.test.fider.io:3000/sitemap.xml"). Execute(handlers.Sitemap()) - bytes, _ := ioutil.ReadAll(response.Body) + bytes, _ := io.ReadAll(response.Body) Expect(code).Equals(http.StatusOK) Expect(string(bytes)).Equals(` http://demo.test.fider.io:3000 http://demo.test.fider.io:3000/posts/1/my-new-idea-1 http://demo.test.fider.io:3000/posts/2/the-other-idea `) } diff --git a/app/handlers/images.go b/app/handlers/images.go index 3f57547a8..6cdbd2cc0 100644 --- a/app/handlers/images.go +++ b/app/handlers/images.go @@ -5,8 +5,8 @@ import ( "fmt" "image/color" "image/png" - "io/ioutil" "net/http" + "os" "strings" "time" @@ -23,7 +23,7 @@ import ( "github.com/goenning/letteravatar" ) -//LetterAvatar returns a letter gravatar picture based on given name +// LetterAvatar returns a letter gravatar picture based on given name func LetterAvatar() web.HandlerFunc { return func(c *web.Context) error { id := c.Param("id") @@ -55,7 +55,7 @@ func LetterAvatar() web.HandlerFunc { } } -//Gravatar returns a gravatar picture of fallsback to letter avatar based on name +// Gravatar returns a gravatar picture of fallsback to letter avatar based on name func Gravatar() web.HandlerFunc { return func(c *web.Context) error { id, err := c.ParamAsInt("id") @@ -109,7 +109,7 @@ func Gravatar() web.HandlerFunc { } } -//Favicon returns the Fider favicon by given size +// Favicon returns the Fider favicon by given size func Favicon() web.HandlerFunc { return func(c *web.Context) error { var ( @@ -128,7 +128,7 @@ func Favicon() web.HandlerFunc { bytes = q.Result.Content contentType = q.Result.ContentType } else { - bytes, err = ioutil.ReadFile(env.Path("favicon.png")) + bytes, err = os.ReadFile(env.Path("favicon.png")) contentType = "image/png" if err != nil { return c.Failure(err) @@ -161,7 +161,7 @@ func Favicon() web.HandlerFunc { } } -//ViewUploadedImage returns any uploaded image by given ID and size +// ViewUploadedImage returns any uploaded image by given ID and size func ViewUploadedImage() web.HandlerFunc { return func(c *web.Context) error { bkey := c.Param("bkey") diff --git a/app/handlers/images_test.go b/app/handlers/images_test.go index c3eaf169d..501ec11d0 100644 --- a/app/handlers/images_test.go +++ b/app/handlers/images_test.go @@ -2,7 +2,7 @@ package handlers_test import ( "context" - "io/ioutil" + "io" "net/http" "testing" @@ -81,7 +81,7 @@ func TestGravatarNotFound_LetterAvatarHandler(t *testing.T) { expectedAvatar := []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 50, 0, 0, 0, 50, 8, 2, 0, 0, 0, 145, 93, 31, 230, 0, 0, 3, 6, 73, 68, 65, 84, 120, 156, 236, 152, 75, 79, 19, 81, 20, 128, 207, 204, 212, 210, 18, 90, 232, 211, 34, 196, 40, 6, 65, 129, 0, 209, 2, 11, 100, 97, 140, 113, 225, 2, 127, 3, 198, 196, 184, 55, 38, 38, 36, 198, 132, 168, 11, 149, 152, 24, 35, 97, 99, 220, 24, 23, 46, 140, 186, 49, 38, 242, 42, 20, 10, 72, 241, 149, 64, 75, 12, 125, 208, 86, 104, 7, 90, 103, 134, 206, 29, 211, 14, 25, 154, 66, 116, 46, 96, 101, 113, 191, 213, 225, 204, 153, 123, 191, 204, 185, 15, 82, 205, 197, 87, 157, 176, 255, 160, 255, 183, 192, 246, 16, 45, 28, 136, 22, 14, 68, 11, 7, 162, 133, 3, 209, 194, 129, 104, 225, 64, 180, 112, 32, 90, 56, 104, 212, 20, 117, 84, 158, 57, 119, 248, 172, 242, 103, 50, 157, 138, 164, 34, 19, 97, 143, 55, 54, 171, 36, 105, 138, 190, 209, 114, 93, 199, 20, 45, 115, 203, 15, 39, 31, 109, 29, 228, 90, 211, 213, 131, 197, 118, 1, 173, 223, 113, 223, 75, 163, 244, 30, 104, 89, 245, 150, 26, 243, 241, 188, 228, 133, 35, 231, 125, 9, 255, 125, 79, 111, 52, 21, 5, 0, 36, 161, 53, 97, 181, 177, 162, 1, 0, 94, 124, 127, 25, 74, 134, 243, 70, 232, 168, 108, 7, 0, 119, 120, 226, 175, 78, 216, 77, 124, 58, 211, 255, 192, 211, 251, 120, 250, 201, 251, 31, 31, 214, 81, 186, 170, 244, 104, 79, 251, 109, 147, 206, 36, 63, 29, 12, 12, 203, 65, 75, 121, 75, 222, 139, 173, 229, 173, 27, 53, 139, 67, 106, 38, 194, 211, 154, 138, 76, 143, 134, 220, 31, 23, 7, 251, 102, 250, 187, 71, 110, 241, 34, 111, 212, 26, 174, 52, 116, 201, 79, 63, 69, 103, 18, 60, 155, 145, 112, 56, 243, 94, 108, 203, 138, 38, 215, 147, 147, 145, 169, 189, 215, 202, 197, 23, 247, 189, 158, 127, 3, 0, 205, 246, 102, 171, 222, 42, 247, 209, 21, 116, 1, 192, 177, 178, 42, 139, 222, 162, 84, 154, 117, 166, 234, 178, 106, 0, 24, 13, 185, 213, 116, 112, 183, 59, 209, 21, 26, 5, 0, 138, 2, 167, 227, 148, 156, 217, 236, 163, 227, 180, 82, 230, 116, 56, 41, 74, 126, 170, 170, 131, 187, 213, 10, 174, 133, 228, 192, 166, 183, 201, 193, 92, 124, 62, 156, 92, 202, 106, 109, 246, 177, 181, 60, 19, 71, 127, 197, 190, 254, 252, 86, 8, 45, 36, 33, 94, 20, 0, 160, 180, 168, 84, 73, 14, 7, 71, 0, 160, 214, 92, 99, 212, 26, 0, 192, 168, 53, 156, 48, 215, 102, 242, 129, 17, 245, 35, 239, 246, 56, 213, 208, 153, 35, 70, 16, 121, 37, 35, 239, 53, 154, 162, 157, 217, 15, 230, 116, 56, 105, 42, 51, 203, 192, 226, 96, 129, 180, 76, 58, 19, 147, 157, 50, 198, 45, 43, 201, 80, 50, 60, 31, 247, 41, 189, 147, 247, 160, 63, 177, 16, 88, 11, 22, 72, 171, 222, 114, 82, 14, 230, 86, 230, 114, 243, 242, 210, 174, 183, 212, 217, 139, 109, 117, 214, 186, 220, 173, 240, 207, 181, 180, 140, 246, 82, 117, 39, 0, 172, 112, 241, 220, 91, 40, 187, 188, 92, 162, 132, 24, 154, 185, 220, 208, 197, 80, 52, 146, 208, 112, 1, 180, 40, 138, 170, 53, 215, 116, 183, 221, 172, 40, 57, 4, 0, 125, 222, 126, 36, 161, 220, 2, 150, 103, 189, 81, 47, 0, 52, 218, 50, 119, 209, 108, 236, 115, 156, 79, 96, 77, 161, 234, 78, 84, 184, 219, 209, 35, 73, 168, 228, 64, 9, 67, 51, 0, 32, 34, 241, 217, 151, 231, 158, 165, 201, 173, 149, 3, 129, 161, 38, 123, 227, 70, 140, 179, 216, 119, 162, 37, 239, 121, 0, 224, 69, 97, 44, 228, 126, 235, 127, 231, 79, 44, 108, 91, 57, 30, 158, 224, 210, 156, 78, 163, 227, 210, 220, 88, 120, 28, 87, 139, 82, 243, 179, 155, 81, 107, 80, 78, 38, 9, 128, 21, 88, 54, 123, 247, 253, 25, 123, 177, 189, 136, 209, 242, 162, 16, 73, 69, 112, 181, 84, 125, 45, 86, 88, 101, 133, 85, 220, 161, 119, 96, 163, 176, 79, 255, 59, 37, 90, 56, 16, 45, 28, 136, 22, 14, 68, 11, 7, 162, 133, 3, 209, 194, 129, 104, 225, 240, 59, 0, 0, 255, 255, 193, 108, 28, 164, 14, 189, 96, 131, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130} Expect(code).Equals(http.StatusOK) - bytes, _ := ioutil.ReadAll(response.Body) + bytes, _ := io.ReadAll(response.Body) Expect(bytes).Equals(expectedAvatar) } @@ -99,6 +99,6 @@ func TestUnknownUser_LetterAvatarHandler(t *testing.T) { expectedAvatar := []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 50, 0, 0, 0, 50, 8, 2, 0, 0, 0, 145, 93, 31, 230, 0, 0, 2, 137, 73, 68, 65, 84, 120, 156, 236, 152, 75, 79, 19, 81, 20, 199, 255, 3, 51, 244, 65, 95, 80, 74, 43, 160, 149, 135, 36, 5, 177, 169, 137, 40, 42, 209, 152, 200, 74, 19, 87, 110, 248, 84, 126, 7, 227, 70, 23, 110, 140, 137, 154, 248, 32, 33, 152, 72, 20, 13, 6, 8, 62, 210, 74, 209, 218, 161, 239, 55, 237, 152, 67, 167, 37, 141, 36, 222, 139, 19, 202, 226, 254, 114, 51, 28, 78, 239, 220, 249, 245, 204, 205, 153, 73, 101, 237, 225, 61, 28, 63, 58, 218, 45, 112, 48, 66, 139, 7, 161, 197, 131, 208, 226, 65, 104, 241, 32, 180, 120, 16, 90, 60, 8, 45, 30, 132, 22, 15, 242, 127, 157, 237, 61, 133, 241, 243, 20, 124, 120, 141, 76, 162, 177, 164, 130, 145, 41, 156, 24, 134, 205, 65, 255, 22, 114, 248, 21, 198, 151, 143, 40, 230, 143, 74, 203, 100, 129, 219, 71, 129, 210, 165, 103, 44, 54, 92, 190, 5, 187, 107, 127, 142, 98, 130, 163, 23, 167, 39, 176, 244, 20, 234, 246, 145, 104, 253, 77, 232, 26, 57, 105, 26, 214, 222, 97, 251, 59, 180, 42, 122, 188, 152, 184, 8, 179, 21, 211, 115, 120, 254, 0, 187, 21, 150, 101, 12, 221, 91, 138, 9, 253, 39, 41, 136, 108, 96, 125, 25, 105, 21, 153, 36, 194, 235, 120, 255, 10, 245, 210, 14, 140, 48, 174, 100, 104, 181, 58, 26, 95, 178, 82, 106, 201, 199, 163, 248, 246, 153, 130, 114, 169, 29, 90, 165, 2, 149, 199, 238, 162, 157, 164, 254, 68, 244, 171, 158, 175, 238, 98, 229, 13, 215, 74, 70, 55, 136, 149, 5, 212, 106, 232, 148, 105, 39, 221, 184, 139, 241, 16, 172, 246, 67, 44, 99, 180, 86, 124, 11, 11, 143, 145, 138, 83, 236, 232, 165, 205, 62, 55, 143, 43, 183, 209, 235, 109, 171, 22, 128, 68, 12, 47, 31, 97, 241, 9, 194, 27, 168, 148, 41, 227, 25, 196, 236, 29, 186, 179, 204, 24, 221, 32, 154, 196, 34, 52, 58, 58, 49, 56, 138, 201, 25, 152, 45, 8, 206, 66, 141, 210, 230, 99, 128, 185, 90, 157, 50, 186, 204, 52, 90, 144, 244, 191, 154, 70, 71, 103, 31, 134, 198, 104, 72, 141, 124, 173, 74, 205, 98, 249, 197, 222, 92, 137, 90, 63, 27, 204, 213, 26, 11, 34, 112, 129, 130, 103, 247, 145, 207, 234, 73, 171, 77, 15, 202, 69, 58, 246, 15, 97, 242, 18, 5, 233, 29, 26, 77, 82, 170, 30, 40, 102, 198, 171, 49, 87, 43, 249, 91, 15, 134, 167, 244, 192, 210, 13, 127, 128, 130, 66, 22, 185, 52, 5, 212, 214, 247, 202, 118, 238, 42, 53, 207, 58, 146, 132, 209, 198, 41, 153, 29, 198, 171, 49, 87, 43, 22, 33, 51, 151, 7, 103, 130, 240, 249, 233, 185, 235, 242, 64, 81, 232, 163, 213, 183, 250, 156, 108, 18, 171, 75, 56, 59, 131, 190, 1, 220, 156, 167, 130, 85, 138, 176, 247, 232, 61, 34, 165, 226, 199, 38, 227, 213, 36, 142, 223, 183, 76, 22, 132, 174, 147, 83, 147, 82, 129, 156, 194, 107, 45, 211, 124, 126, 4, 166, 225, 116, 239, 103, 106, 53, 108, 109, 226, 211, 162, 126, 175, 13, 214, 170, 99, 181, 195, 225, 134, 44, 211, 27, 75, 34, 70, 155, 250, 64, 186, 157, 176, 57, 233, 205, 162, 84, 160, 54, 198, 252, 216, 169, 195, 223, 32, 242, 25, 26, 255, 36, 151, 162, 113, 88, 142, 233, 219, 169, 208, 226, 65, 104, 241, 32, 180, 120, 16, 90, 60, 8, 45, 30, 132, 22, 15, 66, 139, 135, 63, 1, 0, 0, 255, 255, 117, 91, 183, 108, 67, 255, 85, 68, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130} Expect(code).Equals(http.StatusOK) - bytes, _ := ioutil.ReadAll(response.Body) + bytes, _ := io.ReadAll(response.Body) Expect(bytes).Equals(expectedAvatar) } diff --git a/app/handlers/notification.go b/app/handlers/notification.go index f39221785..e00af53ed 100644 --- a/app/handlers/notification.go +++ b/app/handlers/notification.go @@ -9,6 +9,18 @@ import ( "github.com/getfider/fider/app/pkg/web" ) +// GetAllNotifications will get all the notifications for the new modal +func GetAllNotifications() web.HandlerFunc { + return func(c *web.Context) error { + q := &query.GetActiveNotifications{} + if err := bus.Dispatch(c, q); err != nil { + return c.Failure(err) + } + + return c.Ok(q.Result) + } +} + // TotalUnreadNotifications returns the total number of unread notifications func TotalUnreadNotifications() web.HandlerFunc { return func(c *web.Context) error { @@ -65,7 +77,6 @@ func ReadNotification() web.HandlerFunc { // ReadAllNotifications marks all unread notifications as read func ReadAllNotifications() web.HandlerFunc { return func(c *web.Context) error { - if err := bus.Dispatch(c, &cmd.MarkAllNotificationsAsRead{}); err != nil { return c.Failure(err) } diff --git a/app/handlers/oauth.go b/app/handlers/oauth.go index 959d24f6c..2a8672097 100644 --- a/app/handlers/oauth.go +++ b/app/handlers/oauth.go @@ -163,14 +163,17 @@ func OAuthCallback() web.HandlerFunc { provider := c.Param("provider") state := c.QueryParam("state") - parts := strings.Split(state, "|") + claims, err := jwt.DecodeOAuthStateClaims(state) + if err != nil { + return c.Forbidden() + } - if parts[0] == "" { + if claims.Redirect == "" { log.Warnf(c, "Missing redirect URL in OAuth callback state for provider @{Provider}.", dto.Props{"Provider": provider}) return c.NotFound() } - redirectURL, err := url.ParseRequestURI(parts[0]) + redirectURL, err := url.ParseRequestURI(claims.Redirect) if err != nil { return c.Failure(err) } @@ -184,7 +187,7 @@ func OAuthCallback() web.HandlerFunc { if redirectURL.Path == fmt.Sprintf("/oauth/%s/echo", provider) { var query = redirectURL.Query() query.Set("code", code) - query.Set("identifier", parts[1]) + query.Set("identifier", claims.Identifier) redirectURL.RawQuery = query.Encode() return c.Redirect(redirectURL.String()) } @@ -221,7 +224,7 @@ func OAuthCallback() web.HandlerFunc { var query = redirectURL.Query() query.Set("code", code) query.Set("redirect", redirectURL.RequestURI()) - query.Set("identifier", parts[1]) + query.Set("identifier", claims.Identifier) redirectURL.RawQuery = query.Encode() redirectURL.Path = fmt.Sprintf("/oauth/%s/token", provider) return c.Redirect(redirectURL.String()) @@ -239,6 +242,8 @@ func SignInByOAuth() web.HandlerFunc { if redirect == "" { redirect = c.BaseURL() + } else if redirect != c.BaseURL() && !strings.HasPrefix(redirect, c.BaseURL()+"/") { + return c.Forbidden() } redirectURL, _ := url.ParseRequestURI(redirect) diff --git a/app/handlers/oauth_test.go b/app/handlers/oauth_test.go index c185aaf02..c38b9f342 100644 --- a/app/handlers/oauth_test.go +++ b/app/handlers/oauth_test.go @@ -41,10 +41,75 @@ func TestSignOutHandler(t *testing.T) { Expect(response.Header().Get("Set-Cookie")).ContainsSubstring("Max-Age=0; HttpOnly") } -func TestSignInByOAuthHandler(t *testing.T) { +func TestSignInByOAuthHandler_RootRedirect(t *testing.T) { RegisterT(t) bus.Init(&oauth.Service{}) + server := mock.NewServer() + code, _ := server. + AddParam("provider", app.FacebookProvider). + AddCookie(web.CookieSessionName, "MY_SESSION_ID"). + WithURL("http://avengers.test.fider.io/oauth/facebook?redirect=http://avengers.test.fider.io"). + Use(middlewares.Session()). + Execute(handlers.SignInByOAuth()) + + Expect(code).Equals(http.StatusTemporaryRedirect) +} + +func TestSignInByOAuthHandler_PathRedirect(t *testing.T) { + RegisterT(t) + bus.Init(&oauth.Service{}) + + server := mock.NewServer() + code, _ := server. + AddParam("provider", app.FacebookProvider). + AddCookie(web.CookieSessionName, "MY_SESSION_ID"). + WithURL("http://avengers.test.fider.io/oauth/facebook?redirect=http://avengers.test.fider.io/something"). + Use(middlewares.Session()). + Execute(handlers.SignInByOAuth()) + + Expect(code).Equals(http.StatusTemporaryRedirect) +} + +func TestSignInByOAuthHandler_EvilRedirect(t *testing.T) { + RegisterT(t) + bus.Init(&oauth.Service{}) + + server := mock.NewServer() + code, _ := server. + AddParam("provider", app.FacebookProvider). + AddCookie(web.CookieSessionName, "MY_SESSION_ID"). + WithURL("http://avengers.test.fider.io/oauth/facebook?redirect=http://evil.com"). + Use(middlewares.Session()). + Execute(handlers.SignInByOAuth()) + + Expect(code).Equals(http.StatusForbidden) +} + +func TestSignInByOAuthHandler_EvilRedirect2(t *testing.T) { + RegisterT(t) + bus.Init(&oauth.Service{}) + + server := mock.NewServer() + code, _ := server. + AddParam("provider", app.FacebookProvider). + AddCookie(web.CookieSessionName, "MY_SESSION_ID"). + WithURL("http://avengers.test.fider.io/oauth/facebook?redirect=http://avengers.test.fider.io.evil.com"). + Use(middlewares.Session()). + Execute(handlers.SignInByOAuth()) + + Expect(code).Equals(http.StatusForbidden) +} + +func TestSignInByOAuthHandler_InvalidURL(t *testing.T) { + RegisterT(t) + bus.Init(&oauth.Service{}) + + state, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://avengers.test.fider.io", + Identifier: "MY_SESSION_ID", + }) + server := mock.NewServer() code, response := server. AddParam("provider", app.FacebookProvider). @@ -54,7 +119,7 @@ func TestSignInByOAuthHandler(t *testing.T) { Execute(handlers.SignInByOAuth()) Expect(code).Equals(http.StatusTemporaryRedirect) - Expect(response.Header().Get("Location")).Equals("https://www.facebook.com/v3.2/dialog/oauth?client_id=FB_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%2Foauth%2Ffacebook%2Fcallback&response_type=code&scope=public_profile+email&state=http%3A%2F%2Favengers.test.fider.io%7CMY_SESSION_ID") + Expect(response.Header().Get("Location")).Equals("https://www.facebook.com/v3.2/dialog/oauth?client_id=FB_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%2Foauth%2Ffacebook%2Fcallback&response_type=code&scope=public_profile+email&state=" + state) } func TestSignInByOAuthHandler_AuthenticatedUser(t *testing.T) { @@ -87,8 +152,13 @@ func TestSignInByOAuthHandler_AuthenticatedUser_UsingEcho(t *testing.T) { Use(middlewares.Session()). Execute(handlers.SignInByOAuth()) + state, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://avengers.test.fider.io/oauth/facebook/echo", + Identifier: "MY_SESSION_ID", + }) + Expect(code).Equals(http.StatusTemporaryRedirect) - Expect(response.Header().Get("Location")).Equals("https://www.facebook.com/v3.2/dialog/oauth?client_id=FB_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%2Foauth%2Ffacebook%2Fcallback&response_type=code&scope=public_profile+email&state=http%3A%2F%2Favengers.test.fider.io%2Foauth%2Ffacebook%2Fecho%7CMY_SESSION_ID") + Expect(response.Header().Get("Location")).Equals("https://www.facebook.com/v3.2/dialog/oauth?client_id=FB_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%2Foauth%2Ffacebook%2Fcallback&response_type=code&scope=public_profile+email&state=" + state) } func TestCallbackHandler_InvalidState(t *testing.T) { @@ -100,16 +170,20 @@ func TestCallbackHandler_InvalidState(t *testing.T) { AddParam("provider", app.FacebookProvider). Execute(handlers.OAuthCallback()) - Expect(code).Equals(http.StatusInternalServerError) + Expect(code).Equals(http.StatusForbidden) } func TestCallbackHandler_InvalidCode(t *testing.T) { RegisterT(t) server := mock.NewServer() + state, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://avengers.test.fider.io", + Identifier: "", + }) code, response := server. - WithURL("http://login.test.fider.io/oauth/callback?state=http://avengers.test.fider.io"). + WithURL("http://login.test.fider.io/oauth/callback?state="+state). AddParam("provider", app.FacebookProvider). Execute(handlers.OAuthCallback()) @@ -120,9 +194,14 @@ func TestCallbackHandler_InvalidCode(t *testing.T) { func TestCallbackHandler_SignIn(t *testing.T) { RegisterT(t) + state, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://avengers.test.fider.io", + Identifier: "888", + }) + server := mock.NewServer() code, response := server. - WithURL("http://login.test.fider.io/oauth/callback?state=http://avengers.test.fider.io|888&code=123"). + WithURL("http://login.test.fider.io/oauth/callback?state="+state+"&code=123"). AddParam("provider", app.FacebookProvider). Execute(handlers.OAuthCallback()) @@ -134,8 +213,13 @@ func TestCallbackHandler_SignIn_WithPath(t *testing.T) { RegisterT(t) server := mock.NewServer() + state, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://avengers.test.fider.io/some-page", + Identifier: "888", + }) + code, response := server. - WithURL("http://login.test.fider.io/oauth/callback?state=http://avengers.test.fider.io/some-page|888&code=123"). + WithURL("http://login.test.fider.io/oauth/callback?state="+state+"&code=123"). AddParam("provider", app.FacebookProvider). Execute(handlers.OAuthCallback()) @@ -160,9 +244,14 @@ func TestCallbackHandler_SignUp(t *testing.T) { return app.ErrNotFound }) + state, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://demo.test.fider.io/signup", + Identifier: "", + }) + server := mock.NewServer() code, response := server. - WithURL("http://login.test.fider.io/oauth/callback?state=http://demo.test.fider.io/signup&code=123"). + WithURL("http://login.test.fider.io/oauth/callback?state="+state+"&code=123"). AddParam("provider", app.FacebookProvider). Execute(handlers.OAuthCallback()) Expect(code).Equals(http.StatusTemporaryRedirect) diff --git a/app/handlers/settings.go b/app/handlers/settings.go index 4080e2e75..49da7dd67 100644 --- a/app/handlers/settings.go +++ b/app/handlers/settings.go @@ -9,6 +9,7 @@ import ( "github.com/getfider/fider/app/models/cmd" "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/tasks" @@ -65,6 +66,10 @@ func VerifyChangeEmailKey() web.HandlerFunc { return c.Failure(err) } + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListUpdateUser(c.User().ID, "", result.Email)) + } + return c.Redirect(c.BaseURL() + "/settings") } } @@ -112,6 +117,10 @@ func UpdateUserSettings() web.HandlerFunc { return c.Failure(err) } + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListUpdateUser(c.User().ID, action.Name, "")) + } + return c.Ok(web.Map{}) } } @@ -133,6 +142,11 @@ func ChangeUserRole() web.HandlerFunc { return c.Failure(err) } + // Handle userlist + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListAddOrRemoveUser(action.UserID, action.Role)) + } + return c.Ok(web.Map{}) } } @@ -145,6 +159,12 @@ func DeleteUser() web.HandlerFunc { } c.RemoveCookie(web.CookieAuthName) + + // Handle userlist (easiest way is to demote them which will remove them from the userlist) + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListAddOrRemoveUser(c.User().ID, enum.RoleVisitor)) + } + return c.Ok(web.Map{}) } } diff --git a/app/handlers/signup.go b/app/handlers/signup.go index a8df45d24..e6dcdcdb1 100644 --- a/app/handlers/signup.go +++ b/app/handlers/signup.go @@ -42,7 +42,7 @@ func CheckAvailability() web.HandlerFunc { } } -//CreateTenant creates a new tenant +// CreateTenant creates a new tenant func CreateTenant() web.HandlerFunc { return func(c *web.Context) error { if env.Config.SignUpDisabled { @@ -79,6 +79,8 @@ func CreateTenant() web.HandlerFunc { Role: enum.RoleAdministrator, } + siteURL := web.TenantBaseURL(c, c.Tenant()) + if socialSignUp { user.Name = action.UserClaims.OAuthName user.Email = action.UserClaims.OAuthEmail @@ -112,14 +114,23 @@ func CreateTenant() web.HandlerFunc { return c.Failure(err) } - c.Enqueue(tasks.SendSignUpEmail(action, web.TenantBaseURL(c, createTenant.Result))) + c.Enqueue(tasks.SendSignUpEmail(action, siteURL)) + } + + if status == enum.TenantActive && user.Email != "" { + c.Enqueue(tasks.SendWelcomeEmail(user.Name, user.Email, siteURL)) + } + + // Handle userlist. + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListCreateCompany(*createTenant.Result, *user)) } return c.Ok(web.Map{}) } } -//SignUp is the entry point for installation / signup +// SignUp is the entry point for installation / signup func SignUp() web.HandlerFunc { return func(c *web.Context) error { if env.Config.SignUpDisabled { @@ -186,6 +197,8 @@ func VerifySignUpKey() web.HandlerFunc { webutil.AddAuthUserCookie(c, user) + c.Enqueue(tasks.SendWelcomeEmail(user.Name, user.Email, c.BaseURL())) + return c.Redirect(c.BaseURL()) } } diff --git a/app/handlers/signup_test.go b/app/handlers/signup_test.go index 4f3666118..e0a07540e 100644 --- a/app/handlers/signup_test.go +++ b/app/handlers/signup_test.go @@ -133,6 +133,12 @@ func TestCreateTenantHandler_WithSocialAccount(t *testing.T) { var newTenant *cmd.CreateTenant bus.AddHandler(func(ctx context.Context, c *cmd.CreateTenant) error { newTenant = c + c.Result = &entity.Tenant{ + ID: 1, + Name: c.Name, + Subdomain: c.Subdomain, + Status: enum.TenantActive, + } return nil }) @@ -190,6 +196,12 @@ func TestCreateTenantHandler_SingleHost_WithSocialAccount(t *testing.T) { var newTenant *cmd.CreateTenant bus.AddHandler(func(ctx context.Context, c *cmd.CreateTenant) error { newTenant = c + newTenant.Result = &entity.Tenant{ + ID: 1, + Name: c.Name, + Subdomain: c.Subdomain, + Status: enum.TenantActive, + } return nil }) diff --git a/app/handlers/webhooks/paddle.go b/app/handlers/webhooks/paddle.go index fe085b48e..9469b6e56 100644 --- a/app/handlers/webhooks/paddle.go +++ b/app/handlers/webhooks/paddle.go @@ -15,11 +15,13 @@ import ( "github.com/getfider/fider/app/models/cmd" "github.com/getfider/fider/app/models/dto" + "github.com/getfider/fider/app/models/enum" "github.com/getfider/fider/app/pkg/bus" "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/pkg/errors" "github.com/getfider/fider/app/pkg/log" "github.com/getfider/fider/app/pkg/web" + "github.com/getfider/fider/app/tasks" ) // IncomingPaddleWebhook handles all incoming requests from Paddle Webhooks @@ -66,6 +68,14 @@ func handlePaddleSubscriptionCreated(c *web.Context, params url.Values) error { return c.Failure(err) } + // Handle userlist. + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListUpdateCompany(&dto.UserListUpdateCompany{ + TenantID: passthrough.TenantID, + BillingStatus: enum.BillingActive, + })) + } + return c.Ok(web.Map{}) } @@ -91,6 +101,14 @@ func handlePaddleSubscriptionCancelled(c *web.Context, params url.Values) error return c.Failure(err) } + // Handle userlist. + if env.Config.UserList.Enabled { + c.Enqueue(tasks.UserListUpdateCompany(&dto.UserListUpdateCompany{ + TenantID: passthrough.TenantID, + BillingStatus: enum.BillingCancelled, + })) + } + return c.Ok(web.Map{}) } diff --git a/app/jobs/lock_expired_tenants_job.go b/app/jobs/lock_expired_tenants_job.go index f29209086..3128ff0a1 100644 --- a/app/jobs/lock_expired_tenants_job.go +++ b/app/jobs/lock_expired_tenants_job.go @@ -3,7 +3,9 @@ package jobs import ( "github.com/getfider/fider/app/models/cmd" "github.com/getfider/fider/app/models/dto" + "github.com/getfider/fider/app/models/enum" "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/pkg/log" ) @@ -25,5 +27,16 @@ func (e LockExpiredTenantsJobHandler) Run(ctx Context) error { "Count": c.NumOfTenantsLocked, }) + // Handle userlist + if env.Config.UserList.Enabled && c.NumOfTenantsLocked > 0 { + for _, tenant := range c.TenantsLocked { + err := bus.Dispatch(ctx, &cmd.UserListUpdateCompany{TenantId: tenant, BillingStatus: enum.BillingCancelled}) + if err != nil { + return err + } + } + + } + return nil } diff --git a/app/jobs/trial_reminder_job.go b/app/jobs/trial_reminder_job.go index af24659a4..fa5ce44a8 100644 --- a/app/jobs/trial_reminder_job.go +++ b/app/jobs/trial_reminder_job.go @@ -47,8 +47,8 @@ func (e TrialReminderJobHandler) Run(ctx Context) error { if len(to) > 0 { bus.Publish(ctx, &cmd.SendMail{ From: dto.Recipient{ - Name: "Guilherme", - Address: "goenning@fider.io", + Name: "Fider", + Address: "contact@fider.io", }, To: to, TemplateName: e.TemplateName, diff --git a/app/middlewares/compress_test.go b/app/middlewares/compress_test.go index b56196d7e..23036bd91 100644 --- a/app/middlewares/compress_test.go +++ b/app/middlewares/compress_test.go @@ -2,7 +2,7 @@ package middlewares_test import ( "compress/gzip" - "io/ioutil" + "io" "net/http" "testing" @@ -31,7 +31,7 @@ func TestCompress(t *testing.T) { Execute(handler) reader, _ := gzip.NewReader(response.Body) - bytes, _ := ioutil.ReadAll(reader) + bytes, _ := io.ReadAll(reader) Expect(bytes).Equals([]byte(data)) Expect(status).Equals(http.StatusOK) Expect(response.Header().Get("Vary")).Equals("Accept-Encoding") diff --git a/app/middlewares/security.go b/app/middlewares/security.go index 6cfdc3342..c48216809 100644 --- a/app/middlewares/security.go +++ b/app/middlewares/security.go @@ -28,3 +28,16 @@ func Secure() web.MiddlewareFunc { } } } + +// Secure middleware is responsible for blocking CSRF attacks +func CSRF() web.MiddlewareFunc { + return func(next web.HandlerFunc) web.HandlerFunc { + return func(c *web.Context) error { + var isWriteRequest = c.Request.Method == "POST" || c.Request.Method == "PUT" || c.Request.Method == "DELETE" + if isWriteRequest && !c.IsAjax() { + return c.Forbidden() + } + return next(c) + } + } +} diff --git a/app/models/cmd/billing.go b/app/models/cmd/billing.go index 996ff89ac..d211fb3d8 100644 --- a/app/models/cmd/billing.go +++ b/app/models/cmd/billing.go @@ -28,4 +28,5 @@ type CancelBillingSubscription struct { type LockExpiredTenants struct { //Output NumOfTenantsLocked int64 + TenantsLocked []int } diff --git a/app/models/cmd/reaction.go b/app/models/cmd/reaction.go new file mode 100644 index 000000000..36782deb9 --- /dev/null +++ b/app/models/cmd/reaction.go @@ -0,0 +1,10 @@ +package cmd + +import "github.com/getfider/fider/app/models/entity" + +type ToggleCommentReaction struct { + Comment *entity.Comment + Emoji string + User *entity.User + Result bool +} diff --git a/app/models/cmd/userlist.go b/app/models/cmd/userlist.go new file mode 100644 index 000000000..2da89f581 --- /dev/null +++ b/app/models/cmd/userlist.go @@ -0,0 +1,32 @@ +package cmd + +import "github.com/getfider/fider/app/models/enum" + +type UserListCreateCompany struct { + Name string + TenantId int + SignedUpAt string + BillingStatus string + Subdomain string + UserId int + UserEmail string + UserName string +} + +type UserListUpdateCompany struct { + TenantId int + Name string + BillingStatus enum.BillingStatus +} + +type UserListUpdateUser struct { + Id int + TenantId int + Email string + Name string +} + +type UserListHandleRoleChange struct { + Id int + Role enum.Role +} diff --git a/app/models/dto/userlist.go b/app/models/dto/userlist.go new file mode 100644 index 000000000..8679684d9 --- /dev/null +++ b/app/models/dto/userlist.go @@ -0,0 +1,9 @@ +package dto + +import "github.com/getfider/fider/app/models/enum" + +type UserListUpdateCompany struct { + TenantID int + Name string + BillingStatus enum.BillingStatus +} diff --git a/app/models/entity/comment.go b/app/models/entity/comment.go index 43be67fdd..b0ef76b98 100644 --- a/app/models/entity/comment.go +++ b/app/models/entity/comment.go @@ -2,13 +2,20 @@ package entity import "time" -//Comment represents an user comment on an post +type ReactionCounts struct { + Emoji string `json:"emoji"` + Count int `json:"count"` + IncludesMe bool `json:"includesMe"` +} + +// Comment represents an user comment on an post type Comment struct { - ID int `json:"id"` - Content string `json:"content"` - CreatedAt time.Time `json:"createdAt"` - User *User `json:"user"` - Attachments []string `json:"attachments,omitempty"` - EditedAt *time.Time `json:"editedAt,omitempty"` - EditedBy *User `json:"editedBy,omitempty"` + ID int `json:"id"` + Content string `json:"content"` + CreatedAt time.Time `json:"createdAt"` + User *User `json:"user"` + Attachments []string `json:"attachments,omitempty"` + EditedAt *time.Time `json:"editedAt,omitempty"` + EditedBy *User `json:"editedBy,omitempty"` + ReactionCounts []ReactionCounts `json:"reactionCounts,omitempty"` } diff --git a/app/models/entity/notification.go b/app/models/entity/notification.go index 385876920..28dc81275 100644 --- a/app/models/entity/notification.go +++ b/app/models/entity/notification.go @@ -1,12 +1,21 @@ package entity -import "time" +import ( + "time" + + "github.com/getfider/fider/app/models/enum" +) // Notification is the system generated notification entity type Notification struct { - ID int `json:"id" db:"id"` - Title string `json:"title" db:"title"` - Link string `json:"link" db:"link"` - Read bool `json:"read" db:"read"` - CreatedAt time.Time `json:"createdAt" db:"created_at"` + ID int `json:"id" db:"id"` + Title string `json:"title" db:"title"` + Link string `json:"link" db:"link"` + Read bool `json:"read" db:"read"` + CreatedAt time.Time `json:"createdAt" db:"created_at"` + AuthorName string `json:"authorName" db:"name"` + AuthorID int `json:"-" db:"author_id"` + AvatarBlobKey string `json:"-" db:"avatar_bkey"` + AvatarType enum.AvatarType `json:"-" db:"avatar_type"` + AvatarURL string `json:"avatarURL,omitempty"` } diff --git a/app/models/entity/reaction.go b/app/models/entity/reaction.go new file mode 100644 index 000000000..3fbbd5a61 --- /dev/null +++ b/app/models/entity/reaction.go @@ -0,0 +1,12 @@ +package entity + +import "time" + +// Reaction represents a user's emoji reaction to a comment +type Reaction struct { + ID int `json:"id"` + Emoji string `json:"emoji"` + Comment *Comment `json:"-"` + User *User `json:"user"` + CreatedAt time.Time `json:"createdAt"` +} diff --git a/app/models/entity/user.go b/app/models/entity/user.go index bcf37e02b..8e270e293 100644 --- a/app/models/entity/user.go +++ b/app/models/entity/user.go @@ -1,8 +1,12 @@ package entity -import "github.com/getfider/fider/app/models/enum" +import ( + "encoding/json" -//User represents an user inside our application + "github.com/getfider/fider/app/models/enum" +) + +// User represents an user inside our application type User struct { ID int `json:"id"` Name string `json:"name"` @@ -16,7 +20,7 @@ type User struct { Status enum.UserStatus `json:"status"` } -//HasProvider returns true if current user has registered with given provider +// HasProvider returns true if current user has registered with given provider func (u *User) HasProvider(provider string) bool { for _, p := range u.Providers { if p.Name == provider { @@ -36,8 +40,24 @@ func (u *User) IsAdministrator() bool { return u.Role == enum.RoleAdministrator } -//UserProvider represents the relationship between an User and an Authentication provide +// UserProvider represents the relationship between an User and an Authentication provide type UserProvider struct { Name string UID string } + +// UserWithEmail is a wrapper around User that includes the email field when marshaling to JSON +type UserWithEmail struct { + *User +} + +func (umc UserWithEmail) MarshalJSON() ([]byte, error) { + type Alias User // Prevent recursion + return json.Marshal(&struct { + *Alias + Email string `json:"email"` + }{ + Alias: (*Alias)(umc.User), + Email: umc.User.Email, + }) +} diff --git a/app/models/entity/user_test.go b/app/models/entity/user_test.go new file mode 100644 index 000000000..af391886b --- /dev/null +++ b/app/models/entity/user_test.go @@ -0,0 +1,55 @@ +package entity_test + +import ( + "encoding/json" + "testing" + + "github.com/getfider/fider/app/models/entity" + . "github.com/getfider/fider/app/pkg/assert" +) + +func TestUserWithEmail_MarshalJSON(t *testing.T) { + + RegisterT(t) + user := entity.UserWithEmail{ + User: &entity.User{ + ID: 1, + Name: "John Doe", + Email: "johndoe@example.com", + Role: 1, + Status: 1, + }, + } + + expectedJSON := `{"id":1,"name":"John Doe","role":"visitor","status":"active","email":"johndoe@example.com"}` + + jsonData, err := json.Marshal(user) + if err != nil { + t.Errorf("Failed to marshal user to JSON: %v", err) + } + + Expect(string(jsonData)).Equals(expectedJSON) + +} + +func TestUser_MarshalJSON(t *testing.T) { + + RegisterT(t) + user := entity.User{ + ID: 1, + Name: "John Doe", + Email: "johndoe@example.com", + Role: 1, + Status: 1, + } + + expectedJSON := `{"id":1,"name":"John Doe","role":"visitor","status":"active"}` + + jsonData, err := json.Marshal(user) + if err != nil { + t.Errorf("Failed to marshal user to JSON: %v", err) + } + + Expect(string(jsonData)).Equals(expectedJSON) + +} diff --git a/app/pkg/csv/csv_test.go b/app/pkg/csv/csv_test.go index fbbc1b80d..081ad992d 100644 --- a/app/pkg/csv/csv_test.go +++ b/app/pkg/csv/csv_test.go @@ -1,7 +1,7 @@ package csv_test import ( - "io/ioutil" + "os" "testing" "time" @@ -15,7 +15,7 @@ func TestExportPostsToCSV_Empty(t *testing.T) { RegisterT(t) posts := []*entity.Post{} - expected, err := ioutil.ReadFile("./testdata/empty.csv") + expected, err := os.ReadFile("./testdata/empty.csv") Expect(err).IsNil() actual, err := csv.FromPosts(posts) Expect(err).IsNil() @@ -29,7 +29,7 @@ func TestExportPostsToCSV_OnePost(t *testing.T) { declinedPost, } - expected, err := ioutil.ReadFile("./testdata/one-post.csv") + expected, err := os.ReadFile("./testdata/one-post.csv") Expect(err).IsNil() actual, err := csv.FromPosts(posts) Expect(err).IsNil() @@ -45,7 +45,7 @@ func TestExportPostsToCSV_MorePosts(t *testing.T) { duplicatePost, } - expected, err := ioutil.ReadFile("./testdata/more-posts.csv") + expected, err := os.ReadFile("./testdata/more-posts.csv") Expect(err).IsNil() actual, err := csv.FromPosts(posts) Expect(err).IsNil() diff --git a/app/pkg/dbx/dbx.go b/app/pkg/dbx/dbx.go index 1b21f95d4..87d593612 100644 --- a/app/pkg/dbx/dbx.go +++ b/app/pkg/dbx/dbx.go @@ -3,7 +3,7 @@ package dbx import ( "context" "database/sql" - "io/ioutil" + "os" "reflect" "time" @@ -53,7 +53,7 @@ func BeginTx(ctx context.Context) (*Trx, error) { } func load(path string) { - content, err := ioutil.ReadFile(env.Path(path)) + content, err := os.ReadFile(env.Path(path)) if err != nil { panic(wrap(err, "failed to read file %s", path)) } @@ -71,7 +71,7 @@ func Seed() { } } -//Trx represents a Database transaction +// Trx represents a Database transaction type Trx struct { tx *sql.Tx ctx context.Context @@ -209,7 +209,7 @@ func (trx *Trx) Count(command string, args ...any) (int, error) { return count, nil } -//Select all matched rows bind to given data +// Select all matched rows bind to given data func (trx *Trx) Select(data any, command string, args ...any) error { if log.IsEnabled(log.DEBUG) { command = formatter.Replace(command) @@ -250,7 +250,7 @@ func (trx *Trx) Select(data any, command string, args ...any) error { return nil } -//Query all matched rows and return raw sql.Rows +// Query all matched rows and return raw sql.Rows func (trx *Trx) Query(command string, args ...any) (*sql.Rows, error) { if log.IsEnabled(log.DEBUG) { command = formatter.Replace(command) diff --git a/app/pkg/dbx/dbx_test.go b/app/pkg/dbx/dbx_test.go index db7db1abd..e6384f55d 100644 --- a/app/pkg/dbx/dbx_test.go +++ b/app/pkg/dbx/dbx_test.go @@ -3,7 +3,6 @@ package dbx_test import ( "context" "encoding/json" - "io/ioutil" "os" "testing" @@ -262,7 +261,7 @@ func TestByteArray(t *testing.T) { Content []byte `db:"file"` } - fileContent, err := ioutil.ReadFile(env.Path("/favicon.png")) + fileContent, err := os.ReadFile(env.Path("/favicon.png")) Expect(err).IsNil() _, err = trx.Execute(` diff --git a/app/pkg/dbx/migrate.go b/app/pkg/dbx/migrate.go index bfd04cea2..9204c5cf7 100644 --- a/app/pkg/dbx/migrate.go +++ b/app/pkg/dbx/migrate.go @@ -4,7 +4,6 @@ import ( "context" "database/sql" stdErrors "errors" - "io/ioutil" "os" "sort" "strconv" @@ -92,7 +91,7 @@ func Migrate(ctx context.Context, path string) error { func runMigration(ctx context.Context, version int, path, fileName string) error { filePath := env.Path(path + "/" + fileName) - content, err := ioutil.ReadFile(filePath) + content, err := os.ReadFile(filePath) if err != nil { return errors.Wrap(err, "failed to read file '%s'", filePath) } diff --git a/app/pkg/dbx/setup.sql b/app/pkg/dbx/setup.sql index 4f1f7185e..d10a8ed7c 100644 --- a/app/pkg/dbx/setup.sql +++ b/app/pkg/dbx/setup.sql @@ -30,3 +30,15 @@ INSERT INTO users (name, email, tenant_id, created_at, role, status, avatar_type VALUES ('The Hulk', 'the.hulk@avengers.com', 2, now(), 1, 1, 2, ''); INSERT INTO user_providers (user_id, tenant_id, provider, provider_uid, created_at) VALUES (5, 2, 'google', 'GO1111', now()); + +-- Create a tenant that has reached the end of it's trial period +INSERT INTO tenants (name, subdomain, created_at, cname, invitation, welcome_message, status, is_private, custom_css, logo_bkey, locale, is_email_auth_allowed) +VALUES ('Trial Expired', 'trial-expired', now(), 'feedback.trial-expired.com', '', '', 1, false, '', '', 'en', true); +INSERT INTO tenants_billing (tenant_id, paddle_plan_id, paddle_subscription_id, status, subscription_ends_at, trial_ends_at) +VALUES (3, 1, 1,1, now(), CURRENT_DATE - INTERVAL '10 days'); +INSERT INTO users (name, email, tenant_id, created_at, role, status, avatar_type, avatar_bkey) +VALUES ('Trial Expired', 'trial.expired@trial-expired.com', 3, now(), 3, 1, 2, ''); +INSERT INTO user_providers (user_id, tenant_id, provider, provider_uid, created_at) +VALUES (6, 3, 'facebook', 'FB3333', now()); + + diff --git a/app/pkg/env/env.go b/app/pkg/env/env.go index e9221d509..027036338 100644 --- a/app/pkg/env/env.go +++ b/app/pkg/env/env.go @@ -68,6 +68,10 @@ type config struct { CDN struct { Host string `env:"CDN_HOST"` } + UserList struct { + Enabled bool `env:"USER_LIST_ENABLED,default=false"` + ApiKey string `env:"USER_LIST_APIKEY"` + } Log struct { Level string `env:"LOG_LEVEL,default=INFO"` Structured bool `env:"LOG_STRUCTURED,default=false"` diff --git a/app/pkg/i18n/i18n.go b/app/pkg/i18n/i18n.go index a3cf003f5..77fc55047 100644 --- a/app/pkg/i18n/i18n.go +++ b/app/pkg/i18n/i18n.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "os" "sync" "github.com/getfider/fider/app" @@ -53,7 +53,7 @@ func getLocaleData(locale string) localeData { return item } - content, err := ioutil.ReadFile(env.Path(fmt.Sprintf("locale/%s/server.json", locale))) + content, err := os.ReadFile(env.Path(fmt.Sprintf("locale/%s/server.json", locale))) if err != nil { panic(errors.Wrap(err, "failed to read locale file")) } diff --git a/app/pkg/jwt/jwt.go b/app/pkg/jwt/jwt.go index 8ba5f1126..33e27fe85 100644 --- a/app/pkg/jwt/jwt.go +++ b/app/pkg/jwt/jwt.go @@ -43,6 +43,13 @@ type OAuthClaims struct { Metadata } +// OAuthStateClaims represents what goes into JWT tokens used for OAuth state parameter +type OAuthStateClaims struct { + Redirect string `json:"oauthstate/redirect"` + Identifier string `json:"oauthstate/identifier"` + Metadata +} + // Encode creates new JWT token with given claims func Encode(claims jwtgo.Claims) (string, error) { jwtToken := jwtgo.NewWithClaims(jwtgo.GetSigningMethod("HS256"), claims) @@ -73,6 +80,16 @@ func DecodeOAuthClaims(token string) (*OAuthClaims, error) { return claims, nil } +// DecodeOAuthStateClaims extract OAuthClaims from given JWT token +func DecodeOAuthStateClaims(token string) (*OAuthStateClaims, error) { + claims := &OAuthStateClaims{} + err := decode(token, claims) + if err != nil { + return nil, errors.Wrap(err, "failed to decode OAuthState claims") + } + return claims, nil +} + func decode(token string, claims jwtgo.Claims) error { jwtToken, err := jwtgo.ParseWithClaims(token, claims, func(t *jwtgo.Token) (any, error) { if _, ok := t.Method.(*jwtgo.SigningMethodHMAC); !ok { diff --git a/app/pkg/log/parse.go b/app/pkg/log/parse.go index ecc0d148e..f90c746f8 100644 --- a/app/pkg/log/parse.go +++ b/app/pkg/log/parse.go @@ -13,7 +13,7 @@ var placeholderFinder = regexp.MustCompile("@{.*?}") // Parse is used to merge props into format and return a text message func Parse(format string, props dto.Props, colorize bool) string { - if props == nil || len(props) == 0 { + if len(props) == 0 { return format } diff --git a/app/pkg/mock/server.go b/app/pkg/mock/server.go index 4ca3bc04e..331c62bac 100644 --- a/app/pkg/mock/server.go +++ b/app/pkg/mock/server.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "net/http/httptest" "net/url" @@ -171,7 +171,7 @@ func (s *Server) ExecuteAsPage(handler web.HandlerFunc) (int, *web.Props) { } func toJSONQuery(response *httptest.ResponseRecorder) *jsonq.Query { - b, err := ioutil.ReadAll(response.Body) + b, err := io.ReadAll(response.Body) if err != nil { panic(err) } diff --git a/app/pkg/validate/subdomain.go b/app/pkg/validate/subdomain.go index f34d3972c..fa7ed62ce 100644 --- a/app/pkg/validate/subdomain.go +++ b/app/pkg/validate/subdomain.go @@ -13,7 +13,7 @@ import ( var domainRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]$") -//Subdomain validates given subdomain +// Subdomain validates given subdomain func Subdomain(ctx context.Context, subdomain string) ([]string, error) { subdomain = strings.ToLower(subdomain) @@ -33,8 +33,8 @@ func Subdomain(ctx context.Context, subdomain string) ([]string, error) { case "signup", "fider", "login", "customers", "admin", "setup", "about", "wecanhearyou", "dev", "mail", "billing", "www", "web", "translate", - "help", "support", "status", "staging", "cdn", "assets", "live", - "manage", "mgmt", "platform", "production", "development": + "love", "api", "reports", "help", "support", "status", "staging", "cdn", + "assets", "live", "manage", "mgmt", "platform", "production", "development": return []string{fmt.Sprintf("%s is a reserved subdomain.", subdomain)}, nil } diff --git a/app/pkg/validate/upload_test.go b/app/pkg/validate/upload_test.go index 9f3f24ad3..f4a2c0fb2 100644 --- a/app/pkg/validate/upload_test.go +++ b/app/pkg/validate/upload_test.go @@ -2,7 +2,7 @@ package validate_test import ( "context" - "io/ioutil" + "os" "testing" "github.com/getfider/fider/app/models/dto" @@ -28,7 +28,7 @@ func TestValidateImageUpload(t *testing.T) { } for _, testCase := range testCases { - img, _ := ioutil.ReadFile(env.Path(testCase.fileName)) + img, _ := os.ReadFile(env.Path(testCase.fileName)) upload := &dto.ImageUpload{ Upload: &dto.ImageUploadData{ @@ -49,7 +49,7 @@ func TestValidateImageUpload(t *testing.T) { func TestValidateImageUpload_ExactRatio(t *testing.T) { RegisterT(t) - img, _ := ioutil.ReadFile(env.Path("/app/pkg/web/testdata/logo3-200w.gif")) + img, _ := os.ReadFile(env.Path("/app/pkg/web/testdata/logo3-200w.gif")) opts := validate.ImageUploadOpts{ IsRequired: false, MaxKilobytes: 200, @@ -126,7 +126,7 @@ func TestValidateImageUpload_Required(t *testing.T) { func TestValidateMultiImageUpload(t *testing.T) { RegisterT(t) - img, _ := ioutil.ReadFile(env.Path("/app/pkg/web/testdata/logo3-200w.gif")) + img, _ := os.ReadFile(env.Path("/app/pkg/web/testdata/logo3-200w.gif")) uploads := []*dto.ImageUpload{ { @@ -157,7 +157,7 @@ func TestValidateMultiImageUpload(t *testing.T) { func TestValidateMultiImageUpload_Existing(t *testing.T) { RegisterT(t) - img, _ := ioutil.ReadFile(env.Path("/app/pkg/web/testdata/logo3-200w.gif")) + img, _ := os.ReadFile(env.Path("/app/pkg/web/testdata/logo3-200w.gif")) uploads := []*dto.ImageUpload{ { diff --git a/app/pkg/web/binder_test.go b/app/pkg/web/binder_test.go index 81fa28d68..30e655957 100644 --- a/app/pkg/web/binder_test.go +++ b/app/pkg/web/binder_test.go @@ -3,7 +3,7 @@ package web_test import ( "encoding/base64" "fmt" - "io/ioutil" + "os" "testing" . "github.com/getfider/fider/app/pkg/assert" @@ -61,7 +61,7 @@ func TestDefaultBinder_TrimSpaces(t *testing.T) { func TestDefaultBinder_Base64ToBytes(t *testing.T) { RegisterT(t) - resume, _ := ioutil.ReadFile(env.Path("./README.md")) + resume, _ := os.ReadFile(env.Path("./README.md")) resumeBase64 := base64.StdEncoding.EncodeToString(resume) type user struct { @@ -82,7 +82,7 @@ func TestDefaultBinder_Base64ToBytes(t *testing.T) { func TestDefaultBinder_NestedJson(t *testing.T) { RegisterT(t) - resume, _ := ioutil.ReadFile(env.Path("./README.md")) + resume, _ := os.ReadFile(env.Path("./README.md")) resumeBase64 := base64.StdEncoding.EncodeToString(resume) type user struct { diff --git a/app/pkg/web/context.go b/app/pkg/web/context.go index e566a03f6..0ebca912b 100644 --- a/app/pkg/web/context.go +++ b/app/pkg/web/context.go @@ -63,7 +63,7 @@ const CookieAuthName = "auth" // CookieSignUpAuthName is the name of the cookie that holds the temporary Authentication Token const CookieSignUpAuthName = "__signup_auth" -//Context shared between http pipeline +// Context shared between http pipeline type Context struct { context.Context Response Response @@ -75,7 +75,7 @@ type Context struct { tasks []worker.Task } -//NewContext creates a new web Context +// NewContext creates a new web Context func NewContext(engine *Engine, req *http.Request, rw http.ResponseWriter, params StringMap) *Context { contextID := rand.String(32) @@ -99,28 +99,28 @@ func NewContext(engine *Engine, req *http.Request, rw http.ResponseWriter, param } } -//Engine returns main HTTP engine +// Engine returns main HTTP engine func (c *Context) Engine() *Engine { return c.engine } -//SessionID returns the current session ID +// SessionID returns the current session ID func (c *Context) SessionID() string { return c.sessionID } -//SetSessionID sets the session ID on current context +// SetSessionID sets the session ID on current context func (c *Context) SetSessionID(id string) { c.sessionID = id c.Context = log.WithProperty(c.Context, log.PropertyKeySessionID, id) } -//ContextID returns the unique id for this context +// ContextID returns the unique id for this context func (c *Context) ContextID() string { return c.id } -//Commit everything that is pending on current context +// Commit everything that is pending on current context func (c *Context) Commit() error { trx, ok := c.Value(app.TransactionCtxKey).(*dbx.Trx) if ok && trx != nil { @@ -136,7 +136,7 @@ func (c *Context) Commit() error { return nil } -//Rollback everything that is pending on current context +// Rollback everything that is pending on current context func (c *Context) Rollback() { trx, ok := c.Value(app.TransactionCtxKey).(*dbx.Trx) if ok && trx != nil { @@ -144,13 +144,13 @@ func (c *Context) Rollback() { } } -//Enqueue given task to be processed in background +// Enqueue given task to be processed in background func (c *Context) Enqueue(task worker.Task) { task.OriginContext = c c.tasks = append(c.tasks, task) } -//Tenant returns current tenant +// Tenant returns current tenant func (c *Context) Tenant() *entity.Tenant { tenant, ok := c.Value(app.TenantCtxKey).(*entity.Tenant) if ok { @@ -159,7 +159,7 @@ func (c *Context) Tenant() *entity.Tenant { return nil } -//SetTenant update HTTP context with current tenant +// SetTenant update HTTP context with current tenant func (c *Context) SetTenant(tenant *entity.Tenant) { if tenant != nil { c.Set(log.PropertyKeyTenantID, tenant.ID) @@ -168,7 +168,7 @@ func (c *Context) SetTenant(tenant *entity.Tenant) { c.Set(app.TenantCtxKey, tenant) } -//Bind context values into given model +// Bind context values into given model func (c *Context) Bind(i any) error { err := c.engine.binder.Bind(i, c) if err != nil { @@ -177,7 +177,7 @@ func (c *Context) Bind(i any) error { return nil } -//BindTo context values into given model +// BindTo context values into given model func (c *Context) BindTo(i actions.Actionable) *validate.Result { err := c.engine.binder.Bind(i, c) if err != nil { @@ -200,19 +200,19 @@ func (c *Context) BindTo(i actions.Actionable) *validate.Result { return i.Validate(c, c.User()) } -//IsAuthenticated returns true if user is authenticated +// IsAuthenticated returns true if user is authenticated func (c *Context) IsAuthenticated() bool { return c.Value(app.UserCtxKey) != nil } -//IsAjax returns true if request is AJAX +// IsAjax returns true if request is AJAX func (c *Context) IsAjax() bool { accept := c.Request.GetHeader("Accept") contentType := c.Request.GetHeader("Content-Type") return strings.Contains(accept, JSONContentType) || strings.Contains(contentType, JSONContentType) } -//Unauthorized returns a 401 error response +// Unauthorized returns a 401 error response func (c *Context) Unauthorized() error { if c.IsAjax() { return c.JSON(http.StatusUnauthorized, Map{}) @@ -225,7 +225,7 @@ func (c *Context) Unauthorized() error { }) } -//Forbidden returns a 403 error response +// Forbidden returns a 403 error response func (c *Context) Forbidden() error { if c.IsAjax() { return c.JSON(http.StatusForbidden, Map{}) @@ -238,7 +238,7 @@ func (c *Context) Forbidden() error { }) } -//NotFound returns a 404 error page +// NotFound returns a 404 error page func (c *Context) NotFound() error { if c.IsAjax() { return c.JSON(http.StatusNotFound, Map{}) @@ -251,7 +251,7 @@ func (c *Context) NotFound() error { }) } -//Gone returns a 410 error page +// Gone returns a 410 error page func (c *Context) Gone() error { return c.Page(http.StatusGone, Props{ Page: "Error/Error410.page", @@ -260,7 +260,7 @@ func (c *Context) Gone() error { }) } -//Failure returns a 500 page +// Failure returns a 500 page func (c *Context) Failure(err error) error { err = errors.StackN(err, 1) cause := errors.Cause(err) @@ -283,7 +283,7 @@ func (c *Context) Failure(err error) error { return err } -//HandleValidation handles given validation result property to return 400 or 500 +// HandleValidation handles given validation result property to return 400 or 500 func (c *Context) HandleValidation(result *validate.Result) error { if result.Err != nil { return c.Failure(result.Err) @@ -298,24 +298,24 @@ func (c *Context) HandleValidation(result *validate.Result) error { }) } -//Attachment returns an attached file +// Attachment returns an attached file func (c *Context) Attachment(fileName, contentType string, file []byte) error { c.Response.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", fileName)) return c.Blob(http.StatusOK, contentType, file) } -//Ok returns 200 OK with JSON result +// Ok returns 200 OK with JSON result func (c *Context) Ok(data any) error { return c.JSON(http.StatusOK, data) } -//BadRequest returns 400 BadRequest with JSON result +// BadRequest returns 400 BadRequest with JSON result func (c *Context) BadRequest(dict Map) error { return c.JSON(http.StatusBadRequest, dict) } -//Page returns a page with given variables +// Page returns a page with given variables func (c *Context) Page(code int, props Props) error { if c.IsAjax() { return c.JSON(code, Map{}) @@ -327,12 +327,12 @@ func (c *Context) Page(code int, props Props) error { return c.Blob(code, UTF8HTMLContentType, buf.Bytes()) } -//AddParam add a single param to route parameters list +// AddParam add a single param to route parameters list func (c *Context) AddParam(name, value string) { c.params[name] = value } -//User returns authenticated user +// User returns authenticated user func (c *Context) User() *entity.User { user, ok := c.Value(app.UserCtxKey).(*entity.User) if ok { @@ -341,7 +341,7 @@ func (c *Context) User() *entity.User { return nil } -//SetUser update HTTP context with current user +// SetUser update HTTP context with current user func (c *Context) SetUser(user *entity.User) { if user != nil { c.Context = log.WithProperty(c.Context, log.PropertyKeyUserID, user.ID) @@ -349,7 +349,7 @@ func (c *Context) SetUser(user *entity.User) { c.Set(app.UserCtxKey, user) } -//AddCookie adds a cookie +// AddCookie adds a cookie func (c *Context) AddCookie(name, value string, expires time.Time) *http.Cookie { cookie := &http.Cookie{ Name: name, @@ -363,7 +363,7 @@ func (c *Context) AddCookie(name, value string, expires time.Time) *http.Cookie return cookie } -//RemoveCookie removes a cookie +// RemoveCookie removes a cookie func (c *Context) RemoveCookie(name string) { http.SetCookie(&c.Response, &http.Cookie{ Name: name, @@ -375,17 +375,17 @@ func (c *Context) RemoveCookie(name string) { }) } -//BaseURL returns base URL +// BaseURL returns base URL func (c *Context) BaseURL() string { return c.Request.BaseURL() } -//QueryParam returns querystring parameter for given key +// QueryParam returns querystring parameter for given key func (c *Context) QueryParam(key string) string { return c.Request.URL.Query().Get(key) } -//QueryParamAsInt returns querystring parameter for given key +// QueryParamAsInt returns querystring parameter for given key func (c *Context) QueryParamAsInt(key string) (int, error) { value := c.QueryParam(key) if value == "" { @@ -398,7 +398,7 @@ func (c *Context) QueryParamAsInt(key string) (int, error) { return intValue, nil } -//QueryParamAsArray returns querystring parameter for given key as an array +// QueryParamAsArray returns querystring parameter for given key as an array func (c *Context) QueryParamAsArray(key string) []string { param := c.QueryParam(key) if param != "" { @@ -407,7 +407,7 @@ func (c *Context) QueryParamAsArray(key string) []string { return []string{} } -//Param returns parameter as string +// Param returns parameter as string func (c *Context) Param(name string) string { if c.params == nil { return "" @@ -417,7 +417,7 @@ func (c *Context) Param(name string) string { return strings.TrimLeft(c.params[name], "/") } -//ParamAsInt returns parameter as int +// ParamAsInt returns parameter as int func (c *Context) ParamAsInt(name string) (int, error) { value := c.Param(name) intValue, err := strconv.Atoi(value) @@ -427,7 +427,7 @@ func (c *Context) ParamAsInt(name string) (int, error) { return intValue, nil } -//GetMatchedRoutePath returns the Matched Route name +// GetMatchedRoutePath returns the Matched Route name func (c *Context) GetMatchedRoutePath() string { return "/" + c.Param(httprouter.MatchedRoutePathParam) } @@ -473,6 +473,11 @@ func (c *Context) Blob(code int, contentType string, b []byte) error { c.Response.Header().Set("Content-Type", contentType) c.Response.WriteHeader(code) + // Don't write any body for HEAD requests + if c.Request.Method == http.MethodHead { + return nil + } + _, err := c.Response.Write(b) if err != nil { return errors.Wrap(err, "failed to write response") @@ -528,7 +533,7 @@ func (c *Context) SetCanonicalURL(rawurl string) { } } -//TenantBaseURL returns base URL for a given tenant +// TenantBaseURL returns base URL for a given tenant func TenantBaseURL(ctx context.Context, tenant *entity.Tenant) string { if env.IsSingleHostMode() { return BaseURL(ctx) diff --git a/app/pkg/web/engine.go b/app/pkg/web/engine.go index 77c565f47..adf6f03e5 100644 --- a/app/pkg/web/engine.go +++ b/app/pkg/web/engine.go @@ -3,7 +3,7 @@ package web import ( "context" "fmt" - "io/ioutil" + "io" stdLog "log" "net/http" "os" @@ -51,13 +51,13 @@ func (h *notFoundHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) _ = h.handler(ctx) } -//HandlerFunc represents an HTTP handler +// HandlerFunc represents an HTTP handler type HandlerFunc func(*Context) error -//MiddlewareFunc represents an HTTP middleware +// MiddlewareFunc represents an HTTP middleware type MiddlewareFunc func(HandlerFunc) HandlerFunc -//Engine is our web engine wrapper +// Engine is our web engine wrapper type Engine struct { context.Context mux *httprouter.Router @@ -70,7 +70,7 @@ type Engine struct { cache *cache.Cache } -//New creates a new Engine +// New creates a new Engine func New() *Engine { ctx := context.Background() ctx = log.WithProperties(ctx, dto.Props{ @@ -94,7 +94,7 @@ func New() *Engine { return router } -//Start the server. +// Start the server. func (e *Engine) Start(address string) { log.Info(e, "Application is starting") log.Infof(e, "Version: @{Version}", dto.Props{ @@ -114,7 +114,7 @@ func (e *Engine) Start(address string) { keyFilePath = env.Etc(env.Config.TLS.CertificateKey) } - stdLog.SetOutput(ioutil.Discard) + stdLog.SetOutput(io.Discard) e.webServer = &http.Server{ ReadTimeout: env.Config.HTTP.ReadTimeout, WriteTimeout: env.Config.HTTP.WriteTimeout, @@ -167,7 +167,7 @@ func (e *Engine) Start(address string) { } } -//Stop the server. +// Stop the server. func (e *Engine) Stop() error { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() @@ -199,17 +199,17 @@ func (e *Engine) Stop() error { return nil } -//Cache returns current cache +// Cache returns current cache func (e *Engine) Cache() *cache.Cache { return e.cache } -//Worker returns current worker reference +// Worker returns current worker reference func (e *Engine) Worker() worker.Worker { return e.worker } -//Group creates a new route group +// Group creates a new route group func (e *Engine) Group() *Group { g := &Group{ engine: e, @@ -218,7 +218,7 @@ func (e *Engine) Group() *Group { return g } -//Use adds a middleware to the root engine +// Use adds a middleware to the root engine func (e *Engine) Use(middleware MiddlewareFunc) { if middleware == nil { return @@ -227,27 +227,27 @@ func (e *Engine) Use(middleware MiddlewareFunc) { e.middlewares = append(e.middlewares, middleware) } -//Get handles HTTP GET requests +// Get handles HTTP GET requests func (e *Engine) Get(path string, handler HandlerFunc) { e.mux.Handle("GET", path, e.handle(e.middlewares, handler)) } -//Post handles HTTP POST requests +// Post handles HTTP POST requests func (e *Engine) Post(path string, handler HandlerFunc) { e.mux.Handle("POST", path, e.handle(e.middlewares, handler)) } -//Put handles HTTP PUT requests +// Put handles HTTP PUT requests func (e *Engine) Put(path string, handler HandlerFunc) { e.mux.Handle("PUT", path, e.handle(e.middlewares, handler)) } -//Delete handles HTTP DELETE requests +// Delete handles HTTP DELETE requests func (e *Engine) Delete(path string, handler HandlerFunc) { e.mux.Handle("DELETE", path, e.handle(e.middlewares, handler)) } -//NotFound register how to handle routes that are not found +// NotFound register how to handle routes that are not found func (e *Engine) NotFound(handler HandlerFunc) { e.mux.NotFound = ¬FoundHandler{ engine: e, @@ -271,13 +271,13 @@ func (e *Engine) handle(middlewares []MiddlewareFunc, handler HandlerFunc) httpr return h } -//Group is our router group wrapper +// Group is our router group wrapper type Group struct { engine *Engine middlewares []MiddlewareFunc } -//Group creates a new route group +// Group creates a new route group func (g *Group) Group() *Group { g2 := &Group{ engine: g.engine, @@ -286,27 +286,27 @@ func (g *Group) Group() *Group { return g2 } -//Use adds a middleware to current route stack +// Use adds a middleware to current route stack func (g *Group) Use(middleware MiddlewareFunc) { g.middlewares = append(g.middlewares, middleware) } -//Get handles HTTP GET requests +// Get handles HTTP GET requests func (g *Group) Get(path string, handler HandlerFunc) { g.engine.mux.Handle("GET", path, g.engine.handle(g.middlewares, handler)) } -//Post handles HTTP POST requests +// Post handles HTTP POST requests func (g *Group) Post(path string, handler HandlerFunc) { g.engine.mux.Handle("POST", path, g.engine.handle(g.middlewares, handler)) } -//Put handles HTTP PUT requests +// Put handles HTTP PUT requests func (g *Group) Put(path string, handler HandlerFunc) { g.engine.mux.Handle("PUT", path, g.engine.handle(g.middlewares, handler)) } -//Delete handles HTTP DELETE requests +// Delete handles HTTP DELETE requests func (g *Group) Delete(path string, handler HandlerFunc) { g.engine.mux.Handle("DELETE", path, g.engine.handle(g.middlewares, handler)) } diff --git a/app/pkg/web/engine_test.go b/app/pkg/web/engine_test.go index 0d7dc42fe..baffc039f 100644 --- a/app/pkg/web/engine_test.go +++ b/app/pkg/web/engine_test.go @@ -1,7 +1,7 @@ package web_test import ( - "io/ioutil" + "io" "net/http" "testing" @@ -96,7 +96,7 @@ func TestEngine_MiddlewareAfterHandler(t *testing.T) { resp, err = http.Get("http://127.0.0.1:8080/api/echo?name=John") Expect(err).IsNil() Expect(resp.StatusCode).Equals(http.StatusOK) - content, err := ioutil.ReadAll(resp.Body) + content, err := io.ReadAll(resp.Body) Expect(err).IsNil() Expect(string(content)).Equals("John") resp.Body.Close() diff --git a/app/pkg/web/renderer.go b/app/pkg/web/renderer.go index f1fa88278..32634989f 100644 --- a/app/pkg/web/renderer.go +++ b/app/pkg/web/renderer.go @@ -17,8 +17,6 @@ import ( "github.com/getfider/fider/app/pkg/log" "github.com/getfider/fider/app/pkg/tpl" - "io/ioutil" - "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/pkg/errors" ) @@ -44,7 +42,7 @@ type assetsFile struct { } `json:"namedChunkGroups"` } -//Renderer is the default HTML Render +// Renderer is the default HTML Render type Renderer struct { templates map[string]*template.Template assets *clientAssets @@ -87,7 +85,7 @@ func (r *Renderer) loadAssets() error { } defer jsonFile.Close() - jsonBytes, _ := ioutil.ReadAll(jsonFile) + jsonBytes, _ := io.ReadAll(jsonFile) file := &assetsFile{} err = json.Unmarshal([]byte(jsonBytes), file) if err != nil { @@ -131,7 +129,7 @@ func getClientAssets(assets []distAsset) *clientAssets { return clientAssets } -//Render a template based on parameters +// Render a template based on parameters func (r *Renderer) Render(w io.Writer, statusCode int, props Props, ctx *Context) { var err error diff --git a/app/pkg/web/renderer_test.go b/app/pkg/web/renderer_test.go index 91c533dfb..bc51497c1 100644 --- a/app/pkg/web/renderer_test.go +++ b/app/pkg/web/renderer_test.go @@ -3,8 +3,8 @@ package web_test import ( "bytes" "context" - "io/ioutil" "net/http" + "os" "strings" "testing" @@ -21,8 +21,8 @@ import ( ) func compareRendererResponse(buf *bytes.Buffer, fileName string, ctx *web.Context) { - // ioutil.WriteFile(env.Path(fileName), []byte(strings.Replace(buf.String(), ctx.ContextID(), "CONTEXT_ID", -1)), 0744) - bytes, err := ioutil.ReadFile(env.Path(fileName)) + // os.WriteFile(env.Path(fileName), []byte(strings.Replace(buf.String(), ctx.ContextID(), "CONTEXT_ID", -1)), 0744) + bytes, err := os.ReadFile(env.Path(fileName)) Expect(err).IsNil() Expect(strings.Replace(buf.String(), ctx.ContextID(), "CONTEXT_ID", -1)).Equals(string(bytes)) } diff --git a/app/pkg/web/request.go b/app/pkg/web/request.go index 87807ff51..39a9c1c4f 100644 --- a/app/pkg/web/request.go +++ b/app/pkg/web/request.go @@ -1,7 +1,7 @@ package web import ( - "io/ioutil" + "io" "net/http" "net/url" "regexp" @@ -12,7 +12,7 @@ import ( "github.com/getfider/fider/app/pkg/errors" ) -//Request wraps the http request object +// Request wraps the http request object type Request struct { instance *http.Request Method string @@ -43,7 +43,7 @@ func WrapRequest(request *http.Request) Request { var bodyBytes []byte if request.ContentLength > 0 { - bodyBytes, err = ioutil.ReadAll(request.Body) + bodyBytes, err = io.ReadAll(request.Body) if err != nil { panic(errors.Wrap(err, "failed to read body").Error()) } @@ -101,7 +101,7 @@ func (r *Request) IsCustomDomain() bool { return !strings.HasSuffix(r.URL.Hostname(), env.Config.HostDomain) } -//BaseURL returns base URL +// BaseURL returns base URL func (r *Request) BaseURL() string { address := r.URL.Scheme + "://" + r.URL.Hostname() diff --git a/app/pkg/web/ssl.go b/app/pkg/web/ssl.go index f1136e353..a52437480 100644 --- a/app/pkg/web/ssl.go +++ b/app/pkg/web/ssl.go @@ -72,7 +72,7 @@ func isValidHostName(ctx context.Context, host string) error { cname, err := net.DefaultResolver.LookupCNAME(ctx, host) if err != nil { - return errors.Wrap(err, "failed to lookup CNAME") + return errors.Wrap(errInvalidHostName, "failed to lookup CNAME") } if cname == "" { @@ -86,7 +86,7 @@ func isValidHostName(ctx context.Context, host string) error { return nil } -//CertificateManager is used to manage SSL certificates +// CertificateManager is used to manage SSL certificates type CertificateManager struct { ctx context.Context cert tls.Certificate @@ -94,7 +94,7 @@ type CertificateManager struct { autotls autocert.Manager } -//NewCertificateManager creates a new CertificateManager +// NewCertificateManager creates a new CertificateManager func NewCertificateManager(ctx context.Context, certFile, keyFile string) (*CertificateManager, error) { manager := &CertificateManager{ ctx: ctx, @@ -122,9 +122,9 @@ func NewCertificateManager(ctx context.Context, certFile, keyFile string) (*Cert return manager, nil } -//GetCertificate decides which certificate to use -//It first tries to use loaded certificate for incoming request if it's compatible -//Otherwise fallsback to a automatically generated certificate by Let's Encrypt +// GetCertificate decides which certificate to use +// It first tries to use loaded certificate for incoming request if it's compatible +// Otherwise fallsback to a automatically generated certificate by Let's Encrypt func (m *CertificateManager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { if m.leaf != nil { serverName, err := idna.Lookup.ToASCII(hello.ServerName) @@ -168,7 +168,7 @@ func (m *CertificateManager) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Ce return cert, err } -//StartHTTPServer creates a new HTTP server on port 80 that is used for the ACME HTTP Challenge +// StartHTTPServer creates a new HTTP server on port 80 that is used for the ACME HTTP Challenge func (m *CertificateManager) StartHTTPServer() { err := http.ListenAndServe(":80", m.autotls.HTTPHandler(nil)) if err != nil { diff --git a/app/pkg/web/testdata/basic.html b/app/pkg/web/testdata/basic.html index 98ae6191e..d5fa504ff 100755 --- a/app/pkg/web/testdata/basic.html +++ b/app/pkg/web/testdata/basic.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/canonical.html b/app/pkg/web/testdata/canonical.html index 5d52faee9..81b1e2040 100755 --- a/app/pkg/web/testdata/canonical.html +++ b/app/pkg/web/testdata/canonical.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/chunk.html b/app/pkg/web/testdata/chunk.html index bf893eaf1..ab125af24 100644 --- a/app/pkg/web/testdata/chunk.html +++ b/app/pkg/web/testdata/chunk.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/home.html b/app/pkg/web/testdata/home.html index 8cdc49f56..3fe3afec8 100755 --- a/app/pkg/web/testdata/home.html +++ b/app/pkg/web/testdata/home.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/home_ssr.html b/app/pkg/web/testdata/home_ssr.html index 1a16c2a68..52729866a 100755 --- a/app/pkg/web/testdata/home_ssr.html +++ b/app/pkg/web/testdata/home_ssr.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/oauth.html b/app/pkg/web/testdata/oauth.html index 7d9713aeb..fab7303d8 100755 --- a/app/pkg/web/testdata/oauth.html +++ b/app/pkg/web/testdata/oauth.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/tenant.html b/app/pkg/web/testdata/tenant.html index 9c87fac08..8503fd045 100755 --- a/app/pkg/web/testdata/tenant.html +++ b/app/pkg/web/testdata/tenant.html @@ -6,6 +6,9 @@ + + + diff --git a/app/pkg/web/testdata/user.html b/app/pkg/web/testdata/user.html index 99b571dd9..b98c6fa06 100755 --- a/app/pkg/web/testdata/user.html +++ b/app/pkg/web/testdata/user.html @@ -6,6 +6,9 @@ + + + diff --git a/app/services/blob/blob_test.go b/app/services/blob/blob_test.go index cc5c7e1f8..8f7c9a241 100644 --- a/app/services/blob/blob_test.go +++ b/app/services/blob/blob_test.go @@ -2,7 +2,6 @@ package blob_test import ( "context" - "io/ioutil" "os" "testing" @@ -103,7 +102,7 @@ func AllOperations(ctx context.Context) { } for _, testCase := range testCases { - bytes, _ := ioutil.ReadFile(env.Path(testCase.localPath)) + bytes, _ := os.ReadFile(env.Path(testCase.localPath)) err := bus.Dispatch(ctx, &cmd.StoreBlob{ Key: testCase.key, Content: bytes, @@ -147,7 +146,7 @@ func SameKey_DifferentTenant(ctx context.Context) { ctxWithTenant2 := context.WithValue(ctx, app.TenantCtxKey, tenant2) key := "path/to/file3.txt" - bytes, _ := ioutil.ReadFile(env.Path("/app/services/blob/testdata/file3.txt")) + bytes, _ := os.ReadFile(env.Path("/app/services/blob/testdata/file3.txt")) err := bus.Dispatch(ctxWithTenant1, &cmd.StoreBlob{ Key: key, @@ -180,8 +179,8 @@ func SameKey_DifferentTenant_Delete(ctx context.Context) { ctxWithTenant2 := context.WithValue(ctx, app.TenantCtxKey, tenant2) key := "path/to/super-file.txt" - bytes1, _ := ioutil.ReadFile(env.Path("/app/services/blob/testdata/file.txt")) - bytes2, _ := ioutil.ReadFile(env.Path("/app/services/blob/testdata/file3.txt")) + bytes1, _ := os.ReadFile(env.Path("/app/services/blob/testdata/file.txt")) + bytes2, _ := os.ReadFile(env.Path("/app/services/blob/testdata/file3.txt")) err := bus.Dispatch(ctxWithTenant1, &cmd.StoreBlob{ Key: key, diff --git a/app/services/blob/fs/fs.go b/app/services/blob/fs/fs.go index 045d86179..9f22d61ea 100644 --- a/app/services/blob/fs/fs.go +++ b/app/services/blob/fs/fs.go @@ -2,7 +2,6 @@ package fs import ( "context" - "io/ioutil" "net/http" "os" "path" @@ -83,7 +82,7 @@ func getBlobByKey(ctx context.Context, q *query.GetBlobByKey) error { return errors.Wrap(err, "failed to get stats '%s' from FileSystem", q.Key) } - file, err := ioutil.ReadFile(fullPath) + file, err := os.ReadFile(fullPath) if err != nil { return errors.Wrap(err, "failed to get read '%s' from FileSystem", q.Key) } @@ -108,7 +107,7 @@ func storeBlob(ctx context.Context, c *cmd.StoreBlob) error { return errors.Wrap(err, "failed to create folder '%s' on FileSystem", fullPath) } - err = ioutil.WriteFile(fullPath, c.Content, perm) + err = os.WriteFile(fullPath, c.Content, perm) if err != nil { return errors.Wrap(err, "failed to create file '%s' on FileSystem", fullPath) } diff --git a/app/services/blob/s3/s3.go b/app/services/blob/s3/s3.go index 20988497c..87c41856c 100644 --- a/app/services/blob/s3/s3.go +++ b/app/services/blob/s3/s3.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "fmt" - "io/ioutil" + "io" "path" "sort" "strconv" @@ -28,7 +28,7 @@ import ( "github.com/getfider/fider/app/pkg/bus" ) -//DefaultClient is an S3 Client +// DefaultClient is an S3 Client var DefaultClient *s3.S3 func init() { @@ -119,7 +119,7 @@ func getBlobByKey(ctx context.Context, q *query.GetBlobByKey) error { } defer resp.Body.Close() - bytes, err := ioutil.ReadAll(resp.Body) + bytes, err := io.ReadAll(resp.Body) if err != nil { return wrap(err, "failed to read blob body '%s' from S3", q.Key) } diff --git a/app/services/email/mailgun/sendmail_test.go b/app/services/email/mailgun/sendmail_test.go index 5f579d71a..ca5c839ef 100644 --- a/app/services/email/mailgun/sendmail_test.go +++ b/app/services/email/mailgun/sendmail_test.go @@ -2,7 +2,7 @@ package mailgun_test import ( "context" - "io/ioutil" + "io" "net/url" "testing" @@ -53,7 +53,7 @@ func TestSend_Success(t *testing.T) { Expect(httpclientmock.RequestsHistory[0].Header.Get("Authorization")).Equals("Basic YXBpOm15czNjcjN0azN5") Expect(httpclientmock.RequestsHistory[0].Header.Get("Content-Type")).Equals("application/x-www-form-urlencoded") - bytes, err := ioutil.ReadAll(httpclientmock.RequestsHistory[0].Body) + bytes, err := io.ReadAll(httpclientmock.RequestsHistory[0].Body) Expect(err).IsNil() values, err := url.ParseQuery(string(bytes)) Expect(err).IsNil() @@ -175,7 +175,7 @@ func TestBatch_Success(t *testing.T) { Expect(httpclientmock.RequestsHistory[0].Header.Get("Authorization")).Equals("Basic YXBpOm15czNjcjN0azN5") Expect(httpclientmock.RequestsHistory[0].Header.Get("Content-Type")).Equals("application/x-www-form-urlencoded") - bytes, err := ioutil.ReadAll(httpclientmock.RequestsHistory[0].Body) + bytes, err := io.ReadAll(httpclientmock.RequestsHistory[0].Body) Expect(err).IsNil() values, err := url.ParseQuery(string(bytes)) Expect(err).IsNil() diff --git a/app/services/email/smtp/auth.go b/app/services/email/smtp/auth.go index d3b2e72c0..d3a3d2e91 100644 --- a/app/services/email/smtp/auth.go +++ b/app/services/email/smtp/auth.go @@ -11,20 +11,17 @@ type agnosticAuth struct { auth gosmtp.Auth } -func (a *agnosticAuth) FindAuth(server *gosmtp.ServerInfo) gosmtp.Auth { - for _, auth := range server.Auth { - switch auth { - case "LOGIN": - return LoginAuth(a.username, a.password) - case "PLAIN": - return gosmtp.PlainAuth(a.identity, a.username, a.password, a.host) - case "CRAM-MD5": - return gosmtp.CRAMMD5Auth(a.username, a.password) - default: - continue - } +func (a *agnosticAuth) createAuth(mode string) gosmtp.Auth { + switch mode { + case "LOGIN": + return LoginAuth(a.username, a.password) + case "PLAIN": + return gosmtp.PlainAuth(a.identity, a.username, a.password, a.host) + case "CRAM-MD5": + return gosmtp.CRAMMD5Auth(a.username, a.password) + default: + return nil } - return nil } // AgnosticAuth returns an Auth that match the correct authentication @@ -34,11 +31,19 @@ func AgnosticAuth(identity, username, password, host string) gosmtp.Auth { } func (a *agnosticAuth) Start(server *gosmtp.ServerInfo) (string, []byte, error) { - a.auth = a.FindAuth(server) - if a.auth != nil { - return a.auth.Start(server) + for _, auth := range server.Auth { + a.auth = a.createAuth(auth) + if a.auth == nil { + continue + } + + proto, toServer, err := a.auth.Start(server) + if err == nil { + return proto, toServer, err + } } - return "", nil, errors.New("server auth mechanism not supported") + + return "", nil, errors.New("could not find any suitable auth mechanism") } func (a *agnosticAuth) Next(fromServer []byte, more bool) ([]byte, error) { diff --git a/app/services/httpclient/httpclient.go b/app/services/httpclient/httpclient.go index b5069061b..4bc5e7045 100644 --- a/app/services/httpclient/httpclient.go +++ b/app/services/httpclient/httpclient.go @@ -2,7 +2,7 @@ package httpclient import ( "context" - "io/ioutil" + "io" "net/http" "time" @@ -59,7 +59,7 @@ func requestHandler(ctx context.Context, c *cmd.HTTPRequest) error { } defer res.Body.Close() - respBody, err := ioutil.ReadAll(res.Body) + respBody, err := io.ReadAll(res.Body) if err != nil { return err } diff --git a/app/services/oauth/oauth.go b/app/services/oauth/oauth.go index d94ee3eb3..70af7906b 100644 --- a/app/services/oauth/oauth.go +++ b/app/services/oauth/oauth.go @@ -17,6 +17,7 @@ import ( "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/pkg/errors" "github.com/getfider/fider/app/pkg/jsonq" + "github.com/getfider/fider/app/pkg/jwt" "github.com/getfider/fider/app/pkg/validate" "github.com/getfider/fider/app/pkg/web" "golang.org/x/oauth2" @@ -155,7 +156,17 @@ func getOAuthAuthorizationURL(ctx context.Context, q *query.GetOAuthAuthorizatio parameters.Add("scope", config.Scope) parameters.Add("redirect_uri", fmt.Sprintf("%s/oauth/%s/callback", oauthBaseURL, q.Provider)) parameters.Add("response_type", "code") - parameters.Add("state", q.Redirect+"|"+q.Identifier) + + state, err := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: q.Redirect, + Identifier: q.Identifier, + }) + + if err != nil { + return err + } + + parameters.Add("state", state) authURL.RawQuery = parameters.Encode() q.Result = authURL.String() diff --git a/app/services/oauth/oauth_test.go b/app/services/oauth/oauth_test.go index 56f7c46ee..83f5efcb1 100644 --- a/app/services/oauth/oauth_test.go +++ b/app/services/oauth/oauth_test.go @@ -16,6 +16,7 @@ import ( "github.com/getfider/fider/app/pkg/bus" "github.com/getfider/fider/app/pkg/errors" + "github.com/getfider/fider/app/pkg/jwt" "github.com/getfider/fider/app/pkg/web" . "github.com/getfider/fider/app/pkg/assert" @@ -46,9 +47,14 @@ func TestGetAuthURL_Facebook(t *testing.T) { Identifier: "456", } + expectedState, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://example.org", + Identifier: "456", + }) + err := bus.Dispatch(ctx, authURL) Expect(err).IsNil() - Expect(authURL.Result).Equals("https://www.facebook.com/v3.2/dialog/oauth?client_id=FB_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2Ffacebook%2Fcallback&response_type=code&scope=public_profile+email&state=http%3A%2F%2Fexample.org%7C456") + Expect(authURL.Result).Equals("https://www.facebook.com/v3.2/dialog/oauth?client_id=FB_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2Ffacebook%2Fcallback&response_type=code&scope=public_profile+email&state="+expectedState) } func TestGetAuthURL_Google(t *testing.T) { @@ -63,9 +69,14 @@ func TestGetAuthURL_Google(t *testing.T) { Identifier: "123", } + expectedState, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://example.org", + Identifier: "123", + }) + err := bus.Dispatch(ctx, authURL) Expect(err).IsNil() - Expect(authURL.Result).Equals("https://accounts.google.com/o/oauth2/v2/auth?client_id=GO_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2Fgoogle%2Fcallback&response_type=code&scope=profile+email&state=http%3A%2F%2Fexample.org%7C123") + Expect(authURL.Result).Equals("https://accounts.google.com/o/oauth2/v2/auth?client_id=GO_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2Fgoogle%2Fcallback&response_type=code&scope=profile+email&state="+expectedState) } func TestGetAuthURL_GitHub(t *testing.T) { @@ -80,9 +91,14 @@ func TestGetAuthURL_GitHub(t *testing.T) { Identifier: "456", } + expectedState, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://example.org", + Identifier: "456", + }) + err := bus.Dispatch(ctx, authURL) Expect(err).IsNil() - Expect(authURL.Result).Equals("https://github.com/login/oauth/authorize?client_id=GH_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2Fgithub%2Fcallback&response_type=code&scope=user%3Aemail&state=http%3A%2F%2Fexample.org%7C456") + Expect(authURL.Result).Equals("https://github.com/login/oauth/authorize?client_id=GH_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2Fgithub%2Fcallback&response_type=code&scope=user%3Aemail&state="+expectedState) } func TestGetAuthURL_Custom(t *testing.T) { @@ -108,9 +124,14 @@ func TestGetAuthURL_Custom(t *testing.T) { Identifier: "456", } + expectedState, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://example.org", + Identifier: "456", + }) + err := bus.Dispatch(ctx, authURL) Expect(err).IsNil() - Expect(authURL.Result).Equals("https://example.org/oauth/authorize?client_id=CU_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2F_custom%2Fcallback&response_type=code&scope=profile+email&state=http%3A%2F%2Fexample.org%7C456") + Expect(authURL.Result).Equals("https://example.org/oauth/authorize?client_id=CU_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2F_custom%2Fcallback&response_type=code&scope=profile+email&state="+expectedState) } func TestGetAuthURL_Twitch(t *testing.T) { @@ -136,9 +157,14 @@ func TestGetAuthURL_Twitch(t *testing.T) { Identifier: "456", } + expectedState, _ := jwt.Encode(jwt.OAuthStateClaims{ + Redirect: "http://example.org", + Identifier: "456", + }) + err := bus.Dispatch(ctx, authURL) Expect(err).IsNil() - Expect(authURL.Result).Equals("https://id.twitch.tv/oauth/authorize?claims=%7B%22userinfo%22%3A%7B%22preferred_username%22%3Anull%2C%22email%22%3Anull%2C%22email_verified%22%3Anull%7D%7D&client_id=CU_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2F_custom%2Fcallback&response_type=code&scope=openid&state=http%3A%2F%2Fexample.org%7C456") + Expect(authURL.Result).Equals("https://id.twitch.tv/oauth/authorize?claims=%7B%22userinfo%22%3A%7B%22preferred_username%22%3Anull%2C%22email%22%3Anull%2C%22email_verified%22%3Anull%7D%7D&client_id=CU_CL_ID&redirect_uri=http%3A%2F%2Flogin.test.fider.io%3A3000%2Foauth%2F_custom%2Fcallback&response_type=code&scope=openid&state="+expectedState) } func TestParseProfileResponse_AllFields(t *testing.T) { diff --git a/app/services/sqlstore/postgres/billing.go b/app/services/sqlstore/postgres/billing.go index ce2fa93b5..4b830e612 100644 --- a/app/services/sqlstore/postgres/billing.go +++ b/app/services/sqlstore/postgres/billing.go @@ -140,6 +140,7 @@ func lockExpiredTenants(ctx context.Context, c *cmd.LockExpiredTenants) error { } c.NumOfTenantsLocked = count + c.TenantsLocked = ids } return nil diff --git a/app/services/sqlstore/postgres/billing_test.go b/app/services/sqlstore/postgres/billing_test.go new file mode 100644 index 000000000..a34445b42 --- /dev/null +++ b/app/services/sqlstore/postgres/billing_test.go @@ -0,0 +1,24 @@ +package postgres_test + +import ( + "testing" + + "github.com/getfider/fider/app/models/cmd" + + . "github.com/getfider/fider/app/pkg/assert" + "github.com/getfider/fider/app/pkg/bus" +) + +func TestLockExpiredTenants_ShouldTriggerForOneTenant(t *testing.T) { + ctx := SetupDatabaseTest(t) + defer TeardownDatabaseTest() + + // There is a tenant with an expired trial setup in the seed for the test database. + q := &cmd.LockExpiredTenants{} + + err := bus.Dispatch(ctx, q) + Expect(err).IsNil() + Expect(q.NumOfTenantsLocked).Equals(int64(1)) + Expect(q.TenantsLocked).Equals([]int{3}) + +} diff --git a/app/services/sqlstore/postgres/comment.go b/app/services/sqlstore/postgres/comment.go index 868eef81e..eaaa17d73 100644 --- a/app/services/sqlstore/postgres/comment.go +++ b/app/services/sqlstore/postgres/comment.go @@ -2,6 +2,7 @@ package postgres import ( "context" + "encoding/json" "time" "github.com/getfider/fider/app/models/cmd" @@ -12,13 +13,14 @@ import ( ) type dbComment struct { - ID int `db:"id"` - Content string `db:"content"` - CreatedAt time.Time `db:"created_at"` - User *dbUser `db:"user"` - Attachments []string `db:"attachment_bkeys"` - EditedAt dbx.NullTime `db:"edited_at"` - EditedBy *dbUser `db:"edited_by"` + ID int `db:"id"` + Content string `db:"content"` + CreatedAt time.Time `db:"created_at"` + User *dbUser `db:"user"` + Attachments []string `db:"attachment_bkeys"` + EditedAt dbx.NullTime `db:"edited_at"` + EditedBy *dbUser `db:"edited_by"` + ReactionCounts dbx.NullString `db:"reaction_counts"` } func (c *dbComment) toModel(ctx context.Context) *entity.Comment { @@ -33,6 +35,10 @@ func (c *dbComment) toModel(ctx context.Context) *entity.Comment { comment.EditedBy = c.EditedBy.toModel(ctx) comment.EditedAt = &c.EditedAt.Time } + + if c.ReactionCounts.Valid { + _ = json.Unmarshal([]byte(c.ReactionCounts.String), &comment.ReactionCounts) + } return comment } @@ -57,6 +63,38 @@ func addNewComment(ctx context.Context, c *cmd.AddNewComment) error { }) } +func toggleCommentReaction(ctx context.Context, c *cmd.ToggleCommentReaction) error { + return using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error { + var added bool + err := trx.Scalar(&added, ` + WITH toggle_reaction AS ( + INSERT INTO reactions (comment_id, user_id, emoji, created_on) + VALUES ($1, $2, $3, $4) + ON CONFLICT (comment_id, user_id, emoji) DO NOTHING + RETURNING true AS added + ), + delete_existing AS ( + DELETE FROM reactions + WHERE comment_id = $1 AND user_id = $2 AND emoji = $3 + AND NOT EXISTS (SELECT 1 FROM toggle_reaction) + RETURNING false AS added + ) + SELECT COALESCE( + (SELECT added FROM toggle_reaction), + (SELECT added FROM delete_existing), + false + ) + `, c.Comment.ID, user.ID, c.Emoji, time.Now()) + + if err != nil { + return errors.Wrap(err, "failed to toggle reaction") + } + + c.Result = added + return nil + }) +} + func updateComment(ctx context.Context, c *cmd.UpdateComment) error { return using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error { _, err := trx.Execute(` @@ -130,8 +168,13 @@ func getCommentsByPost(ctx context.Context, q *query.GetCommentsByPost) error { q.Result = make([]*entity.Comment, 0) comments := []*dbComment{} + userId := 0 + if user != nil { + userId = user.ID + } err := trx.Select(&comments, - `WITH agg_attachments AS ( + ` + WITH agg_attachments AS ( SELECT c.id as comment_id, ARRAY_REMOVE(ARRAY_AGG(at.attachment_bkey), NULL) as attachment_bkeys @@ -144,6 +187,26 @@ func getCommentsByPost(ctx context.Context, q *query.GetCommentsByPost) error { AND at.tenant_id = $2 AND at.comment_id IS NOT NULL GROUP BY c.id + ), + agg_reactions AS ( + SELECT + comment_id, + json_agg(json_build_object( + 'emoji', emoji, + 'count', count, + 'includesMe', CASE WHEN $3 = ANY(user_ids) THEN true ELSE false END + ) ORDER BY count DESC) as reaction_counts + FROM ( + SELECT + comment_id, + emoji, + COUNT(*) as count, + array_agg(user_id) as user_ids + FROM reactions + WHERE comment_id IN (SELECT id FROM comments WHERE post_id = $1) + GROUP BY comment_id, emoji + ) r + GROUP BY comment_id ) SELECT c.id, c.content, @@ -163,7 +226,8 @@ func getCommentsByPost(ctx context.Context, q *query.GetCommentsByPost) error { e.status AS edited_by_status, e.avatar_type AS edited_by_avatar_type, e.avatar_bkey AS edited_by_avatar_bkey, - at.attachment_bkeys + at.attachment_bkeys, + ar.reaction_counts FROM comments c INNER JOIN posts p ON p.id = c.post_id @@ -176,10 +240,12 @@ func getCommentsByPost(ctx context.Context, q *query.GetCommentsByPost) error { AND e.tenant_id = c.tenant_id LEFT JOIN agg_attachments at ON at.comment_id = c.id + LEFT JOIN agg_reactions ar + ON ar.comment_id = c.id WHERE p.id = $1 AND p.tenant_id = $2 AND c.deleted_at IS NULL - ORDER BY c.created_at ASC`, q.Post.ID, tenant.ID) + ORDER BY c.created_at ASC`, q.Post.ID, tenant.ID, userId) if err != nil { return errors.Wrap(err, "failed get comments of post with id '%d'", q.Post.ID) } diff --git a/app/services/sqlstore/postgres/common.go b/app/services/sqlstore/postgres/common.go index 2a0aeee99..8a0437c87 100644 --- a/app/services/sqlstore/postgres/common.go +++ b/app/services/sqlstore/postgres/common.go @@ -19,6 +19,12 @@ func ToTSQuery(input string) string { return strings.Join(strings.Fields(input), "|") } +// SanitizeString converts input to another string that only contains utf-8 characters and not-null characters +func SanitizeString(input string) string { + input = strings.Replace(input, "\u0000", "", -1) + return strings.ToValidUTF8(input, "") +} + func getViewData(view string) (string, []enum.PostStatus, string) { var ( condition string diff --git a/app/services/sqlstore/postgres/notification.go b/app/services/sqlstore/postgres/notification.go index 2e7d0fc50..f5f724b10 100644 --- a/app/services/sqlstore/postgres/notification.go +++ b/app/services/sqlstore/postgres/notification.go @@ -102,16 +102,23 @@ func getNotificationByID(ctx context.Context, q *query.GetNotificationByID) erro func getActiveNotifications(ctx context.Context, q *query.GetActiveNotifications) error { return using(ctx, func(trx *dbx.Trx, tenant *entity.Tenant, user *entity.User) error { - q.Result = []*entity.Notification{} err := trx.Select(&q.Result, ` - SELECT id, title, link, read, created_at - FROM notifications - WHERE tenant_id = $1 AND user_id = $2 - AND (read = false OR updated_at > CURRENT_DATE - INTERVAL '30 days') + SELECT n.id, n.title, n.link, n.read, n.created_at, n.author_id, u.avatar_type, u.avatar_bkey, u.name + FROM notifications n + LEFT JOIN users u ON u.id = n.author_id + WHERE n.tenant_id = $1 AND n.user_id = $2 + AND (n.read = false OR n.updated_at > CURRENT_DATE - INTERVAL '30 days') + ORDER BY n.updated_at DESC `, tenant.ID, user.ID) if err != nil { return errors.Wrap(err, "failed to get active notifications") } + + // Iterate over notifications and build avatar URL + for i := range q.Result { + q.Result[i].AvatarURL = buildAvatarURL(ctx, q.Result[i].AvatarType, int(q.Result[i].AuthorID), q.Result[i].AuthorName, q.Result[i].AvatarBlobKey) + } + return nil }) } diff --git a/app/services/sqlstore/postgres/post.go b/app/services/sqlstore/postgres/post.go index c1c49cd54..e6b86a839 100644 --- a/app/services/sqlstore/postgres/post.go +++ b/app/services/sqlstore/postgres/post.go @@ -392,7 +392,7 @@ func searchPosts(ctx context.Context, q *query.SearchPosts) error { enum.PostPlanned, enum.PostCompleted, enum.PostDeclined, - }), ToTSQuery(q.Query), q.Query) + }), ToTSQuery(q.Query), SanitizeString(q.Query)) } else { condition, statuses, sort := getViewData(q.View) sql := fmt.Sprintf(` diff --git a/app/services/sqlstore/postgres/post_test.go b/app/services/sqlstore/postgres/post_test.go index dccd2ab02..81f2ab7f4 100644 --- a/app/services/sqlstore/postgres/post_test.go +++ b/app/services/sqlstore/postgres/post_test.go @@ -1,11 +1,12 @@ package postgres_test import ( - "io/ioutil" + "os" "testing" "time" "github.com/getfider/fider/app/models/dto" + "github.com/getfider/fider/app/models/entity" "github.com/getfider/fider/app/models/enum" "github.com/getfider/fider/app/models/query" @@ -577,7 +578,7 @@ func TestPostStorage_Attachments(t *testing.T) { Expect(err).IsNil() Expect(getAttachments1.Result).HasLen(0) - bytes, err := ioutil.ReadFile(env.Path("favicon.png")) + bytes, err := os.ReadFile(env.Path("favicon.png")) Expect(err).IsNil() err = bus.Dispatch(jonSnowCtx, &cmd.SetAttachments{ @@ -651,3 +652,79 @@ func TestPostStorage_Attachments(t *testing.T) { Expect(err).IsNil() Expect(getAttachments1.Result).HasLen(0) } + +func TestToggleReaction_Add(t *testing.T) { + SetupDatabaseTest(t) + defer TeardownDatabaseTest() + + newPost := &cmd.AddNewPost{Title: "My new post", Description: "with this description"} + err := bus.Dispatch(jonSnowCtx, newPost) + Expect(err).IsNil() + + newComment := &cmd.AddNewComment{Post: newPost.Result, Content: "This is my comment"} + err = bus.Dispatch(jonSnowCtx, newComment) + Expect(err).IsNil() + + // Now add a reaction + reaction := &cmd.ToggleCommentReaction{Comment: newComment.Result, Emoji: "👍", User: jonSnow} + err = bus.Dispatch(jonSnowCtx, reaction) + Expect(err).IsNil() + Expect(reaction.Result).IsTrue() + + // Get the comment, and check that the reaction was added + commentByID := &query.GetCommentsByPost{Post: &entity.Post{ID: newPost.Result.ID}} + err = bus.Dispatch(jonSnowCtx, commentByID) + Expect(err).IsNil() + + Expect(commentByID.Result).IsNotNil() + Expect(commentByID.Result[0].ReactionCounts).IsNotNil() + Expect(len(commentByID.Result[0].ReactionCounts)).Equals(1) + Expect(commentByID.Result[0].ReactionCounts[0].Emoji).Equals("👍") + Expect(commentByID.Result[0].ReactionCounts[0].Count).Equals(1) + Expect(commentByID.Result[0].ReactionCounts[0].IncludesMe).IsTrue() + + // Now remove the reaction + reaction = &cmd.ToggleCommentReaction{Comment: newComment.Result, Emoji: "👍", User: jonSnow} + err = bus.Dispatch(jonSnowCtx, reaction) + Expect(err).IsNil() + Expect(reaction.Result).IsFalse() + + // Get the comment, and check that the reaction was removed + commentByID = &query.GetCommentsByPost{Post: &entity.Post{ID: newPost.Result.ID}} + err = bus.Dispatch(jonSnowCtx, commentByID) + Expect(err).IsNil() + + Expect(commentByID.Result).IsNotNil() + Expect(commentByID.Result[0].ReactionCounts).IsNil() +} + +func TestViewReactions_AnonymousUser(t *testing.T) { + SetupDatabaseTest(t) + defer TeardownDatabaseTest() + + newPost := &cmd.AddNewPost{Title: "My new post", Description: "with this description"} + err := bus.Dispatch(jonSnowCtx, newPost) + Expect(err).IsNil() + + newComment := &cmd.AddNewComment{Post: newPost.Result, Content: "This is my comment"} + err = bus.Dispatch(jonSnowCtx, newComment) + Expect(err).IsNil() + + // Now add a reaction + reaction := &cmd.ToggleCommentReaction{Comment: newComment.Result, Emoji: "👍", User: jonSnow} + err = bus.Dispatch(jonSnowCtx, reaction) + Expect(err).IsNil() + Expect(reaction.Result).IsTrue() + + // Get the comment as an anonymous user, and check that the reaction was added + commentByID := &query.GetCommentsByPost{Post: &entity.Post{ID: newPost.Result.ID}} + err = bus.Dispatch(demoTenantCtx, commentByID) + Expect(err).IsNil() + + Expect(commentByID.Result).IsNotNil() + Expect(commentByID.Result[0].ReactionCounts).IsNotNil() + Expect(len(commentByID.Result[0].ReactionCounts)).Equals(1) + Expect(commentByID.Result[0].ReactionCounts[0].Emoji).Equals("👍") + Expect(commentByID.Result[0].ReactionCounts[0].Count).Equals(1) + Expect(commentByID.Result[0].ReactionCounts[0].IncludesMe).IsFalse() +} diff --git a/app/services/sqlstore/postgres/postgres.go b/app/services/sqlstore/postgres/postgres.go index 0f64e4709..8d0f3103a 100644 --- a/app/services/sqlstore/postgres/postgres.go +++ b/app/services/sqlstore/postgres/postgres.go @@ -76,6 +76,7 @@ func (s Service) Init() { bus.AddHandler(addNewComment) bus.AddHandler(updateComment) + bus.AddHandler(toggleCommentReaction) bus.AddHandler(deleteComment) bus.AddHandler(getCommentByID) bus.AddHandler(getCommentsByPost) diff --git a/app/services/sqlstore/postgres/user_test.go b/app/services/sqlstore/postgres/user_test.go index 004dc60e5..ac7189c05 100644 --- a/app/services/sqlstore/postgres/user_test.go +++ b/app/services/sqlstore/postgres/user_test.go @@ -124,7 +124,7 @@ func TestUserStorage_Register(t *testing.T) { err = bus.Dispatch(demoTenantCtx, getUser) Expect(err).IsNil() - Expect(getUser.Result.ID).Equals(int(6)) + Expect(getUser.Result.ID).Equals(int(7)) Expect(getUser.Result.Role).Equals(enum.RoleCollaborator) Expect(getUser.Result.Name).Equals("Rob Stark") Expect(getUser.Result.Email).Equals("rob.stark@got.com") diff --git a/app/services/userlist/mocks/mockUserQueryService.go b/app/services/userlist/mocks/mockUserQueryService.go new file mode 100644 index 000000000..ea77ace44 --- /dev/null +++ b/app/services/userlist/mocks/mockUserQueryService.go @@ -0,0 +1,41 @@ +package userlist_mock + +import ( + "context" + + "github.com/getfider/fider/app/models/entity" + "github.com/getfider/fider/app/models/enum" + "github.com/getfider/fider/app/models/query" + "github.com/getfider/fider/app/pkg/bus" +) + +type Service struct{} + +func (s Service) Name() string { + return "PostgreSQL" +} + +func (s Service) Category() string { + return "sqlstore" +} + +func (s Service) Enabled() bool { + return true +} + +func (s Service) Init() { + bus.AddHandler(GetUserByID) +} + +func GetUserByID(ctx context.Context, q *query.GetUserByID) error { + q.Result = &entity.User{ + ID: 1, + Name: "John Doe", + Email: "john.doe@example.com", + Tenant: &entity.Tenant{ID: 1, Name: "Example Tenant"}, + Role: enum.RoleAdministrator, + Providers: []*entity.UserProvider{}, + Status: enum.UserActive, + } + return nil +} diff --git a/app/services/userlist/userlist.go b/app/services/userlist/userlist.go new file mode 100644 index 000000000..8e37e120b --- /dev/null +++ b/app/services/userlist/userlist.go @@ -0,0 +1,227 @@ +// Company represents a company in UserList.com +package userlist + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/getfider/fider/app/models/cmd" + "github.com/getfider/fider/app/models/enum" + "github.com/getfider/fider/app/models/query" + "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/env" + "github.com/getfider/fider/app/pkg/errors" +) + +// Company represents a company in UserList.com. It contains information about the company, +// including its identifier, name, sign-up date, custom properties, and associated users. +type Company struct { + Identifier string `json:"identifier"` + Name string `json:"name,omitempty"` + SignedUpAt string `json:"signed_up_at,omitempty"` + Properties map[string]interface{} `json:"properties,omitempty"` + Users []UserListUser `json:"users,omitempty"` +} + +// UserListUser represents a user in UserList.com. It contains information about the user, +// including their identifier, email, sign-up date, and custom properties. +type UserListUser struct { + Identifier string `json:"identifier,omitempty"` + Company string `json:"company,omitempty"` + Email string `json:"email,omitempty"` + SignedUpAt string `json:"signed_up_at,omitempty"` + Properties map[string]interface{} `json:"properties,omitempty"` +} + +type UserListUserToDelete struct { + Identifier string `json:"identifier"` +} + +type CompanyCreateResponse struct { + Identifier string `json:"id"` +} + +const ( + UserListBaseUrl = "https://push.userlist.com" +) + +func init() { + bus.Register(Service{}) +} + +type Service struct{} + +func (s Service) Name() string { + return "UserList" +} + +func (s Service) Category() string { + return "userlist" +} + +func (s Service) Enabled() bool { + return env.Config.UserList.Enabled +} + +func (s Service) Init() { + bus.AddHandler(createUserListCompany) + bus.AddHandler(updateUserListCompany) + bus.AddHandler(updateUserListUser) + bus.AddHandler(addOrRemoveUserListUser) +} + +func addOrRemoveUserListUser(ctx context.Context, u *cmd.UserListHandleRoleChange) error { + if u.Role == enum.RoleAdministrator { + // Get the user so we can add it to userlist. + user := &query.GetUserByID{ + UserID: u.Id, + } + err := bus.Dispatch(ctx, user) + if err != nil { + return err + } + + err = updateUserListUser(ctx, &cmd.UserListUpdateUser{ + Id: u.Id, + TenantId: user.Result.Tenant.ID, + Email: user.Result.Email, + Name: user.Result.Name, + }) + if err != nil { + return err + } + return nil + } + + // If the user is not an administrator, we remove it from userlist. + userToDelete := &UserListUserToDelete{ + Identifier: strconv.Itoa(u.Id), + } + + err := pushUserListUpdate(userToDelete, ctx) + if err != nil { + return err + } + return nil + +} + +func updateUserListUser(ctx context.Context, u *cmd.UserListUpdateUser) error { + + user := &UserListUser{ + Identifier: strconv.Itoa(u.Id), + Company: strconv.Itoa(u.TenantId), + } + + if len(u.Email) > 0 { + user.Email = u.Email + } + + if len(u.Name) > 0 { + user.Properties = map[string]interface{}{ + "name": u.Name, + } + } + + err := pushUserListUpdate(user, ctx) + if err != nil { + return err + } + return nil + +} + +func updateUserListCompany(ctx context.Context, c *cmd.UserListUpdateCompany) error { + company := &Company{ + Identifier: strconv.Itoa(c.TenantId), + Name: c.Name, + } + + if c.BillingStatus > 0 { + company.Properties = map[string]interface{}{ + "billing_status": c.BillingStatus.String(), + } + } + + err := pushUserListUpdate(company, ctx) + if err != nil { + return err + } + return nil + +} + +func createUserListCompany(ctx context.Context, c *cmd.UserListCreateCompany) error { + + company := &Company{ + Identifier: strconv.Itoa(c.TenantId), + Name: c.Name, + SignedUpAt: c.SignedUpAt, + Properties: map[string]interface{}{ + "billing_status": c.BillingStatus, + "subdomain": c.Subdomain, + }, + Users: []UserListUser{ + { + Identifier: strconv.Itoa(c.UserId), + Email: c.UserEmail, + SignedUpAt: c.SignedUpAt, + Properties: map[string]interface{}{ + "name": c.UserName, + }, + }, + }, + } + + err := pushUserListUpdate(company, ctx) + if err != nil { + return err + } + return nil + +} + +func pushUserListUpdate(obj interface{}, ctx context.Context) error { + var url string + method := http.MethodPost + switch obj.(type) { + case *Company: + url = fmt.Sprintf("%s/companies", UserListBaseUrl) + case *UserListUser: + url = fmt.Sprintf("%s/users", UserListBaseUrl) + case *UserListUserToDelete: + url = fmt.Sprintf("%s/users", UserListBaseUrl) + method = http.MethodDelete + default: + return errors.New("invalid type passed to pushUserListUpdate") + } + + jsonContent, err := json.Marshal(obj) + if err != nil { + return errors.Wrap(err, "failed to marshal object") + } + + req := &cmd.HTTPRequest{ + URL: url, + Body: bytes.NewBuffer(jsonContent), + Method: method, + Headers: map[string]string{ + "Content-Type": "application/json", + "Authorization": fmt.Sprintf("Push %s", env.Config.UserList.ApiKey), + }, + } + + if err := bus.Dispatch(ctx, req); err != nil { + return errors.Wrap(err, "Failed to send userlist update") + } + + if req.ResponseStatusCode >= 300 { + return errors.New("unexpected status code while updating userlist: %d", req.ResponseStatusCode) + } + + return nil +} diff --git a/app/services/userlist/userlist_test.go b/app/services/userlist/userlist_test.go new file mode 100644 index 000000000..7875b7c12 --- /dev/null +++ b/app/services/userlist/userlist_test.go @@ -0,0 +1,226 @@ +package userlist_test + +import ( + "context" + "io" + "strings" + "testing" + "time" + + "github.com/getfider/fider/app" + "github.com/getfider/fider/app/models/cmd" + "github.com/getfider/fider/app/models/entity" + "github.com/getfider/fider/app/models/enum" + "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/env" + "github.com/getfider/fider/app/services/httpclient/httpclientmock" + "github.com/getfider/fider/app/services/userlist" + userlist_mock "github.com/getfider/fider/app/services/userlist/mocks" + + . "github.com/getfider/fider/app/pkg/assert" +) + +var ctx context.Context + +func reset() { + ctx = context.WithValue(context.Background(), app.TenantCtxKey, &entity.Tenant{ + Subdomain: "got", + }) + bus.Init(userlist.Service{}, httpclientmock.Service{}, userlist_mock.Service{}) +} + +func TestCreateTenant_Success(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + createCompanyCmd := &cmd.UserListCreateCompany{ + Name: "Fider", + UserId: 1, + UserEmail: "jon.snow@got.com", + UserName: "Jon Snow", + TenantId: 1, + SignedUpAt: time.Now().Format(time.UnixDate), + BillingStatus: "active", + Subdomain: "got", + } + + err := bus.Dispatch(ctx, createCompanyCmd) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + Expect(httpclientmock.RequestsHistory[0].URL.String()).Equals("https://push.userlist.com/companies") + Expect(httpclientmock.RequestsHistory[0].Header.Get("Authorization")).Equals("Push abcdefg") + Expect(httpclientmock.RequestsHistory[0].Header.Get("Content-Type")).Equals("application/json") +} + +func TestUpdateTenant_Success(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + updateCompanyCmd := &cmd.UserListUpdateCompany{ + Name: "Fider", + TenantId: 1, + BillingStatus: enum.BillingActive, + } + + err := bus.Dispatch(ctx, updateCompanyCmd) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + Expect(httpclientmock.RequestsHistory[0].URL.String()).Equals("https://push.userlist.com/companies") + Expect(httpclientmock.RequestsHistory[0].Header.Get("Authorization")).Equals("Push abcdefg") + Expect(httpclientmock.RequestsHistory[0].Header.Get("Content-Type")).Equals("application/json") +} + +func TestUpdateTenant_BillingStatusUpdatedIfSet(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + updateCompanyCmd := &cmd.UserListUpdateCompany{ + Name: "Fider", + TenantId: 1, + BillingStatus: enum.BillingActive, + } + + err := bus.Dispatch(ctx, updateCompanyCmd) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + containsBillingStatus := strings.Contains(string(body), "billing_status") + Expect(containsBillingStatus).IsTrue() + + // Also check we're using the enum string, not the int value + Expect(strings.Contains(string(body), "billing_status\":\"active\"")).IsTrue() + +} + +func TestUpdateTenant_BillingStatusNotUpdatedIfNotSet(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + updateCompanyCmd := &cmd.UserListUpdateCompany{ + Name: "Fider", + TenantId: 1, + } + + err := bus.Dispatch(ctx, updateCompanyCmd) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + containsBillingStatus := strings.Contains(string(body), "billing_status") + Expect(containsBillingStatus).IsFalse() +} + +func TestUpdateTenant_NameShouldUpdateIfSet(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + updateCompanyCmd := &cmd.UserListUpdateCompany{ + Name: "Fider", + TenantId: 1, + } + + err := bus.Dispatch(ctx, updateCompanyCmd) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + containsName := strings.Contains(string(body), "name") + Expect(containsName).IsTrue() +} + +func TestUpdateTenant_NameShouldNotUpdateIfNotSet(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + updateCompanyCmd := &cmd.UserListUpdateCompany{ + TenantId: 1, + } + + err := bus.Dispatch(ctx, updateCompanyCmd) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + containsName := strings.Contains(string(body), "name") + Expect(containsName).IsFalse() +} + +func TestUpdateUser_NameOnly(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + err := bus.Dispatch(ctx, &cmd.UserListUpdateUser{ + Id: 1, + TenantId: 1, + Name: "Freddy", + }) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + containsName := strings.Contains(string(body), "name") + Expect(containsName).IsTrue() + + containsEmail := strings.Contains(string(body), "email") + Expect(containsEmail).IsFalse() +} + +func TestUpdateUser_EmailOnly(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + err := bus.Dispatch(ctx, &cmd.UserListUpdateUser{ + Id: 1, + TenantId: 1, + Email: "Freddy@example.com", + }) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + containsName := strings.Contains(string(body), "name") + Expect(containsName).IsFalse() + + containsEmail := strings.Contains(string(body), "email") + Expect(containsEmail).IsTrue() +} + +func TestMakeUserAdministrator(t *testing.T) { + RegisterT(t) + env.Config.HostMode = "multi" + reset() + + err := bus.Dispatch(ctx, &cmd.UserListHandleRoleChange{ + Id: 1, + Role: enum.RoleAdministrator, + }) + Expect(err).IsNil() + + Expect(httpclientmock.RequestsHistory).HasLen(1) + + Expect(httpclientmock.RequestsHistory[0].URL.String()).Equals("https://push.userlist.com/users") + Expect(httpclientmock.RequestsHistory[0].Method).Equals("POST") + + body, _ := io.ReadAll(httpclientmock.RequestsHistory[0].Body) + Expect(strings.Contains(string(body), "\"email\":\"john.doe@example.com\"")).IsTrue() + Expect(strings.Contains(string(body), "\"name\":\"John Doe\"")).IsTrue() + Expect(strings.Contains(string(body), "\"identifier\":\"1\"")).IsTrue() + +} diff --git a/app/tasks/delete_post.go b/app/tasks/delete_post.go index fece47789..b5b31ec4e 100644 --- a/app/tasks/delete_post.go +++ b/app/tasks/delete_post.go @@ -15,18 +15,41 @@ import ( "github.com/getfider/fider/app/pkg/worker" ) -//NotifyAboutDeletedPost sends a notification (web and email) to subscribers of the post that has been deleted -func NotifyAboutDeletedPost(post *entity.Post) worker.Task { +// NotifyAboutDeletedPost sends a notification (web and email) to subscribers of the post that has been deleted +func NotifyAboutDeletedPost(post *entity.Post, deleteCommentAdded bool) worker.Task { return describe("Notify about deleted post", func(c *worker.Context) error { + tenant := c.Tenant() + baseURL, logoURL := web.BaseURL(c), web.LogoURL(c) + author := c.User() + title := fmt.Sprintf("**%s** deleted **%s**", author.Name, post.Title) + + // Webhook + webhookProps := webhook.Props{} + webhookProps.SetPost(post, "post", baseURL, true, true) + webhookProps.SetUser(author, "author") + webhookProps.SetTenant(tenant, "tenant", baseURL, logoURL) + + err := bus.Dispatch(c, &cmd.TriggerWebhooks{ + Type: enum.WebhookDeletePost, + Props: webhookProps, + }) + if err != nil { + return c.Failure(err) + } + + // If no comment was added, we can stop here + // (I'm not sure about the rational of this business rule, but this is how it currently works) + if !deleteCommentAdded { + return nil + } + // Web notification users, err := getActiveSubscribers(c, post, enum.NotificationChannelWeb, enum.NotificationEventChangeStatus) if err != nil { return c.Failure(err) } - author := c.User() - title := fmt.Sprintf("**%s** deleted **%s**", author.Name, post.Title) for _, user := range users { if user.ID != author.ID { err = bus.Dispatch(c, &cmd.AddNewNotification{ @@ -53,9 +76,6 @@ func NotifyAboutDeletedPost(post *entity.Post) worker.Task { } } - tenant := c.Tenant() - baseURL, logoURL := web.BaseURL(c), web.LogoURL(c) - props := dto.Props{ "title": post.Title, "siteName": tenant.Name, @@ -71,19 +91,6 @@ func NotifyAboutDeletedPost(post *entity.Post) worker.Task { Props: props, }) - webhookProps := webhook.Props{} - webhookProps.SetPost(post, "post", baseURL, true, true) - webhookProps.SetUser(author, "author") - webhookProps.SetTenant(tenant, "tenant", baseURL, logoURL) - - err = bus.Dispatch(c, &cmd.TriggerWebhooks{ - Type: enum.WebhookDeletePost, - Props: webhookProps, - }) - if err != nil { - return c.Failure(err) - } - return nil }) } diff --git a/app/tasks/delete_post_test.go b/app/tasks/delete_post_test.go index aa90002d7..04d45c92c 100644 --- a/app/tasks/delete_post_test.go +++ b/app/tasks/delete_post_test.go @@ -60,7 +60,7 @@ func TestNotifyAboutDeletePostTask(t *testing.T) { }, } - task := tasks.NotifyAboutDeletedPost(post) + task := tasks.NotifyAboutDeletedPost(post, true) err := worker. OnTenant(mock.DemoTenant). @@ -127,3 +127,88 @@ func TestNotifyAboutDeletePostTask(t *testing.T) { "tenant_url": "http://domain.com", }) } + +func TestNotifyAboutDeletePostTask_NoComment(t *testing.T) { + RegisterT(t) + bus.Init(emailmock.Service{}) + + var addNewNotification *cmd.AddNewNotification + bus.AddHandler(func(ctx context.Context, c *cmd.AddNewNotification) error { + addNewNotification = c + return nil + }) + + bus.AddHandler(func(ctx context.Context, q *query.GetActiveSubscribers) error { + q.Result = []*entity.User{ + mock.AryaStark, + } + return nil + }) + + var triggerWebhooks *cmd.TriggerWebhooks + bus.AddHandler(func(ctx context.Context, c *cmd.TriggerWebhooks) error { + triggerWebhooks = c + return nil + }) + + worker := mock.NewWorker() + post := &entity.Post{ + ID: 1, + Number: 1, + Title: "Add support for TypeScript", + Slug: "add-support-for-typescript", + Description: "TypeScript is great, please add support for it", + User: mock.AryaStark, + Status: enum.PostDeleted, + Response: &entity.PostResponse{ + RespondedAt: time.Now(), + Text: "Invalid post!", + User: mock.JonSnow, + }, + } + + task := tasks.NotifyAboutDeletedPost(post, false) + + err := worker. + OnTenant(mock.DemoTenant). + AsUser(mock.JonSnow). + WithBaseURL("http://domain.com"). + Execute(task) + + Expect(err).IsNil() + Expect(emailmock.MessageHistory).HasLen(0) + + Expect(addNewNotification).IsNil() + + Expect(triggerWebhooks).IsNotNil() + Expect(triggerWebhooks.Type).Equals(enum.WebhookDeletePost) + Expect(triggerWebhooks.Props).ContainsProps(webhook.Props{ + "post_id": post.ID, + "post_number": post.Number, + "post_title": post.Title, + "post_slug": post.Slug, + "post_description": post.Description, + "post_status": post.Status.Name(), + "post_url": "http://domain.com/posts/1/add-support-for-typescript", + "post_author_id": mock.AryaStark.ID, + "post_author_name": mock.AryaStark.Name, + "post_author_email": mock.AryaStark.Email, + "post_author_role": mock.AryaStark.Role.String(), + "post_response": true, + "post_response_text": post.Response.Text, + "post_response_responded_at": post.Response.RespondedAt, + "post_response_author_id": mock.JonSnow.ID, + "post_response_author_name": mock.JonSnow.Name, + "post_response_author_email": mock.JonSnow.Email, + "post_response_author_role": mock.JonSnow.Role.String(), + "author_id": mock.JonSnow.ID, + "author_name": mock.JonSnow.Name, + "author_email": mock.JonSnow.Email, + "author_role": mock.JonSnow.Role.String(), + "tenant_id": mock.DemoTenant.ID, + "tenant_name": mock.DemoTenant.Name, + "tenant_subdomain": mock.DemoTenant.Subdomain, + "tenant_status": mock.DemoTenant.Status.String(), + "tenant_url": "http://domain.com", + }) +} diff --git a/app/tasks/signup.go b/app/tasks/signup.go index d8555a604..5b655896b 100644 --- a/app/tasks/signup.go +++ b/app/tasks/signup.go @@ -5,11 +5,12 @@ import ( "github.com/getfider/fider/app/models/cmd" "github.com/getfider/fider/app/models/dto" "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/env" "github.com/getfider/fider/app/pkg/web" "github.com/getfider/fider/app/pkg/worker" ) -//SendSignUpEmail is used to send the sign up email to requestor +// SendSignUpEmail is used to send the sign up email to requestor func SendSignUpEmail(action *actions.CreateTenant, baseURL string) worker.Task { return describe("Send sign up email", func(c *worker.Context) error { to := dto.NewRecipient(action.Name, action.Email, dto.Props{ @@ -28,3 +29,32 @@ func SendSignUpEmail(action *actions.CreateTenant, baseURL string) worker.Task { return nil }) } + +// SendWelcomeEmail is used to send a welcome email to new tenant admin +// This email is not sent on self hosted instaces +func SendWelcomeEmail(name, email, baseURL string) worker.Task { + return describe("Send welcome email", func(c *worker.Context) error { + if env.IsSingleHostMode() { + return nil + } + + to := dto.NewRecipient(name, email, dto.Props{ + "name": name, + "url": link(baseURL, "/"), + }) + + bus.Publish(c, &cmd.SendMail{ + From: dto.Recipient{ + Name: "Fider", + Address: "contact@fider.io", + }, + To: []dto.Recipient{to}, + TemplateName: "welcome_email", + Props: dto.Props{ + "logo": web.LogoURL(c), + }, + }) + + return nil + }) +} diff --git a/app/tasks/userlist.go b/app/tasks/userlist.go new file mode 100644 index 000000000..c5e7ea729 --- /dev/null +++ b/app/tasks/userlist.go @@ -0,0 +1,82 @@ +package tasks + +import ( + "time" + + "github.com/getfider/fider/app/models/cmd" + "github.com/getfider/fider/app/models/dto" + "github.com/getfider/fider/app/models/entity" + "github.com/getfider/fider/app/models/enum" + "github.com/getfider/fider/app/pkg/bus" + "github.com/getfider/fider/app/pkg/log" + "github.com/getfider/fider/app/pkg/worker" +) + +func UserListCreateCompany(tenant entity.Tenant, user entity.User) worker.Task { + return describe("Create UserList Company", func(c *worker.Context) error { + log.Debugf(c, "Sending new tenant @{Tenant} to userlist with user email @{User}", dto.Props{ + "Tenant": tenant.Name, + "User": user.Email, + }) + if err := bus.Dispatch(c, &cmd.UserListCreateCompany{ + Name: tenant.Name, + TenantId: tenant.ID, + SignedUpAt: time.Now().Format(time.RFC3339), + BillingStatus: enum.BillingTrial.String(), + Subdomain: tenant.Subdomain, + UserId: user.ID, + UserEmail: user.Email, + UserName: user.Name, + }); err != nil { + return c.Failure(err) + } + return nil + }) +} + +func UserListUpdateCompany(action *dto.UserListUpdateCompany) worker.Task { + return describe("Update Company in UserList", func(c *worker.Context) error { + log.Debugf(c, "Updating company @{Tenant} in UserList", dto.Props{ + "Tenant": action.Name, + }) + if err := bus.Dispatch(c, &cmd.UserListUpdateCompany{ + TenantId: action.TenantID, + Name: action.Name, + BillingStatus: action.BillingStatus, + }); err != nil { + return c.Failure(err) + } + return nil + }) +} + +func UserListUpdateUser(id int, name string, email string) worker.Task { + return describe("Update User in UserList", func(c *worker.Context) error { + log.Debugf(c, "Updating user @{User} in UserList", dto.Props{ + "User": id, + }) + if err := bus.Dispatch(c, &cmd.UserListUpdateUser{ + Id: id, + Email: email, + Name: name, + }); err != nil { + return c.Failure(err) + } + return nil + }) +} + +func UserListAddOrRemoveUser(userID int, role enum.Role) worker.Task { + return describe("Add or Remove User in UserList", func(c *worker.Context) error { + log.Debugf(c, "Handling role change for user in UserList", dto.Props{ + "User": userID, + }) + if err := bus.Dispatch(c, &cmd.UserListHandleRoleChange{ + Id: userID, + Role: role, + }); err != nil { + return c.Failure(err) + } + return nil + }) +} diff --git a/e2e/features/server/ssr.feature b/e2e/features/server/ssr.feature index 3d1fc98b6..497392ee3 100644 --- a/e2e/features/server/ssr.feature +++ b/e2e/features/server/ssr.feature @@ -5,7 +5,7 @@ Feature: SSR And I set the "User-Agent" header to "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" When I send the request Then I should see http status 200 - And I should not see ">Powered by Fider" on the response body + And I should not see ">Powered by Fider ⚡" on the response body And I should see "This website requires JavaScript, please enable and reload the page." on the response body And I should see "/assets/js/vendor" on the response body @@ -14,6 +14,6 @@ Feature: SSR And I set the "User-Agent" header to "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" When I send the request Then I should see http status 200 - And I should see ">Powered by Fider" on the response body + And I should see ">Powered by Fider ⚡" on the response body And I should not see "This website requires JavaScript, please enable and reload the page." on the response body And I should not see "/assets/js/vendor" on the response body diff --git a/etc/browserstack.png b/etc/browserstack.png index b52415919f52584ba8ba24a58cfbd6564e9e1153..49b6155cfb7fa9782c6e7702dded135f7135a009 100644 GIT binary patch literal 4845 zcmV=e!600006VoOIv0RI60 z0RN!9r;`8x5~4{&K~#9!?VSl&6h{`v)x^XjcQ%`B%qAPJsM#0;YE%vx5JbQ;9(Vu) zUhBc-5jCj6&7nrc7~_2*QP8Xx$~Ayu1T`ooD1rzci86qSLO4u}%G*~x)k959_Z&*T z-C)1(`+q=HUsKh;ey?8DG>sbl0aiM-^P9!NHsiISw%d!RcPr42?eUv-Sg+b5FMB9* za|CUl-nCj+r`lq7=exy2U2l~Jcx0A^4*2B8V((WQDW;fWrmZlr?UThJw&RLJZ8H%x zD4y6Aw1e!RsJ9ao*{dv*${DT&c$Sne8#)g(J}s42RZKC)AiPl%;>AirY>EZQCL?46 z(Ste2Lw3bg1(ye@;L=e1IY0$how#irRB&y)=Wi8Ty%$|ioBWj0%8EVmb}i7hO-ZoL zF#$57fbO7mGKTEuzA897M+KSRsNlOJDma*Js6#)hAYG$^tko(wKM~<`r2D!!!>uL5 z%Bm98LzLE5?2$EXs7-$atU?4$JFS~Z}yyA@B?BER8d;S9K%-2Hbk)I^N z8k~3$`l8$tFTeo&Syy)f0uooi9E}IWWEy(9)1Rq8i`mM`?W0LZnfpu9*cX%@QLI7Q z<&ZAV6^GdTq)&zr*gPE!GKhyX%V1A|7XFi843p9fLHhvJCB6V&IB*Uc#pW8Q<^DWq zA9r349sw>W-V0WxyVU`QNtC=$6_kwX2h~Yx5>h5Zcz6?~XB2CA;bXAPDi*Y2|Lz9i zWBRuF2wJhA*++ji0L?k!0<=J&c*uA?9-9X?35B@NMVOc{0|F7aWrzFLg_I|83^z&z zcf!^@qr|XTNdkekXsH9Ao8b3e)Zf!=LhdUapf>LjH0XEc~ zsuZ7&N)IX4V5~UUHrl|eP3mgk)#6X4>b+XXkvgwN#$}HqJg-lj1?}6nht_YrA*l{F z-Qbysod&>li!X%n3G)TmNJz3GlLc zgGJb&G9|!X=_$qj^i~pVJKeymafy+nw4Hj`R%I9ILFr7}dDj3yO>GeOxux&k1 zJ5ZNVHK?1YT+}zHF{tMMXV?1{>Le-)wfBz?Awz95c-V@Zd+X-Z99?iOtw0aklB}zG z*g8fZg|=NWfp-&O%U-HtVDr0M9j|`HOv6nE z%k3DdwSq^z-L%b6dn{=88z?_!zc*16s2u+X*KNmKoAwVq*=4m;GhAT&y8�HhQmC zIA*vWG@^wkujpax;4|55_?VHNuKy&{LqmnKHvjksG~aSafUPlVa{L$r?-rZoBEWWh zw+gEE`sjhH(x?OL5jJ8M{@kZ1Ydr_T+|m{E>vMB*z#r3K;9tEk2bRziC`LEGaorcBMWXQ7qHvluq4e;V}$d2s$I zVY@cF`%EL)7|)ilcB}zxd(IbwZ>nw`WXI0$nuSeP-eU#OTI@&I5(XH+HZQqu+*ZDO zBnumuS~F=0Y;?Qb%yx@t8R^7A8uDb)zxSc;((Niy8&OX&9X|z?M)%R8j-wWmeVKE; zM3V%!P(^&$N}lqlbF@A|;#xZ}`xh|fjZp(oQK%EBQ>cTe2$Zwb!+}0H2pAgFc~lAN zd(<+1{7SbyM?YIWZI7*}Uuk>XM(slV6&1*|=T-7Rv+zbAL&whSzCt34OJJ;{b*z!= zI8D#pMB>;@QQib#`Z=zX01LGe)y`7buxuJCg(~9VV4K%#l@V+~2%DpBJ>=f6h8n_# zns;0`&(^t@;{(IiD(GVYw(hBU2B7gtl8XHXo(WLX^*A$i_leiw>gO=^>zNyAx0&(i52)9<&;7lL?SDg! zWVU~Xt3NNX4*~97R6nkK8)+vCVB0ElEoIC$XDk?df59F1dHUdyGt$3f%)v$^JpM5wfxyXF<#d8csoN0~YoiJO2xFpEBcH!vQ6Jkgsn$JxVq zkOlO*VwmyPeQ{bu0ybjXX?sM_V~k)zOCCmY%mNx6kSUk`sOPxPM*1b2*{2lsEopaV z8x?KKNcy=4p?p#Q;T{w%nSG+T`(O`!0OT{*7G?@I{N0DP2hfP*;WO9Qzi`H*A975_jH1TnKuPmY0a*B>b7g zY~NiXeDXrIV9MTOZzytHZlC!~eX6`E;t(q3PSp}3`EHg<@?dpN9)u)(U<6ylVO@gc$4E!R5VC$@Beui@Y%j>1V>2Jt zarN#}p)7@4G)G$2g`4*iJ?cxe-j}IgDRZnX^ag8UqFol4x#m|nAeu|S_MQb{VGHVg z66qLM&N9RY&ckFQY2+cA11+1ylx?&&K|-PjW?Wh!LR>Fa89mfr(z69&C`sQnGAGs( zzCO9b2sUw&+hO!XAvClEwC5K^!YhgAVCC5&SeWsJ5oko)j_cM)URvX11e+CM1__VbIY%g00!sFE2^`{A#a_)EmmcT}{$37I`LIwohMA%l#h2$2% zcAJj3fe9a*T#CD6>a8d%c zDiix=Fx!oi$%3)gik7!zI`T3tJ5B#y%Y~GQbQ~mlhbwG$k%mK2+}xJbg#C+j`<+&L z{P!ead+{Mt?0=))bFgtCIkEkyxwM}r(Djx) zY!OV^%m;w&K8*~@nPiGfy#ZGdHRPrwY{a{b(yjhqzRq2jmQS68u;j`DXHHQ$Ct#+= zPZBipHJiP-R4e_U6O_#9VU!%Pa#GtAZ0q@O(+b#@G25+?sAp68#hgd-;xd9j=g^wc zdIyPmux8xAJxJ1NSuoo!mQ2uF0~^iIhKV=4iNyp`$s<#+eZr1SC5|~o0=5Zk_VfW@ z3#H}$Oxb0*B#qUEH}#IvS<<1TFb#mO6we;)BEUePn64QE8?!Z5LALvRkudHHNgN^x z8qrex#x{AsWZ~lOaP#Ya65}=XJ}Z`M<AcSed}4%7bc?o+mbK$T&d<1MfmYP(9wy`32Y_uU;|2Cn zkMtyW{4Lz^JZN12QoWs9Fgea*eZ z4!E_}OBOaEob1yZc75n(xY8qS25iVqhF#~c$U;WK&NZj@3L&T*WV(rLPe{VCTF%;@ zP%^D6R2>*&3|q3_6f0n}#K@TFO)Ft*%*}n>rAd=mE(uVYcAk)a_*Uci`&CI5tKC zgjza&3!`usNR8Pz_{FgBFkJ+2g(+WP0c@?9J|)L_`0rHSN}2F%b%NjR(%C)afg|fB zU3$a%C4G%R2~8XZ3%(13#YZD>PHq!K9A6KMGM2*pLo;wG)Al$D;X9le?FnK}ON6oe= z3&6;$nOX7Agm~YYP$W&ayRi#t>Aug>IT|uG;BCRVNXX|(Q_Uo4a)>TJ8q2O`knxOu zv=iNAvY9jJc*NVpabBmZIil%Gm~`r0$pm#<6X&)^eMPtZj{aOiS8DJXPw_hZ`Sy}I z{@-a>xRJI=I=!~7bPeO*OpFgdqTZJ*DLcm1cSU_nj}u9^Z9}IPrqWdalc?*C=fqath-JBCSkHGC~XvY(x@=3cP|W0-*0OT5ap`F5s(qyH}Iw67zq#JMnQ zA)AigY{L;(Tp?l)S7+Gjk6FIHza(g=M5T8WYf$!Uitp=qV^@>pL}^%0^T5%!aGjju z2wRrB!AJW%WC07oaoOi7?yxj(#yIKkc(P7t@!2{M*Az=e7EucksI_6d-c(Z4TH+{v{ zL11dq`$2T$b0?_WH_C)ZQ=hGf8}+=>8;Ujja1!UV$PKT*`Qv@y=4wwUnc4lJAiK7} z0V<+DFa;U$Xy8z(C8__70PZ9S4pcra{kll9isWw$KflFyhkS}Z`;%`ND6OVgL$&_`mHOs@ Tkk+t-00000NkvXXu0mjf*(p=_ literal 18073 zcmZ^}18`=+vo{<&8{6L4#>Uv#wry);CmY+gZCg*0C$??t+yA}yMZHzushTr$`uw_k zX8Kg0>FJ43kdr`!!-WF@0YQ|K6jl0HKmIFxFi`*QJ!&5~ARutnmLehwQX(S63QqQB zmNup!Ad(Tusn80_rrP1|o;LJ1AS;_ikHV-&5nynXJcO&R40|ncSdx?za>P zE-J9ZB3bl^_xC2FLnHN4z2JmD^AP0v4&WQeH|FMuU$lMOpvO+U)}0p5ug||KlR_di z!9d8-_aO{Zh{5-bHJV_^0X87`mwL6?N6R9Mgv;5fYP#tg$7S@?qk&I+&LV$I?ll$%n%IMVnINrFqkJWH z507~xQ+mCR-S0_yc9X9wUr|dTB`;HzypP{&a_`=mH`ar5^p}79nUl&@c>NMYegVZJ zt!D=t_ya%R2X22eE~mriRnkwZ+#pKxTW;LUxn4VQ>?i_KZDFMa$ngYH=5#R9gW5<0B#}`=he&TFSxCiA##l@c zm4ea9OeGjNMqPByqK~@i}99r7V zaI|e(Z?oH=-7x1vnH_4pP4U3$`XzwM*vB|j+gCf9x?6dR_;UZU{zCXc{KXp}G)Jm| zoCV7#j6jlJ7p@@qlSBn27L5V<3iS25$JiPeR#PsdW67e%Jr7XtK<_N?=)_l6@rr}l46p4lguU%e-oLeRmiaCcPNpSl`k$WDp?Ucf<2-<62yovlyc9T zEr>R$HYu$cu2Eqg3z{ht`w&Hd*awGHtfP znF_9w8O{37u%G5XYt;qvd^FqjLyC;5_6kW=#?@CVo#cvBBaCsGy3@dpaE}CzAkB!P z##jt*HOi|*XGTj-OUf0SR$T1H>^WK;YvRphR?mw)GV?hD*$G^x zn@JtittCDxxfNIWIc0ifdbNJ)pHWcSgA!!2#*N~IBgV2_CGAHx(_$H&?2HyY850?2 zEUHY+4rlS@NKFd#&ecrS#aiCYHI|5$=N9jl(oOCbxeI>9g(ds>i4~2i$4xVT7?hV~ z)r&e+pQEqfTWB&T<;+tXW*ea&n;t$MO}sF?F1-fdDBt4WJl`JQ;t!xlC`0TBm^305!y@ml=TpHnYZkjGKWHQbflsRhL)e8xB{~8}L%y$a7ZHjJiVlg3ND>JFi4NWe*MyK9(JCio1}?4H z6j*3bXyE8z3=@1K+!D<9gB?~E`)%E3?_zHCurW7eHJBdW8s0pV5#|^27s&vtk@3)= zEiG$T#7$vFx94j< z*sDHTot-r;E#Ft&N8WGMM(8bM)n@n7^gcuP5?R5c!xcehTk8U^UQxaaPez|y-Ok;r z-t~Ucbt#$Xswh3Ub{l*q=i2zud|H}_079Q)e&D&=liH!$ceJkhI=j|8Iodg1r)X;9 zwluV2+WGd{_P0z@u>O9sDYZ+ry=Fk9v0XE4GhT?THKjInpX8rBcelFKX}#ZP*sam- zR1Wx2yct{gtjwUa6Oq@#K}|k8=sR6TQvK z!~l0^Hg~IAK*(yO+2O2CXTPV{C-?v?2Hl5lkD8cux1)sf;>6T!#@x1nc7VsyuGJv> zyY*=8y8f@NtGO+Q!CUbK+0x8u0#;tRZKqz>rH9<30~>mz(?3`g=G5oMiUP zy$c?#-=ERX)gt*K@&YD4*k2kiQv1q}<}=4FjPv?ANQ`g4-?ZMQFSPHU`>x}}S;WQ3 zeW?9y(EAJnC@Da@Hj(|C1?F(pG`(K7(+(3T~TL71k&V# zojWa29P}w4K8as^UL=vb^XmZ#ml^UQXvpsOzx6AugQTW22namde+no_Miw>*2pGJj ziiV4ZtPGE_y)A>GiM^32gNLodKlHyRGqA1aTMsk6O} z>wm{Wrel%0#I(?4bZ!~MTH`2UaiA6a~i|Cz4;Yx@4%HvdKaXB+`I zKF0rTXaP7RF`7gW5N>ZNQ6Uu%(93M-EZt$(u-Wcf`vs227Ft+XHYwg}=o zguE^Np$3_4@k1O+8QQ2}*m&XAI!q~hkzyETDkgd+wg+3HW;L zOlPM06L3$Inf^%PzS$lQ=$nE+nvR_4jb{PNJpRRREN;`k(H_q!T$0%ZZD}U zotE3~CGIkEIcvf{>p{l_>mFq)ZUSgm^joW)Zjn%G2Zm#vhC=~$`^Hg+D)vt;2DUNI zPc{{LJ#Kr9+^`@aiUy5 zj`6G3$NHYJLhftrM>FwXsh&Tst?GL2QADQdM|}$T9=gK171^BI4r}##!0)ExbzUo_ z_z9a<^UZai$;;@2KmiDWfI0E$XD_hXC(@{F7_$)bSH%~ez2DE>eUo{e&rqKJ5(Zy6 z#JKWeT`%F`rsAXr(-E%Y`=Or_ms$0#-elj7rMM_`=~$0uv*)eIp;j6=dPjY`69FQa zX9{__JznBAGGccNLR$h+Ov_IucPU%@$M=~=p67R;#5gZ{S@bs?vt7C@6*?1g(<`|K8CUR!??y7@0;bkh_3;{~90Oc)vRh&cJFDH3n%MC6>8eegtaYoI zm<;qVtoTjkgzq(@iom6>#x-0qf>d4G8Me}M!^W6RJ9u^t`o)gzZn>_7tAG4kVKT_I=Y+}4H z;prqvr#cHU4ZPiT>esd8W3*>asE>xJv;?$`ebdui8x4Vpj~eFYh~2iZy_+ z8G$JY$M#ofhn*ea>7yjJho`t)=FI7ukfmEm5edpn@g1YrYDdOiZX-RgfY?S4Jt7Ua zH_Y|VE5#P`H=D`Q*j5>{q|2+C7J7b^_0>@TPQaD1w``_4T`7HkV8_6drmsm<-tI+xWH@l&8t|vKykn<@sEmEBi`Lr4 zvEX6?Ul0vx7$Te98(-75*Y9ZD^H*;f3#R48)BzxeXy~5TI7J_eRUVfIrFCpV?mWA3 znWOg|Zk_iFzv)JFeF38t~NX$lgVPlfFC@hDf-hucIYV~ngGF8jpuc1 zo6lTbV*)a{7RizUj+W;&WpA%)*2%Xt@VcM8S^^ZNb;k=9rwE-kI4hOb#*RKy#v;+x zcYJ?||JnDxx1qki^kOUn3NO*9P}?&Nk<{0$0oF}vP{L=&UPS>U(!l;iuC+R z5iR~cy3gqfYF-q`n*{}n1b%;OrJ2~43R9m*lRfGN`}&Zm0bFadt^aT?P2ml={;Is!D8 zHZ94<)uyXe^it2O9S;KM2v+o1-O+~+=-w^e3pv|(gQ60J_lYsyE$4T?t)IP&F8wVg zRaB@dob(*LM>mP^YwoRK-Bv=KH2yiVu>kPkH3D5n(WXn~QhCwQFAS)bBEHEuA`>5Y zH)BExuI`Bj-p$747QYjobymj?3Y0ZBj-k}nqq+%jwx-4zTP(0{bVEOG)Mg&Ghq0DT z4xf81yp~gp%C(Ly)a=U(4`VN~6IU4s6te)+)voSvgKJn^`pe!WCBH2-H?Z}|bk5|6 z;(MU>wf5vj(Ia0c<63hgueNGt#?0=^b|rYWL1T{qK5yg35exKCfM4}d)5AbW$U9K; znrG_j_WeyE7hj`Y#1ses#x^-^UHs~u(E8;VbLp`lg*j>AYSU6fX5P87R+AJOssRu7 ziJT}bre78*ijqTIjmMB-5Ec_bnCvf&XBECjfo1S-0@&^1K zqMtFn#abh4>6~r+*(fe(SWPutW$x}yzMMFzqDG}j?2!w5)g!Rm#ExekHs@*eZS6T9 zF}0Jd5E3TX7=8C^Hejquv#}_TyvwUn9<4*zv%g^Yi#FOEoJ+RSNPowmJ(y@2z8 zX^@QvTzOeP)_iI=pDK|FLVca@bK(ZhB_kHv9-g`Kxvm!5dsp(i-XB+cA9GZ;e}DtC zE1I-o2lWN5n>i7k4Vzt$&utNxrL6IgZCU`{;u5y@z9SXSW@MZA-ou4oRWmwA zEa6+_PCxoFXk1{zXZh}rBgf3*xA`B3g<2O2F?Rj zRaLtmGG)f;@}-X@jC&R%mHp=9m2(O2(j2(Iy!}*i9Rg|SNrF=c^f26o38q92j_9W# zH_o??R*Pe^Fc;;@VB7dm>mH|;P$p&ZZEZ*K%{|$y5UMjJ{;V^F#ar5iLAJyZTvV@f zu9gw`O*_H3I3Q%SI5Vo!-O$8g)>f4@Jyxo%oP~1ZhILfAv$ayiO7hiu-5rHvVu+#N zh~Rk|*@Fx)kj$Kh1Hn9Rw=5qrZA>V|irLd<_rAWqwhy4$o(X5yC_Fvhu>3o}Rvivi9o^FfxJ+9EM8+`kZ zGB352CYhQEalaj%vq(F`-hm4lhcHv5-Q2A`xtogoA8g?QR`BY<1lJSTFZ=Ib(CPEX zV@`iO!4o$d&!$T90gVU=so3P4_8V=to#a+bU6eu46k1R{ia&z0G3JPzPcmzFN>iT< zEp>dux52MAgE`4IKCQejR_YO>gS1q`>*tyc2ce!TuJNjOh|={h6U-Q>Mlj0-R0KIqRTN+lFHq!XpYoPkTtSKSOonvMkjop+*&lQhbW~BE&0;{ ze?rDX|HW2?#olgq^((dZjRp^r_g)^`4MjhU?8L-Ex|^($r+Ln8crV$;_4*&{^MUCM z8g28Y((!W)vBRW5OyVXXQxtfilBrEPXdafVMn#VfKw}R2D~o6Dwhe_fbWL8*uxVPS zLgwuO_J(4v9ditm2uzLjGw9gv4skT#b#!3knvIjwKR=wjpD^JIGen&=*7j{81qMum@pe60r!-+Cpd{ z;otWpSj^dil_tIzCrd%j;XJPfcLGCzK&d@Xsu8Y+fkR?N>?+b^a7q$0^G^3ghnc^w zHr2QIJQBmzr3-laEhkTE@KzGU7G*D>xX4f)GKrM(EI>XI(D%W+!>5e~s*AL8WxD&J zP0aPqu>Be^hNs#=W!17kSCVeqw>dCXn3bNhYD%!FC5=afKG*tPf37b3{^omRf<6o*7$WkAq7X`>$(83v8!7$a`+A$1LVn-6u?D7X&w zR=-1t`WX_j(w)OkE@6LqzT!&X{N?-n4kr7RufOslheQ<&6IcKRy07hF?diaD#a3YQ${P}-v7y}! z`K3MYyk1dTBzCQjioaB@=V}EdY`6H3h`M|}lOUXUV8N`E`j6;_kS!*XpN{<9G-3|t z^H5}T$1|RKn}DjDU>q$@)tyP!lIkW^)jI6}x2p}yrKP2(y(q@D<=!vXR4OcKEx&16 z%+&=N-C^V=_Et5|TWQya1q<)0PqNPS&RDR9jab4p2&~e+ zcr<5Iqgm}ENf4>M<3INhdP^t-A^GsUI?VtVG#*53{;;;1 z4bm!f`ImvEDQcn)rraEOnQeL6A=q_vptZr~Ko^|!X~-)^Xprn9Q8-#ja!Vmw?JsK} zU2aTe{vDjVf%f1>v1vIze`?EiA)`^+*n~gzCo@jKQMK;Y4pLw)sK2>n8Jo#8fA;b0 zpT_j!1$pU(@XiQa99mIwSj7@chUn z&ePis{bwVI8n!zLs8yfM>gJ}ca;Z!`mH)T*d#eAJd8UAG2fapJAEDm?3h&t%nJkg6 zLI^2=_aWc0yGbX^H-rL5%@!f6RyASFSMcC;Fq-@UDYRff*_ z{)ytU3asywX)LC{5f4lEZav%`S>=RD+y!;vh@bJEk}ME0u>jWn1o;U>^9k3rsj-1` zHjb1AmsK!ZxoSg*lRNba%X>Q<>Fp7s1w28<1nX)E>bB|vuXSI=E+AMF0gSLON|O!M z*29q)*$*LSB<}dex@dk7wa3@z<}Ww9sxXeZdlw$GB-$Iq?|%%O#6Vp>C>XuF?PiCl zkxs(!@~zA@I8D#D4VMQ&u+XWP1E9}qk&i}#Wqj6@#a4ZjMj4#G+h9VxL0;AQEA*U- zeHH&G9G|eRyQqoD-uYDbHFl5&2}3N?r8Ebl>XaRLTXu1bFiD)E^{J)aaL)`Fg@u&W z2}yWLDtMk6^BUcmbUwDM3)d0&E-C_-RxSN1*7`l9)`m94t76x%@eEu7&Uq)4LpEu% z>Lgik!ZE-qLVZx_QDa{Gc-)JKpE`roM)QMz$?zEUF#jz;ker^tO~YN}clq%0Afx2L z&w0mLTU>lF?_*TZa{%u3&X_m~>_UUYm>sh~&8Y3UyScj3Z*+UNa^N{7Qppnr9Ny_! zWJ`15`uso#`0m(|`2D)!jm)kALQYRl`wMx{p#2uqb^r5zm_VSIKqs$f`{wh5vC>{=$uLJgu;fkFkM8oL)M)!F)Js67L)_o*yY+(O}cRM^b6bJQCeAhEEPnbJC@kr+C%j-EC zpof%i;tqmZX_kok1GqxJUpI~>lI z@D&hW{}qPwL6Ad$Ot|>>OK~9SrVmFJ_q`}yIjKBNJ!K1aQTB2HV3i1Puv{a)e|MhK zMck~@XX}^L?o?RQoP}wkMf`*lsP5Z~7{mJeRf+B$0&rAk_qlR{5+@N+I&j(xNO@juO2?k>>VSUj%}-rQX1)Nu-p9z8BW0h9z!E2%R!= z59yJ%bFw|}(=DmQXSk8I4#5v%&YS#3vL+W|dbCX5J>aU@SCJHOnG5c%hah|JtbBW9 zUH8JLGk~-Mx(SOG9NA!8+>kUNF+eEqWW#K=D@b(=C4^f!O;MdBkA28A1(xCd8kJ|K zRt(W2YbFtRI5_+{b6Ehs41yQht3xm{v?Q!k*r^vy<*VrI+;~R-`SB}YDX0__gF<%5 z>sAWDrr}gXgych#aY1UfliY`?lxp3NBaTaCjyOZXusgx*0Xr15(`BT|AB>uC4Og6^G|ZAb-5escB>M4Q#GYDIoiEU(fh8Fwr{Ik(*}S+3L(ZAy61?2@q=qUMZN;WJwbAhIsl4Ok$K0m(BhJU@3eX zOFHi(@SK?^>xyU}^Byuq3C?xf=u-{~|f*UQ@q?VC!Uzq2lyYS=n`Hq@e!uR=N5q zJR-$*b*eP_M7rrsA@+B>=4_02bw3)$2A$#ZdlI~jwk*HZcq19D_sK>~k|N^rV1FRG z!V-+0>1dl=g{_ZklyyK+ru%px1<}tm3rY8#WPRV z9<`Oe+);fB#9`wxk5Px>{epvC#Dx!6mxFYdCbo~#{6{jLvq4-PzH{tiLVQ<-R=uFG zfbO^()SO>}FX*!J9*~=G|X(+k!CQK$n(0% zCmUazY8nfxXHSSrGntT1U^VOU^S(Vv4@~WsciTUogk{l!6rtWQFeaDKn#D6k{>8f| zpl8B~tQY+&$Lm`ZqgLj$y$0=2&UQX25-i-Hdbx=CjF!#j}Ofspyl! z1Jy$Ih34QG0t+NlOegV<^JcG~W#U7_f;m7L`=Ur_kZk%k+$~G4`N=Ta z(;TBJUS~1#$-Rms8A;3gF(cXGnO817bxSISJSWuJEsgd6%Db34i2DcWs!=4Q+k725;M@I{d zEH|oKH>L0i0DUw;p|VlIo;XN&XK6fYg;RWfH^MgWuK1B7Yi?mek^hN)+bW{W+UkrT zoNj=-IEp^`3)+?+Hp{ioPdWqWHjphBmLvGW%kRJ~-tFnaJe}UKgLM3AvtxZ@XA5&- zvNsd|1mmh(3%#~o^w*`?6ANu)T8sqQgVT?|55*Qc?rEJauc=8mYs%?Rj2B`O`HnWq z8#+X#D&*+MtS262L(k?NeIirV=qI0DAh|z6R&`&k_#aMm)?S$t%ACDMD327fd3nWH zwmqsm3cb*b#e5-aY!pqo1<6hX*%!q#hipnRNo!$U&|3GuHBU71=8go_ZCP*Z3V7+r z0?`JKDH}gsU_QG3O8?@>!c5RYrd+uBB zjMQQ_>7mv1*ts6urhQvGq_bkV)yyu&(d=x&wK2@OmdrElnV94=>AUIvwjiqcBxkCU8eeVFZ$NWw3Q9L5FFTAyMxvBi>}WYpaHjFQlt zt?BA)J$bL-!lR#<#yXpKR>%V?BWK#7+H-Gdmlj+Ll&Z4^C}94U;T6-c^)beXKJ)YY z)q5Rym$ATZOnLG^Mb z3YEV{7L|rO#G=Z1md?gbPm2}_NwgFd26K>2>dU_Gq}|7OwLGLzta5d7$Url?Hg72*y7oUbj>8uY>s7jaLyB}PL0Em=LUd@ z7rWMlhs|oG+#`v!CR8 z1($7txN9^jHlx5{RN!i@ML-B2%63l(kx1r1cLMP3?aehBT2q>Y-qf(r<~b59G1mU% z;k(YUw${DG^*(fhyHusAPCvbI16zP|$Ro2acgeHovXz5HpkFCMoMYxq(A*tgMf18a z(X;a)$=GJE_al@4X)t13*fBHb#N51zmsnBa;0wf^qdh6KgGNe()mc zji#b*RIT*`3Nou;DMU(y9YE;;Nmpj%1y(UF6T07RtFf zM6{TtF3I>xkF!xwy!ru~)>HsN5iKy3_W^#|3q>p|`R$?3Qt9uz-eSAiHvmfIL(wro zoOh)m(^nu!duI0UudWHD#pR)s1}Mh z{~df{jG#c!Tki?@<-wZ7E~V%BJ9`3=|G~65T8)PdlyxjpZq~4i93P>C4;7}J&oy4q zj^>RDa%j3#_8Vlnw*aA)MCwDvpxNTJyXZNU*5pO)?cxQnvGG9(@y2nN9jfk|jn$L2 zrg9U2YXaSmWf3h(3ocLX6&#(0IEOcXjpOU-g%$#EY`@|{#qxVoz* zuWUM7&LrQ{_5P{F?>n1*oWz35r1m4 zEf__5zMzL-P@|+a z;weW$9KB3B8_qOQV?68^GRV6Gt^1a#?&%U{Ty#N62uCFis+9n$O)^5Eqy*54+2_M- z`mW|=Z)}HziIX+~k`ucY#9CQ@Gc-ub$?iU1w6cTM8W9t!5By*FEg$3zHBd-LhLeVy zWNqjaAK52@q4sB?9-x#T1X1XX3@y7<`YXi8aP%D8ff}qn|3w6!;z0l&8I!M`B4OL0qI&&&rJU9raJa|0Emy`4L&E#Duqh??X#K^s z+wC9|_maXtp2A&i{Xj95c*PMSlLOP7xx4!?zaOuXwkiONGnW4r;`|7v(s^6JjD2ll z#-qwBO;ts$ZXDCta4>gmSKq#7R_(fL-OX)78U1A7pd_VoSY@i)4aXEvt~pB;6mx$8 z@u|JBQ&?fZl=!wqn}=6x*l>maF}r&Qrtx#(U+M;OBOFd5BdwC%<`>~W^LIWGj|W5v z9=Lqaz$O`13Qwe9W1St)5(LWPSNb;3j8S30+cnXNt=GsY=`beGJ&6M)Z8j)RY8wPC zoBy?Pmxo(>=n2~d4>%DSAz^wo>8IlE?f?gmkdU|Z%C!+{85u(NnJ4AfzQ^ST+RCd2 z>>zekW_~qA7(+(c59xG#feGiNCsE{R9SMou1m*EHd7_+~{snRhXZ^-B3&O}m?Z_@QHcGRnm$^h7pwK z3j2p-f7Zgc!;a?@AD=KrW;|~|cAXCo%E(1ir<_B?D`|6)&e8(XdBd#~<1*wn9jVH;PwZ~m$7-?M26O9_NYKBeZBpE<);0kEVl=Mn zflcgPNi7y+#`+0YP`v_vd#~LZxDWFE(QeD4;~%&`C{O9?bS+^1C2Pcwqa1Cabm1-& z+0tM`TEYsW2qJH~a@D~Q_6#}(4d>3gRuP5gNd&Y{hMk1bly0I#ScaNkpBi#9Gcq=8 z@BJVdF|I&`fBG4>vHBvQ&1v2oX! z<@?A1>m<)R!&4VJj3i=ojm~AQTBq-T@(pg0L3dS;Mm2m!Py>MIJt;Tul^wNX(Ja{`1kb<$C!Fbou-4cXVkogTpUK zsLLjQsR(~0bb6*Z3m3oy7C4_>7bJ1?g)yS&YZVonB-SOm;j?Y9o>niC9Q1?pQzmb@mi*CC3q3arW+gA|F)&v#|n@Q`#QE5Y+W+TSsK2pJ!DIGRD`ho^NHZK8^5h| z))Ri*`STkRkfj+TZX5hm>~X7%W~wpbe|JL3DQv#`molmT<`v;>$MVEutsnY|60CTk z25QY4%p(rA{lui(5>0gy-PY%BnH1iPtZQA8m#9Qf9W=4P1N!kp+hPN-u&@Bj7cuMr z>GJ};_sqQOi|^MI8XT4Xrbu+EkezK@HC39m>haiZz&Vik&i-merGrxkJ<Z&r(~kF7Cn>9Q}5DHoU( zU(T{n9an^*5)PZYBC;o;hE)Or@S|K^E_W!`7FxRZg~SbzcsGr)vnyu&0@N6~t@sN$ z>>sgFU1>Y2p1A2k8b^)z=VozG`Iq%S=r>@5v-NZMu7R!-oc^YUvx2t)KSCee=^U#c zzht?L&>gW3N7FX~cRhvZ6N=FEK)+l`#sVs{H<@ywgkTroxIQX`u6{WE`v^GuzDQ$qS@pYJPm;4spCJNIeeeqP;)$)5}QuSyyR`}d+K2R0etjBl_)3aJCY(td6kox zQNM$~)GT@uKhR*j#|jCK-~06g1ke2*U~)=PLpujKMG8V5c>7Z8tiVVej(H$) zN0n!og%xyRl=$?8JRmK#pf38YahMX!PeCNG2_;TDw@J}kX}eE2&<6}~+&4}4 z{F0BaQ5lr8qvYHd{i6*SAX*SL=)dUp8lzm7xw}$0ciWU&{EG?g$@Jm;%H?|nUkK@< z>5C$$B)}Hxx4gsS#Ot;TB4XKM;5kdeqc|-XS>MRUhZY7jUabv!p^6^e5MPhc{G+Ns zm=oQmCeO*f$jtmJ7vjW-WY`y4$gQ+^_1^IyNXHQ9A=}9sIgHG6r!@h?<}nQ^Qn3bM zkB|Y{n}aw2Ul;WadHs#WjpCj#QwX^*c_c z3r)DV3L*QU9|XP5q3OD3MhJpG(!Ur(hNakLST?l9%DG$yb374BrEQKhRuOD&13shRqcCoe%30ahE7BQlWOb zbJqU*Mkvb~t!r5{ud)-6Rudk&HkC92$dkDQ}Eoxz_3f&N4eM;l`Mm=Y*gE!a=3dd#E&pId-{bPJX#wvS zuVp;SAOR<@k%oc9@_lR53O1hKw_Z)^5dsQ~N@ z(l~8(ai)e>sfRg=M0PEY6=g4)PI{H4a5WCr&Y=!ZK3gwvh{)JL(qK#a!{&pl3(7*H zMdt94?>oBw0r4!f+bn($cYgnsWQ{HABNxOEv~53P5}?>QERlSReM1z`8QkWKFlJ}a zK{OW*z3I&?gNGa$3neM|)3+rl!BrJ1%Fd5eoS)Z^dz zn8YoXvk$qKJI=m1Qu{!Glor=_iasY9z2%1BIqFgG+r5ZPx^QcwE+oB=KRh~Nzu;;o ze_IDkwnr*l$*)#=q#yV8<;wLyrH*aEwXJ)q5&6e)bd!6`SC{F1$5014U z-PVATfXoMKtv3;_$89mHP!KO$E%E;5O~}%Ove~j2G^=ZQf%(IhUo-H8px6t(7W^uZ z)xpM`C%(HRkiNM7r(4*s)vUM*z;_1eiO5skYpNwTw9LH22C|-Zu`!A9o3Vqb7YW{K zr+GF?&x|r&MIK3FlO=FaUx|FXNBb~D2yyHiK4*{Z; zrJ|5u_ey=e#q`7exf+4*l$v7;2dbzGqdza6U2Qlr+91UAw~UttzAZew zi^kPUSgnH_ea8{NLhM4loA(8cOTNleEA8 z+T-xbVm_QB$FffqZFdzlS)~Ep`SQ}Hqv{@AeL=j;aT@8)QVAa~6qvI2o6V53u3CL0 z60Q>_p>0L$#6D$R%7_fSdqFxzog8U8LaS}T7B|N6_S-=MMPosuIpgKE%W@y*SK*Ho zc;2d;htbc-=d-k+c_q&?Nls!IXr6iOG!A5r8&BdGfccWd3v^}TO$e*X=6i@>xCqy7 z*;a9o3(R6rpuW66f@;Yc=`Rgk2zCA?wGePm#4+w-q?Fz?9|gYXnQu%^qq(g9WdKYiKkZMWOW34(2@GLW@f{Z#Sn2 zHBQlLf(4!CLpx$#?!6zAF3TfeVJ1e>cL1%YKN`^4)Wn48QtQ}H@D(}N^^#ahlio`x zZsRoOY?=BY)I=GZAX`5=bc;=UFhBpQ zVTan{RWOFpuuj$1HTm!(RShcG!da#s5v8d=9Q<~K`}^rj!c$z+)KwP^cwiFvdjzV! zhoA7(mo-Y1Vcq*)XztMJ<;aIA>sGavbLnXa?=G@JH)q#K?wAKo?yMt>cX?n8m$t$y zPHDS87HnG+wK}6Rw5FM3j=aUxYE{@;{lE=jgNipv4QQ)rVsCl4b%OTic1J4VwzoTJ z_+7*kBFL#()MC^tn7AEe5_#?G{%q=gqja^(?%dN&X*1YIlaf1$&xOx*Q<07sa%KP{ zJ?A*f?ys(z{o$jo&a>UxGmLCAPI4_p)-3|d(N3|U=vGYTbCByT44jOql@kE042Ge5 zrK1Bfu;<1ATT(NP%2}+XUQQ_o^3N|HvJAS0=4b_#dC?ysmwG!&td!6O57Q*9nj~~-ypL<1$+#ts7-5N~MlQkdy)z~Tc2GmgBAKqJO2oT6 z`<7K$<|6N+@3#IoZI1PqS&o!B@PB~=`=w-%+J=JNeb05L<-OcpmC0B`cP5|Cr!(<1 zLfyA+x8>V7ML`(7m=@HKbHXZV9)w^i$d$~GLZR!bCzn{b^lh=RwU%fe?#ymSN4Ki> z3$!R_Dl7SxZdZD3#1Ae`UU2)%VO>j$D96hjI2<|PMC)J;57($2_g*_2Yj**~-^GTR9t-$*j+w;oXM>_Y2~IMaTxnb5vH)%*4HlxJ5?}vp51B z<0TDuWF2y9+WVf4MuK;jHT2;$aLqcR9>#(QuV2YG(|4UKisJ>m{Q4BbUa})g4uqxn67NvW9kC zEB}-^Z~zAmNvOjdp%5+MEc@j2j?W=~pG9le^dZ39kL2Pu?^7b&&h%C$QJ0`g8s&I) zn_Yqf(+x70sC0)U1cw)DX1z)oi!lLob@uIG)9r6{Yz2meby2+R${Z+jU_S>WLa)n} z3RBm;SD%>o{2Muzx}0@xB!gy7qq>nyNvk9jMN25HTU5YKnDtY1Bo!Z&$HgVkelij9 zBRYTX=<8->eMig>zAAHD*}`>xkwiHtbD+$D5)Qm>p;lg9Csn8`r3yRmx#nCRK1B2q zcBO|2mf;2H4D!w05_j!euuyyp_O*i)eh_%HyC3I_Ix15f@$TwQ?;`j$f8*g&1lYOg>SKA=@)AV!0v?a! z1?7fBk~Oo_#r(K1%uT4$3tHTI*lf$^gPq_!!|Sj2X43h4hrP9+nU$l|LeO*Bl{rx6 zz~CHsLqaW*dS#P0Z++bt4~vj_+)-aUIhym|#8UZa6mc_YqghYaBG|wG6xRAfj_xW4_1~Fbjj%a`3IJ#znsAw vuzv@9u-s)>nFD1GlsQo5K$!!FF$ew&M?@W+TYX^n00000NkvXXu0mjfL&1Fm diff --git a/go.mod b/go.mod index da40933e7..caaa62604 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ -// +heroku goVersion go1.18 +// +heroku goVersion go1.22 module github.com/getfider/fider -go 1.18 +go 1.22.0 require ( github.com/aws/aws-sdk-go v1.41.14 @@ -10,82 +10,96 @@ require ( github.com/goenning/imagic v0.0.1 github.com/goenning/letteravatar v0.0.0-20180605200324-553181ed4055 github.com/golang-jwt/jwt/v4 v4.1.0 - github.com/golangci/golangci-lint v1.45.0 - github.com/gomarkdown/markdown v0.0.0-20220527210340-c82b80a9daf2 + github.com/golangci/golangci-lint v1.59.1 + github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8 github.com/gosimple/slug v1.11.0 github.com/gotnospirit/messageformat v0.0.0-20190719172517-c1d0bdacdea2 github.com/joeshaw/envdecode v0.0.0-20200121155833-099f1fc765bd github.com/joho/godotenv v1.4.0 github.com/julienschmidt/httprouter v1.3.1-0.20200921135023-fe77dd05ab5a - github.com/lib/pq v1.10.5 + github.com/lib/pq v1.10.9 github.com/microcosm-cc/bluemonday v1.0.16 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/prometheus/client_golang v1.11.0 + github.com/prometheus/client_golang v1.12.1 github.com/prometheus/client_model v0.2.0 github.com/robfig/cron v1.2.0 - golang.org/x/crypto v0.0.0-20220214200702-86341886e292 - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 + golang.org/x/crypto v0.24.0 + golang.org/x/net v0.26.0 + golang.org/x/oauth2 v0.15.0 rogchap.com/v8go v0.7.1-0.20211222173054-943fcf9e74cc ) require ( - 4d63.com/gochecknoglobals v0.1.0 // indirect - github.com/Antonboom/errname v0.1.5 // indirect - github.com/Antonboom/nilnil v0.1.0 // indirect - github.com/BurntSushi/toml v1.0.0 // indirect + 4d63.com/gocheckcompilerdirectives v1.2.1 // indirect + 4d63.com/gochecknoglobals v0.2.1 // indirect + github.com/4meepo/tagalign v1.3.4 // indirect + github.com/Abirdcfly/dupword v0.0.14 // indirect + github.com/Antonboom/errname v0.1.13 // indirect + github.com/Antonboom/nilnil v0.1.9 // indirect + github.com/Antonboom/testifylint v1.3.1 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/Crocmagnon/fatcontext v0.2.2 // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect - github.com/Masterminds/semver v1.5.0 // indirect - github.com/OpenPeeDeeP/depguard v1.1.0 // indirect + github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect + github.com/alecthomas/go-check-sumtype v0.1.4 // indirect + github.com/alexkohler/nakedret/v2 v2.0.4 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect - github.com/ashanbrown/forbidigo v1.3.0 // indirect + github.com/alingse/asasalint v0.0.11 // indirect + github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bkielbasa/cyclop v1.2.0 // indirect - github.com/blizzy78/varnamelen v0.6.0 // indirect - github.com/bombsimon/wsl/v3 v3.3.0 // indirect - github.com/breml/bidichk v0.2.2 // indirect - github.com/breml/errchkjson v0.2.3 // indirect - github.com/butuzov/ireturn v0.1.1 // indirect + github.com/bkielbasa/cyclop v1.2.1 // indirect + github.com/blizzy78/varnamelen v0.8.0 // indirect + github.com/bombsimon/wsl/v4 v4.2.1 // indirect + github.com/breml/bidichk v0.2.7 // indirect + github.com/breml/errchkjson v0.3.6 // indirect + github.com/butuzov/ireturn v0.3.0 // indirect + github.com/butuzov/mirror v1.2.0 // indirect + github.com/catenacyber/perfsprint v0.7.1 // indirect + github.com/ccojocar/zxcvbn-go v1.0.2 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/charithe/durationcheck v0.0.9 // indirect - github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af // indirect + github.com/charithe/durationcheck v0.0.10 // indirect + github.com/chavacava/garif v0.1.0 // indirect + github.com/ckaznocha/intrange v0.1.2 // indirect github.com/creack/pty v1.1.17 // indirect - github.com/daixiang0/gci v0.3.3 // indirect + github.com/curioswitch/go-reassign v0.2.0 // indirect + github.com/daixiang0/gci v0.13.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/denis-tingaikin/go-header v0.4.3 // indirect + github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/disintegration/imaging v1.6.2 // indirect - github.com/esimonov/ifshort v1.0.4 // indirect - github.com/ettle/strcase v0.1.1 // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/ettle/strcase v0.2.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/fsnotify/fsnotify v1.5.1 // indirect - github.com/fzipp/gocyclo v0.4.0 // indirect - github.com/go-critic/go-critic v0.6.2 // indirect - github.com/go-toolsmith/astcast v1.0.0 // indirect - github.com/go-toolsmith/astcopy v1.0.0 // indirect - github.com/go-toolsmith/astequal v1.0.1 // indirect - github.com/go-toolsmith/astfmt v1.0.0 // indirect - github.com/go-toolsmith/astp v1.0.0 // indirect - github.com/go-toolsmith/strparse v1.0.0 // indirect - github.com/go-toolsmith/typep v1.0.2 // indirect - github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect + github.com/firefart/nonamedreturns v1.0.5 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect + github.com/fzipp/gocyclo v0.6.0 // indirect + github.com/ghostiam/protogetter v0.3.6 // indirect + github.com/go-critic/go-critic v0.11.4 // indirect + github.com/go-toolsmith/astcast v1.1.0 // indirect + github.com/go-toolsmith/astcopy v1.1.0 // indirect + github.com/go-toolsmith/astequal v1.2.0 // indirect + github.com/go-toolsmith/astfmt v1.1.0 // indirect + github.com/go-toolsmith/astp v1.1.0 // indirect + github.com/go-toolsmith/strparse v1.1.0 // indirect + github.com/go-toolsmith/typep v1.1.0 // indirect + github.com/go-viper/mapstructure/v2 v2.0.0 // indirect + github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect - github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 // indirect - github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a // indirect - github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect - github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect - github.com/golangci/misspell v0.3.5 // indirect - github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 // indirect - github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect - github.com/google/go-cmp v0.5.7 // indirect - github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect + github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e // indirect + github.com/golangci/misspell v0.6.0 // indirect + github.com/golangci/modinfo v0.3.4 // indirect + github.com/golangci/plugin-module-register v0.1.1 // indirect + github.com/golangci/revgrep v0.5.3 // indirect + github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/gordonklaus/ineffassign v0.1.0 // indirect github.com/gorilla/css v1.0.0 // indirect github.com/gosimple/unidecode v1.0.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect @@ -93,101 +107,119 @@ require ( github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-version v1.2.1 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/jgautheron/goconst v1.5.1 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jgautheron/goconst v1.7.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect + github.com/jjti/go-spancheck v0.6.1 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/julz/importas v0.1.0 // indirect - github.com/kisielk/errcheck v1.6.0 // indirect - github.com/kisielk/gotool v1.0.0 // indirect - github.com/kulti/thelper v0.5.1 // indirect - github.com/kunwardeep/paralleltest v1.0.3 // indirect - github.com/kyoh86/exportloopref v0.1.8 // indirect - github.com/ldez/gomoddirectives v0.2.2 // indirect - github.com/ldez/tagliatelle v0.3.1 // indirect - github.com/leonklingele/grouper v1.1.0 // indirect - github.com/magiconair/properties v1.8.5 // indirect - github.com/maratori/testpackage v1.0.1 // indirect - github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect - github.com/mattn/go-colorable v0.1.12 // indirect - github.com/mattn/go-isatty v0.0.14 // indirect + github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect + github.com/kisielk/errcheck v1.7.0 // indirect + github.com/kkHAIKE/contextcheck v1.1.5 // indirect + github.com/kulti/thelper v0.6.3 // indirect + github.com/kunwardeep/paralleltest v1.0.10 // indirect + github.com/kyoh86/exportloopref v0.1.11 // indirect + github.com/lasiar/canonicalheader v1.1.1 // indirect + github.com/ldez/gomoddirectives v0.2.4 // indirect + github.com/ldez/tagliatelle v0.5.0 // indirect + github.com/leonklingele/grouper v1.1.2 // indirect + github.com/lufeee/execinquery v1.2.1 // indirect + github.com/macabu/inamedparam v0.1.3 // indirect + github.com/magiconair/properties v1.8.6 // indirect + github.com/maratori/testableexamples v1.0.0 // indirect + github.com/maratori/testpackage v1.1.1 // indirect + github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect - github.com/mbilski/exhaustivestruct v1.2.0 // indirect - github.com/mgechev/revive v1.1.4 // indirect + github.com/mgechev/revive v1.3.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.3 // indirect - github.com/moricho/tparallel v0.2.1 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/moricho/tparallel v0.3.1 // indirect github.com/nakabonne/nestif v0.3.1 // indirect - github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect - github.com/nishanths/exhaustive v0.7.11 // indirect - github.com/nishanths/predeclared v0.2.1 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/nishanths/exhaustive v0.12.0 // indirect + github.com/nishanths/predeclared v0.2.2 // indirect + github.com/nunnatsa/ginkgolinter v0.16.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/pelletier/go-toml v1.9.4 // indirect - github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b // indirect + github.com/polyfloyd/go-errorlint v1.5.2 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect - github.com/quasilyte/go-ruleguard v0.3.15 // indirect - github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 // indirect + github.com/quasilyte/go-ruleguard v0.4.2 // indirect + github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect + github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect + github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/rivo/uniseg v0.2.0 // indirect - github.com/ryancurrah/gomodguard v1.2.3 // indirect - github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect + github.com/ryancurrah/gomodguard v1.3.2 // indirect + github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect - github.com/securego/gosec/v2 v2.10.0 // indirect + github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect + github.com/sashamelentyev/interfacebloat v1.1.0 // indirect + github.com/sashamelentyev/usestdlibvars v1.26.0 // indirect + github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 // indirect github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect - github.com/sirupsen/logrus v1.8.1 // indirect - github.com/sivchari/containedctx v1.0.2 // indirect - github.com/sivchari/tenv v1.4.7 // indirect - github.com/sonatard/noctx v0.0.1 // indirect - github.com/sourcegraph/go-diff v0.6.1 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.4.1 // indirect - github.com/spf13/cobra v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sivchari/containedctx v1.0.3 // indirect + github.com/sivchari/tenv v1.7.1 // indirect + github.com/sonatard/noctx v0.0.2 // indirect + github.com/sourcegraph/go-diff v0.7.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cobra v1.7.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.10.1 // indirect + github.com/spf13/viper v1.12.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect - github.com/stretchr/objx v0.3.0 // indirect - github.com/stretchr/testify v1.7.0 // indirect - github.com/subosito/gotenv v1.2.0 // indirect - github.com/sylvia7788/contextcheck v1.0.4 // indirect - github.com/tdakkota/asciicheck v0.1.1 // indirect - github.com/tetafro/godot v1.4.11 // indirect - github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect - github.com/tomarrell/wrapcheck/v2 v2.5.0 // indirect - github.com/tommy-muehle/go-mnd/v2 v2.5.0 // indirect - github.com/ultraware/funlen v0.0.3 // indirect - github.com/ultraware/whitespace v0.0.5 // indirect - github.com/uudashr/gocognit v1.0.5 // indirect + github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect + github.com/stretchr/objx v0.5.2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + github.com/subosito/gotenv v1.4.1 // indirect + github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect + github.com/tdakkota/asciicheck v0.2.0 // indirect + github.com/tetafro/godot v1.4.16 // indirect + github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect + github.com/timonwong/loggercheck v0.9.4 // indirect + github.com/tomarrell/wrapcheck/v2 v2.8.3 // indirect + github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect + github.com/ultraware/funlen v0.1.0 // indirect + github.com/ultraware/whitespace v0.1.1 // indirect + github.com/uudashr/gocognit v1.1.2 // indirect + github.com/xen0n/gosmopolitan v1.2.2 // indirect github.com/yagipy/maintidx v1.0.0 // indirect - github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1 // indirect - gitlab.com/bosi/decorder v0.2.1 // indirect - golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.10 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + github.com/yeya24/promlinter v0.3.0 // indirect + github.com/ykadowak/zerologlint v0.1.5 // indirect + gitlab.com/bosi/decorder v0.4.2 // indirect + go-simpler.org/musttag v0.12.2 // indirect + go-simpler.org/sloglint v0.7.1 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/automaxprocs v1.5.3 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.24.0 // indirect + golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect + golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect + golang.org/x/image v0.18.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/ini.v1 v1.66.2 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - honnef.co/go/tools v0.2.2 // indirect - mvdan.cc/gofumpt v0.3.0 // indirect - mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect - mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect - mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + honnef.co/go/tools v0.4.7 // indirect + mvdan.cc/gofumpt v0.6.0 // indirect + mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect ) diff --git a/go.sum b/go.sum index 90a39744c..473e62f47 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,7 @@ -4d63.com/gochecknoglobals v0.1.0 h1:zeZSRqj5yCg28tCkIV/z/lWbwvNm5qnKVS15PI8nhD0= -4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo= -bitbucket.org/creachadair/shell v0.0.6/go.mod h1:8Qqi/cYk7vPnsOePHroKXDJYmb5x7ENhtiFtfZq8K+M= +4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA= +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -14,19 +15,8 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6 cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -35,166 +25,146 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.5.0/go.mod h1:ZEwJccE3z93Z2HWvstpri00jOg7oO4UZDtKhwDwqF0w= -cloud.google.com/go/spanner v1.7.0/go.mod h1:sd3K2gZ9Fd0vMPLXzeCrF6fq4i63Q7aTLW/lBIfBkIk= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Antonboom/errname v0.1.5 h1:IM+A/gz0pDhKmlt5KSNTVAvfLMb+65RxavBXpRtCUEg= -github.com/Antonboom/errname v0.1.5/go.mod h1:DugbBstvPFQbv/5uLcRRzfrNqKE9tVdVCqWCLp6Cifo= -github.com/Antonboom/nilnil v0.1.0 h1:DLDavmg0a6G/F4Lt9t7Enrbgb3Oph6LnDE6YVsmTt74= -github.com/Antonboom/nilnil v0.1.0/go.mod h1:PhHLvRPSghY5Y7mX4TW+BHZQYo1A8flE5H20D3IPZBo= +github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8= +github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= +github.com/Abirdcfly/dupword v0.0.14 h1:3U4ulkc8EUo+CaT105/GJ1BQwtgyj6+VaBVbAX11Ba8= +github.com/Abirdcfly/dupword v0.0.14/go.mod h1:VKDAbxdY8YbKUByLGg8EETzYSuC4crm9WwI6Y3S0cLI= +github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM= +github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= +github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ= +github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= +github.com/Antonboom/testifylint v1.3.1 h1:Uam4q1Q+2b6H7gvk9RQFw6jyVDdpzIirFOOrbs14eG4= +github.com/Antonboom/testifylint v1.3.1/go.mod h1:NV0hTlteCkViPW9mSR4wEMfwp+Hs1T3dY60bkvSfhpM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU= -github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Crocmagnon/fatcontext v0.2.2 h1:OrFlsDdOj9hW/oBEJBNSuH7QWf+E9WPVHw+x52bXVbk= +github.com/Crocmagnon/fatcontext v0.2.2/go.mod h1:WSn/c/+MMNiD8Pri0ahRj0o9jVpeowzavOQplBJw6u0= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/OpenPeeDeeP/depguard v1.1.0 h1:pjK9nLPS1FwQYGGpPxoMYpe7qACHOhAWQMQzV71i49o= -github.com/OpenPeeDeeP/depguard v1.1.0/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 h1:sATXp1x6/axKxz2Gjxv8MALP0bXaNRfQinEwyfMcx8c= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0/go.mod h1:Nl76DrGNJTA1KJ0LePKBw/vznBX1EHbAZX8mwjR82nI= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= +github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= +github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= +github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= +github.com/alecthomas/go-check-sumtype v0.1.4 h1:WCvlB3l5Vq5dZQTFmodqL2g68uHiSwwlWcT5a2FGK0c= +github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= +github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= +github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alexkohler/nakedret/v2 v2.0.4 h1:yZuKmjqGi0pSmjGpOC016LtPJysIL0WEUiaXW5SUnNg= +github.com/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= -github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/ashanbrown/forbidigo v1.3.0 h1:VkYIwb/xxdireGAdJNZoo24O4lmnEWkactplBlWTShc= -github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI= +github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= +github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= +github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= -github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.36.30/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.41.14 h1:zJnJ8Y964DjyRE55UVoMKgOG4w5i88LpN6xSpBX7z84= github.com/aws/aws-sdk-go v1.41.14/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A= -github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI= -github.com/blizzy78/varnamelen v0.6.0 h1:TOIDk9qRIMspALZKX8x+5hQfAjuvAFogppnxtvuNmBo= -github.com/blizzy78/varnamelen v0.6.0/go.mod h1:zy2Eic4qWqjrxa60jG34cfL0VXcSwzUrIx68eJPb4Q8= -github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM= -github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= -github.com/breml/bidichk v0.2.2 h1:w7QXnpH0eCBJm55zGCTJveZEkQBt6Fs5zThIdA6qQ9Y= -github.com/breml/bidichk v0.2.2/go.mod h1:zbfeitpevDUGI7V91Uzzuwrn4Vls8MoBMrwtt78jmso= -github.com/breml/errchkjson v0.2.3 h1:97eGTmR/w0paL2SwfRPI1jaAZHaH/fXnxWTw2eEIqE0= -github.com/breml/errchkjson v0.2.3/go.mod h1:jZEATw/jF69cL1iy7//Yih8yp/mXp2CBoBr9GJwCAsY= -github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY= -github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc= +github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= +github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= +github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v4 v4.2.1 h1:Cxg6u+XDWff75SIFFmNsqnIOgob+Q9hG6y/ioKbRFiM= +github.com/bombsimon/wsl/v4 v4.2.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= +github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY= +github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= +github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA= +github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= +github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0= +github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= +github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs= +github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= +github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc= +github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= +github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= +github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk= -github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg= -github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af h1:spmv8nSH9h5oCQf40jt/ufBCt9j0/58u4G+rkeMqXGI= -github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU= +github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4= +github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc= +github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/ckaznocha/intrange v0.1.2 h1:3Y4JAxcMntgb/wABQ6e8Q8leMd26JbX2790lIss9MTI= +github.com/ckaznocha/intrange v0.1.2/go.mod h1:RWffCw/vKBwHeOEwWdCikAtY0q4gGt8VhJZEEA5n+RE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmtrek/air v1.27.3 h1:laO93SnYnEiJsH0QIeXyso6FJ5maSNufE5d/MmHKBmk= github.com/cosmtrek/air v1.27.3/go.mod h1:vrGZm+zmL5htsEr6YjqLXyjSoelgDQIl/DuOtsWVLeU= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/daixiang0/gci v0.3.3 h1:55xJKH7Gl9Vk6oQ1cMkwrDWjAkT1D+D1G9kNmRcAIY4= -github.com/daixiang0/gci v0.3.3/go.mod h1:1Xr2bxnQbDxCqqulUOv8qpGqkgRw9RSCGGjEC2LjF8o= -github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/daixiang0/gci v0.13.4 h1:61UGkmpoAcxHM2hhNkZEf5SzwQtWJXTSws7jaPyqwlw= +github.com/daixiang0/gci v0.13.4/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU= -github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= +github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA= -github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= -github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw= -github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= +github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/frankban/quicktest v1.14.2 h1:SPb1KFFmM+ybpEjPUhCCkZOM5xlovT5UbrMvWnXyBns= -github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA= +github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/fullstorydev/grpcurl v1.6.0/go.mod h1:ZQ+ayqbKMJNhzLmbpCiurTVlaK2M/3nqZCxaQ2Ze/sM= -github.com/fzipp/gocyclo v0.4.0 h1:IykTnjwh2YLyYkGa0y92iTTEQcnyAz0r9zOo15EbJ7k= -github.com/fzipp/gocyclo v0.4.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-critic/go-critic v0.6.2 h1:L5SDut1N4ZfsWZY0sH4DCrsHLHnhuuWak2wa165t9gs= -github.com/go-critic/go-critic v0.6.2/go.mod h1:td1s27kfmLpe5G/DPjlnFI7o1UCzePptwU7Az0V5iCM= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= +github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk= +github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw= +github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU= +github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -204,33 +174,36 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-redis/redis v6.15.8+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g= -github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= -github.com/go-toolsmith/astcopy v1.0.0 h1:OMgl1b1MEpjFQ1m5ztEO06rz5CUd3oBv9RF7+DyvdG8= -github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= -github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= -github.com/go-toolsmith/astequal v1.0.1 h1:JbSszi42Jiqu36Gnf363HWS9MTEAz67vTQLponh3Moc= -github.com/go-toolsmith/astequal v1.0.1/go.mod h1:4oGA3EZXTVItV/ipGiOx7NWkY5veFfcsOJVS2YxltLw= -github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k= -github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= -github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg= -github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= -github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o= -github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM= -github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= +github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= +github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= +github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= +github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= +github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk= -github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo= -github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc= +github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/goenning/imagic v0.0.1 h1:JJ1AhdRugiPucmIHCB6GmvigCAfMYV7rTYhus4ROZ50= github.com/goenning/imagic v0.0.1/go.mod h1:uCYR1hKybppzS6QEa7KnPPa3Q69SjcL95eDR5MW1j38= github.com/goenning/letteravatar v0.0.0-20180605200324-553181ed4055 h1:xwq8JGLwF1UughJdViZyiUo6FcTv7mN6L532hBNbnfQ= @@ -238,16 +211,11 @@ github.com/goenning/letteravatar v0.0.0-20180605200324-553181ed4055/go.mod h1:3l github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -258,9 +226,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -276,36 +241,29 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0= -github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM= github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= -github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613 h1:9kfjN3AdxcbsZBf8NjltjWihK2QfBBBZuv91cMFfDHw= -github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a h1:iR3fYXUjHCR97qWS8ch1y9zPNsgXThGwjKPrYfqMPks= -github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= -github.com/golangci/golangci-lint v1.45.0 h1:T2oCVkYoeckBxcNS6DTYiSXN2QcTNuAWaHyLGfqzMlU= -github.com/golangci/golangci-lint v1.45.0/go.mod h1:Y6grRO3drH/7kGP88i9jSl9fGWwCrbA5u7i++jOXll4= -github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA= -github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA= -github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= -github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo= -github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= -github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2 h1:SgM7GDZTxtTTQPU84heOxy34iG5Du7F2jcoZnvp+fXI= -github.com/golangci/revgrep v0.0.0-20210930125155-c22e5001d4f2/go.mod h1:LK+zW4MpyytAWQRz0M4xnzEk50lSvqDQKfx304apFkY= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys= -github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= -github.com/gomarkdown/markdown v0.0.0-20220527210340-c82b80a9daf2 h1:VJwys0mqRBeVxECc/DyXgveOqOqI81J9sjQFZHZwJvs= -github.com/gomarkdown/markdown v0.0.0-20220527210340-c82b80a9daf2/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e h1:ULcKCDV1LOZPFxGZaA6TlQbiM3J2GCPnkx/bGF6sX/g= +github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM= +github.com/golangci/golangci-lint v1.59.1 h1:CRRLu1JbhK5avLABFJ/OHVSQ0Ie5c4ulsOId1h3TTks= +github.com/golangci/golangci-lint v1.59.1/go.mod h1:jX5Oif4C7P0j9++YB2MMJmoNrb01NJ8ITqKWNLewThg= +github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs= +github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= +github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA= +github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= +github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= +github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= +github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs= +github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= +github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8 h1:4txT5G2kqVAKMjzidIabL/8KqjIK71yj30YOeuxLn10= +github.com/gomarkdown/markdown v0.0.0-20240930133441-72d49d9543d8/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -314,64 +272,37 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/trillian v1.3.11/go.mod h1:0tPraVHrSDkA3BO6vKX67zgLXs6SsOAbHEivX+9mPgw= -github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo= -github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U= -github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= -github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75/go.mod h1:g2644b03hfBX9Ov0ZBDgXXens4rxSxmqFBbhvKv2yVA= +github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= +github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosimple/slug v1.11.0 h1:QkFeOkXIEDvvtIt++P7cUuO4G9PZVQEgLuYbYZzawMA= github.com/gosimple/slug v1.11.0/go.mod h1:MICb3w495l9KNdZm+Xn5b6T2Hn831f9DMxiJ1r+bAjw= github.com/gosimple/unidecode v1.0.0 h1:kPdvM+qy0tnk4/BrnkrbdJ82xe88xn7c9hcaipDz4dQ= github.com/gosimple/unidecode v1.0.0/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= -github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= -github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw= -github.com/gostaticanalysis/analysisutil v0.4.1/go.mod h1:18U/DLpRgIUd459wGxVHE0fRgmo1UgHDcbw7F5idXu0= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= -github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI= github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= @@ -381,270 +312,176 @@ github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3 github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976 h1:b70jEaX2iaJSPZULSUxKtm73LBfsCrMsIlYCUgNGSIs= github.com/gotnospirit/makeplural v0.0.0-20180622080156-a5f48d94d976/go.mod h1:ZGQeOwybjD8lkCjIyJfqR5LD2wMVHJ31d6GdPxoTsWY= github.com/gotnospirit/messageformat v0.0.0-20190719172517-c1d0bdacdea2 h1:yUr520KXfjzq/QTGZ2h+DvEydkyBfvifw6ksyDW3Lpg= github.com/gotnospirit/messageformat v0.0.0-20190719172517-c1d0bdacdea2/go.mod h1:NO9UUa4C4cSmRsYSfZMAKhI5ifCRzOjSGe/pi7TKRvs= -github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= -github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM= -github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= -github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= +github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48= github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jjti/go-spancheck v0.6.1 h1:ZK/wE5Kyi1VX3PJpUO2oEgeoI4FWOUm7Shb2Gbv5obI= +github.com/jjti/go-spancheck v0.6.1/go.mod h1:vF1QkOO159prdo6mHRxak2CpzDpHAfKiPUDP/NeRnX8= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joeshaw/envdecode v0.0.0-20200121155833-099f1fc765bd h1:nIzoSW6OhhppWLm4yqBwZsKJlAayUu5FGozhrF3ETSM= github.com/joeshaw/envdecode v0.0.0-20200121155833-099f1fc765bd/go.mod h1:MEQrHur0g8VplbLOv5vXmDzacSaH9Z7XhcgsSh1xciU= github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.1-0.20200921135023-fe77dd05ab5a h1:VTF3sHLbpm2PdWMPKVWUMwKg85VE7Ep7wgBw8ETYri8= github.com/julienschmidt/httprouter v1.3.1-0.20200921135023-fe77dd05ab5a/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY= github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= -github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/errcheck v1.6.0 h1:YTDO4pNy7AUN/021p+JGHycQyYNIyMoenM1YDVK6RlY= -github.com/kisielk/errcheck v1.6.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= +github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos= +github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= +github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0= +github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg= +github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kulti/thelper v0.5.1 h1:Uf4CUekH0OvzQTFPrWkstJvXgm6pnNEtQu3HiqEkpB0= -github.com/kulti/thelper v0.5.1/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U= -github.com/kunwardeep/paralleltest v1.0.3 h1:UdKIkImEAXjR1chUWLn+PNXqWUGs//7tzMeWuP7NhmI= -github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= -github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= -github.com/ldez/gomoddirectives v0.2.2 h1:p9/sXuNFArS2RLc+UpYZSI4KQwGMEDWC/LbtF5OPFVg= -github.com/ldez/gomoddirectives v0.2.2/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0= -github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM= -github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88= -github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg= -github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY= -github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ= -github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/maratori/testpackage v1.0.1 h1:QtJ5ZjqapShm0w5DosRjg0PRlSdAdlx+W6cCKoALdbQ= -github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= -github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA= -github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= +github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs= +github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= +github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4QqyxXmng8I= +github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0= +github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg= +github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= +github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo= +github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= +github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM= +github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= +github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= +github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo= -github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= -github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg= -github.com/mgechev/revive v1.1.4 h1:sZOjY6GU35Kr9jKa/wsKSHgrFz8eASIB5i3tqWZMp0A= -github.com/mgechev/revive v1.1.4/go.mod h1:ZZq2bmyssGh8MSPz3VVziqRNIMYTJXzP8MUKG90vZ9A= +github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE= +github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA= github.com/microcosm-cc/bluemonday v1.0.16 h1:kHmAq2t7WPWLjiGvzKa5o3HzSfahUKiOq7fAPUiMNIc= github.com/microcosm-cc/bluemonday v1.0.16/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4= -github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k= -github.com/mozilla/scribe v0.0.0-20180711195314-fb71baf557c1/go.mod h1:FIczTrinKo8VaLxe6PWTPEXRXDIHz2QAwiaBaP5/4a8= -github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moricho/tparallel v0.3.1 h1:fQKD4U1wRMAYNngDonW5XupoB/ZGJHdpzrWqgyg9krA= +github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo= -github.com/mwitkow/go-proto-validators v0.2.0/go.mod h1:ZfA1hW+UH/2ZHOWvQ3HnQaU0DtnpXu850MZiy+YUgcc= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= -github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= -github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nishanths/exhaustive v0.7.11 h1:xV/WU3Vdwh5BUH4N06JNUznb6d5zhRPOnlgCrpNYNKA= -github.com/nishanths/exhaustive v0.7.11/go.mod h1:gX+MP7DWMKJmNa1HfMozK+u04hQd3na9i0hyqf3/dOI= -github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= -github.com/nishanths/predeclared v0.2.1 h1:1TXtjmy4f3YCFjTxRd8zcFHOmoUir+gp0ESzjFzG2sw= -github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= +github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= +github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.16.2 h1:8iLqHIZvN4fTLDC0Ke9tbSZVcyVHoBs0HIbnVSxfHJk= +github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc= -github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= +github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU= +github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= +github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= +github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= -github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b h1:/BDyEJWLnDUYKGWdlNx/82qSaVu2bUok/EvPUtIGuvw= -github.com/polyfloyd/go-errorlint v0.0.0-20211125173453-6d6d39c5bb8b/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/polyfloyd/go-errorlint v1.5.2 h1:SJhVik3Umsjh7mte1vE0fVZ5T1gznasQG3PV7U5xFdA= +github.com/polyfloyd/go-errorlint v1.5.2/go.mod h1:sH1QC1pxxi0fFecsVIzBmxtrgd9IF/SkJpA6wqyKAJs= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= +github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -661,197 +498,161 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/pseudomuto/protoc-gen-doc v1.3.2/go.mod h1:y5+P6n3iGrbKG+9O04V5ld71in3v/bX88wUwgt+U8EA= -github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= -github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30= -github.com/quasilyte/go-ruleguard v0.3.15 h1:iWYzp1z72IlXTioET0+XI6SjQdPfMGfuAiZiKznOt7g= -github.com/quasilyte/go-ruleguard v0.3.15/go.mod h1:NhuWhnlVEM1gT1A4VJHYfy9MuYSxxwHgxWoPsn9llB4= -github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.12-0.20220101150716-969a394a9451/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/dsl v0.3.12/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc= -github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= -github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3 h1:P4QPNn+TK49zJjXKERt/vyPbv/mCHB/zQ4flDYOMN+M= -github.com/quasilyte/gogrep v0.0.0-20220103110004-ffaa07af02e3/go.mod h1:wSEyW6O61xRV6zb6My3HxrQ5/8ke7NE2OayqCHa3xRM= -github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/go-ruleguard v0.4.2 h1:htXcXDK6/rO12kiTHKfHuqR4kr3Y4M0J0rOL6CH/BYs= +github.com/quasilyte/go-ruleguard v0.4.2/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= +github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= -github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= -github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.2.3 h1:ww2fsjqocGCAFamzvv/b8IsRduuHHeK2MHTcTxZTQX8= -github.com/ryancurrah/gomodguard v1.2.3/go.mod h1:rYbA/4Tg5c54mV1sv4sQTP5WOPBcoLtnBZ7/TEhXAbg= -github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw= -github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= +github.com/ryancurrah/gomodguard v1.3.2 h1:CuG27ulzEB1Gu5Dk5gP8PFxSOZ3ptSdP5iI/3IXxM18= +github.com/ryancurrah/gomodguard v1.3.2/go.mod h1:LqdemiFomEjcxOqirbQCb3JFvSxH2JUYMerTFd3sF2o= +github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= +github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/securego/gosec/v2 v2.10.0 h1:l6BET4EzWtyUXCpY2v7N92v0DDCas0L7ngg3bpqbr8g= -github.com/securego/gosec/v2 v2.10.0/go.mod h1:PVq8Ewh/nCN8l/kKC6zrGXSr7m2NmEK6ITIAWMtIaA0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.26.0 h1:LONR2hNVKxRmzIrZR0PhSF3mhCAzvnr+DcUiHgREfXE= +github.com/sashamelentyev/usestdlibvars v1.26.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= +github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9 h1:rnO6Zp1YMQwv8AyxzuwsVohljJgp4L0ZqiCgtACsPsc= +github.com/securego/gosec/v2 v2.20.1-0.20240525090044-5f0084eb01a9/go.mod h1:dg7lPlu/xK/Ut9SedURCoZbVCR4yC7fM65DtH9/CDHs= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU= github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYIc1yrHI= -github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw= -github.com/sivchari/tenv v1.4.7 h1:FdTpgRlTue5eb5nXIYgS/lyVXSjugU8UUVDwhP1NLU8= -github.com/sivchari/tenv v1.4.7/go.mod h1:5nF+bITvkebQVanjU6IuMbvIot/7ReNsUV7I5NbprB0= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY= -github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI= -github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ= -github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= +github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= +github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= +github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= +github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4= -github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= -github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= +github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= +github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= +github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= -github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/sylvia7788/contextcheck v1.0.4 h1:MsiVqROAdr0efZc/fOCt0c235qm9XJqHtWwM+2h2B04= -github.com/sylvia7788/contextcheck v1.0.4/go.mod h1:vuPKJMQ7MQ91ZTqfdyreNKwZjyUg6KO+IebVyQDedZQ= -github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A= -github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= +github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= +github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= +github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw= -github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro= -github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tomarrell/wrapcheck/v2 v2.5.0 h1:g27SGGHNoQdvHz4KZA9o4v09RcWzylR+b1yueE5ECiw= -github.com/tomarrell/wrapcheck/v2 v2.5.0/go.mod h1:68bQ/eJg55BROaRTbMjC7vuhL2OgfoG8bLp9ZyoBfyY= -github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= -github.com/tommy-muehle/go-mnd/v2 v2.5.0 h1:iAj0a8e6+dXSL7Liq0aXPox36FiN1dBbjA6lt9fl65s= -github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA= -github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= -github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI= -github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/uudashr/gocognit v1.0.5 h1:rrSex7oHr3/pPLQ0xoWq108XMU8s678FJcQ+aSfOHa4= -github.com/uudashr/gocognit v1.0.5/go.mod h1:wgYz0mitoKOTysqxTDMOUXg+Jb5SvtihkfmugIZYpEA= -github.com/viki-org/dnscache v0.0.0-20130720023526-c70c1f23c5d8/go.mod h1:dniwbG03GafCjFohMDmz6Zc6oCuiqgH6tGNyXTkHzXE= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/tetafro/godot v1.4.16 h1:4ChfhveiNLk4NveAZ9Pu2AN8QZ2nkUGFuadM9lrr5D0= +github.com/tetafro/godot v1.4.16/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4= +github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= +github.com/tomarrell/wrapcheck/v2 v2.8.3 h1:5ov+Cbhlgi7s/a42BprYoxsr73CbdMUTzE3bRDFASUs= +github.com/tomarrell/wrapcheck/v2 v2.8.3/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI= +github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= +github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ= +github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= +github.com/uudashr/gocognit v1.1.2 h1:l6BAEKJqQH2UpKAPKdMfZf5kE4W/2xk8pfU1OVLvniI= +github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k= +github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU= +github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= -github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1 h1:YAaOqqMTstELMMGblt6yJ/fcOt4owSYuw3IttMnKfAM= -github.com/yeya24/promlinter v0.1.1-0.20210918184747-d757024714a1/go.mod h1:rs5vtZzeBHqqMwXqFScncpCF6u06lezhZepno9AB1Oc= -github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= +github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= +github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= +github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -gitlab.com/bosi/decorder v0.2.1 h1:ehqZe8hI4w7O4b1vgsDZw1YU1PE7iJXrQWFMsocbQ1w= -gitlab.com/bosi/decorder v0.2.1/go.mod h1:6C/nhLSbF6qZbYD8bRmISBwc6vcWdNsiIBkRvjJFrH0= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.0.0-20200513171258-e048e166ab9c/go.mod h1:xCI7ZzBfRuGgBXyXO6yfWfDmlWd35khcWpUa4L0xI/k= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.mozilla.org/mozlog v0.0.0-20170222151521-4bb13139d403/go.mod h1:jHoPAGnDrCy6kaI2tAze5Prf0Nr0w/oNkROt2lw3n3o= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= +gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= +go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= +go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= +go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs= +go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM= +go-simpler.org/sloglint v0.7.1 h1:qlGLiqHbN5islOxjeLXoPtUdZXb669RW+BDQ+xOSNoU= +go-simpler.org/sloglint v0.7.1/go.mod h1:OlaVDRh/FKKd4X4sIMbsz8st97vomydceL146Fthh/c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -862,14 +663,19 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= +golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= +golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -880,8 +686,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -890,18 +694,19 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -913,9 +718,6 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -923,71 +725,53 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -996,29 +780,20 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1026,68 +801,59 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211213223007-03aa0b5f6827/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1095,25 +861,18 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1126,63 +885,39 @@ golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= @@ -1195,29 +930,15 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1225,7 +946,6 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= @@ -1239,70 +959,26 @@ google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200707001353-8e8330bf89df/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1315,39 +991,28 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1355,19 +1020,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.2.2 h1:MNh1AVMyVX23VUHE2O27jm6lNj3vjO5DexS4A1xvnzk= -honnef.co/go/tools v0.2.2/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY= -mvdan.cc/gofumpt v0.3.0 h1:kTojdZo9AcEYbQYhGuLf/zszYthRdhDNDUi2JKTxas4= -mvdan.cc/gofumpt v0.3.0/go.mod h1:0+VyGZWleeIj5oostkOex+nDBA0eyavuDnDusAJ8ylo= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I= -mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo= -mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= -mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5 h1:Jh3LAeMt1eGpxomyu3jVkmVZWW2MxZ1qIIV2TZ/nRio= -mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5/go.mod h1:b8RRCBm0eeiWR8cfN88xeq2G5SG3VKGO+5UPWi5FSOY= +honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs= +honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= +mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo= +mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA= +mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U= +mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ= rogchap.com/v8go v0.7.1-0.20211222173054-943fcf9e74cc h1:rcoe6etpGGPcdMibCdCI38v0Th/oyxqTFAjnMQiDGnY= rogchap.com/v8go v0.7.1-0.20211222173054-943fcf9e74cc/go.mod h1:MxgP3pL2MW4dpme/72QRs8sgNMmM0pRc8DPhcuLWPAs= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/locale/ar/client.json b/locale/ar/client.json new file mode 100644 index 000000000..5e1edbf3a --- /dev/null +++ b/locale/ar/client.json @@ -0,0 +1,153 @@ +{ + "action.cancel": "إلغاء", + "action.change": "تغيير", + "action.close": "إغلاق", + "action.confirm": "تأكيد", + "action.delete": "حذف", + "action.edit": "تحرير", + "action.markallasread": "تحديد الكل كمقروء", + "action.ok": "موافق", + "action.respond": "رد", + "action.save": "حفظ", + "action.signin": "تسجيل الدخول", + "action.submit": "إرسال", + "enum.poststatus.completed": "مكتمل", + "enum.poststatus.declined": "مرفوض", + "enum.poststatus.deleted": "محذوف", + "enum.poststatus.duplicate": "مكرر", + "enum.poststatus.open": "مفتوح", + "enum.poststatus.planned": "مخطط له", + "enum.poststatus.started": "بدأ", + "error.expired.text": "الرابط الذي نقرت عليه قد انتهت صلاحيته.", + "error.expired.title": "منتهي الصلاحية", + "error.forbidden.text": "أنت غير مخول لعرض هذه الصفحة.", + "error.forbidden.title": "ممنوع", + "error.internalerror.text": "حدث خطأ ونحن نعمل على إصلاح المشكلة! سنكون في الخدمة قريباً.", + "error.internalerror.title": "عفواً! هذا غير متوقع...", + "error.pagenotfound.text": "الرابط الذي نقرت عليه قد يكون مكسورًا أو قد تكون الصفحة قد تمت إزالتها.", + "error.pagenotfound.title": "الصفحة غير موجودة", + "error.unauthorized.text": "أنت غير مخول لعرض هذه الصفحة.", + "error.unauthorized.title": "غير مخول", + "home.form.defaultinvitation": "أدخل اقتراحك هنا...", + "home.form.defaultwelcomemessage": "نود أن نسمع ما تفكر به.\n\nماذا يمكننا أن نفعل بشكل أفضل؟ هذا هو المكان المناسب للتصويت والمناقشة ومشاركة الأفكار.", + "home.lonely.suggestion": "يوصى بإنشاء <0>على الأقل 3 اقتراحات هنا قبل مشاركة هذا الموقع. المحتوى الأولي مهم لبدء جذب جمهورك.", + "home.lonely.text": "لم يتم إنشاء أي منشورات حتى الآن.", + "home.postfilter.label.view": "عرض", + "home.postfilter.option.mostdiscussed": "الأكثر مناقشة", + "home.postfilter.option.mostwanted": "الأكثر رغبة", + "home.postfilter.option.myvotes": "تصويتي", + "home.postfilter.option.recent": "حديث", + "home.postfilter.option.trending": "الشائع", + "home.postinput.description.placeholder": "وصف اقتراحك (اختياري)", + "home.postscontainer.label.noresults": "لم تتطابق أي نتائج مع بحثك، جرب شيئًا مختلفًا.", + "home.postscontainer.label.viewmore": "عرض المزيد من المنشورات", + "home.postscontainer.query.placeholder": "بحث", + "home.similar.subtitle": "فكر في التصويت على المنشورات الموجودة بدلاً من ذلك.", + "home.similar.title": "منشورات مشابهة", + "home.tagsfilter.label.with": "مع", + "home.tagsfilter.selected.none": "أي وسم", + "label.actions": "إجراءات", + "label.avatar": "الصورة الرمزية", + "label.custom": "مخصص", + "label.description": "وصف", + "label.discussion": "نقاش", + "label.email": "البريد الإلكتروني", + "label.gravatar": "Gravatar", + "label.letter": "حرف", + "label.moderation": "إشراف", + "label.name": "الاسم", + "label.none": "لا شيء", + "label.notifications": "إشعارات", + "label.or": "أو", + "label.subscribe": "اشتراك", + "label.tags": "وسوم", + "label.unread": "غير مقروء", + "label.unsubscribe": "إلغاء الاشتراك", + "label.voters": "المصوتون", + "legal.agreement": "لقد قرأت وأوافق على <0/> و <1/>.", + "legal.notice": "بتسجيل الدخول، أنت توافق على <0/> و <1/>.", + "legal.privacypolicy": "سياسة الخصوصية", + "legal.termsofservice": "شروط الخدمة", + "menu.administration": "إدارة", + "menu.mysettings": "إعداداتي", + "menu.signout": "تسجيل الخروج", + "menu.sitesettings": "إعدادات الموقع", + "modal.changeemail.header": "تأكيد بريدك الإلكتروني الجديد", + "modal.changeemail.text": "لقد أرسلنا للتو رابط تأكيد إلى <0>{0}. <1/> انقر على الرابط لتحديث بريدك الإلكتروني.", + "modal.completeprofile.header": "إكمال ملفك الشخصي", + "modal.completeprofile.name.placeholder": "الاسم", + "modal.completeprofile.text": "لأن هذه هي المرة الأولى التي تسجل فيها الدخول، يرجى إدخال اسمك.", + "modal.deleteaccount.header": "حذف الحساب", + "modal.deleteaccount.text": "<0>عند اختيارك حذف حسابك، سنمحو جميع معلوماتك الشخصية إلى الأبد. سيبقى المحتوى الذي قمت بنشره، ولكنه سيصبح مجهولًا.<1>هذه العملية لا رجعة فيها. <2>هل أنت متأكد؟", + "modal.deletecomment.header": "حذف التعليق", + "modal.deletecomment.text": "هذه العملية لا رجعة فيها. <0>هل أنت متأكد؟", + "modal.showvotes.message.zeromatches": "لم يتم العثور على مستخدمين مطابقين لـ <0>{0}.", + "modal.showvotes.query.placeholder": "ابحث عن المستخدمين بالاسم...", + "modal.signin.header": "تسجيل الدخول للمشاركة والتصويت", + "mynotifications.label.readrecently": "مقروء في آخر 30 يومًا.", + "mynotifications.message.nounread": "لا توجد إشعارات غير مقروءة.", + "mynotifications.page.subtitle": "ابقَ على اطلاع بما يحدث", + "mynotifications.page.title": "الإشعارات", + "mysettings.apikey.documentation": "لتعلم كيفية استخدام API، اقرأ <0>التوثيق الرسمي.", + "mysettings.apikey.generate": "إعادة توليد مفتاح API", + "mysettings.apikey.newkey": "مفتاح API الجديد هو: <0>{0}", + "mysettings.apikey.newkeynotice": "احفظه بأمان على خوادمك ولا تخزنه أبدًا في جانب العميل لتطبيقك.", + "mysettings.apikey.notice": "يتم عرض مفتاح API فقط عند توليده. إذا فقدت مفتاحك أو تعرض للاختراق، قم بتوليد مفتاح جديد ودون ملاحظة ذلك.", + "mysettings.apikey.title": "مفتاح API", + "mysettings.dangerzone.delete": "حذف حسابي", + "mysettings.dangerzone.notice": "هذه العملية لا رجعة فيها. يرجى التأكد.", + "mysettings.dangerzone.text": "عند اختيارك حذف حسابك، سنمحو جميع معلوماتك الشخصية إلى الأبد. سيبقى المحتوى الذي قمت بنشره، ولكنه سيصبح مجهولًا.", + "mysettings.dangerzone.title": "حذف الحساب", + "mysettings.message.avatar.custom": "نقبل صور JPG، GIF و PNG، أقل من 100KB وبنسبة عرض إلى ارتفاع 1:1 بأبعاد لا تقل عن 50x50 بكسل.", + "mysettings.message.avatar.gravatar": "سيتم استخدام <0>Gravatar بناءً على بريدك الإلكتروني. إذا لم يكن لديك Gravatar، سيتم إنشاء صورة رمزية من حرف أولي بناءً على الأحرف الأولى من اسمك.", + "mysettings.message.avatar.letter": "سيتم إنشاء صورة رمزية من حرف أولي بناءً على الأحرف الأولى من اسمك.", + "mysettings.message.noemail": "حسابك لا يحتوي على بريد إلكتروني.", + "mysettings.message.privateemail": "بريدك الإلكتروني خاص ولن يتم عرضه علنًا أبدًا.", + "mysettings.notification.channelemail": "البريد الإلكتروني", + "mysettings.notification.channelweb": "الويب", + "mysettings.notification.event.discussion": "نقاش", + "mysettings.notification.event.discussion.staff": "التعليقات على جميع المنشورات إلا إذا تم إلغاء الاشتراك بشكل فردي", + "mysettings.notification.event.discussion.visitors": "التعليقات على المنشورات التي قمت بالاشتراك فيها", + "mysettings.notification.event.newpost": "منشور جديد", + "mysettings.notification.event.newpost.staff": "المنشورات الجديدة على هذا الموقع", + "mysettings.notification.event.newpost.visitors": "المنشورات الجديدة على هذا الموقع", + "mysettings.notification.event.statuschanged": "تغيير الحالة", + "mysettings.notification.event.statuschanged.staff": "تغيير الحالة على جميع المنشورات إلا إذا تم إلغاء الاشتراك بشكل فردي", + "mysettings.notification.event.statuschanged.visitors": "تغيير الحالة على المنشورات التي قمت بالاشتراك فيها", + "mysettings.notification.message.emailonly": "ستتلقى إشعارات <0>البريد الإلكتروني حول {about}.", + "mysettings.notification.message.none": "لن تتلقى <0>أي إشعار حول هذا الحدث.", + "mysettings.notification.message.webandemail": "ستتلقى إشعارات <0>الويب و<1>البريد الإلكتروني حول {about}.", + "mysettings.notification.message.webonly": "ستتلقى إشعارات <0>الويب حول {about}.", + "mysettings.notification.title": "استخدم اللوحة التالية لاختيار الأحداث التي ترغب في تلقي إشعارات عنها", + "mysettings.page.subtitle": "إدارة إعدادات ملفك الشخصي", + "mysettings.page.title": "الإعدادات", + "page.backhome": "أعدني إلى <0>{0} الصفحة الرئيسية.", + "page.notinvited.text": "لم نتمكن من العثور على حساب لبريدك الإلكتروني.", + "page.notinvited.title": "غير مدعو", + "page.pendingactivation.text": "لقد أرسلنا لك بريدًا إلكترونيًا يحتوي على رابط لتفعيل حسابك.", + "page.pendingactivation.text2": "يرجى التحقق من بريدك الوارد لتفعيله.", + "page.pendingactivation.title": "حسابك في انتظار التفعيل", + "showpost.commentinput.placeholder": "اترك تعليقاً", + "showpost.discussionpanel.emptymessage": "لم يقم أحد بالتعليق بعد.", + "showpost.label.author": "نشر بواسطة <0/> · <1/>", + "showpost.message.nodescription": "لم يتم توفير وصف.", + "showpost.moderationpanel.text.help": "هذه العملية <0>لا يمكن التراجع عنها.", + "showpost.moderationpanel.text.placeholder": "لماذا تحذف هذا المنشور؟ (اختياري)", + "showpost.notificationspanel.message.subscribed": "أنت تتلقى إشعارات حول النشاط على هذا المنشور.", + "showpost.notificationspanel.message.unsubscribed": "لن تتلقى أي إشعار حول هذا المنشور.", + "showpost.postsearch.numofvotes": "{0} صوت", + "showpost.postsearch.query.placeholder": "ابحث عن المنشور الأصلي...", + "showpost.responseform.message.mergedvotes": "ستدمج الأصوات من هذا المنشور في المنشور الأصلي.", + "showpost.responseform.text.placeholder": "ما الذي يحدث مع هذا المنشور؟ دع مستخدميك يعرفون ما هي خططك...", + "showpost.votespanel.more": "+{extraVotesCount} أكثر", + "showpost.votespanel.seedetails": "شاهد التفاصيل", + "signin.message.email": "أدخل عنوان بريدك الإلكتروني لتسجيل الدخول", + "signin.message.emaildisabled": "تم تعطيل المصادقة عبر البريد الإلكتروني من قبل المسؤول. إذا كان لديك حساب مسؤول وتحتاج إلى تجاوز هذا التقييد، يرجى <0>النقر هنا.", + "signin.message.emailsent": "لقد أرسلنا للتو رابط تأكيد إلى <0>{email}. انقر على الرابط وستسجل الدخول.", + "signin.message.locked.text": "لتفعيل هذا الموقع، قم بتسجيل الدخول بحساب مسؤول وقم بتحديث الإعدادات المطلوبة.", + "signin.message.locked.title": "<0>{0} مغلق حاليًا.", + "signin.message.onlyadmins": "حاليًا مسموح فقط بتسجيل الدخول إلى حساب مسؤول", + "signin.message.private.text": "إذا كان لديك حساب أو دعوة، يمكنك استخدام الخيارات التالية لتسجيل الدخول.", + "signin.message.private.title": "<0>{0} مساحة خاصة، يجب عليك تسجيل الدخول للمشاركة والتصويت.", + "{count, plural, one {# وسم} other {# وسوم}}": "{count, plural, one {# وسم} other {# وسوم}}" +} diff --git a/locale/ar/server.json b/locale/ar/server.json new file mode 100644 index 000000000..bac763d8c --- /dev/null +++ b/locale/ar/server.json @@ -0,0 +1,62 @@ +{ + "property.avatarType": "نوع الصورة الرمزية", + "property.name": "الاسم", + "property.image": "صورة", + "property.customdomain": "نطاق مخصص", + "property.key": "المفتاح", + "property.email": "البريد الإلكتروني", + "property.title": "العنوان", + "property.comment": "تعليق", + "property.status": "الحالة", + "validation.required": "{name} مطلوب.", + "validation.invalid": "{name} غير صالح.", + "validation.invalidvalue": "{name} يحتوي على قيمة غير صالحة '{value}'.", + "validation.maxstringlen": "{name} يجب أن يحتوي على أقل من {len} حرفًا.", + "validation.custom.maxattachments": "يُسمح بحد أقصى {number} من المرفقات لكل منشور.", + "validation.custom.differentemail": "اختر بريدًا إلكترونيًا مختلفًا.", + "validation.custom.emailtaken": "هذا البريد الإلكتروني مستخدم بالفعل من قبل شخص آخر.", + "validation.custom.descriptivetitle": "يجب أن يكون العنوان أكثر وصفًا.", + "validation.custom.duplicatetitle": "تم نشر هذا من قبل.", + "validation.custom.selfduplicate": "لا يمكن أن يكون مكررًا لنفسه.", + "validation.custom.originalpostnotfound": "لم يتم العثور على المنشور الأصلي.", + "validation.custom.cannotdeleteduplicatepost": "لا يمكن حذف هذا المنشور لأنه مرجع لمنشور مكرر.", + "validation.custom.unknownsettings": "إعدادات غير معروفة باسم '{name}'", + "validation.custom.invalidemail": "'{email}' ليس عنوان بريد إلكتروني صالح.", + "validation.custom.invalidurl": "'{url}' ليس عنوان URL صالح.", + "validation.custom.invalidcustomdomain": "'{domain}' ليس نطاق مخصص صالح.", + "validation.custom.customdomaintaken": "هذا النطاق المخصص مستخدم بالفعل من قبل شخص آخر.", + "validation.custom.unsupportedfileformat": "صيغة هذا الملف غير مدعومة.", + "validation.custom.minimagedimensions": "يجب أن تكون الصورة بأبعاد لا تقل عن {width}x{height} بكسل.", + "validation.custom.imagesquareratio": "يجب أن تكون نسبة عرض الصورة إلى ارتفاعها 1:1.", + "validation.custom.maximagesize": "يجب أن يكون حجم الصورة أقل من {kilobytes} كيلو بايت.", + "enum.poststatus.open": "مفتوح", + "enum.poststatus.started": "بدأ", + "enum.poststatus.completed": "مكتمل", + "enum.poststatus.declined": "مرفوض", + "enum.poststatus.planned": "مخطط له", + "enum.poststatus.duplicate": "مكرر", + "enum.poststatus.deleted": "محذوف", + "email.change_emailaddress.subject": "تأكيد بريدك الإلكتروني الجديد", + "email.change_emailaddress.request": "لقد طلبت تغيير بريدك الإلكتروني من {oldEmail} إلى {newEmail}.", + "email.subscription.view": "عرضه في متصفحك", + "email.subscription.change": "تغيير تفضيلات الإشعارات الخاصة بك", + "email.subscription.unsubscribe": "إلغاء الاشتراك منه", + "email.greetings": "مرحباً!", + "email.greetings_name": "مرحباً، {name}!", + "email.operation_confirmation": "انقر على الرابط أدناه لتأكيد هذه العملية.", + "email.footer.noreply": "تم إرسال هذا البريد الإلكتروني من عنوان إشعار فقط لا يقبل الرسائل الواردة. يرجى عدم الرد على هذه الرسالة.", + "email.change_status.duplicate": "{title} ({postLink}) تم إغلاقه باعتباره مكرر لـ {duplicate}.", + "email.change_status.others": "تم تغيير حالة {title} ({postLink}) إلى {status}.", + "email.delete_post.text": "{title} تم حذفه.", + "email.new_comment.text": "{userName} ترك تعليقًا على {title} ({postLink}).", + "email.new_post.text": "{userName} أنشأ منشورًا جديدًا {title} ({postLink}).", + "email.signin_email.subject": "تسجيل الدخول إلى {siteName}", + "email.signin_email.text": "طلبت منا إرسال رابط تسجيل الدخول لك وها هو.", + "email.signin_email.confirmation": "انقر على الرابط أدناه لتسجيل الدخول إلى {siteName}.", + "email.signup_email.subject": "موقع Fider الجديد الخاص بك", + "email.signup_email.text": "أنت على بعد خطوة واحدة من تفعيل موقع Fider الخاص بك.", + "email.signup_email.confirmation": "من خلال الرابط أدناه يمكنك التحقق من عنوان بريدك الإلكتروني وإكمال عملية التفعيل.", + "email.footer.subscription_notice": "أنت تتلقى هذا البريد الإلكتروني لأنك مشترك في هذا المنشور. يمكنك {view}، {unsubscribe} أو {change}.", + "email.footer.subscription_notice2": "أنت تتلقى هذا البريد الإلكتروني لأنك مشترك في هذا المنشور. يمكنك {change}.", + "email.footer.subscription_notice3": "أنت تتلقى هذا البريد الإلكتروني لأنك مشترك في هذا المنشور. يمكنك {view} أو {change}." +} diff --git a/locale/de/client.json b/locale/de/client.json index f8e875e75..d7e268fcc 100644 --- a/locale/de/client.json +++ b/locale/de/client.json @@ -3,6 +3,7 @@ "action.change": "ändern", "action.close": "Schließen", "action.confirm": "Bestätigen", + "action.copylink": "", "action.delete": "Löschen", "action.edit": "Bearbeiten", "action.markallasread": "Alle als gelesen markieren", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Wenn Sie Ihr Konto löschen, werden wir all Ihre persönlichen Daten für immer löschen. Der von Ihnen veröffentlichte Inhalt bleibt erhalten, wird aber anonymisiert.<1>Dieser Prozess ist irreversibel. <2>Sind Sie sicher? ", "modal.deletecomment.header": "Kommentar löschen", "modal.deletecomment.text": "Dieser Prozess ist unumkehrbar. <0>Bist du dir sicher?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Keine Benutzer gefunden, die <0>{0} entsprechen.", "modal.showvotes.query.placeholder": "Suche nach Benutzern nach Namen...", "modal.signin.header": "Melde dich an, um eine neue Idee zu posten", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Wir haben Ihnen eine Bestätigungs-E-Mail mit einem Link zur Aktivierung Ihrer Website geschickt.", "page.pendingactivation.text2": "Bitte überprüfe deinen Posteingang, um ihn zu aktivieren.", "page.pendingactivation.title": "Dein Account ist nicht aktiviert", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Kommentar hinzufügen", "showpost.discussionpanel.emptymessage": "Niemand hat bisher kommentiert.", "showpost.label.author": "Gepostet von <0/> · <1/>", diff --git a/locale/el/client.json b/locale/el/client.json index 371d9fb02..a9984349a 100644 --- a/locale/el/client.json +++ b/locale/el/client.json @@ -3,6 +3,7 @@ "action.change": "αλλαγή", "action.close": "Κλείσιμο", "action.confirm": "Επιβεβαίωση", + "action.copylink": "", "action.delete": "Διαγραφή", "action.edit": "Επεξεργασία", "action.markallasread": "Σήμανση όλων ως αναγνωσμένων", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Όταν επιλέξετε να διαγράψετε τον λογαριασμό σας, θα διαγράψουμε για πάντα όλες τις προσωπικές σας πληροφορίες. Το περιεχόμενο που δημοσιεύσατε θα παραμείνει, αλλά θα είναι ανώνυμο.<1>Αυτή η διαδικασία είναι μη αναστρέψιμη. <2>Είστε σίγουρος;", "modal.deletecomment.header": "Διαγραφή Σχολίου", "modal.deletecomment.text": "Αυτή η διαδικασία είναι μη αναστρέψιμη. <0>Είστε σίγουρος;", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Δεν βρέθηκαν χρήστες που να ταιριάζουν <0>{0}.", "modal.showvotes.query.placeholder": "Αναζήτηση χρηστών με όνομα...", "modal.signin.header": "Συνδεθείτε για να συμμετάσχετε και να ψηφίσετε", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Σας στείλαμε ένα email επιβεβαίωσης με ένα σύνδεσμο για να ενεργοποιήσετε τον ιστότοπό σας.", "page.pendingactivation.text2": "Παρακαλώ ελέγξτε τα εισερχόμενά σας για να το ενεργοποιήσετε.", "page.pendingactivation.title": "Ο λογαριασμός σας εκκρεμεί ενεργοποίηση", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Αφήστε ένα σχόλιο", "showpost.discussionpanel.emptymessage": "Κανείς δεν έχει σχολιάσει ακόμα.", "showpost.label.author": "Δημοσιεύτηκε από <0/> · <1/>", diff --git a/locale/en/client.json b/locale/en/client.json index 7648d4fa8..4fd1b1ec6 100644 --- a/locale/en/client.json +++ b/locale/en/client.json @@ -3,6 +3,7 @@ "action.change": "change", "action.close": "Close", "action.confirm": "Confirm", + "action.copylink": "Copy link", "action.delete": "Delete", "action.edit": "Edit", "action.markallasread": "Mark All as Read", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>When you choose to delete your account, we will erase all your personal information forever. The content you have published will remain, but it will be anonymised.<1>This process is irreversible. <2>Are you sure?", "modal.deletecomment.header": "Delete Comment", "modal.deletecomment.text": "This process is irreversible. <0>Are you sure?", + "modal.notifications.nonew": "No new notifications", + "modal.notifications.previous": "Previous notifications", + "modal.notifications.unread": "Unread notifications", "modal.showvotes.message.zeromatches": "No users found matching <0>{0}.", "modal.showvotes.query.placeholder": "Search for users by name...", "modal.signin.header": "Sign in to participate and vote", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "We sent you a confirmation email with a link to activate your site.", "page.pendingactivation.text2": "Please check your inbox to activate it.", "page.pendingactivation.title": "Your account is pending activation", + "showpost.comment.copylink.error": "Failed to copy comment link, please copy page URL", + "showpost.comment.copylink.success": "Comment link copied to clipboard", + "showpost.comment.unknownhighlighted": "Invalid comment ID #{id}", "showpost.commentinput.placeholder": "Leave a comment", "showpost.discussionpanel.emptymessage": "No one has commented yet.", "showpost.label.author": "Posted by <0/> · <1/>", diff --git a/locale/en/server.json b/locale/en/server.json index aac2d1e7b..3f31a50d8 100644 --- a/locale/en/server.json +++ b/locale/en/server.json @@ -29,6 +29,7 @@ "validation.custom.minimagedimensions": "The image must have minimum dimensions of {width}x{height} pixels.", "validation.custom.imagesquareratio": "The image must have an aspect ratio of 1:1.", "validation.custom.maximagesize": "The image size must be smaller than {kilobytes}KB.", + "validation.custom.invalidemoji": "Invalid reaction emoji.", "enum.poststatus.open": "Open", "enum.poststatus.started": "Started", "enum.poststatus.completed": "Completed", diff --git a/locale/es-ES/client.json b/locale/es-ES/client.json index 9fa7d186a..a3d595c88 100644 --- a/locale/es-ES/client.json +++ b/locale/es-ES/client.json @@ -3,6 +3,7 @@ "action.change": "cambiar", "action.close": "Cerrar", "action.confirm": "Confirmar", + "action.copylink": "", "action.delete": "Eliminar", "action.edit": "Editar", "action.markallasread": "Marcar Todo como Leído", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Cuando decides eliminar tu cuenta, borraremos toda tu información personal para siempre. El contenido que has publicado permanecerá, pero será anónimo.<1>Este proceso es irreversible. <2>¿Estás seguro?", "modal.deletecomment.header": "Eliminar Comentario", "modal.deletecomment.text": "Este proceso es irreversible. <0>¿Estás seguro?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "No se encontraron usuarios que coincidan con <0>{0}.", "modal.showvotes.query.placeholder": "Buscar usuarios por nombre...", "modal.signin.header": "Inicia sesión para publicar y votar", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Te hemos enviado un correo electrónico de confirmación con un enlace para activar tu sitio.", "page.pendingactivation.text2": "Por favor, revisa tu bandeja de entrada para activarla.", "page.pendingactivation.title": "Tu cuenta está pendiente de activación", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Publica un comentario", "showpost.discussionpanel.emptymessage": "Nadie ha comentado todavía.", "showpost.label.author": "Publicado por <0/> · <1/>", diff --git a/locale/fr/client.json b/locale/fr/client.json index 58293a999..af64d6359 100644 --- a/locale/fr/client.json +++ b/locale/fr/client.json @@ -3,6 +3,7 @@ "action.change": "changer", "action.close": "Fermer", "action.confirm": "Confirmer", + "action.copylink": "", "action.delete": "Supprimer", "action.edit": "Modifier", "action.markallasread": "Tout marquer comme lu", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Lorsque vous choisissez de supprimer votre compte, nous effacerons définitivement toutes vos informations personnelles. Le contenu que vous avez publié restera, mais il sera anonyme.<1>Ce processus est irréversible. <2>Êtes-vous sûr ?", "modal.deletecomment.header": "Supprimer le commentaire", "modal.deletecomment.text": "Ce processus est irréversible. <0>Êtes-vous sûr ?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Aucun utilisateur correspondant à <0>{0}.", "modal.showvotes.query.placeholder": "Rechercher des utilisateurs par nom...", "modal.signin.header": "Connectez-vous pour poster et voter", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Nous vous avons envoyé un e-mail de confirmation avec un lien pour activer votre site.", "page.pendingactivation.text2": "Veuillez vérifier votre boîte de réception pour l'activer.", "page.pendingactivation.title": "Votre compte n'est pas activé", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Rédiger un commentaire", "showpost.discussionpanel.emptymessage": "Personne n'a encore commenté.", "showpost.label.author": "Posté par <0/> · <1/>", diff --git a/locale/locales.ts b/locale/locales.ts index 63e0e651f..d8a9aeafb 100644 --- a/locale/locales.ts +++ b/locale/locales.ts @@ -39,6 +39,9 @@ const locales: { [key: string]: Locale } = { el: { text: "Greek", }, + ar: { + text: "Arabic", + }, } export default locales diff --git a/locale/nl/client.json b/locale/nl/client.json index 1f1233c91..e881681b1 100644 --- a/locale/nl/client.json +++ b/locale/nl/client.json @@ -3,6 +3,7 @@ "action.change": "aanpassen", "action.close": "Sluiten", "action.confirm": "Bevestigen", + "action.copylink": "", "action.delete": "Verwijderen", "action.edit": "Bewerken", "action.markallasread": "Markeer alles als gelezen", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Als je ervoor kiest om je account te verwijderen, verwijderen we al je persoonlijke gegevens voor altijd. De inhoud die je hebt geplaatst blijft bestaan, maar zal geanonimiseerd worden.<1>Dit proces is onomkeerbaar. <2>Weet je het zeker?", "modal.deletecomment.header": "Reactie verwijderen", "modal.deletecomment.text": "Dit proces is onomkeerbaar. <0>Weet je het zeker?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Geen gebruikers gevonden voor <0>{0}.", "modal.showvotes.query.placeholder": "Zoek gebruikers op naam...", "modal.signin.header": "Log in om een bericht achter te laten en om te stemmen", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "We hebben je een bevestigingsmail gestuurd met een link om jouw site te activeren.", "page.pendingactivation.text2": "Controleer je inbox om het te activeren.", "page.pendingactivation.title": "Je account is nog niet geactiveerd", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Laat een reactie achter", "showpost.discussionpanel.emptymessage": "Nog niemand heeft gereageerd.", "showpost.label.author": "Geplaatst door <0/> · <1/>", diff --git a/locale/pl/client.json b/locale/pl/client.json index ee8409f03..5c5bc1c90 100644 --- a/locale/pl/client.json +++ b/locale/pl/client.json @@ -3,6 +3,7 @@ "action.change": "zmień", "action.close": "Zamknij", "action.confirm": "Potwierdź", + "action.copylink": "", "action.delete": "Usuń", "action.edit": "Edytuj", "action.markallasread": "Oznacz wszystkie jako przeczytane", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Jeśli zdecydujesz na usunięcie swojego konta, na zawsze usuniemy wszystkie Twoje dane osobowe. Opublikowana zawartość pozostanie na stronie, ale zostanie anonimowa.<1>Ten proces jest nieodwracalny. <2>Czy jesteś pewien?", "modal.deletecomment.header": "Usuń komentarz", "modal.deletecomment.text": "Ten proces jest nieodwracalny. <0>Czy jesteś pewien?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Nie znaleziono użytkowników pasujących do <0>{0}.", "modal.showvotes.query.placeholder": "Wyszukaj użytkowników według nazwy...", "modal.signin.header": "Zaloguj się aby pisać i głosować", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Wysłaliśmy do Ciebie maila z linkiem do aktywowania Twojej strony.", "page.pendingactivation.text2": "Sprawdź swoją skrzynkę odbiorczą, aby ją aktywować.", "page.pendingactivation.title": "Twoje konto oczekuje na aktywację", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Skomentuj", "showpost.discussionpanel.emptymessage": "Wygląda na to, że nikt jeszcze nie skomentował.", "showpost.label.author": "Wysłane przez <0/> · <1/>", diff --git a/locale/pt-BR/client.json b/locale/pt-BR/client.json index 96e0c68d5..a7439d8cf 100644 --- a/locale/pt-BR/client.json +++ b/locale/pt-BR/client.json @@ -3,6 +3,7 @@ "action.change": "alterar", "action.close": "Fechar", "action.confirm": "Confirmar", + "action.copylink": "", "action.delete": "Deletar", "action.edit": "Editar", "action.markallasread": "Marcar todas como lidas", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Quando você optar por excluir sua conta, todas as suas informações pessoais serão removidas para sempre. O conteúdo que você publicou permanecerá, mas será anonimizado.<1>Esse processo é irreversível. <2>Você tem certeza?", "modal.deletecomment.header": "Excluir comentário", "modal.deletecomment.text": "Este processo é irreversível. <0>Tem certeza?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Nenhum usuário encontrado para <0>{0}.", "modal.showvotes.query.placeholder": "Procurar usuários por nome...", "modal.signin.header": "Faça login para participar e votar", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Enviamos a você um e-mail de confirmação com um link para ativar o seu site.", "page.pendingactivation.text2": "Verifique sua caixa de entrada para ativá-la.", "page.pendingactivation.title": "Sua conta está com ativação pendente", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Deixe um comentário", "showpost.discussionpanel.emptymessage": "Ninguém comentou ainda.", "showpost.label.author": "Publicado por <0/> · <1/>", diff --git a/locale/ru/client.json b/locale/ru/client.json index 7cafb1ada..a1cf12c62 100644 --- a/locale/ru/client.json +++ b/locale/ru/client.json @@ -3,6 +3,7 @@ "action.change": "изменить", "action.close": "Закрыть", "action.confirm": "Подтвердить", + "action.copylink": "", "action.delete": "Удалить", "action.edit": "Изменить", "action.markallasread": "Отметить всё как прочитанное", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Если нужно, мы удалим всю информацию о вашем аккаунте навсегда. Всё, что вы публиковали, останется, но будет анонимизировано.<1>Это действие необратимо. <2>Вы уверены?", "modal.deletecomment.header": "Удалить комментарий", "modal.deletecomment.text": "Это действие необратимо. <0>Вы уверены?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Не удалось найти пользователей с <0>{0}.", "modal.showvotes.query.placeholder": "Найдите пользователей по их имени...", "modal.signin.header": "Войдите, чтобы создавать посты и голосовать", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Мы отправили вам письмо со ссылкой для активации этого сайта.", "page.pendingactivation.text2": "Проверьте свою почту, чтобы продолжить.", "page.pendingactivation.title": "Ваш аккаунт ожидает подтверждения", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Оставить комментарий", "showpost.discussionpanel.emptymessage": "Комментариев нет.", "showpost.label.author": "Создал <0/> · <1/>", diff --git a/locale/sk/client.json b/locale/sk/client.json index a034368de..d60077174 100644 --- a/locale/sk/client.json +++ b/locale/sk/client.json @@ -3,6 +3,7 @@ "action.change": "zmeniť", "action.close": "Zavrieť", "action.confirm": "Potvrdiť", + "action.copylink": "", "action.delete": "Vymazať", "action.edit": "Upraviť", "action.markallasread": "Označiť všetko ako prečítané", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Keď sa rozhodnete odstrániť svoj účet, všetky vaše osobné informácie navždy vymažeme. Obsah, ktorý ste zverejnili, zostane, ale bude anonymizovaný. <1> Tento proces je nevratný.<2>Ste si istí?", "modal.deletecomment.header": "Odstrániť komentár", "modal.deletecomment.text": "Tento proces je nevratný. <0>Ste si istí?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Nenašli sa žiadni používatelia <0>{0}.", "modal.showvotes.query.placeholder": "Vyhľadajte používateľov podľa mena...", "modal.signin.header": "Prihláste sa, aby ste mohli pridávať príspevky a hlasovať", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Poslali sme vám potvrdzovací email s odkazom na aktiváciu vašich stránok.", "page.pendingactivation.text2": "Aktivujte prosím svoju doručenú poštu.", "page.pendingactivation.title": "Váš účet čaká na aktiváciu", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Zanechať komentár", "showpost.discussionpanel.emptymessage": "Zatiaľ sa nikto nevyjadril.", "showpost.label.author": "Pridané <0/> · <1/>", diff --git a/locale/sv-SE/client.json b/locale/sv-SE/client.json index 2096a2fea..56ee466a3 100644 --- a/locale/sv-SE/client.json +++ b/locale/sv-SE/client.json @@ -3,6 +3,7 @@ "action.change": "ändra", "action.close": "Stäng", "action.confirm": "Bekräfta", + "action.copylink": "", "action.delete": "Radera", "action.edit": "Ändra", "action.markallasread": "Markera alla som lästa", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>När du väljer att radera ditt konto kommer vi att radera all din personliga information för evigt. Innehållet du har publicerat kommer att finnas kvar, men det kommer att vara anonymiserat.<1>Denna process är oåterkallelig. <2>Är du säker?", "modal.deletecomment.header": "Radera kommentar", "modal.deletecomment.text": "Denna process är oåterkallelig. <0>Är du säker?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Inga användare hittades som matchar <0>{0}.", "modal.showvotes.query.placeholder": "Sök efter användare med namn...", "modal.signin.header": "Logga in för att skriva inlägg och rösta", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Vi har skickat ett bekräftelsemail med en länk för att aktivera din webbplats.", "page.pendingactivation.text2": "Kontrollera din inkorg för att aktivera den.", "page.pendingactivation.title": "Ditt konto väntar på aktivering", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Skriv en kommentar", "showpost.discussionpanel.emptymessage": "Ingen har kommenterat ännu.", "showpost.label.author": "Skriven av <0/> · <1/>", diff --git a/locale/tr/client.json b/locale/tr/client.json index 00529164e..3d0083f41 100644 --- a/locale/tr/client.json +++ b/locale/tr/client.json @@ -3,6 +3,7 @@ "action.change": "değiştir", "action.close": "Kapat", "action.confirm": "Onayla", + "action.copylink": "", "action.delete": "Sil", "action.edit": "Düzenle", "action.markallasread": "Tümünü Okundu olarak işaretle", @@ -81,6 +82,9 @@ "modal.deleteaccount.text": "<0>Hesabınızı kaldırdığınız zaman size ait bütün kişisel bilgileri kalıcı olarak sileceğiz. Yayınladığınız öneriler sitede anonim olarak kalmaya devam edecek.<1>Bu geri alınamaz bir işlemdir. <2>Devam etmek istiyor musunuz?", "modal.deletecomment.header": "Yorumu Sil", "modal.deletecomment.text": "Bu geri alınamaz bir işlemdir. <0>Emin misiniz?", + "modal.notifications.nonew": "", + "modal.notifications.previous": "", + "modal.notifications.unread": "", "modal.showvotes.message.zeromatches": "Eşleşen kullanıcı bulunamadı <0>{0}.", "modal.showvotes.query.placeholder": "Kullanıcıları ismiyle arayın...", "modal.signin.header": "Öneride bulunmak ve oy vermek için giriş yapın", @@ -127,6 +131,9 @@ "page.pendingactivation.text": "Size, sayfanız için aktivasyon bağlantısı barındıran bir onay e-postası gönderdik.", "page.pendingactivation.text2": "Aktivasyon için lütfen gelen kutunuzu kontrol edin.", "page.pendingactivation.title": "Hesabınız aktivasyon beklemektedir", + "showpost.comment.copylink.error": "", + "showpost.comment.copylink.success": "", + "showpost.comment.unknownhighlighted": "", "showpost.commentinput.placeholder": "Yorum yazın", "showpost.discussionpanel.emptymessage": "Henüz hiç kimse yorum yapmadı.", "showpost.label.author": "<0/> · <1/> tarafından gönderildi", diff --git a/migrations/202406111146_add_posts_user_id_index.sql b/migrations/202406111146_add_posts_user_id_index.sql new file mode 100644 index 000000000..c4478d035 --- /dev/null +++ b/migrations/202406111146_add_posts_user_id_index.sql @@ -0,0 +1 @@ +CREATE INDEX post_user_key ON posts (user_id); diff --git a/migrations/202410122105_create_reactions_up.sql b/migrations/202410122105_create_reactions_up.sql new file mode 100644 index 000000000..ca8fb6e72 --- /dev/null +++ b/migrations/202410122105_create_reactions_up.sql @@ -0,0 +1,11 @@ +create table if not exists reactions ( + id serial primary key, + emoji varchar(8) not null, + comment_id int not null, + user_id int not null, + created_on timestamptz not null, + foreign key (comment_id) references comments(id), + foreign key (user_id) references users(id) +); + +ALTER TABLE reactions ADD CONSTRAINT unique_reaction UNIQUE (comment_id, user_id, emoji); diff --git a/package-lock.json b/package-lock.json index 0d64857f5..90c0acc14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,7 +54,7 @@ "jest": "28.1.0", "jest-environment-jsdom": "28.1.0", "mini-css-extract-plugin": "2.6.0", - "playwright": "1.21.1", + "playwright": "1.29.2", "prettier": "2.6.2", "purgecss-webpack-plugin": "4.1.3", "sass": "1.51.0", @@ -62,13 +62,13 @@ "svg-sprite-loader": "6.0.11", "svgo-loader": "3.0.0", "typescript": "4.6.4", - "webpack": "5.72.0", + "webpack": "5.94.0", "webpack-bundle-analyzer": "4.5.0", "webpack-cli": "4.9.2" }, "engines": { - "node": "16.x || 17.x", - "npm": "8.x" + "node": "21.x || 22.x", + "npm": "10.x" } }, "node_modules/@ampproject/remapping": { @@ -85,12 +85,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -136,19 +137,34 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.10.tgz", - "integrity": "sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==", + "version": "7.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", "dev": true, "dependencies": { - "@babel/types": "^7.17.10", - "@jridgewell/gen-mapping": "^0.1.0", + "@babel/types": "^7.25.4", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.16.7", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", @@ -427,10 +443,19 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -475,24 +500,28 @@ } }, "node_modules/@babel/highlight": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", - "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", - "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", "dev": true, + "dependencies": { + "@babel/types": "^7.25.4" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -1752,34 +1781,31 @@ } }, "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.10.tgz", - "integrity": "sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.10", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.10", - "@babel/types": "^7.17.10", - "debug": "^4.1.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.4", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -1787,12 +1813,13 @@ } }, "node_modules/@babel/types": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.10.tgz", - "integrity": "sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", + "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2919,37 +2946,61 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.10.tgz", - "integrity": "sha512-Q0YbBd6OTsXm8Y21+YUSDXupHnodNC2M4O18jtd3iwJ3+vMZNdKGols0a9G6JOK0dcJ3IdUUHoh908ZI6qhk8Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@lingui/babel-plugin-extract-messages": { @@ -3566,30 +3617,10 @@ "@types/trusted-types": "*" } }, - "node_modules/@types/eslint": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", - "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "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==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/graceful-fs": { @@ -3783,16 +3814,6 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, - "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz", @@ -4008,148 +4029,148 @@ } }, "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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true }, "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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true }, "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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true }, "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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true }, "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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true }, "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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -4208,9 +4229,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -4250,10 +4271,10 @@ "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==", + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "dev": true, "peerDependencies": { "acorn": "^8" @@ -4975,9 +4996,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -4987,14 +5008,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -5036,15 +5060,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -5112,9 +5127,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001434", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", - "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", + "version": "1.0.30001653", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", + "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", "dev": true, "funding": [ { @@ -5124,6 +5139,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -5155,7 +5174,7 @@ "node_modules/chalk/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { "node": ">=4" @@ -5486,7 +5505,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/colorette": { @@ -6193,9 +6212,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", "dev": true }, "node_modules/emittery": { @@ -6225,19 +6244,10 @@ "node": ">= 4" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -6312,9 +6322,9 @@ } }, "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==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "dev": true }, "node_modules/es-shim-unscopables": { @@ -6440,9 +6450,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -7328,41 +7338,6 @@ "node": ">=0.10.0" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/extsprintf": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", @@ -7449,15 +7424,6 @@ "bser": "2.1.1" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -8006,9 +7972,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "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==", "dev": true }, "node_modules/gzip-size": { @@ -8522,12 +8488,6 @@ "node": ">= 0.10" } }, - "node_modules/ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, "node_modules/is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -11007,12 +10967,6 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jpeg-js": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", - "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==", - "dev": true - }, "node_modules/js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -11129,12 +11083,6 @@ "node": ">=4" } }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -11154,9 +11102,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "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" @@ -11325,12 +11273,6 @@ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", "dev": true }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -11579,18 +11521,6 @@ "node": ">=8" } }, - "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -11946,9 +11876,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "node_modules/normalize-path": { @@ -12515,16 +12445,10 @@ "node": ">=8" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -12548,27 +12472,6 @@ "node": ">= 6" } }, - "node_modules/pixelmatch": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.2.1.tgz", - "integrity": "sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==", - "dev": true, - "dependencies": { - "pngjs": "^4.0.1" - }, - "bin": { - "pixelmatch": "bin/pixelmatch" - } - }, - "node_modules/pixelmatch/node_modules/pngjs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-4.0.1.tgz", - "integrity": "sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -12640,86 +12543,31 @@ } }, "node_modules/playwright": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.21.1.tgz", - "integrity": "sha512-Of0h1XAvsqK1XfHVZ8sL2PjJVoQUu9gTmmMTtLS7MEyWMRD0kn8myeI90xj1ncJhUysQxGboH64S5v+lL2USrg==", + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.29.2.tgz", + "integrity": "sha512-hKBYJUtdmYzcjdhYDkP9WGtORwwZBBKAW8+Lz7sr0ZMxtJr04ASXVzH5eBWtDkdb0c3LLFsehfPBTRfvlfKJOA==", "dev": true, "hasInstallScript": true, "dependencies": { - "playwright-core": "1.21.1" + "playwright-core": "1.29.2" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=12" + "node": ">=14" } }, "node_modules/playwright-core": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.21.1.tgz", - "integrity": "sha512-SbK5dEsai9ZUKlxcinqegorBq4GnftXd4/GfW+pLsdQIQWrLCM/JNh6YQ2Rf2enVykXCejtoXW8L5vJXBBVSJQ==", - "dev": true, - "dependencies": { - "colors": "1.4.0", - "commander": "8.3.0", - "debug": "4.3.3", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", - "jpeg-js": "0.4.3", - "mime": "3.0.0", - "pixelmatch": "5.2.1", - "pngjs": "6.0.0", - "progress": "2.0.3", - "proper-lockfile": "4.1.2", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "socks-proxy-agent": "6.1.1", - "stack-utils": "2.0.5", - "ws": "8.4.2", - "yauzl": "2.10.0", - "yazl": "2.5.1" - }, + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.2.tgz", + "integrity": "sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==", + "dev": true, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=12" - } - }, - "node_modules/playwright-core/node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/playwright-core/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/playwright-core/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">=14" } }, "node_modules/plurals-cldr": { @@ -12728,15 +12576,6 @@ "integrity": "sha512-4nLXqtel7fsCgzi8dvRZvUjfL8SXpP982sKg7b2TgpnR8rDnes06iuQ83trQ/+XdtyMIQkBBbKzX6x97eLfsJQ==", "dev": true }, - "node_modules/pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", - "dev": true, - "engines": { - "node": ">=12.13.0" - } - }, "node_modules/pofile": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.1.3.tgz", @@ -13017,29 +12856,12 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "dev": true }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, "node_modules/property-expr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==", "dev": true }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "node_modules/pseudolocale": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pseudolocale/-/pseudolocale-1.2.0.tgz", @@ -13055,16 +12877,6 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -13561,15 +13373,6 @@ "node": ">=0.12" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -13776,9 +13579,9 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -13881,16 +13684,6 @@ "node": ">=8" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, "node_modules/snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -14078,34 +13871,6 @@ "urix": "^0.1.0" } }, - "node_modules/socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", - "dev": true, - "dependencies": { - "ip": "^1.1.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" - }, - "engines": { - "node": ">= 10" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -14714,9 +14479,9 @@ } }, "node_modules/svg-baker/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "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" @@ -14862,9 +14627,9 @@ } }, "node_modules/svg-sprite-loader/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "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" @@ -14919,9 +14684,9 @@ } }, "node_modules/svgo-loader/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "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" @@ -14985,14 +14750,14 @@ } }, "node_modules/terser": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", - "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, "dependencies": { - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "bin": { @@ -15003,16 +14768,16 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -15051,9 +14816,9 @@ } }, "node_modules/terser-webpack-plugin/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==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -15074,44 +14839,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/terser/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==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/terser/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/terser/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==", - "dev": true - }, - "node_modules/terser/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==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -15590,6 +15317,36 @@ "node": ">=0.10.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/upper-case-first": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", @@ -15756,9 +15513,9 @@ } }, "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -15784,34 +15541,33 @@ "dev": true }, "node_modules/webpack": { - "version": "5.72.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", - "integrity": "sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w==", - "dev": true, - "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.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "graceful-fs": "^4.2.11", + "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", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "bin": { @@ -15924,9 +15680,9 @@ } }, "node_modules/webpack-bundle-analyzer/node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, "engines": { "node": ">=8.3.0" @@ -16019,9 +15775,9 @@ } }, "node_modules/webpack/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==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.8", @@ -16201,16 +15957,16 @@ } }, "node_modules/ws": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz", - "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -16287,25 +16043,6 @@ "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", @@ -16346,12 +16083,13 @@ } }, "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" } }, "@babel/compat-data": { @@ -16384,14 +16122,28 @@ } }, "@babel/generator": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.10.tgz", - "integrity": "sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==", + "version": "7.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", "dev": true, "requires": { - "@babel/types": "^7.17.10", - "@jridgewell/gen-mapping": "^0.1.0", + "@babel/types": "^7.25.4", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + } } }, "@babel/helper-annotate-as-pure": { @@ -16603,10 +16355,16 @@ "@babel/types": "^7.16.7" } }, + "@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true }, "@babel/helper-validator-option": { @@ -16639,21 +16397,25 @@ } }, "@babel/highlight": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", - "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" } }, "@babel/parser": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", - "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==", - "dev": true + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "dev": true, + "requires": { + "@babel/types": "^7.25.4" + } }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.16.7", @@ -17490,41 +17252,39 @@ } }, "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" } }, "@babel/traverse": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.10.tgz", - "integrity": "sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.10", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.10", - "@babel/types": "^7.17.10", - "debug": "^4.1.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.4", + "debug": "^4.3.1", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.10.tgz", - "integrity": "sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", + "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" } }, @@ -18404,31 +18164,54 @@ } }, "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true }, "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true }, + "@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + } + } + } + }, "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.10.tgz", - "integrity": "sha512-Q0YbBd6OTsXm8Y21+YUSDXupHnodNC2M4O18jtd3iwJ3+vMZNdKGols0a9G6JOK0dcJ3IdUUHoh908ZI6qhk8Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@lingui/babel-plugin-extract-messages": { @@ -18908,30 +18691,10 @@ "@types/trusted-types": "*" } }, - "@types/eslint": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", - "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "@types/graceful-fs": { @@ -19125,16 +18888,6 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "requires": { - "@types/node": "*" - } - }, "@typescript-eslint/eslint-plugin": { "version": "5.22.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.22.0.tgz", @@ -19253,148 +19006,148 @@ } }, "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "@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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true }, "@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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true }, "@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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "@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==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" } }, "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "requires": { "@xtuc/ieee754": "^1.2.0" } }, "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "requires": { "@xtuc/long": "4.2.2" } }, "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "requires": { - "@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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "requires": { - "@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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "requires": { - "@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" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@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==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -19440,9 +19193,9 @@ "dev": true }, "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true }, "acorn-globals": { @@ -19469,10 +19222,10 @@ } } }, - "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==", + "acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", "dev": true, "requires": {} }, @@ -20001,16 +19754,15 @@ "dev": true }, "browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" } }, "bser": { @@ -20032,12 +19784,6 @@ "ieee754": "^1.1.13" } }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -20092,9 +19838,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001434", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", - "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", + "version": "1.0.30001653", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz", + "integrity": "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw==", "dev": true }, "capital-case": { @@ -20122,7 +19868,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, "supports-color": { @@ -20381,7 +20127,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "colorette": { @@ -20937,9 +20683,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", "dev": true }, "emittery": { @@ -20960,19 +20706,10 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -21032,9 +20769,9 @@ } }, "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==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", "dev": true }, "es-shim-unscopables": { @@ -21132,9 +20869,9 @@ "requires": {} }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true }, "escape-string-regexp": { @@ -21799,29 +21536,6 @@ "to-regex": "^3.0.1" } }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, "extsprintf": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", @@ -21901,15 +21615,6 @@ "bser": "2.1.1" } }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, "figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -22294,9 +21999,9 @@ } }, "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "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==", "dev": true }, "gzip-size": { @@ -22671,12 +22376,6 @@ "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", @@ -24527,12 +24226,6 @@ "supports-color": "^8.0.0" } }, - "jpeg-js": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.3.tgz", - "integrity": "sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q==", - "dev": true - }, "js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -24622,12 +24315,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -24647,9 +24334,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsonfile": { @@ -24783,12 +24470,6 @@ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -24976,12 +24657,6 @@ "picomatch": "^2.0.5" } }, - "mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", - "dev": true - }, "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -25257,9 +24932,9 @@ "dev": true }, "node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "normalize-path": { @@ -25680,16 +25355,10 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "picomatch": { @@ -25704,23 +25373,6 @@ "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, - "pixelmatch": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.2.1.tgz", - "integrity": "sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ==", - "dev": true, - "requires": { - "pngjs": "^4.0.1" - }, - "dependencies": { - "pngjs": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-4.0.1.tgz", - "integrity": "sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg==", - "dev": true - } - } - }, "pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -25776,62 +25428,19 @@ } }, "playwright": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.21.1.tgz", - "integrity": "sha512-Of0h1XAvsqK1XfHVZ8sL2PjJVoQUu9gTmmMTtLS7MEyWMRD0kn8myeI90xj1ncJhUysQxGboH64S5v+lL2USrg==", + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.29.2.tgz", + "integrity": "sha512-hKBYJUtdmYzcjdhYDkP9WGtORwwZBBKAW8+Lz7sr0ZMxtJr04ASXVzH5eBWtDkdb0c3LLFsehfPBTRfvlfKJOA==", "dev": true, "requires": { - "playwright-core": "1.21.1" + "playwright-core": "1.29.2" } }, "playwright-core": { - "version": "1.21.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.21.1.tgz", - "integrity": "sha512-SbK5dEsai9ZUKlxcinqegorBq4GnftXd4/GfW+pLsdQIQWrLCM/JNh6YQ2Rf2enVykXCejtoXW8L5vJXBBVSJQ==", - "dev": true, - "requires": { - "colors": "1.4.0", - "commander": "8.3.0", - "debug": "4.3.3", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.0", - "jpeg-js": "0.4.3", - "mime": "3.0.0", - "pixelmatch": "5.2.1", - "pngjs": "6.0.0", - "progress": "2.0.3", - "proper-lockfile": "4.1.2", - "proxy-from-env": "1.1.0", - "rimraf": "3.0.2", - "socks-proxy-agent": "6.1.1", - "stack-utils": "2.0.5", - "ws": "8.4.2", - "yauzl": "2.10.0", - "yazl": "2.5.1" - }, - "dependencies": { - "colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true - }, - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.2.tgz", + "integrity": "sha512-94QXm4PMgFoHAhlCuoWyaBYKb92yOcGVHdQLoxQ7Wjlc7Flg4aC/jbFW7xMR52OfXMVkWicue4WXE7QEegbIRA==", + "dev": true }, "plurals-cldr": { "version": "1.0.4", @@ -25839,12 +25448,6 @@ "integrity": "sha512-4nLXqtel7fsCgzi8dvRZvUjfL8SXpP982sKg7b2TgpnR8rDnes06iuQ83trQ/+XdtyMIQkBBbKzX6x97eLfsJQ==", "dev": true }, - "pngjs": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", - "dev": true - }, "pofile": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.1.3.tgz", @@ -26049,29 +25652,12 @@ } } }, - "proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, "property-expr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz", "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA==", "dev": true }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, "pseudolocale": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pseudolocale/-/pseudolocale-1.2.0.tgz", @@ -26087,16 +25673,6 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -26469,12 +26045,6 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", - "dev": true - }, "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -26606,9 +26176,9 @@ "dev": true }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -26690,12 +26260,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -26853,27 +26417,6 @@ } } }, - "socks": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", - "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", - "dev": true, - "requires": { - "ip": "^1.1.5", - "smart-buffer": "^4.2.0" - } - }, - "socks-proxy-agent": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", - "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.1", - "socks": "^2.6.1" - } - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -27332,9 +26875,9 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -27468,9 +27011,9 @@ "dev": true }, "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -27523,9 +27066,9 @@ }, "dependencies": { "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "requires": { "minimist": "^1.2.0" @@ -27567,14 +27110,14 @@ } }, "terser": { - "version": "5.13.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", - "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, "requires": { - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "dependencies": { @@ -27583,55 +27126,20 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true - }, - "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==", - "dev": true, - "requires": { - "whatwg-url": "^7.0.0" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "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==", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } } } }, "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" }, "dependencies": { "jest-worker": { @@ -27646,9 +27154,9 @@ } }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "requires": { "@types/json-schema": "^7.0.8", @@ -28027,6 +27535,16 @@ } } }, + "update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "requires": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + } + }, "upper-case-first": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", @@ -28160,9 +27678,9 @@ } }, "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -28185,41 +27703,40 @@ "dev": true }, "webpack": { - "version": "5.72.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", - "integrity": "sha512-qmSmbspI0Qo5ld49htys8GY9XhS9CGqFoHTsOVAnjBdg0Zn79y135R+k4IR4rKK6+eKaabMhJwiVB7xw0SJu5w==", - "dev": true, - "requires": { - "@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.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dev": true, + "requires": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "graceful-fs": "^4.2.11", + "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", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", "webpack-sources": "^3.2.3" }, "dependencies": { "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "requires": { "@types/json-schema": "^7.0.8", @@ -28296,9 +27813,9 @@ } }, "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "dev": true, "requires": {} } @@ -28478,9 +27995,9 @@ } }, "ws": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz", - "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, "requires": {} }, @@ -28535,25 +28052,6 @@ "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 902a53c51..5262b9fc7 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "jest": "28.1.0", "jest-environment-jsdom": "28.1.0", "mini-css-extract-plugin": "2.6.0", - "playwright": "1.21.1", + "playwright": "1.29.2", "prettier": "2.6.2", "purgecss-webpack-plugin": "4.1.3", "sass": "1.51.0", @@ -58,7 +58,7 @@ "svg-sprite-loader": "6.0.11", "svgo-loader": "3.0.0", "typescript": "4.6.4", - "webpack": "5.72.0", + "webpack": "5.94.0", "webpack-bundle-analyzer": "4.5.0", "webpack-cli": "4.9.2" }, @@ -116,8 +116,8 @@ } }, "engines": { - "npm": "8.x", - "node": "16.x || 17.x" + "npm": "10.x", + "node": "21.x || 22.x" }, "scripts": { "heroku-postbuild": "make build-ssr && make build-ui" diff --git a/public/assets/images/reaction-add.svg b/public/assets/images/reaction-add.svg new file mode 100644 index 000000000..5761c7e7f --- /dev/null +++ b/public/assets/images/reaction-add.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/assets/styles/reset.scss b/public/assets/styles/reset.scss index 45670f2e7..9d3b9cb2e 100644 --- a/public/assets/styles/reset.scss +++ b/public/assets/styles/reset.scss @@ -16,7 +16,7 @@ body { overflow-x: hidden; min-width: 320px; color: get("colors.gray.900"); - background-color: get("colors.white"); + background-color: get("colors.gray.100"); font-size: get("font.size.base"); font-family: $font-base; } diff --git a/public/assets/styles/utility/display.scss b/public/assets/styles/utility/display.scss index 6c283adef..51866812a 100644 --- a/public/assets/styles/utility/display.scss +++ b/public/assets/styles/utility/display.scss @@ -10,6 +10,10 @@ position: relative; } +.absolute { + position: absolute; +} + .inline-block { display: inline-block; } @@ -63,6 +67,13 @@ } } +.box { + border-radius: get("border.radius.large"); + background-color: get("colors.white"); + border: 1px solid get("colors.gray.200"); + padding: spacing(4); +} + .flex { display: flex; } @@ -176,10 +187,18 @@ visibility: hidden; } +.bt { + border-top: 1px solid; +} + .overflow-scroll { overflow: scroll; } +.overflow-auto { + overflow: auto; +} + .border { border: 1px solid transparent; } @@ -192,3 +211,9 @@ cursor: pointer; pointer-events: inherit; } + +.hover { + &:hover { + background-color: get("colors.gray.100"); + } +} diff --git a/public/assets/styles/utility/page.scss b/public/assets/styles/utility/page.scss index d8c8b9fb8..b6b31e8cb 100644 --- a/public/assets/styles/utility/page.scss +++ b/public/assets/styles/utility/page.scss @@ -5,7 +5,7 @@ } .page { - padding-top: spacing(4); + padding-top: spacing(5); padding-bottom: spacing(4); } diff --git a/public/assets/styles/utility/text.scss b/public/assets/styles/utility/text.scss index bbafbc6f6..9cc2fc946 100644 --- a/public/assets/styles/utility/text.scss +++ b/public/assets/styles/utility/text.scss @@ -10,8 +10,8 @@ pre:last-child { } .text-display2 { - font-size: get("font.size.2xl"); - font-weight: get("font.weight.bold"); + font-size: get("font.size.xl"); + font-weight: get("font.weight.medium"); letter-spacing: -1px; } @@ -20,11 +20,21 @@ pre:last-child { font-weight: get("font.weight.semibold"); } +.text-header { + font-size: get("font.size.xl"); + font-weight: get("font.weight.medium"); +} + .text-title { font-size: get("font.size.lg"); font-weight: get("font.weight.medium"); } +.text-subtitle { + font-size: get("font.size.base"); + font-weight: get("font.weight.medium"); +} + .text-body { font-size: get("font.size.base"); } @@ -49,6 +59,12 @@ pre:last-child { color: get("colors.blue.600"); } +.nowrap { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + .text-link:hover { color: get("colors.blue.800"); text-decoration: underline; diff --git a/public/assets/styles/variables/_text.scss b/public/assets/styles/variables/_text.scss index f24cf6bd9..8d8ca00ef 100644 --- a/public/assets/styles/variables/_text.scss +++ b/public/assets/styles/variables/_text.scss @@ -1,4 +1,4 @@ -$font-base: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, +$font-base: 'Inter', ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; $font-code: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; diff --git a/public/components/Header.tsx b/public/components/Header.tsx index b4c754677..65a240f37 100644 --- a/public/components/Header.tsx +++ b/public/components/Header.tsx @@ -16,14 +16,14 @@ export const Header = () => { const hideModal = () => setIsSignInModalOpen(false) return ( -
+
- +
-

{fider.session.tenant.name}

+

{fider.session.tenant.name}

{fider.session.isAuthenticated && ( diff --git a/public/components/NotificationIndicator.scss b/public/components/NotificationIndicator.scss index d36e2da63..40d9434f1 100644 --- a/public/components/NotificationIndicator.scss +++ b/public/components/NotificationIndicator.scss @@ -13,3 +13,11 @@ border-radius: 100%; } } + +.c-notifications-container { + max-height: 80vh; + overflow-y: auto; + @include media("lg") { + min-width: 400px; + } +} diff --git a/public/components/NotificationIndicator.tsx b/public/components/NotificationIndicator.tsx index 9a547ee44..e2084809b 100644 --- a/public/components/NotificationIndicator.tsx +++ b/public/components/NotificationIndicator.tsx @@ -1,14 +1,52 @@ import "./NotificationIndicator.scss" +import NoDataIllustration from "@fider/assets/images/undraw-empty.svg" import React, { useEffect, useState } from "react" import IconBell from "@fider/assets/images/heroicons-bell.svg" import { useFider } from "@fider/hooks" -import { actions } from "@fider/services" -import { Icon } from "./common" +import { actions, Fider } from "@fider/services" +import { Avatar, Icon, Markdown, Moment } from "./common" +import { Dropdown } from "./common/Dropdown" +import { Notification } from "@fider/models" +import { HStack, VStack } from "./layout" + +import { Trans } from "@lingui/macro" + +export const NotificationItem = ({ notification }: { notification: Notification }) => { + const openNotification = () => { + window.location.href = `/notifications/${notification.id}` + } + + return ( + + +
+ + + + +
+
+ ) +} + +const NotificationIcon = ({ unreadNotifications }: { unreadNotifications: number }) => { + return ( + <> + + + {unreadNotifications > 0 &&
} + + + ) +} export const NotificationIndicator = () => { const fider = useFider() const [unreadNotifications, setUnreadNotifications] = useState(0) + const [showingNotifications, setShowingNotifications] = useState(false) + const [recent, setRecent] = useState() + const [unread, setUnread] = useState() useEffect(() => { if (fider.session.isAuthenticated) { @@ -20,10 +58,83 @@ export const NotificationIndicator = () => { } }, [fider.session.isAuthenticated]) + useEffect(() => { + if (showingNotifications) { + actions.getAllNotifications().then((result) => { + if (result) { + const [unread, recent] = (result.data || []).reduce( + (result, item) => { + result[item.read ? 1 : 0].push(item) + return result + }, + [[] as Notification[], [] as Notification[]] + ) + setRecent(recent) + setUnread(unread) + setUnreadNotifications(unread.length) + } + }) + } + }, [showingNotifications]) + + const markAllAsRead = async (e: React.MouseEvent) => { + e.preventDefault() + const response = await actions.markAllAsRead() + if (response.ok) { + location.reload() + } + } + return ( - - - {unreadNotifications > 0 &&
} - + setShowingNotifications(isOpen)} + renderHandle={} + > +
+ {showingNotifications && (unread !== undefined || recent !== undefined) && ( + <> + {unread !== undefined && unread?.length > 0 ? ( + <> +

+ Unread notifications + {unread.length > 1 && ( + + Mark All as Read + + )} +

+ + {unread.map((n) => ( + + ))} + + + ) : ( +
+

+ No new notifications +

+ {recent?.length === 0 && } +
+ )} + {recent !== undefined && recent?.length > 0 && ( + <> +

+ Previous notifications +

+ + {recent.map((n) => ( + + ))} + + + )} + + )} +
+
) } diff --git a/public/components/Reactions.scss b/public/components/Reactions.scss new file mode 100644 index 000000000..056f154b1 --- /dev/null +++ b/public/components/Reactions.scss @@ -0,0 +1,20 @@ +@import "~@fider/assets/styles/variables.scss"; + +.c-reactions { + + &-add-reaction { + svg { + position: relative; + top:1px; + left:0; + } + } + + &-emojis { + top: -30px; + } + + button { + background-color: 'pink'; + } +} \ No newline at end of file diff --git a/public/components/Reactions.tsx b/public/components/Reactions.tsx new file mode 100644 index 000000000..613030a75 --- /dev/null +++ b/public/components/Reactions.tsx @@ -0,0 +1,86 @@ +import React, { useEffect, useState } from "react" +import { ReactionCount } from "@fider/models" +import { Icon } from "@fider/components" +import ReactionAdd from "@fider/assets/images/reaction-add.svg" +import { HStack } from "@fider/components/layout" +import { classSet } from "@fider/services" +import { useFider } from "@fider/hooks" +import "./Reactions.scss" + +interface ReactionsProps { + emojiSelectorRef: React.RefObject + toggleReaction: (emoji: string) => void + reactions?: ReactionCount[] +} + +const availableEmojis = ["👍", "👎", "😄", "🎉", "😕", "❤️", "🚀", "👀"] + +export const Reactions: React.FC = ({ emojiSelectorRef, toggleReaction, reactions }) => { + const fider = useFider() + const [isEmojiSelectorOpen, setIsEmojiSelectorOpen] = useState(false) + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (emojiSelectorRef.current && !emojiSelectorRef.current.contains(event.target as Node)) { + setIsEmojiSelectorOpen(false) + } + } + + document.addEventListener("click", handleClickOutside) + return () => { + document.removeEventListener("click", handleClickOutside) + } + }, []) + + return ( +
+ + {fider.session.isAuthenticated && ( + <> + setIsEmojiSelectorOpen(!isEmojiSelectorOpen)} + className="c-reactions-add-reaction relative text-gray-600 clickable inline-flex items-center px-1 py-1 rounded-full text-xs bg-blue-100 hover:bg-blue-200" + > + + + {isEmojiSelectorOpen && ( + + )} + + )} + {reactions !== undefined && ( + <> + {reactions.map((reaction) => ( + toggleReaction(reaction.emoji) })} + className={classSet({ + "inline-flex items-center px-2 py-1 rounded-full text-xs": true, + "bg-blue-100": reaction.includesMe, + "bg-gray-100": !reaction.includesMe, + "clickable hover:bg-blue-200": fider.session.isAuthenticated && reaction.includesMe, + "clickable hover:bg-gray-200": fider.session.isAuthenticated && !reaction.includesMe, + })} + > + {reaction.emoji} {reaction.count} + + ))} + + )} + +
+ ) +} diff --git a/public/components/common/Dropdown.scss b/public/components/common/Dropdown.scss index 265bf97ca..38d94f00e 100644 --- a/public/components/common/Dropdown.scss +++ b/public/components/common/Dropdown.scss @@ -29,6 +29,19 @@ &--left { right: 0; } + + &--wide { + max-width: sizing(180); + } + + &--fullscreen-small { + @include media("sm") { + position: fixed; + left: 0; + width: 100vw; + } + } + } &__listitem { diff --git a/public/components/common/Dropdown.tsx b/public/components/common/Dropdown.tsx index 8da23d576..1f9e5b5ac 100644 --- a/public/components/common/Dropdown.tsx +++ b/public/components/common/Dropdown.tsx @@ -42,7 +42,10 @@ const Divider = () => { interface DropdownProps { renderHandle: JSX.Element position?: "left" | "right" + onToggled?: (isOpen: boolean) => void children: React.ReactNode + wide?: boolean + fullsceenSm?: boolean } interface DropdownContextFuncs { @@ -57,12 +60,19 @@ export const Dropdown = (props: DropdownProps) => { const [isOpen, setIsOpen] = useState(false) const position = props.position || "right" + const changeToggleState = (newState: boolean) => { + setIsOpen(newState) + if (props.onToggled) { + props.onToggled(newState) + } + } + const toggleIsOpen = () => { - setIsOpen(!isOpen) + changeToggleState(!isOpen) } const close = () => { - setIsOpen(false) + changeToggleState(false) } const handleClick = (e: MouseEvent) => { @@ -82,7 +92,9 @@ export const Dropdown = (props: DropdownProps) => { }, []) const listClassName = classSet({ + "c-dropdown__list--wide": props.wide, "c-dropdown__list shadow-lg": true, + "c-dropdown__list--fullscreen-small": props.fullsceenSm, [`c-dropdown__list--${position}`]: position === "left", }) diff --git a/public/components/common/PoweredByFider.scss b/public/components/common/PoweredByFider.scss index 8b5bc3582..a2693d84e 100644 --- a/public/components/common/PoweredByFider.scss +++ b/public/components/common/PoweredByFider.scss @@ -4,8 +4,8 @@ text-align: center; a { - color: get("colors.gray.700"); - font-size: 11px; + color: get("colors.blue.700"); + font-size: 12px; } a:hover { color: get("colors.gray.900"); diff --git a/public/components/common/PoweredByFider.tsx b/public/components/common/PoweredByFider.tsx index 1618eb6a9..791b93598 100644 --- a/public/components/common/PoweredByFider.tsx +++ b/public/components/common/PoweredByFider.tsx @@ -1,5 +1,4 @@ import React from "react" -import { useFider } from "@fider/hooks" import { classSet } from "@fider/services" import "./PoweredByFider.scss" @@ -10,9 +9,7 @@ interface PoweredByFiderProps { } export const PoweredByFider = (props: PoweredByFiderProps) => { - const fider = useFider() - - const source = encodeURIComponent(fider.session.tenant.subdomain) + const source = encodeURIComponent(window?.location?.host || "") const medium = "powered-by" const campaign = props.slot @@ -24,7 +21,7 @@ export const PoweredByFider = (props: PoweredByFiderProps) => { return ( ) diff --git a/public/components/common/UserName.scss b/public/components/common/UserName.scss index aaa8a796b..e4c70594f 100644 --- a/public/components/common/UserName.scss +++ b/public/components/common/UserName.scss @@ -6,6 +6,13 @@ display: inline-flex; align-items: center; + &--email { + margin-left: 10px; + color: get("colors.gray.600"); + font-size: get("font.size.xs"); + font-weight: 400; + } + &--staff { color: get("colors.primary.base"); border-color: get("colors.primary.base"); diff --git a/public/components/common/UserName.tsx b/public/components/common/UserName.tsx index 8559d3bd0..0f06751a7 100644 --- a/public/components/common/UserName.tsx +++ b/public/components/common/UserName.tsx @@ -9,7 +9,9 @@ interface UserNameProps { id: number name: string role?: UserRole + email?: string } + showEmail?: boolean } export const UserName = (props: UserNameProps) => { @@ -22,6 +24,8 @@ export const UserName = (props: UserNameProps) => { return (
{props.user.name || "Anonymous"} + <>{props.showEmail && props.user.email && ({props.user.email})} + {isStaff && (
diff --git a/public/components/common/form/Form.scss b/public/components/common/form/Form.scss index 6d46824f4..a3d12f5cb 100644 --- a/public/components/common/form/Form.scss +++ b/public/components/common/form/Form.scss @@ -1,11 +1,11 @@ @import "~@fider/assets/styles/variables.scss"; .c-form-field { - margin-bottom: spacing(5); + margin-bottom: spacing(7); > label { display: block; - font-size: get("font.size.sm"); + font-size: get("font.size.base"); margin-bottom: spacing(1); font-weight: 500; } @@ -14,7 +14,7 @@ margin-bottom: 0; .flex-x > & { - margin-bottom: spacing(2); + // margin-bottom: spacing(2); } } } diff --git a/public/components/common/form/Select.tsx b/public/components/common/form/Select.tsx index a45323a96..e864e68bc 100644 --- a/public/components/common/form/Select.tsx +++ b/public/components/common/form/Select.tsx @@ -19,75 +19,58 @@ interface SelectProps { onChange?: (option?: SelectOption) => void } -interface SelectState { - selected?: SelectOption -} - -export class Select extends React.Component { - constructor(props: SelectProps) { - super(props) - this.state = { - selected: this.getOption(props.defaultValue), - } - } - - private getOption(value?: string): SelectOption | undefined { - if (value && this.props.options) { - const filtered = this.props.options.filter((x) => x.value === value) +export const Select: React.FunctionComponent = (props) => { + const getOption = (value?: string) => { + if (value && props.options) { + const filtered = props.options.filter((x) => x.value === value) if (filtered && filtered.length > 0) { return filtered[0] } } } - - private onChange = (e: React.FormEvent) => { + const [selected, setSelected] = React.useState(getOption(props.defaultValue)) + const onChange = (e: React.FormEvent) => { let selected: SelectOption | undefined if (e.currentTarget.value) { - const options = this.props.options.filter((o) => o.value === e.currentTarget.value) + const options = props.options.filter((o) => o.value === e.currentTarget.value) if (options && options.length > 0) { selected = options[0] } } - this.setState({ selected }, () => { - if (this.props.onChange) { - this.props.onChange(this.state.selected) - } - }) + setSelected(selected) + if (props.onChange) { + props.onChange(selected) + } } - public render() { - const options = this.props.options.map((option) => { - return ( - - ) - }) - - return ( - - {(ctx) => ( - <> -
- {!!this.props.label && } - - - {this.props.children} -
- - )} - - ) - } + return ( + + {(ctx) => ( + <> +
+ {!!props.label && } + + + {props.children} +
+ + )} +
+ ) } diff --git a/public/components/index.tsx b/public/components/index.tsx index c4fc4afce..0e5109b29 100644 --- a/public/components/index.tsx +++ b/public/components/index.tsx @@ -7,5 +7,6 @@ export * from "./SignInModal" export * from "./VoteCounter" export * from "./NotificationIndicator" export * from "./UserMenu" +export * from "./Reactions" export * from "./ReadOnlyNotice" export * from "./common" diff --git a/public/components/layout/Stack.tsx b/public/components/layout/Stack.tsx index dd70f4825..be356c4ca 100644 --- a/public/components/layout/Stack.tsx +++ b/public/components/layout/Stack.tsx @@ -12,7 +12,7 @@ interface StackProps { } const Stack = (props: StackProps, dir: "x" | "y") => { - const spacing = props.spacing === undefined ? 1 : props.spacing + const spacing = props.spacing === undefined ? 2 : props.spacing const className = classSet({ [`${props.className}`]: props.className, flex: true, diff --git a/public/models/identity.ts b/public/models/identity.ts index 8b561fbd9..47755d91e 100644 --- a/public/models/identity.ts +++ b/public/models/identity.ts @@ -22,6 +22,7 @@ export enum TenantStatus { export interface User { id: number name: string + email?: string role: UserRole status: UserStatus avatarURL: string diff --git a/public/models/notification.ts b/public/models/notification.ts index b85940827..a2cece932 100644 --- a/public/models/notification.ts +++ b/public/models/notification.ts @@ -4,4 +4,6 @@ export interface Notification { link: string read: boolean createdAt: string + authorName: string + avatarURL: string } diff --git a/public/models/post.ts b/public/models/post.ts index 57bc2b372..0f12c52af 100644 --- a/public/models/post.ts +++ b/public/models/post.ts @@ -51,12 +51,19 @@ export interface PostResponse { } } +export interface ReactionCount { + emoji: string + count: number + includesMe: boolean +} + export interface Comment { id: number content: string createdAt: string user: User attachments?: string[] + reactionCounts?: ReactionCount[] editedAt?: string editedBy?: User } diff --git a/public/pages/Administration/components/AdminBasePage.scss b/public/pages/Administration/components/AdminBasePage.scss index aabb8706f..5059bc7f4 100644 --- a/public/pages/Administration/components/AdminBasePage.scss +++ b/public/pages/Administration/components/AdminBasePage.scss @@ -6,6 +6,6 @@ gap: spacing(4); @include media("lg") { - grid-template-columns: 1fr 5fr; + grid-template-columns: 1fr 4fr 1fr; } } diff --git a/public/pages/Administration/components/SideMenu.scss b/public/pages/Administration/components/SideMenu.scss index 444f856d0..1bd480e73 100644 --- a/public/pages/Administration/components/SideMenu.scss +++ b/public/pages/Administration/components/SideMenu.scss @@ -2,7 +2,7 @@ .c-side-menu { &__item { - padding: spacing(3); + padding: spacing(4); border-bottom: 1px solid get("colors.gray.200"); color: get("colors.gray.900"); diff --git a/public/pages/Administration/components/SideMenu.tsx b/public/pages/Administration/components/SideMenu.tsx index f0f80ba14..b88e7b321 100644 --- a/public/pages/Administration/components/SideMenu.tsx +++ b/public/pages/Administration/components/SideMenu.tsx @@ -39,7 +39,7 @@ export const SideMenu = (props: SiteMenuProps) => { return (
- + diff --git a/public/pages/Administration/components/webhook/WebhookForm.tsx b/public/pages/Administration/components/webhook/WebhookForm.tsx index 02cf50ac5..ca9d93089 100644 --- a/public/pages/Administration/components/webhook/WebhookForm.tsx +++ b/public/pages/Administration/components/webhook/WebhookForm.tsx @@ -152,7 +152,7 @@ export const WebhookForm = (props: WebhookFormProps) => { This webhook has failed )} -

{title}

+

{title}

}> - + {Object.entries(httpHeaders).map(([header, value]) => ( ))} diff --git a/public/pages/Administration/components/webhook/WebhookListItem.tsx b/public/pages/Administration/components/webhook/WebhookListItem.tsx index 51d3b6776..2381fb123 100644 --- a/public/pages/Administration/components/webhook/WebhookListItem.tsx +++ b/public/pages/Administration/components/webhook/WebhookListItem.tsx @@ -1,7 +1,7 @@ import "./WebhookListItem.scss" import React, { useState } from "react" -import { Webhook, WebhookStatus, WebhookTriggerResult } from "@fider/models" +import { Webhook, WebhookStatus, WebhookTriggerResult, WebhookType } from "@fider/models" import { Button, Icon } from "@fider/components" import { actions, notify } from "@fider/services" @@ -63,6 +63,19 @@ export const WebhookListItem = (props: WebhookListItemProps) => { } } + const getWebhookType = (type: WebhookType) => { + switch (type) { + case WebhookType.CHANGE_STATUS: + return "Change Status" + case WebhookType.NEW_COMMENT: + return "New Comment" + case WebhookType.DELETE_POST: + return "Delete Post" + case WebhookType.NEW_POST: + return "New Post" + } + } + const testWebhook = async () => { const result = await actions.testWebhook(props.webhook.id) setTriggerResult(result.data) @@ -100,8 +113,9 @@ export const WebhookListItem = (props: WebhookListItemProps) => { -

- #{props.webhook.id} {props.webhook.name} +

+ #{props.webhook.id} + {getWebhookType(props.webhook.type)} - {props.webhook.name}

{triggerResult?.success === false && ( diff --git a/public/pages/Administration/pages/GeneralSettings.page.tsx b/public/pages/Administration/pages/GeneralSettings.page.tsx index 0885fd757..414d4012d 100644 --- a/public/pages/Administration/pages/GeneralSettings.page.tsx +++ b/public/pages/Administration/pages/GeneralSettings.page.tsx @@ -44,11 +44,8 @@ const GeneralSettingsPage = () => { return ( - -

- The title is used on the header, emails, notifications and SEO content. Keep it short and simple. The product/service name is usually the best - choice. -

+ +

Keep it short and snappy. Your product / service name is usually best.

@@ -73,16 +70,11 @@ const GeneralSettingsPage = () => { placeholder="Enter your suggestion here..." onChange={setInvitation} > -

- This text is used as a placeholder for the suggestion's text box. Use it to invite your visitors into sharing their suggestions and feedback. - Leave it empty for a default message. -

+

Placeholder text in the suggestion's box. It should invite your visitors into sharing their feedback.

- -

- We accept JPG, GIF and PNG images, smaller than 100KB and with an aspect ratio of 1:1 with minimum dimensions of 200x200 pixels. -

+ +

JPG, GIF or PNG smaller than 100KB, minimum size 200x200 pixels.

{!Fider.isSingleHostMode() && ( @@ -104,8 +96,7 @@ const GeneralSettingsPage = () => { ] ) : (

- Custom domains allow you to access your app via your own domain name (for example, feedback.yourcompany.com - ). + Use custom domains to access Fider via your own domain name feedback.yourcompany.com

)}
diff --git a/public/pages/Administration/pages/ManageMembers.page.tsx b/public/pages/Administration/pages/ManageMembers.page.tsx index 37a44592c..4ed17c0a4 100644 --- a/public/pages/Administration/pages/ManageMembers.page.tsx +++ b/public/pages/Administration/pages/ManageMembers.page.tsx @@ -38,7 +38,7 @@ const UserListItem = (props: UserListItemProps) => { - + {admin} {collaborator} {blocked} @@ -69,6 +69,7 @@ export default class ManageMembersPage extends AdminBasePage { + return user.name.toLowerCase().indexOf(query.toLowerCase()) >= 0 || (user.email && user.email.toLowerCase().indexOf(query.toLowerCase()) >= 0) || false + } + private handleSearchFilterChanged = (query: string) => { - const users = this.props.users.filter((x) => x.name.toLowerCase().indexOf(query.toLowerCase()) >= 0).sort(this.sortByStaff) + const users = this.props.users.filter((x) => this.memberFilter(query, x)).sort(this.sortByStaff) this.setState({ query, users, visibleUsers: users.slice(0, 10) }) } @@ -145,7 +150,7 @@ export default class ManageMembersPage extends AdminBasePage @@ -156,7 +161,7 @@ export default class ManageMembersPage extends AdminBasePage
-

+

{!this.state.query && ( <> Showing {this.state.visibleUsers.length} of {this.state.users.length} registered users. diff --git a/public/pages/Administration/pages/ManageWebhooks.page.tsx b/public/pages/Administration/pages/ManageWebhooks.page.tsx index f40f8c7e7..0a739ed4a 100644 --- a/public/pages/Administration/pages/ManageWebhooks.page.tsx +++ b/public/pages/Administration/pages/ManageWebhooks.page.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react" import { Button } from "@fider/components" -import { Webhook, WebhookData, WebhookStatus, WebhookType } from "@fider/models" +import { Webhook, WebhookData, WebhookStatus } from "@fider/models" import { actions, Failure } from "@fider/services" import { AdminPageContainer } from "../components/AdminBasePage" import { WebhookForm } from "../components/webhook/WebhookForm" @@ -30,10 +30,9 @@ interface WebhooksListProps { const WebhooksList = (props: WebhooksListProps) => { return (

-

{props.title}

-

These webhooks are triggered every time {props.description}.

+

My Webhooks

- {props.list.length === 0 ?

There aren’t any "{props.title.toLowerCase()}" webhook yet.

: props.list} + {props.list.length === 0 ?

There aren’t any webhooks yet.

: props.list}
) @@ -98,8 +97,8 @@ const ManageWebhooksPage = (props: ManageWebhooksPageProps) => { sortWebhooks() } - const getWebhookList = (filter: (webhook: Webhook) => boolean) => { - return allWebhooks.filter(filter).map((w) => { + const getWebhookItems = () => { + return allWebhooks.map((w) => { return ( { return render() } - const newPostList = getWebhookList((w) => w.type === WebhookType.NEW_POST) - const newCommentList = getWebhookList((w) => w.type === WebhookType.NEW_COMMENT) - const changeStatusList = getWebhookList((w) => w.type === WebhookType.CHANGE_STATUS) - const deletePostList = getWebhookList((w) => w.type === WebhookType.DELETE_POST) - return render(

@@ -140,13 +134,10 @@ const ManageWebhooksPage = (props: ManageWebhooksPageProps) => { .

- - - - +
diff --git a/public/pages/Home/Home.page.scss b/public/pages/Home/Home.page.scss index 46a301ca2..9fb06910a 100644 --- a/public/pages/Home/Home.page.scss +++ b/public/pages/Home/Home.page.scss @@ -14,13 +14,22 @@ .p-home { &__welcome-col { - background-color: get("colors.gray.100"); - padding: spacing(2); - border-radius: get("border.radius.medium"); + > :first-child { + background-color: get("colors.white"); + border-radius: get("border.radius.large"); + border: 1px solid get("colors.gray.200"); + + @include media("lg") { + } + } + } + + &__posts-col { + background-color: get("colors.white"); + border-radius: get("border.radius.large"); + border: 1px solid get("colors.gray.200"); @include media("lg") { - padding: 0; - background-color: transparent; } } diff --git a/public/pages/Home/Home.page.tsx b/public/pages/Home/Home.page.tsx index 834d45017..a0b1c4f7c 100644 --- a/public/pages/Home/Home.page.tsx +++ b/public/pages/Home/Home.page.tsx @@ -77,13 +77,13 @@ What can we do better? This is the place for you to vote, discuss and share idea
- + - +
-
+
{isLonely() ? ( ) : title ? ( diff --git a/public/pages/Home/components/TagsFilter.tsx b/public/pages/Home/components/TagsFilter.tsx index cee7dbb60..902f0e600 100644 --- a/public/pages/Home/components/TagsFilter.tsx +++ b/public/pages/Home/components/TagsFilter.tsx @@ -32,7 +32,9 @@ export const TagsFilter = (props: TagsFilterProps) => { return ( - with + + with + {label}
}> {props.tags.map((t) => ( diff --git a/public/pages/MySettings/components/NotificationSettings.tsx b/public/pages/MySettings/components/NotificationSettings.tsx index 254bf456c..8585e8351 100644 --- a/public/pages/MySettings/components/NotificationSettings.tsx +++ b/public/pages/MySettings/components/NotificationSettings.tsx @@ -94,7 +94,7 @@ export const NotificationSettings = (props: NotificationSettingsProps) => {

- +
New Post diff --git a/public/pages/ShowPost/ShowPost.page.scss b/public/pages/ShowPost/ShowPost.page.scss index c2efacbf9..a23a0f93c 100644 --- a/public/pages/ShowPost/ShowPost.page.scss +++ b/public/pages/ShowPost/ShowPost.page.scss @@ -5,27 +5,40 @@ flex-grow: 1; } + .p-show-post { + &__main-col { + background-color: get("colors.white"); + padding: spacing(4); + border-radius: get("border.radius.large"); + margin-bottom: spacing(4); + } + + &__action-col { + > :first-child { + background-color: get("colors.white"); + padding: spacing(4); + border-radius: get("border.radius.large"); + } + } + } + @include media("lg") { .p-show-post { display: grid; gap: spacing(4); - grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-columns: 1fr 3fr; grid-template-rows: auto; grid-template-areas: - "Header Header Header Action" - "Discussion Discussion Discussion Action"; + "Action Main" + "Action Main"; - &__header-col { - grid-area: Header; + &__main-col { + grid-area: Main; } &__action-col { grid-area: Action; } - - &__discussion_col { - grid-area: Discussion; - } } } } diff --git a/public/pages/ShowPost/ShowPost.page.tsx b/public/pages/ShowPost/ShowPost.page.tsx index 3c200926b..a83fd6004 100644 --- a/public/pages/ShowPost/ShowPost.page.tsx +++ b/public/pages/ShowPost/ShowPost.page.tsx @@ -3,7 +3,7 @@ import "./ShowPost.page.scss" import React from "react" import { Comment, Post, Tag, Vote, ImageUpload, CurrentUser } from "@fider/models" -import { actions, Failure, Fider, timeAgo } from "@fider/services" +import { actions, clearUrlHash, Failure, Fider, notify, timeAgo } from "@fider/services" import { VoteCounter, @@ -48,6 +48,7 @@ interface ShowPostPageState { newTitle: string attachments: ImageUpload[] newDescription: string + highlightedComment?: number error?: Failure } @@ -72,6 +73,15 @@ export default class ShowPostPage extends React.Component { const result = await actions.updatePost(this.props.post.number, this.state.newTitle, this.state.newDescription, this.state.attachments) if (result.ok) { @@ -103,107 +113,137 @@ export default class ShowPostPage extends React.Component { + const hash = window.location.hash + const result = /#comment-([0-9]+)/.exec(hash) + + let highlightedComment + if (result === null) { + // No match + highlightedComment = undefined + } else { + // Match, extract numeric ID + const id = parseInt(result[1]) + if (this.props.comments.map((comment) => comment.id).includes(id)) { + highlightedComment = id + } else { + // Unknown comment + if (e?.cancelable) { + e.preventDefault() + } else { + clearUrlHash(true) + } + notify.error(Unknown comment ID #{id}) + highlightedComment = undefined + } + } + this.setState({ highlightedComment }) + } + public render() { return ( <>
- -
- - - +
+
+
+ + + + +
+ {this.state.editMode ? ( + + + + ) : ( +

{this.props.post.title}

+ )} -
+ + + Posted by · + + +
+ + + + Description + {this.state.editMode ? (
- +