Compare commits

..

60 Commits

Author SHA1 Message Date
8019d07cab Update CHANGELOG.md 2022-04-12 15:35:19 +05:00
d21a6f2797 Added possibility to disable error pages auto-localization (#94) 2022-04-12 15:34:35 +05:00
a3389aaafa Changing UID/GID to the numeric values (#93) 2022-04-09 20:39:52 +05:00
c6a7e30609 Bump github.com/fasthttp/router from 1.4.6 to 1.4.7 (#90) 2022-04-01 22:07:18 +00:00
01abc48a01 CI updated 2022-04-01 13:14:16 +05:00
d6374d7edf Bump actions/setup-go from 2 to 3 2022-04-01 13:01:22 +05:00
7ebfac9dc2 Bump actions/cache from 2 to 3.0.1 (#89) 2022-04-01 07:51:10 +00:00
64d4798156 Bump peter-evans/dockerhub-description from 2 to 3 (#88) 2022-04-01 07:48:54 +00:00
4adad3df10 CI updated (#87) 2022-03-30 21:23:42 +05:00
30a7b2793f Fix translation FR (#86) 2022-03-30 18:00:32 +05:00
2d9deb7370 CI now purges the CDN cache (#84) 2022-03-28 22:13:19 +05:00
873944f90f Changelog updated 2022-03-28 16:05:44 +05:00
cd5abe458b l10n file formatted, CI updated (#83) 2022-03-28 16:04:23 +05:00
481e11d527 Error pages now translated in 🇫🇷 (#82) 2022-03-28 15:11:44 +05:00
fac7394ae2 Update CHANGELOG.md 2022-03-27 20:38:04 +05:00
4a918b1899 Template matrix (#81) 2022-03-27 20:33:31 +05:00
05be3841d7 Update .gitattributes 2022-03-25 14:51:50 +05:00
02cadcd907 Create .gitattributes 2022-03-25 14:46:59 +05:00
94dff2421c Changelog updated 2022-03-24 13:54:50 +05:00
51f8824659 shuffle template fixed 2022-03-24 13:54:07 +05:00
e82c02c768 fix the translation mistakes 2022-03-24 12:28:03 +05:00
dc51e3192c Update CHANGELOG.md 2022-03-24 00:32:40 +05:00
45ca69432b Translated in 🇺🇦 and 🇷🇺 languages (#80) 2022-03-24 00:31:34 +05:00
f5f572a4d3 small template fixes 2022-03-23 12:30:33 +05:00
2d418ecffa Changelog updated 2022-03-22 23:46:01 +05:00
c6b3342361 Readme file updated 2022-03-22 23:44:31 +05:00
3614f0503f New template connection added (#79) 2022-03-22 23:31:33 +05:00
a2ee92acc4 v2.8.1 2022-03-21 13:23:21 +05:00
93dddd75d9 Update README.md 2022-03-20 23:31:45 +05:00
c17587ca6b Changelog updated 2022-03-20 12:44:27 +05:00
d7d5245d07 Template app-down added (#74) 2022-03-20 11:32:40 +05:00
6c0885a5d3 Bump golang from 1.17.7-alpine to 1.18.0-alpine (#76) 2022-03-19 11:33:30 +00:00
4b83ce7d09 Bump github.com/valyala/fasthttp from 1.33.0 to 1.34.0 (#77) 2022-03-19 11:33:19 +00:00
d6cebc27ab Bump github.com/spf13/cobra from 1.3.0 to 1.4.0 (#78) 2022-03-19 11:28:55 +00:00
2bcbd4ba41 Bump github.com/stretchr/testify from 1.7.0 to 1.7.1 (#75) 2022-03-19 11:25:36 +00:00
edc05ec6d2 an attempt to fix the ci 2022-03-04 10:49:40 +05:00
94b6af6d53 Bump golangci/golangci-lint-action from 2 to 3.1.0 (#72) 2022-03-04 05:43:59 +00:00
8d24125eee Bump golang from 1.17.6-alpine to 1.17.7-alpine (#69) 2022-03-04 05:25:18 +00:00
97fc3b8693 Bump actions/setup-node from 2 to 3 (#73) 2022-03-02 03:41:56 +00:00
ac1c19df28 Bump go.uber.org/zap from 1.20.0 to 1.21.0 (#70) 2022-03-02 03:39:14 +00:00
b7f82e4635 Bump actions/checkout from 2 to 3 (#71) 2022-03-02 03:38:28 +00:00
62493411b4 Update README.md 2022-02-24 09:47:53 +05:00
0e20e39cd2 Update README.md 2022-02-24 02:35:49 +05:00
4bdbb882b5 Update README.md 2022-02-24 02:34:31 +05:00
4b2a792148 Update README.md 2022-02-24 02:31:44 +05:00
1d41cf190b Update CHANGELOG.md 2022-02-23 11:14:57 +05:00
e857c0309b proxy headers (#67) 2022-02-23 11:09:54 +05:00
06aff4ecb3 Update README.md 2022-02-22 21:20:32 +05:00
3145bdfa00 fix the theme (auto-dark mode) 2022-02-22 20:58:26 +05:00
178e6b2d9b New template lost-in-space (#68) 2022-02-22 20:48:55 +05:00
7a3dc917a2 Readme file updated 2022-02-22 13:16:47 +05:00
8a14836bd1 migrate to the another docker scanning action (#66) 2022-02-21 16:48:35 +05:00
ae2bf27463 issue templates update 2022-02-21 16:08:07 +05:00
c53a87b816 Update README.md 2022-02-14 15:45:34 +05:00
8463ecf00d Update README.md 2022-02-08 11:03:23 +05:00
1d7596b3df Bump github.com/prometheus/client_golang from 1.12.0 to 1.12.1 (#63) 2022-02-02 04:09:32 +00:00
251e0a01cf Bump github.com/fasthttp/router from 1.4.5 to 1.4.6 (#64) 2022-02-02 04:08:52 +00:00
22d3e3485e Changelog updated 2022-02-01 20:12:11 +05:00
375272b561 Change themes in random order once a day/hour (#62) 2022-02-01 19:39:50 +05:00
7e7f956fae template docs added 2022-01-31 14:45:12 +05:00
48 changed files with 2688 additions and 583 deletions

9
.gitattributes vendored Normal file
View File

@ -0,0 +1,9 @@
# Text files have auto line endings
* text=auto
# Go source files always have LF line endings
*.go text eol=lf
# Disable next extensions in project "used languages" list
*.lua linguist-detectable=false
*.html linguist-detectable=false

View File

@ -12,6 +12,8 @@ body:
options:
- label: I have searched the existing issues
required: true
- label: And it has nothing to do with Traefik
required: true
- type: textarea
attributes:

View File

@ -6,3 +6,7 @@ contact_links:
- name: 🗣 Ask a Question, Discuss
url: https://github.com/tarampampam/error-pages/discussions
about: Feel free to ask anything
- name: 🌀 I have a question about Traefik..
url: https://community.traefik.io/
about: In this case - ask in the Traefik community

View File

@ -10,9 +10,9 @@ jobs:
name: Docker Hub Description
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: peter-evans/dockerhub-description@v2 # Action page: <https://github.com/peter-evans/dockerhub-description>
- uses: peter-evans/dockerhub-description@v3 # Action page: <https://github.com/peter-evans/dockerhub-description>
with:
username: ${{ secrets.DOCKER_LOGIN }}
password: ${{ secrets.DOCKER_USER_PASSWORD }}

View File

@ -5,6 +5,18 @@ on:
types: [published]
jobs:
purge-cdn-cache:
name: Purge jsDelivr CDN cache
runs-on: ubuntu-20.04
steps:
- uses: gacts/purge-jsdelivr-cache@v1 # Action page: <https://github.com/gacts/purge-jsdelivr-cache>
with:
url: |
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.js
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@latest/l10n/l10n.js
https://cdn.jsdelivr.net/gh/tarampampam/error-pages@latest/l10n/l10n.min.js
build:
name: Build for ${{ matrix.os }} (${{ matrix.arch }})
runs-on: ubuntu-20.04
@ -14,10 +26,10 @@ jobs:
os: [linux, darwin] # linux, freebsd, darwin, windows
arch: [amd64] # amd64, 386
steps:
- uses: actions/setup-go@v2
with: {go-version: 1.17.6}
- uses: actions/setup-go@v3
with: {go-version: 1.18.0}
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: gacts/github-slug@v1
id: slug
@ -46,7 +58,7 @@ jobs:
name: Build docker image
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: gacts/github-slug@v1
id: slug
@ -75,8 +87,12 @@ jobs:
build-args: "APP_VERSION=${{ steps.slug.outputs.version }}"
tags: |
tarampampam/error-pages:${{ steps.slug.outputs.version }}
tarampampam/error-pages:${{ steps.slug.outputs.version-major }}.${{ steps.slug.outputs.version-minor }}
tarampampam/error-pages:${{ steps.slug.outputs.version-major }}
tarampampam/error-pages:latest
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:${{ steps.slug.outputs.version }}
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:${{ steps.slug.outputs.version-major }}.${{ steps.slug.outputs.version-minor }}
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:${{ steps.slug.outputs.version-major }}
ghcr.io/${{ github.actor }}/${{ github.event.repository.name }}:latest
demo:

View File

@ -13,7 +13,7 @@ jobs: # Docs: <https://git.io/JvxXE>
name: Gitleaks
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with: {fetch-depth: 0}
- uses: zricethezav/gitleaks-action@v1 # Action page: <https://github.com/zricethezav/gitleaks-action>
@ -22,10 +22,13 @@ jobs: # Docs: <https://git.io/JvxXE>
name: Golang-CI (lint)
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with: {go-version: 1.17} # On v1.18 I had an error "panic: load embedded ruleguard rules: rules/rules.go:13: can't load fmt"
- name: Run linter
uses: golangci/golangci-lint-action@v2 # Action page: <https://github.com/golangci/golangci-lint-action>
uses: golangci/golangci-lint-action@v3 # Action page: <https://github.com/golangci/golangci-lint-action>
with:
version: v1.44 # without patch version
only-new-issues: false # show only new issues if it's a pull request
@ -34,9 +37,9 @@ jobs: # Docs: <https://git.io/JvxXE>
name: Validate config file
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with: {node-version: '16'}
- name: Install linter
@ -45,18 +48,34 @@ jobs: # Docs: <https://git.io/JvxXE>
- name: Run linter
run: ajv validate --all-errors --verbose -s ./schemas/config/1.0.schema.json -d ./error-pages.y*ml
lint-l10n:
name: Lint l10n file(s)
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with: {node-version: '16'}
- name: Install eslint
run: npm install -g eslint@v8 # Package page: <https://www.npmjs.com/package/eslint>
- name: Run linter
working-directory: l10n
run: eslint ./*.js
go-test:
name: Unit tests
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with: {go-version: 1.17}
- uses: actions/setup-go@v3
with: {go-version: 1.18}
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with: {fetch-depth: 2} # Fixes codecov error 'Issue detecting commit SHA'
- name: Go modules Cache # Docs: <https://git.io/JfAKn#go---modules>
uses: actions/cache@v2
uses: actions/cache@v3
id: go-cache
with:
path: ~/go/pkg/mod
@ -85,16 +104,16 @@ jobs: # Docs: <https://git.io/JvxXE>
arch: [amd64] # amd64, 386
needs: [golangci-lint, go-test, validate-config-file]
steps:
- uses: actions/setup-go@v2
with: {go-version: 1.17}
- uses: actions/setup-go@v3
with: {go-version: 1.18}
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: gacts/github-slug@v1
id: slug
- name: Go modules Cache # Docs: <https://git.io/JfAKn#go---modules>
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@ -126,7 +145,7 @@ jobs: # Docs: <https://git.io/JvxXE>
runs-on: ubuntu-20.04
needs: [build]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
@ -150,13 +169,17 @@ jobs: # Docs: <https://git.io/JvxXE>
test -f ./out/noise/404.html
test -f ./out/hacker-terminal/404.html
test -f ./out/cats/404.html
test -f ./out/lost-in-space/404.html
test -f ./out/app-down/404.html
test -f ./out/connection/404.html
test -f ./out/matrix/404.html
docker-image:
name: Build docker image
runs-on: ubuntu-20.04
needs: [golangci-lint, go-test, validate-config-file]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: gacts/github-slug@v1
id: slug
@ -182,21 +205,25 @@ jobs: # Docs: <https://git.io/JvxXE>
runs-on: ubuntu-20.04
needs: [docker-image]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3 # is needed for `upload-sarif` action
- uses: actions/download-artifact@v2
with:
name: docker-image
path: .artifact
- working-directory: .artifact
run: docker load < docker-image.tar
- uses: anchore/scan-action@v3 # action page: <https://github.com/anchore/scan-action>
- uses: aquasecurity/trivy-action@0.2.2 # action page: <https://github.com/aquasecurity/trivy-action>
with:
image: app:ci
fail-build: true
severity-cutoff: low # negligible, low, medium, high or critical
input: .artifact/docker-image.tar
format: sarif
severity: MEDIUM,HIGH,CRITICAL
exit-code: 1
output: trivy-results.sarif
- uses: github/codeql-action/upload-sarif@v1
if: always()
continue-on-error: true
with: {sarif_file: trivy-results.sarif}
poke-docker-image:
name: Run the docker image
@ -204,7 +231,7 @@ jobs: # Docs: <https://git.io/JvxXE>
needs: [docker-image]
timeout-minutes: 2
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- uses: actions/download-artifact@v2
with:
@ -223,7 +250,7 @@ jobs: # Docs: <https://git.io/JvxXE>
run: sudo dpkg -i hurl.deb
- name: Run container with the app
run: docker run --rm -d -p "8080:8080/tcp" -e "SHOW_DETAILS=true" --name app app:ci
run: docker run --rm -d -p "8080:8080/tcp" -e "SHOW_DETAILS=true" -e "PROXY_HTTP_HEADERS=X-Foo,Bar,Baz_blah" --name app app:ci
- name: Wait for container "healthy" state
run: until [[ "`docker inspect -f {{.State.Health.Status}} app`" == "healthy" ]]; do echo "wait 1 sec.."; sleep 1; done

View File

@ -1,3 +0,0 @@
ignore:
# temporary ignore this CVE as false positive on the Go package
- vulnerability: CVE-2015-5237

View File

@ -4,6 +4,118 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog][keepachangelog] and this project adheres to [Semantic Versioning][semver].
## v2.13.0
### Added
- Possibility to disable error pages auto-localization (using `--disable-l10n` flag for the `serve` & `build` commands or environment variable `DISABLE_L10N`) [#91]
### Fixed
- User UID/GID changed to the numeric values in the dockerfile [#92]
[#92]:https://github.com/tarampampam/error-pages/issues/92
[#91]:https://github.com/tarampampam/error-pages/issues/91
## v2.12.1
### Fixed
- Fix translation 🇫🇷 [#86]
[#85]:https://github.com/tarampampam/error-pages/pull/86
## v2.12.0
### Changed
- Error pages now translated in 🇫🇷 [#82]
[#82]:https://github.com/tarampampam/error-pages/pull/82
## v2.11.0
### Added
- Template `matrix` [#81]
### Fixed
- Localization mistakes [#81]
[#81]:https://github.com/tarampampam/error-pages/pull/81
## v2.10.1
### Fixed
- Template `shuffle`
- Localization mistakes
## v2.10.0
### Changed
- Error pages now translated in 🇺🇦 and 🇷🇺 languages [#80]
[#80]:https://github.com/tarampampam/error-pages/pull/80
## v2.9.0
### Added
- Template `connection` [#79]
[#79]:https://github.com/tarampampam/error-pages/pull/79
## v2.8.1
### Fixed
- Dark mode for `app-down` template
### Changed
- The index page for built error pages now supports a dark theme
## v2.8.0
### Added
- Template `app-down` [#74]
### Changed
- Go updated from `1.17.6` up to `1.18.0`
[#74]:https://github.com/tarampampam/error-pages/pull/74
## v2.7.0
### Changed
- Logs includes request/response headers now [#67]
### Added
- Possibility to proxy HTTP headers from the requests to the responses (can be enabled using `--proxy-headers` flag for the `serve` command or environment variable `PROXY_HTTP_HEADERS`, headers list should be comma-separated) [#67]
- Template `lost-in-space` [#68]
### Fixed
- Template `l7-light` uses the dark colors in the browsers with the preferred dark theme
[#67]:https://github.com/tarampampam/error-pages/pull/67
[#68]:https://github.com/tarampampam/error-pages/pull/68
## v2.6.0
### Added
- Possibility to change the template to the random once a day using "special" template name `random-daily` (or hourly, using `random-hourly`) [#48]
[#48]:https://github.com/tarampampam/error-pages/issues/48
## v2.5.0
### Changed

View File

@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1.2
# Image page: <https://hub.docker.com/_/golang>
FROM golang:1.17.6-alpine as builder
FROM golang:1.18.0-alpine as builder
# can be passed with any prefix (like `v1.2.3@GITHASH`), e.g.: `docker build --build-arg "APP_VERSION=v1.2.3@GITHASH" .`
ARG APP_VERSION="undefined@docker"
@ -60,7 +60,7 @@ LABEL \
COPY --from=builder /tmp/rootfs /
# Use an unprivileged user
USER appuser:appuser
USER 10001:10001
WORKDIR /opt
@ -68,7 +68,8 @@ ENV LISTEN_PORT="8080" \
TEMPLATE_NAME="ghost" \
DEFAULT_ERROR_PAGE="404" \
DEFAULT_HTTP_CODE="404" \
SHOW_DETAILS="false"
SHOW_DETAILS="false" \
DISABLE_L10N="false"
# Docs: <https://docs.docker.com/engine/reference/builder/#healthcheck>
HEALTHCHECK --interval=7s --timeout=2s CMD ["/bin/error-pages", "healthcheck", "--log-json"]

View File

@ -1,36 +1,40 @@
<p align="center">
<img src="https://hsto.org/webt/rm/9y/ww/rm9ywwx3gjv9agwkcmllhsuyo7k.png" width="94" alt="" />
<a href="https://github.com/tarampampam/error-pages#readme"><img src="https://socialify.git.ci/tarampampam/error-pages/image?description=1&font=Raleway&forks=1&issues=1&logo=https%3A%2F%2Fhsto.org%2Fwebt%2Frm%2F9y%2Fww%2Frm9ywwx3gjv9agwkcmllhsuyo7k.png&owner=1&pulls=1&pattern=Solid&stargazers=1&theme=Dark" alt="banner" width="100%" /></a>
</p>
# HTTP's error pages
<p align="center">
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/tarampampam/error-pages?longCache=true&label=&logo=go&logoColor=white&style=flat-square" alt="" /></a>
<a href="https://codecov.io/gh/tarampampam/error-pages"><img src="https://img.shields.io/codecov/c/github/tarampampam/error-pages/master.svg?maxAge=30&label=&logo=codecov&logoColor=white&style=flat-square" alt="" /></a>
<a href="https://github.com/tarampampam/error-pages/actions"><img src="https://img.shields.io/github/workflow/status/tarampampam/error-pages/tests?maxAge=30&label=tests&logo=github&style=flat-square" alt="" /></a>
<a href="https://github.com/tarampampam/error-pages/actions"><img src="https://img.shields.io/github/workflow/status/tarampampam/error-pages/release?maxAge=30&label=release&logo=github&style=flat-square" alt="" /></a>
<a href="https://hub.docker.com/r/tarampampam/error-pages"><img src="https://img.shields.io/docker/pulls/tarampampam/error-pages.svg?maxAge=30&label=pulls&logo=docker&logoColor=white&style=flat-square" alt="" /></a>
<a href="https://hub.docker.com/r/tarampampam/error-pages"><img src="https://img.shields.io/docker/image-size/tarampampam/error-pages/latest?maxAge=30&label=size&logo=docker&logoColor=white&style=flat-square" alt="" /></a>
<a href="https://github.com/tarampampam/error-pages/blob/master/LICENSE"><img src="https://img.shields.io/github/license/tarampampam/error-pages.svg?maxAge=30&style=flat-square" alt="" /></a>
</p>
[![Release version][badge-release]][releases]
![Project language][badge-lang]
[![Build Status][badge-ci-build]][actions-page]
[![Release Status][badge-ci-release]][actions-page]
[![Coverage][badge-coverage]][coverage]
[![Image size][badge-image-size]][docker-hub]
[![License][badge-license]][license]
<p align="center"><sup>22 feb. 2022 - ⚡ Our Docker image was downloaded <strong>one MILLION times</strong> from the docker hub! ⚡</sup></p>
One day you may want to replace the standard error pages of your HTTP server with something more original and pretty. That's what this repository was created for :) It contains:
- Simple error pages generator, written on Go
- Simple error pages generator, written in Go
- Single-page error page templates with different designs (located in the [templates](https://github.com/tarampampam/error-pages/tree/master/templates) directory)
- Fast and lightweight HTTP server
- Already generated error pages (sources can be [found here][preview-sources], the **demonstration** is always accessible [here][preview-demo])
## 🔥 Features list
- HTTP server written on Go, with the extremely fast [FastHTTP][fasthttp] under the hood
- Respects the `Content-Type` HTTP header (and `X-Format`) value and responds with the corresponding format (supported formats is `json` and `xml`)
- HTTP server written in Go, with the extremely fast [FastHTTP][fasthttp] under the hood
- Respects the `Content-Type` HTTP header (and `X-Format`) value and responds with the corresponding format (supported formats are `json` and `xml`)
- Writes logs in `json` format
- Contains healthcheck endpoint (`/healthz`)
- Contains metrics endpoint (`/metrics`) in Prometheus format
- Lightweight docker image _(~4.3Mb compressed size)_, distroless and uses the unleveled user by default
- Lightweight docker image _(~4.6Mb compressed size)_, distroless and uses the unleveled user by default
- [Go-template](https://pkg.go.dev/text/template) tags are allowed in the templates
- Ready for integration with [Traefik][traefik] ([error pages customization](https://doc.traefik.io/traefik/middlewares/http/errorpages/)) and [Ingress-nginx][ingress-nginx]
- Error pages can be [embedded into your own `nginx`][wiki-usage-with-nginx] docker image
- Fully configurable (take a look at the [configuration file](https://github.com/tarampampam/error-pages/blob/master/error-pages.yml) and [project Wiki][wiki])
- Distributed using docker image and compiled binary files
- Localized (🇺🇸, 🇫🇷, 🇺🇦, 🇷🇺) HTML error pages (translation process [described here](https://github.com/tarampampam/error-pages/tree/master/l10n) - other translations are welcome!)
## 🧩 Install
@ -45,6 +49,11 @@ Download the latest binary file for your os/arch from the [releases page][releas
> Using the `latest` tag for the docker image is highly discouraged because of possible backward-incompatible changes during **major** upgrades. Please, use tags in `X.Y.Z` format
💣 **Or** you can download **already rendered** error pages pack as a [zip][pages-pack-zip] or [tar.gz][pages-pack-tar-gz] archive.
[pages-pack-zip]:https://github.com/tarampampam/error-pages/zipball/gh-pages/
[pages-pack-tar-gz]:https://github.com/tarampampam/error-pages/tarball/gh-pages/
## 🛠 Usage
Please, take a look at [our Wiki][wiki] for the common usage stories:
@ -112,12 +121,16 @@ Transfer/sec: 140.23MB
| `noise` | [![noise][noise-screen]][noise-link] |
| `hacker-terminal` | [![hacker-terminal][hacker-terminal-screen]][hacker-terminal-link] |
| `cats` | [![cats][cats-screen]][cats-link] |
| `lost-in-space` | [![lost-in-space][lost-in-space-screen]][lost-in-space-link] |
| `app-down` | [![app-down][app-down-screen]][app-down-link] |
| `connection` | [![connection][connection-screen]][connection-link] |
| `matrix` | [![matrix][matrix-screen]][matrix-link] |
> Note: `noise` template highly uses the CPU, be careful
[ghost-screen]:https://hsto.org/webt/oj/cl/4k/ojcl4ko_cvusy5xuki6efffzsyo.gif
[ghost-link]:https://tarampampam.github.io/error-pages/ghost/404.html
[l7-light-screen]:https://hsto.org/webt/xc/iq/vt/xciqvty-aoj-rchfarsjhutpjny.png
[l7-light-screen]:https://hsto.org/webt/hx/ca/mm/hxcammfm7qjmogtvsjxcidgf7c8.png
[l7-light-link]:https://tarampampam.github.io/error-pages/l7-light/404.html
[l7-dark-screen]:https://hsto.org/webt/s1/ih/yr/s1ihyrqs_y-sgraoimfhk6ypney.png
[l7-dark-link]:https://tarampampam.github.io/error-pages/l7-dark/404.html
@ -129,6 +142,14 @@ Transfer/sec: 140.23MB
[hacker-terminal-link]:https://tarampampam.github.io/error-pages/hacker-terminal/404.html
[cats-screen]:https://hsto.org/webt/_g/y-/ke/_gy-keqinz-3867jbw36v37-iwe.jpeg
[cats-link]:https://tarampampam.github.io/error-pages/cats/404.html
[lost-in-space-screen]:https://hsto.org/webt/lf/ln/x8/lflnx8fuy4rofxju34ttskijdsu.gif
[lost-in-space-link]:https://tarampampam.github.io/error-pages/lost-in-space/404.html
[app-down-screen]:https://habrastorage.org/webt/j2/la/fj/j2lafjvu_xjflzrvhiixobxy_ca.png
[app-down-link]:https://tarampampam.github.io/error-pages/app-down/404.html
[connection-screen]:https://hsto.org/webt/x4/ah/jb/x4ahjboo4-arm3bxpaash_sflmw.png
[connection-link]:https://tarampampam.github.io/error-pages/connection/404.html
[matrix-screen]:https://hsto.org/webt/ng/tf/oi/ngtfoiolvmq6hf15kimcxmhprhk.gif
[matrix-link]:https://tarampampam.github.io/error-pages/matrix/404.html
## 🦾 Contributors
@ -156,20 +177,12 @@ If you find any bugs in the project, please [create an issue][new-issue] in the
This is open-sourced software licensed under the [MIT License][license].
[badge-ci-build]:https://img.shields.io/github/workflow/status/tarampampam/error-pages/tests?maxAge=30&label=tests&logo=github
[badge-ci-release]:https://img.shields.io/github/workflow/status/tarampampam/error-pages/release?maxAge=30&label=release&logo=github
[badge-coverage]:https://img.shields.io/codecov/c/github/tarampampam/error-pages/master.svg?maxAge=30
[badge-release]:https://img.shields.io/github/release/tarampampam/error-pages.svg?maxAge=30
[badge-image-size]:https://img.shields.io/docker/image-size/tarampampam/error-pages/latest?maxAge=30
[badge-lang]:https://img.shields.io/github/go-mod/go-version/tarampampam/error-pages?longCache=true
[badge-license]:https://img.shields.io/github/license/tarampampam/error-pages.svg?longCache=true
[badge-release-date]:https://img.shields.io/github/release-date/tarampampam/error-pages.svg?maxAge=180
[badge-commits]:https://img.shields.io/github/commits-since/tarampampam/error-pages/latest.svg?maxAge=45
[badge-issues]:https://img.shields.io/github/issues/tarampampam/error-pages.svg?maxAge=45
[badge-prs]:https://img.shields.io/github/issues-pr/tarampampam/error-pages.svg?maxAge=45
[coverage]:https://codecov.io/gh/tarampampam/error-pages
[actions-page]:https://github.com/tarampampam/error-pages/actions
[docker-hub]:https://hub.docker.com/r/tarampampam/error-pages
[docker-hub-tags]:https://hub.docker.com/r/tarampampam/error-pages/tags
[license]:https://github.com/tarampampam/error-pages/blob/master/LICENSE

View File

@ -8,7 +8,7 @@ volumes:
services:
app: &app-service
image: golang:1.17.6-buster # Image page: <https://hub.docker.com/_/golang>
image: golang:1.18.0-buster # Image page: <https://hub.docker.com/_/golang>
working_dir: /src
environment:
HOME: /tmp
@ -31,6 +31,7 @@ services:
- --verbose
- --port=8080
- --show-details
- --proxy-headers=X-Foo,Bar,Baz_blah
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://127.0.0.1:8080/healthz']
interval: 5s

View File

@ -11,6 +11,10 @@ templates:
- path: ./templates/noise.html
- path: ./templates/hacker-terminal.html
- path: ./templates/cats.html
- path: ./templates/lost-in-space.html
- path: ./templates/app-down.html
- path: ./templates/connection.html
- path: ./templates/matrix.html
formats:
json:

20
go.mod
View File

@ -1,20 +1,20 @@
module github.com/tarampampam/error-pages
go 1.17
go 1.18
require (
github.com/a8m/envsubst v1.3.0
github.com/fasthttp/router v1.4.5
github.com/fasthttp/router v1.4.7
github.com/fatih/color v1.13.0
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.0
github.com/prometheus/client_golang v1.12.1
github.com/prometheus/client_model v0.2.0
github.com/spf13/cobra v1.3.0
github.com/spf13/cobra v1.4.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
github.com/valyala/fasthttp v1.33.0
go.uber.org/zap v1.20.0
github.com/stretchr/testify v1.7.1
github.com/valyala/fasthttp v1.34.0
go.uber.org/zap v1.21.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
)
@ -25,17 +25,17 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/klauspost/compress v1.14.1 // indirect
github.com/klauspost/compress v1.15.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899 // indirect
github.com/savsgio/gotils v0.0.0-20220323135742-7576ce6963fd // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)

353
go.sum
View File

@ -13,20 +13,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
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 v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
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,7 +21,6 @@ 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.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
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=
@ -48,8 +33,6 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg=
github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -57,47 +40,23 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
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/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
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/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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
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/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/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
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/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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=
@ -105,22 +64,11 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
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/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
github.com/fasthttp/router v1.4.5 h1:YZonsKCssEwEi3veDMhL6okIx550qegAiuXAK8NnM3Y=
github.com/fasthttp/router v1.4.5/go.mod h1:UYExWhCy7pUmavRZ0XfjEgHwzxyKwyS8uzXhaTRDG9Y=
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/fasthttp/router v1.4.7 h1:G0kCNSx859t9U9akXANfSnYDmXngETipVPZfGGnGO8g=
github.com/fasthttp/router v1.4.7/go.mod h1:auS9NLoeFXaVcw1lHqe+LDLbb26QidGKtAQDZJ6jAMI=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
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=
@ -131,14 +79,11 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
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=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@ -146,8 +91,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.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=
@ -163,10 +106,8 @@ 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/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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -176,17 +117,12 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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=
@ -194,59 +130,17 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
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-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-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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
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/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.11.0/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/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1/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-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
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/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/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/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
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/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
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.9/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=
@ -256,47 +150,25 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d h1:cVtBfNW5XTHiKQe7jDaDBSh/EVM4XLPutLAGboIXuM0=
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.14.1 h1:hLQYb23E8/fO+1u53d02A97a8UnsddcvYzq4ERRU4ds=
github.com/klauspost/compress v1.14.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U=
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
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.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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
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.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.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-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/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/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.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
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.3/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=
@ -304,118 +176,82 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
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 v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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/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.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.0 h1:C+UIj/QWtmqY13Arb8kwMt5j34/0Z2iKamrJ+ryC0Gg=
github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
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=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
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/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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899 h1:Orn7s+r1raRTBKLSc9DmbktTT04sL+vkzsbRD2Q8rOI=
github.com/savsgio/gotils v0.0.0-20211223103454-d0aaa54c5899/go.mod h1:oejLrk1Y/5zOF+c/aHtXqn3TFlzzbAgPWg8zBiAHDas=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/savsgio/gotils v0.0.0-20220323135742-7576ce6963fd h1:3URMJjR2af28gZjgZf5zJreZfq8EqXnRMj5fV2XdwqI=
github.com/savsgio/gotils v0.0.0-20220323135742-7576ce6963fd/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
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/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
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/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.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
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/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/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.32.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
github.com/valyala/fasthttp v1.33.0 h1:mHBKd98J5NcXuBddgjvim1i3kWzlng1SzLhrnBOU9g8=
github.com/valyala/fasthttp v1.33.0/go.mod h1:KJRK/MXx0J+yd0c5hlR+s1tIHD72sniU8ZJjl97LIw4=
github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4=
github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
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=
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
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.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
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/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
go.uber.org/zap v1.20.0 h1:N4oPlghZwYG55MlU6LXk/Zp00FVNE9X9wrYO8CEs4lc=
go.uber.org/zap v1.20.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
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-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-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
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=
@ -438,8 +274,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=
@ -448,13 +282,9 @@ 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.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
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-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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -467,7 +297,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-20190923162816-aa69164e4478/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=
@ -482,38 +311,16 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
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-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220111093109-d55c255bac03/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
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-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
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=
@ -522,16 +329,12 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20181026203630-95b1ffbd15a5/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-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=
@ -540,18 +343,13 @@ 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-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-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-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=
@ -565,47 +363,26 @@ 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-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-20210303074136-134d130e1a04/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-20210816183151-1e6c022a8912/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-20210908233432-aa78b53d3365/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-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/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/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -624,7 +401,6 @@ 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-20190911174233-4f2ddba30aff/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-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@ -649,21 +425,9 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
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-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-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/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-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/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/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=
@ -686,29 +450,12 @@ 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.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
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.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/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/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=
@ -732,46 +479,12 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/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-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/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
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=
@ -784,22 +497,6 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
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 v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
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=
@ -820,10 +517,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.66.2/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.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -15,6 +15,7 @@ import (
func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
var (
generateIndex bool
disableL10n bool
cfg *config.Config
)
@ -39,7 +40,7 @@ func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
return errors.New("wrong arguments count")
}
return run(log, cfg, args[0], generateIndex)
return run(log, cfg, args[0], generateIndex, disableL10n)
},
}
@ -50,6 +51,13 @@ func NewCommand(log *zap.Logger, configFile *string) *cobra.Command {
"generate index page",
)
cmd.Flags().BoolVarP(
&disableL10n,
"disable-l10n", "",
false,
"disable error pages localization",
)
return cmd
}
@ -60,7 +68,7 @@ const (
outDirPerm = os.FileMode(0775)
)
func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateIndex bool) error { //nolint:funlen
func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateIndex, disableL10n bool) error { //nolint:funlen,lll
if len(cfg.Templates) == 0 {
return errors.New("no loaded templates")
}
@ -92,6 +100,7 @@ func run(log *zap.Logger, cfg *config.Config, outDirectoryPath string, generateI
Message: page.Message(),
Description: page.Description(),
ShowRequestDetails: false,
L10nDisabled: disableL10n,
})
if renderingErr != nil {
return renderingErr

View File

@ -1,3 +1,4 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
@ -6,6 +7,11 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css"
integrity="sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
@media (prefers-color-scheme:dark){
:root {--bs-light:#212529;--bs-light-rgb:33,37,41;--bs-body-color:#eee}a{color:#91b4e8}a:hover{color:#a2bfec}
}
</style>
</head>
<body class="bg-light">
<div class="container">

View File

@ -30,7 +30,7 @@ func NewCommand(ctx context.Context, log *zap.Logger, configFile *string) *cobra
return errors.New("path to the config file is required for this command")
}
if err = f.overrideUsingEnv(cmd.Flags()); err != nil {
if err = f.OverrideUsingEnv(cmd.Flags()); err != nil {
return err
}
@ -38,18 +38,18 @@ func NewCommand(ctx context.Context, log *zap.Logger, configFile *string) *cobra
return err
}
return f.validate()
return f.Validate()
},
RunE: func(*cobra.Command, []string) error { return run(ctx, log, f, cfg) },
RunE: func(*cobra.Command, []string) error { return run(ctx, log, cfg, f) },
}
f.init(cmd.Flags())
f.Init(cmd.Flags())
return cmd
}
// run current command.
func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config) error { //nolint:funlen
func run(parentCtx context.Context, log *zap.Logger, cfg *config.Config, f flags) error { //nolint:funlen
var (
ctx, cancel = context.WithCancel(parentCtx) // serve context creation
oss = breaker.NewOSSignals(ctx) // OS signals listener
@ -69,10 +69,12 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
var (
templateNames = cfg.TemplateNames()
picker *pick.StringsSlice
picker interface{ Pick() string }
opt = f.ToOptions()
)
switch f.template.name {
switch opt.Template.Name {
case useRandomTemplate:
log.Info("A random template will be used")
@ -83,17 +85,27 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
picker = pick.NewStringsSlice(templateNames, pick.RandomEveryTime)
case useRandomTemplateDaily:
log.Info("A random template will be used and changed once a day")
picker = pick.NewStringsSliceWithInterval(templateNames, pick.RandomEveryTime, time.Hour*24) //nolint:gomnd
case useRandomTemplateHourly:
log.Info("A random template will be used and changed hourly")
picker = pick.NewStringsSliceWithInterval(templateNames, pick.RandomEveryTime, time.Hour)
case "":
log.Info("The first template (ordered by name) will be used")
picker = pick.NewStringsSlice(templateNames, pick.First)
default:
if t, found := cfg.Template(f.template.name); found {
if t, found := cfg.Template(opt.Template.Name); found {
log.Info("We will use the requested template", zap.String("name", t.Name()))
picker = pick.NewStringsSlice([]string{t.Name()}, pick.First)
} else {
return errors.New("requested nonexistent template: " + f.template.name)
return errors.New("requested nonexistent template: " + opt.Template.Name)
}
}
@ -101,7 +113,7 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
server := appHttp.NewServer(log)
// register server routes, middlewares, etc.
if err := server.Register(cfg, picker, f.defaultErrorPage, f.defaultHTTPCode, f.showDetails); err != nil {
if err := server.Register(cfg, picker, opt); err != nil {
return err
}
@ -112,14 +124,16 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
defer close(errCh)
log.Info("Server starting",
zap.String("addr", f.listen.ip),
zap.Uint16("port", f.listen.port),
zap.String("default error page", f.defaultErrorPage),
zap.Uint16("default HTTP response code", f.defaultHTTPCode),
zap.Bool("show request details", f.showDetails),
zap.String("addr", f.Listen.IP),
zap.Uint16("port", f.Listen.Port),
zap.String("default error page", opt.Default.PageCode),
zap.Uint16("default HTTP response code", opt.Default.HTTPCode),
zap.Strings("proxy headers", opt.ProxyHTTPHeaders),
zap.Bool("show request details", opt.ShowDetails),
zap.Bool("localization disabled", opt.L10n.Disabled),
)
if err := server.Start(f.listen.ip, f.listen.port); err != nil {
if err := server.Start(f.Listen.IP, f.Listen.Port); err != nil {
errCh <- err
}
}(startingErrCh)
@ -132,6 +146,12 @@ func run(parentCtx context.Context, log *zap.Logger, f flags, cfg *config.Config
case <-ctx.Done(): // ..or context cancellation
log.Info("Gracefully server stopping", zap.Duration("uptime", time.Since(startedAt)))
if p, ok := picker.(interface{ Close() error }); ok {
if err := p.Close(); err != nil {
return err
}
}
// stop the server using created context above
if err := server.Stop(); err != nil {
return err

View File

@ -3,24 +3,30 @@ package serve
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"github.com/spf13/pflag"
"github.com/tarampampam/error-pages/internal/env"
"github.com/tarampampam/error-pages/internal/options"
)
type flags struct {
listen struct {
ip string
port uint16
Listen struct {
IP string
Port uint16
}
template struct {
name string
}
l10n struct {
disabled bool
}
defaultErrorPage string
defaultHTTPCode uint16
showDetails bool
proxyHTTPHeaders string // comma-separated
}
const (
@ -30,33 +36,42 @@ const (
defaultErrorPageFlagName = "default-error-page"
defaultHTTPCodeFlagName = "default-http-code"
showDetailsFlagName = "show-details"
proxyHTTPHeadersFlagName = "proxy-headers"
disableL10nFlagName = "disable-l10n"
)
const (
useRandomTemplate = "random"
useRandomTemplateOnEachRequest = "i-said-random"
useRandomTemplateDaily = "random-daily"
useRandomTemplateHourly = "random-hourly"
)
func (f *flags) init(flagSet *pflag.FlagSet) {
func (f *flags) Init(flagSet *pflag.FlagSet) {
flagSet.StringVarP(
&f.listen.ip,
&f.Listen.IP,
listenFlagName, "l",
"0.0.0.0",
fmt.Sprintf("IP address to listen on [$%s]", env.ListenAddr),
fmt.Sprintf("IP address to Listen on [$%s]", env.ListenAddr),
)
flagSet.Uint16VarP(
&f.listen.port,
&f.Listen.Port,
portFlagName, "p",
8080, //nolint:gomnd // must be same as default healthcheck `--port` flag value
fmt.Sprintf("TCP port number [$%s]", env.ListenPort),
fmt.Sprintf("TCP prt number [$%s]", env.ListenPort),
)
flagSet.StringVarP(
&f.template.name,
templateNameFlagName, "t",
"",
fmt.Sprintf(
"template name (set \"%s\" to use a randomized or \"%s\" to use a randomized template on each request) [$%s]", //nolint:lll
useRandomTemplate, useRandomTemplateOnEachRequest, env.TemplateName,
"template name (set \"%s\" to use a randomized or \"%s\" to use a randomized template on each request "+
"or \"%s/%s\" daily/hourly randomized) [$%s]",
useRandomTemplate,
useRandomTemplateOnEachRequest,
useRandomTemplateDaily,
useRandomTemplateHourly,
env.TemplateName,
),
)
flagSet.StringVarP(
@ -77,22 +92,34 @@ func (f *flags) init(flagSet *pflag.FlagSet) {
false,
fmt.Sprintf("show request details in response [$%s]", env.ShowDetails),
)
flagSet.StringVarP(
&f.proxyHTTPHeaders,
proxyHTTPHeadersFlagName, "",
"",
fmt.Sprintf("proxy HTTP request headers list (comma-separated) [$%s]", env.ProxyHTTPHeaders),
)
flagSet.BoolVarP(
&f.l10n.disabled,
disableL10nFlagName, "",
false,
fmt.Sprintf("disable error pages localization [$%s]", env.DisableL10n),
)
}
func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nolint:gocognit,gocyclo
func (f *flags) OverrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nolint:gocognit,gocyclo
flagSet.VisitAll(func(flag *pflag.Flag) {
// flag was NOT defined using CLI (flags should have maximal priority)
if !flag.Changed { //nolint:nestif
switch flag.Name {
case listenFlagName:
if envVar, exists := env.ListenAddr.Lookup(); exists {
f.listen.ip = strings.TrimSpace(envVar)
f.Listen.IP = strings.TrimSpace(envVar)
}
case portFlagName:
if envVar, exists := env.ListenPort.Lookup(); exists {
if p, err := strconv.ParseUint(envVar, 10, 16); err == nil { //nolint:gomnd
f.listen.port = uint16(p)
f.Listen.Port = uint16(p)
} else {
lastErr = fmt.Errorf("wrong TCP port environment variable [%s] value", envVar)
}
@ -123,6 +150,18 @@ func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nol
f.showDetails = b
}
}
case proxyHTTPHeadersFlagName:
if envVar, exists := env.ProxyHTTPHeaders.Lookup(); exists {
f.proxyHTTPHeaders = strings.TrimSpace(envVar)
}
case disableL10nFlagName:
if envVar, exists := env.DisableL10n.Lookup(); exists {
if b, err := strconv.ParseBool(envVar); err == nil {
f.l10n.disabled = b
}
}
}
}
})
@ -130,14 +169,67 @@ func (f *flags) overrideUsingEnv(flagSet *pflag.FlagSet) (lastErr error) { //nol
return lastErr
}
func (f *flags) validate() error {
if net.ParseIP(f.listen.ip) == nil {
return fmt.Errorf("wrong IP address [%s] for listening", f.listen.ip)
func (f *flags) Validate() error {
if net.ParseIP(f.Listen.IP) == nil {
return fmt.Errorf("wrong IP address [%s] for listening", f.Listen.IP)
}
if f.defaultHTTPCode > 599 { //nolint:gomnd
return fmt.Errorf("wrong default HTTP response code [%d]", f.defaultHTTPCode)
}
if strings.ContainsRune(f.proxyHTTPHeaders, ' ') {
return fmt.Errorf("whitespaces in the HTTP headers for proxying [%s] are not allowed", f.proxyHTTPHeaders)
}
return nil
}
// headersToProxy converts a comma-separated string with headers list into strings slice (with a sorting and without
// duplicates).
func (f *flags) headersToProxy() []string {
var raw = strings.Split(f.proxyHTTPHeaders, ",")
if len(raw) == 0 {
return []string{}
} else if len(raw) == 1 {
if h := strings.TrimSpace(raw[0]); h != "" {
return []string{h}
} else {
return []string{}
}
}
var m = make(map[string]struct{}, len(raw))
// make unique and ignore empty strings
for _, h := range raw {
if h = strings.TrimSpace(h); h != "" {
if _, ok := m[h]; !ok {
m[h] = struct{}{}
}
}
}
// convert map into slice
var headers = make([]string, 0, len(m))
for h := range m {
headers = append(headers, h)
}
// make sort
sort.Strings(headers)
return headers
}
func (f *flags) ToOptions() (o options.ErrorPage) {
o.Default.PageCode = f.defaultErrorPage
o.Default.HTTPCode = f.defaultHTTPCode
o.L10n.Disabled = f.l10n.disabled
o.Template.Name = f.template.name
o.ShowDetails = f.showDetails
o.ProxyHTTPHeaders = f.headersToProxy()
return o
}

2
internal/env/env.go vendored
View File

@ -13,6 +13,8 @@ const (
DefaultErrorPage envVariable = "DEFAULT_ERROR_PAGE" // default error page (code)
DefaultHTTPCode envVariable = "DEFAULT_HTTP_CODE" // default HTTP response code
ShowDetails envVariable = "SHOW_DETAILS" // show request details in response
ProxyHTTPHeaders envVariable = "PROXY_HTTP_HEADERS" // proxy HTTP request headers list (request -> response)
DisableL10n envVariable = "DISABLE_L10N" // disable pages localization
)
// String returns environment variable name in the string representation.

View File

@ -15,6 +15,8 @@ func TestConstants(t *testing.T) {
assert.Equal(t, "DEFAULT_ERROR_PAGE", string(DefaultErrorPage))
assert.Equal(t, "DEFAULT_HTTP_CODE", string(DefaultHTTPCode))
assert.Equal(t, "SHOW_DETAILS", string(ShowDetails))
assert.Equal(t, "PROXY_HTTP_HEADERS", string(ProxyHTTPHeaders))
assert.Equal(t, "DISABLE_L10N", string(DisableL10n))
}
func TestEnvVariable_Lookup(t *testing.T) {
@ -28,6 +30,8 @@ func TestEnvVariable_Lookup(t *testing.T) {
{giveEnv: DefaultErrorPage},
{giveEnv: DefaultHTTPCode},
{giveEnv: ShowDetails},
{giveEnv: ProxyHTTPHeaders},
{giveEnv: DisableL10n},
}
for _, tt := range cases {

View File

@ -9,17 +9,32 @@ import (
)
func LogRequest(h fasthttp.RequestHandler, log *zap.Logger) fasthttp.RequestHandler {
const headersSeparator = ": "
return func(ctx *fasthttp.RequestCtx) {
var (
startedAt = time.Now()
ua = string(ctx.UserAgent())
)
var ua = string(ctx.UserAgent())
if strings.Contains(strings.ToLower(ua), "healthcheck") { // skip healthcheck requests logging
h(ctx)
return
}
var reqHeaders = make([]string, 0, 24) //nolint:gomnd
ctx.Request.Header.VisitAll(func(key, value []byte) {
reqHeaders = append(reqHeaders, string(key)+headersSeparator+string(value))
})
var startedAt = time.Now()
h(ctx)
if strings.Contains(strings.ToLower(ua), "healthcheck") { // skip healthcheck requests logging
return
}
var respHeaders = make([]string, 0, 16) //nolint:gomnd
ctx.Response.Header.VisitAll(func(key, value []byte) {
respHeaders = append(respHeaders, string(key)+headersSeparator+string(value))
})
log.Info("HTTP request processed",
zap.String("useragent", ua),
@ -30,6 +45,8 @@ func LogRequest(h fasthttp.RequestHandler, log *zap.Logger) fasthttp.RequestHand
zap.String("content_type", string(ctx.Response.Header.ContentType())),
zap.Bool("connection_close", ctx.Response.ConnectionClose()),
zap.Duration("duration", time.Since(startedAt)),
zap.Strings("request_headers", reqHeaders),
zap.Strings("response_headers", respHeaders),
)
}
}

View File

@ -4,6 +4,7 @@ import (
"strconv"
"github.com/tarampampam/error-pages/internal/config"
"github.com/tarampampam/error-pages/internal/options"
"github.com/tarampampam/error-pages/internal/tpl"
"github.com/valyala/fasthttp"
)
@ -17,14 +18,14 @@ type renderer interface {
Render(content []byte, props tpl.Properties) ([]byte, error)
}
func RespondWithErrorPage( //nolint:funlen
func RespondWithErrorPage( //nolint:funlen,gocyclo
ctx *fasthttp.RequestCtx,
cfg *config.Config,
p templatePicker,
rdr renderer,
pageCode string,
httpCode int,
showRequestDetails bool,
opt options.ErrorPage,
) {
ctx.Response.Header.Set("X-Robots-Tag", "noindex") // block Search indexing
@ -32,10 +33,14 @@ func RespondWithErrorPage( //nolint:funlen
clientWant = ClientWantFormat(ctx)
json, canJSON = cfg.JSONFormat()
xml, canXML = cfg.XMLFormat()
props = tpl.Properties{Code: pageCode, ShowRequestDetails: showRequestDetails}
props = tpl.Properties{
Code: pageCode,
ShowRequestDetails: opt.ShowDetails,
L10nDisabled: opt.L10n.Disabled,
}
)
if showRequestDetails {
if opt.ShowDetails {
props.OriginalURI = string(ctx.Request.Header.Peek(OriginalURI))
props.Namespace = string(ctx.Request.Header.Peek(Namespace))
props.IngressName = string(ctx.Request.Header.Peek(IngressName))
@ -64,6 +69,13 @@ func RespondWithErrorPage( //nolint:funlen
return
}
// proxy required HTTP headers from the request to the response
for _, headerToProxy := range opt.ProxyHTTPHeaders {
if reqHeader := ctx.Request.Header.Peek(headerToProxy); len(reqHeader) > 0 {
ctx.Response.Header.SetBytesV(headerToProxy, reqHeader)
}
}
switch {
case clientWant == JSONContentType && canJSON: // JSON
{

View File

@ -3,6 +3,7 @@ package errorpage
import (
"github.com/tarampampam/error-pages/internal/config"
"github.com/tarampampam/error-pages/internal/http/core"
"github.com/tarampampam/error-pages/internal/options"
"github.com/tarampampam/error-pages/internal/tpl"
"github.com/valyala/fasthttp"
)
@ -19,12 +20,12 @@ type (
)
// NewHandler creates handler for error pages serving.
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, showRequestDetails bool) fasthttp.RequestHandler {
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, opt options.ErrorPage) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
core.SetClientFormat(ctx, core.PlainTextContentType) // default content type
if code, ok := ctx.UserValue("code").(string); ok {
core.RespondWithErrorPage(ctx, cfg, p, rdr, code, fasthttp.StatusOK, showRequestDetails)
core.RespondWithErrorPage(ctx, cfg, p, rdr, code, fasthttp.StatusOK, opt)
} else { // will never occur
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
_, _ = ctx.WriteString("cannot extract requested code from the request")

View File

@ -5,6 +5,7 @@ import (
"github.com/tarampampam/error-pages/internal/config"
"github.com/tarampampam/error-pages/internal/http/core"
"github.com/tarampampam/error-pages/internal/options"
"github.com/tarampampam/error-pages/internal/tpl"
"github.com/valyala/fasthttp"
)
@ -21,22 +22,15 @@ type (
)
// NewHandler creates handler for the index page serving.
func NewHandler(
cfg *config.Config,
p templatePicker,
rdr renderer,
defaultPageCode string,
defaultHTTPCode uint16,
showRequestDetails bool,
) fasthttp.RequestHandler {
func NewHandler(cfg *config.Config, p templatePicker, rdr renderer, opt options.ErrorPage) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
pageCode, httpCode := defaultPageCode, int(defaultHTTPCode)
pageCode, httpCode := opt.Default.PageCode, int(opt.Default.HTTPCode)
if returnCode, ok := extractCodeToReturn(ctx); ok {
pageCode, httpCode = strconv.Itoa(returnCode), returnCode
}
core.RespondWithErrorPage(ctx, cfg, p, rdr, pageCode, httpCode, showRequestDetails)
core.RespondWithErrorPage(ctx, cfg, p, rdr, pageCode, httpCode, opt)
}
}

View File

@ -15,6 +15,7 @@ import (
notfoundHandler "github.com/tarampampam/error-pages/internal/http/handlers/notfound"
versionHandler "github.com/tarampampam/error-pages/internal/http/handlers/version"
"github.com/tarampampam/error-pages/internal/metrics"
"github.com/tarampampam/error-pages/internal/options"
"github.com/tarampampam/error-pages/internal/tpl"
"github.com/tarampampam/error-pages/internal/version"
"github.com/valyala/fasthttp"
@ -66,13 +67,7 @@ type templatePicker interface {
// Register server routes, middlewares, etc.
// Router docs: <https://github.com/fasthttp/router>
func (s *Server) Register(
cfg *config.Config,
templatePicker templatePicker,
defaultPageCode string,
defaultHTTPCode uint16,
showDetails bool,
) error {
func (s *Server) Register(cfg *config.Config, templatePicker templatePicker, opt options.ErrorPage) error {
reg, m := metrics.NewRegistry(), metrics.NewMetrics()
if err := m.Register(reg); err != nil {
@ -81,8 +76,9 @@ func (s *Server) Register(
s.fast.Handler = common.DurationMetrics(common.LogRequest(s.router.Handler, s.log), &m)
s.router.GET("/", indexHandler.NewHandler(cfg, templatePicker, s.rdr, defaultPageCode, defaultHTTPCode, showDetails)) //nolint:lll
s.router.GET("/{code}.html", errorpageHandler.NewHandler(cfg, templatePicker, s.rdr, showDetails))
s.router.GET("/", indexHandler.NewHandler(cfg, templatePicker, s.rdr, opt))
s.router.GET("/{code}.html", errorpageHandler.NewHandler(cfg, templatePicker, s.rdr, opt))
s.router.GET("/version", versionHandler.NewHandler(version.Version()))
liveHandler := healthzHandler.NewHandler(checkers.NewLiveChecker())

View File

@ -0,0 +1,16 @@
package options
type ErrorPage struct {
Default struct {
PageCode string // default error page code
HTTPCode uint16 // default HTTP response code
}
L10n struct {
Disabled bool // disable error pages localization
}
Template struct {
Name string // template name
}
ShowDetails bool // show request details in response
ProxyHTTPHeaders []string // proxy HTTP request headers list
}

View File

@ -51,33 +51,38 @@ func (p *picker) NextIndex() uint32 {
case RandomOnce:
if p.lastIdx == unsetIdx {
p.mu.Lock()
defer p.mu.Unlock()
p.lastIdx = uint32(p.rand.Intn(int(p.maxIdx)))
return p.randomizeNext()
}
return p.lastIdx
case RandomEveryTime:
var idx = uint32(p.rand.Intn(int(p.maxIdx + 1)))
p.mu.Lock()
defer p.mu.Unlock()
if idx == p.lastIdx {
p.lastIdx++
} else {
p.lastIdx = idx
}
if p.lastIdx > p.maxIdx { // overflow?
p.lastIdx = 0
}
return p.lastIdx
return p.randomizeNext()
default:
panic("picker.NextIndex(): unsupported mode")
}
}
func (p *picker) randomizeNext() uint32 {
var idx = uint32(p.rand.Intn(int(p.maxIdx + 1)))
p.mu.Lock()
defer p.mu.Unlock()
if idx == p.lastIdx {
p.lastIdx++
} else {
p.lastIdx = idx
}
if p.lastIdx > p.maxIdx { // overflow?
p.lastIdx = 0
}
if p.lastIdx == unsetIdx {
p.lastIdx--
}
return p.lastIdx
}

View File

@ -1,5 +1,11 @@
package pick
import (
"errors"
"sync"
"time"
)
type StringsSlice struct {
s []string
p *picker
@ -7,7 +13,13 @@ type StringsSlice struct {
// NewStringsSlice creates new StringsSlice.
func NewStringsSlice(items []string, mode pickMode) *StringsSlice {
return &StringsSlice{s: items, p: NewPicker(uint32(len(items)-1), mode)}
maxIdx := len(items) - 1
if maxIdx < 0 {
maxIdx = 0
}
return &StringsSlice{s: items, p: NewPicker(uint32(maxIdx), mode)}
}
// Pick an element from the strings slice.
@ -18,3 +30,106 @@ func (s *StringsSlice) Pick() string {
return s.s[s.p.NextIndex()]
}
type StringsSliceWithInterval struct {
s []string
p *picker
d time.Duration
idxMu sync.RWMutex
idx uint32
close chan struct{}
closedMu sync.RWMutex
closed bool
}
// NewStringsSliceWithInterval creates new StringsSliceWithInterval.
func NewStringsSliceWithInterval(items []string, mode pickMode, interval time.Duration) *StringsSliceWithInterval {
maxIdx := len(items) - 1
if maxIdx < 0 {
maxIdx = 0
}
if interval <= time.Duration(0) {
panic("NewStringsSliceWithInterval: wrong interval")
}
s := &StringsSliceWithInterval{
s: items,
p: NewPicker(uint32(maxIdx), mode),
d: interval,
close: make(chan struct{}, 1),
}
s.next()
go s.rotate()
return s
}
func (s *StringsSliceWithInterval) rotate() {
defer close(s.close)
timer := time.NewTimer(s.d)
defer timer.Stop()
for {
select {
case <-s.close:
return
case <-timer.C:
s.next()
timer.Reset(s.d)
}
}
}
func (s *StringsSliceWithInterval) next() {
idx := s.p.NextIndex()
s.idxMu.Lock()
s.idx = idx
s.idxMu.Unlock()
}
// Pick an element from the strings slice.
func (s *StringsSliceWithInterval) Pick() string {
if s.isClosed() {
panic("StringsSliceWithInterval.Pick(): closed")
}
if len(s.s) == 0 {
return ""
}
s.idxMu.RLock()
defer s.idxMu.RUnlock()
return s.s[s.idx]
}
func (s *StringsSliceWithInterval) isClosed() (closed bool) {
s.closedMu.RLock()
closed = s.closed
s.closedMu.RUnlock()
return
}
func (s *StringsSliceWithInterval) Close() error {
if s.isClosed() {
return errors.New("closed")
}
s.closedMu.Lock()
s.closed = true
s.closedMu.Unlock()
s.close <- struct{}{}
return nil
}

View File

@ -2,6 +2,7 @@ package pick_test
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/tarampampam/error-pages/internal/pick"
@ -47,3 +48,83 @@ func TestStringsSlice_Pick(t *testing.T) {
}
})
}
func TestNewStringsSliceWithInterval_Pick(t *testing.T) {
t.Run("first", func(t *testing.T) {
for i := uint8(0); i < 50; i++ {
p := pick.NewStringsSliceWithInterval([]string{}, pick.First, time.Millisecond)
assert.Equal(t, "", p.Pick())
assert.NoError(t, p.Close())
assert.Panics(t, func() { p.Pick() })
}
p := pick.NewStringsSliceWithInterval([]string{"foo", "bar", "baz"}, pick.First, time.Millisecond)
for i := uint8(0); i < 50; i++ {
assert.Equal(t, "foo", p.Pick())
<-time.After(time.Millisecond * 2)
}
assert.NoError(t, p.Close())
assert.Error(t, p.Close())
assert.Panics(t, func() { p.Pick() })
})
t.Run("random once", func(t *testing.T) {
for i := uint8(0); i < 50; i++ {
p := pick.NewStringsSliceWithInterval([]string{}, pick.RandomOnce, time.Millisecond)
assert.Equal(t, "", p.Pick())
assert.NoError(t, p.Close())
assert.Panics(t, func() { p.Pick() })
}
var (
p = pick.NewStringsSliceWithInterval([]string{"foo", "bar", "baz"}, pick.RandomOnce, time.Millisecond)
picked = p.Pick()
)
for i := uint8(0); i < 50; i++ {
assert.Equal(t, picked, p.Pick())
<-time.After(time.Millisecond * 2)
}
assert.NoError(t, p.Close())
assert.Error(t, p.Close())
assert.Panics(t, func() { p.Pick() })
})
t.Run("random every time", func(t *testing.T) {
for i := uint8(0); i < 50; i++ {
p := pick.NewStringsSliceWithInterval([]string{}, pick.RandomEveryTime, time.Millisecond)
assert.Equal(t, "", p.Pick())
assert.NoError(t, p.Close())
assert.Panics(t, func() { p.Pick() })
}
var changed int
for i := uint8(0); i < 50; i++ {
p := pick.NewStringsSliceWithInterval([]string{"foo", "bar", "baz"}, pick.RandomEveryTime, time.Millisecond) //nolint:lll
one, two := p.Pick(), p.Pick()
assert.Equal(t, one, two)
<-time.After(time.Millisecond * 2)
three, four := p.Pick(), p.Pick()
assert.Equal(t, three, four)
if one != three {
changed++
}
assert.NoError(t, p.Close())
assert.Error(t, p.Close())
assert.Panics(t, func() { p.Pick() })
}
assert.GreaterOrEqual(t, changed, 25)
})
}

View File

@ -16,6 +16,7 @@ type Properties struct { // only string properties with a "token" tag, please
RequestID string `token:"request_id"`
ForwardedFor string `token:"forwarded_for"`
Host string `token:"host"`
L10nDisabled bool
ShowRequestDetails bool
}

View File

@ -140,8 +140,10 @@ func (tr *TemplateRenderer) Render(content []byte, props Properties) ([]byte, er
}
var funcMap = template.FuncMap{
"show_details": func() bool { return props.ShowRequestDetails },
"hide_details": func() bool { return !props.ShowRequestDetails },
"show_details": func() bool { return props.ShowRequestDetails },
"hide_details": func() bool { return !props.ShowRequestDetails },
"l10n_disabled": func() bool { return props.L10nDisabled },
"l10n_enabled": func() bool { return !props.L10nDisabled },
}
// make a copy of template functions map

View File

@ -56,6 +56,17 @@ func Test_Render(t *testing.T) {
giveProps: tpl.Properties{Code: "201", Message: "lorem ipsum"},
wantContent: `{"code": "201", "message": {"here":[ " Yeah " ]}}`,
},
"fn l10n_enabled": {
giveContent: "{{ if l10n_enabled }}Y{{ else }}N{{ end }}",
giveProps: tpl.Properties{L10nDisabled: true},
wantContent: "N",
},
"fn l10n_disabled": {
giveContent: "{{ if l10n_disabled }}Y{{ else }}N{{ end }}",
giveProps: tpl.Properties{L10nDisabled: true},
wantContent: "Y",
},
} {
t.Run(name, func(t *testing.T) {
content, err := renderer.Render([]byte(tt.giveContent), tt.giveProps)

11
l10n/.eslintrc.json Normal file
View File

@ -0,0 +1,11 @@
{
"extends": [
"eslint:recommended"
],
"parserOptions": {
"ecmaVersion": 2017
},
"env": {
"browser": true
}
}

440
l10n/l10n.js Normal file
View File

@ -0,0 +1,440 @@
Object.defineProperty(window, 'l10n', {
value: new function () {
// language codes list: <https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes>
const data = { // all keys should be in english (it is default/main locale)
'Error': {
fr: 'Erreur',
ru: 'Ошибка',
uk: 'Помилка',
},
'Good luck': {
fr: 'Bonne chance',
ru: 'Удачи',
uk: 'Успіхів',
},
'UH OH': {
fr: 'Oups',
ru: 'Ох',
uk: 'Ох',
},
'Request details': {
fr: 'Détails de la requête',
ru: 'Детали запроса',
uk: 'Деталі запиту',
},
'Double-check the URL': {
fr: 'Vérifiez lURL',
ru: 'Дважды проверьте URL',
uk: 'Двічі перевіряйте URL-адресу',
},
'Alternatively, go back': {
fr: 'Essayer de revenir en arrière',
ru: 'Или можете вернуться назад',
uk: 'Або ви можете повернутися',
},
'Here\'s what might have happened': {
fr: 'Voici ce qui aurait pu se passer',
ru: 'Из-за чего это могло случиться',
uk: 'Що це може статися',
},
'You may have mistyped the URL': {
fr: 'Vous avez peut-être mal tapé lURL',
ru: 'Вы могли ошибиться в URL',
uk: 'Ви можете зробити помилку в URL-адресі',
},
'The site was moved': {
fr: 'Le site a été déplacé',
ru: 'Сайт был перемещён',
uk: 'Сайт був переміщений',
},
'It was never here': {
fr: 'Il na jamais été ici',
ru: 'Он никогда не был здесь',
uk: 'Він ніколи не був тут',
},
'Bad Request': {
fr: 'Mauvaise requête',
ru: 'Некорректный запрос',
uk: 'Неправильний запит',
},
'The server did not understand the request': {
fr: 'Le serveur ne comprend pas la requête',
ru: 'Сервер не смог обработать запрос из-за ошибки в нём',
uk: 'Сервер не міг обробити запит через помилку в ньому',
},
'Unauthorized': {
fr: 'Non autorisé',
ru: 'Запрос не авторизован',
uk: 'Несанкціонований доступ',
},
'The requested page needs a username and a password': {
fr: 'La page demandée nécessite un nom dutilisateur et un mot de passe',
ru: 'Для доступа к странице требуется логин и пароль',
uk: 'Щоб отримати доступ до сторінки, потрібний логін та пароль',
},
'Forbidden': {
fr: 'Interdit',
ru: 'Запрещено',
uk: 'Заборонено',
},
'Access is forbidden to the requested page': {
fr: 'Accès interdit à la page demandée',
ru: 'Доступ к странице запрещён',
uk: 'Доступ до сторінки заборонено',
},
'Not Found': {
fr: 'Introuvable',
ru: 'Страница не найдена',
uk: 'Сторінка не знайдена',
},
'The server can not find the requested page': {
fr: 'Le serveur ne peut trouver la page demandée',
ru: 'Сервер не смог найти запрашиваемую страницу',
uk: 'Сервер не міг знайти запитану сторінку',
},
'Method Not Allowed': {
fr: 'Méthode Non Autorisée',
ru: 'Метод не поддерживается',
uk: 'Неприпустимий метод',
},
'The method specified in the request is not allowed': {
fr: 'La méthode spécifiée dans la requête nest pas autorisée',
ru: 'Указанный в запросе метод не поддерживается',
uk: 'Метод, зазначений у запиті, не підтримується',
},
'Proxy Authentication Required': {
fr: 'Authentification proxy requise',
ru: 'Нужна аутентификация прокси',
uk: 'Потрібна ідентифікація проксі',
},
'You must authenticate with a proxy server before this request can be served': {
fr: 'Vous devez vous authentifier avec un serveur proxy avant que cette requête puisse être servie',
ru: 'Вы должны быть авторизованы на прокси сервере для обработки этого запроса',
uk: 'Ви повинні увійти до проксі-сервера для обробки цього запиту',
},
'Request Timeout': {
fr: 'Requête expiré',
ru: 'Истекло время ожидания',
uk: 'Час запиту закінчився',
},
'The request took longer than the server was prepared to wait': {
fr: 'La requête prend plus de temps que prévu',
ru: 'Отправка запроса заняла слишком много времени',
uk: 'Надсилання запиту зайняв занадто багато часу',
},
'Conflict': {
fr: 'Conflit',
ru: 'Конфликт',
uk: 'Конфлікт',
},
'The request could not be completed because of a conflict': {
fr: 'La requête na pas pu être complétée à cause dun conflit',
ru: 'Запрос не может быть обработан из-за конфликта',
uk: 'Запит не може бути оброблений через конфлікт',
},
'Gone': {
fr: 'Supprimé',
ru: 'Удалено',
uk: 'Вилучений',
},
'The requested page is no longer available': {
fr: 'La page demandée nest plus disponible',
ru: 'Запрошенная страница была удалена',
uk: 'Запитана сторінка була видалена',
},
'Length Required': {
fr: 'Longueur requise',
ru: 'Необходима длина',
uk: 'Потрібно вказати розмір',
},
'The "Content-Length" is not defined. The server will not accept the request without it': {
fr: 'Le "Content-Length" nest pas défini. Le serveur ne prendra pas en compte la requête',
ru: 'Заголовок "Content-Length" не был передан. Сервер не может обработать запрос без него',
uk: 'Заголовок "Content-Length" не був переданий. Сервер не може обробити запит без нього',
},
'Precondition Failed': {
fr: 'Échec de la condition préalable',
ru: 'Условие ложно',
uk: 'Збій під час обробки попередньої умови',
},
'The pre condition given in the request evaluated to false by the server': {
fr: 'La précondition donnée dans la requête a été évaluée comme étant fausse par le serveur',
ru: 'Ни одно из условных полей заголовка запроса не было выполнено',
uk: 'Жодна з умовних полів заголовка запиту не була виконана',
},
'Payload Too Large': {
fr: 'Charge trop volumineuse',
ru: 'Слишком большой запрос',
uk: 'Занадто великий запит',
},
'The server will not accept the request, because the request entity is too large': {
fr: 'Le serveur ne prendra pas en compte la requête, car lentité de la requête est trop volumineuse',
ru: 'Сервер не может обработать запрос, так как он слишком большой',
uk: 'Сервер не може обробити запит, оскільки він занадто великий',
},
'Requested Range Not Satisfiable': {
fr: 'Requête non satisfaisante',
ru: 'Диапазон не достижим',
uk: 'Запитуваний діапазон недосяжний',
},
'The requested byte range is not available and is out of bounds': {
fr: 'Le byte range demandé nest pas disponible et est hors des limites',
ru: 'Запрошенный диапазон данных недоступен или вне допустимых пределов',
uk: 'Описаний діапазон даних недоступний або з допустимих меж',
},
'I\'m a teapot': {
fr: 'Je suis une théière',
ru: 'Я чайник',
uk: 'Я чайник',
},
'Attempt to brew coffee with a teapot is not supported': {
fr: 'Tenter de préparer du café avec une théière nest pas pris en charge',
ru: 'Попытка заварить кофе в чайнике обречена на фиаско',
uk: 'Спроба виварити каву в чайник приречена на фіаско',
},
'Too Many Requests': {
fr: 'Trop de requêtes',
ru: 'Слишком много запросов',
uk: 'Занадто багато запитів',
},
'Too many requests in a given amount of time': {
fr: 'Trop de requêtes dans un délai donné',
ru: 'Отправлено слишком много запросов за короткое время',
uk: 'Надіслано занадто багато запитів на короткий час',
},
'Internal Server Error': {
fr: 'Erreur interne du serveur',
ru: 'Внутренняя ошибка сервера',
uk: 'Внутрішня помилка сервера',
},
'The server met an unexpected condition': {
fr: 'Le serveur a rencontré une condition inattendue',
ru: 'Произошло что-то неожиданное на сервере',
uk: 'На сервері було щось несподіване',
},
'Bad Gateway': {
fr: 'Mauvaise passerelle',
ru: 'Ошибка шлюза',
uk: 'Помилка шлюзу',
},
'The server received an invalid response from the upstream server': {
fr: 'Le serveur a reçu une réponse invalide du serveur distant',
ru: 'Сервер получил некорректный ответ от вышестоящего сервера',
uk: 'Сервер отримав неправильну відповідь з сервера Upstream',
},
'Service Unavailable': {
fr: 'Service indisponible',
ru: 'Сервис недоступен',
uk: 'Сервіс недоступний',
},
'The server is temporarily overloading or down': {
fr: 'Le serveur est temporairement en surcharge ou indisponible',
ru: 'Сервер временно не может обрабатывать запросы по техническим причинам',
uk: 'Сервер тимчасово не може обробляти запити з технічних причин',
},
'Gateway Timeout': {
fr: 'Expiration Passerelle',
ru: 'Шлюз не отвечает',
uk: 'Шлюз не відповідає',
},
'The gateway has timed out': {
fr: 'Le temps dattente de la passerelle est dépassé',
ru: 'Сервер не дождался ответа от вышестоящего сервера',
uk: 'Сервер не чекав відповіді від сервера Upstream',
},
'HTTP Version Not Supported': {
fr: 'Version HTTP non prise en charge',
ru: 'Версия HTTP не поддерживается',
uk: 'Версія НТТР не підтримується',
},
'The server does not support the "http protocol" version': {
fr: 'Le serveur ne supporte pas la version du protocole HTTP',
ru: 'Сервер не поддерживает запрошенную версию HTTP протокола',
uk: 'Сервер не підтримує запитану версію HTTP-протоколу',
},
'Host': {
fr: 'Hôte',
ru: 'Хост',
uk: 'Хост',
},
'Original URI': {
fr: 'URI dorigine',
ru: 'Исходный URI',
uk: 'Вихідний URI',
},
'Forwarded for': {
fr: 'Transmis pour',
ru: 'Перенаправлен',
uk: 'Перенаправлений',
},
'Namespace': {
fr: 'Espace de noms',
ru: 'Пространство имён',
uk: 'Простір імен',
},
'Ingress name': {
fr: 'Nom ingress',
ru: 'Имя Ingress',
uk: 'Ім\'я Ingress',
},
'Service name': {
fr: 'Nom du service',
ru: 'Имя сервиса',
uk: 'Ім\'я сервісу',
},
'Service port': {
fr: 'Port du service',
ru: 'Порт сервиса',
uk: 'Порт сервісу',
},
'Request ID': {
fr: 'Identifiant de la requête',
ru: 'ID запроса',
uk: 'ID запиту',
},
'Timestamp': {
fr: 'Horodatage',
ru: 'Временная метка',
uk: 'Тимчасова мітка',
},
'client-side error': {
fr: 'Erreur Client',
ru: 'ошибка на стороне клиента',
uk: 'помилка на стороні клієнта',
},
'server-side error': {
fr: 'Erreur Serveur',
ru: 'ошибка на стороне сервера',
uk: 'помилка на стороні сервера',
},
'Your Client': {
fr: 'Votre Client',
ru: 'Ваш Браузер',
uk: 'Ваш Браузер',
},
'Network': {
fr: 'Réseau',
ru: 'Сеть',
uk: 'Сіть',
},
'Web Server': {
fr: 'Serveur Web',
ru: 'Web Сервер',
uk: 'Web Сервер',
},
'What happened?': {
fr: 'Que sest-il passé ?',
ru: 'Что произошло?',
uk: 'Що сталося?',
},
'What can i do?': {
fr: 'Que puis-je faire ?',
ru: 'Что можно сделать?',
uk: 'Що можна зробити?',
},
'Please try again in a few minutes': {
fr: 'Veuillez réessayer dans quelques minutes',
ru: 'Пожалуйста, попробуйте повторить запрос ещё раз чуть позже',
uk: 'Будь ласка, спробуйте повторити запит ще раз трохи пізніше',
},
'Working': {
fr: 'Opérationnel',
ru: 'Работает',
uk: 'Працює',
},
'Unknown': {
fr: 'Inconnu',
ru: 'Неизвестно',
uk: 'Невідомо',
},
'Please try to change the request method, headers, payload, or URL': {
fr: 'Veuillez essayer de changer la méthode de requête, les en-têtes, le contenu ou lURL',
ru: 'Пожалуйста, попробуйте изменить метод запроса, заголовки, его содержимое или URL',
uk: 'Будь ласка, спробуйте змінити метод запиту, заголовки, його вміст або URL-адресу',
},
'Please check your authorization data': {
fr: 'Veuillez vérifier vos données dautorisation',
ru: 'Пожалуйста, проверьте данные авторизации',
uk: 'Будь ласка, перевірте дані авторизації',
},
'Please double-check the URL and try again': {
fr: 'Veuillez vérifier lURL et réessayer',
ru: 'Пожалуйста, дважды проверьте URL и попробуйте снова',
uk: 'Будь ласка, двічі перевірте URL-адресу і спробуйте знову',
},
};
/**
* @param {string} token
* @return {string}
*/
const serializeToken = function (token) {
return token.toLowerCase().replaceAll(/[^a-z0-9]/g, '');
};
// normalize the data keys
for (const key in data) {
Object.defineProperty(data, serializeToken(key), Object.getOwnPropertyDescriptor(data, key));
delete data[key];
}
// detect browser locale (take only 2 first symbols)
let activeLocale = navigator.language.substring(0, 2).toLowerCase();
/**
* @param {string} locale
*/
this.setLocale = function (locale) {
activeLocale = locale.toLowerCase();
}
/**
* @param {string} token
* @param {string|undefined?} def
*/
this.translate = function (token, def) {
const t = serializeToken(token);
if (activeLocale === 'en' && Object.prototype.hasOwnProperty.call(data, t)) {
return token
}
if (Object.prototype.hasOwnProperty.call(data, t) && Object.prototype.hasOwnProperty.call(data[t], activeLocale)) {
return data[t][activeLocale];
}
return def;
};
/**
* Localize all elements with HTML attribute `data-l10n`.
*/
this.localizeDocument = function () {
const dataAttributeName = 'data-l10n';
Array.prototype.forEach.call(document.querySelectorAll('[' + dataAttributeName + ']'), ($el) => {
const attr = $el.getAttribute(dataAttributeName).trim(),
token = attr.length > 0 ? attr : $el.innerText.trim(),
localized = this.translate(token, undefined);
if (attr.length === 0) {
$el.setAttribute(dataAttributeName, token);
}
if (localized !== undefined) {
$el.innerText = localized;
} else {
console.debug(`Unsupported l10n token detected: "${token}" (locale "${activeLocale}")`, $el);
}
});
};
},
writable: false,
enumerable: false,
});
window.l10n.localizeDocument();

16
l10n/readme.md Normal file
View File

@ -0,0 +1,16 @@
# 🔤 Localization
[![jsDelivr hits](https://img.shields.io/jsdelivr/gh/hm/tarampampam/error-pages)](https://www.jsdelivr.com/package/gh/tarampampam/error-pages)
This directory contains file [l10n.js](l10n.js) for the error pages localization. The working logic is very simple - pages load this script using [jsdelivr.com](https://www.jsdelivr.com/) as a CDN for [versioned content from the GitHub repository](https://www.jsdelivr.com/features#gh), and it translates tag content with the special HTML attribute `data-l10n`.
By default, pages markup contains strings in English (`en` locale). If you want to localize the error pages on the different locales, you should:
- Find your locale name on [this page](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (column `639-1`)
- Make a fork of this repository
- Edit file [l10n.js](l10n.js) in `data` section (append new localized strings) using locale name from the step 1
- Make a PR with your changes
## 👍 Translators
- 🇫🇷 French by [@jvin042](https://github.com/jvin042)

244
templates/app-down.html Normal file
View File

@ -0,0 +1,244 @@
<!DOCTYPE html>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="robots" content="noindex, nofollow"/>
<title>{{ message }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
:root{--color-bg-primary:#fff;--color-bg-secondary:#eef6fa;--color-bg-sign:#fff;--color-text-primary:#333;--color-text-secondary:#777;--color-img-details:#f62f37;--color-img-primary:#7990a1;--color-img-secondary:#00baff;--font-size-small:13px;--font-size-normal:16px;--font-size-large:45px}
@media (prefers-color-scheme:dark){
:root{--color-bg-primary:#222526;--color-bg-secondary:#292e2f;--color-bg-sign:#262828;--color-text-primary:#fff;--color-text-secondary:#999;--color-img-details:#c72d34;--color-img-primary:#adacac;--color-img-secondary:#86d3ff}
}
body,html{background-color:var(--color-bg-primary);color:var(--color-text-primary);font-family:Roboto,Helvetica,sans-serif;font-size:0;margin:0;padding:0;height:100vh;overflow-x:hidden}
body{align-items:center;display:flex;justify-content:center;height:100vh}
main{width:100%;max-width:1024px;padding:0 40px;display:flex;justify-content:space-between}
.content,.picture{box-sizing:border-box}
.content{display:flex;flex-direction:column;flex-shrink:0;justify-content:space-around;width:45%;z-index:1}
a,p,ul li{font-size:var(--font-size-normal)}
.title{line-height:1.2;font-size:var(--font-size-large);margin:0 0 30px;width:130%}
.subtitle{display:flex;flex-direction:column;justify-content:center;margin:16px 0}
ul{padding:0;list-style:none;line-height:24px}
ul li::before{content:'•';padding-right:7px;color:var(--color-img-secondary)}
/* {{ if show_details }} */
.details{margin:0 0 16px 0}
.details p{font-size:var(--font-size-small)}
.details ul{line-height:0}
.details ul li{padding-top:calc(var(--font-size-small) * 1.5)}
.details ul li:first-child{padding-top:calc(var(--font-size-small) * .6)}
.details code,.details span,.details ul li::before{font-size:var(--font-size-small);font-weight:400}
.details code{padding-left:7px}
/* {{ end }} */
a{text-decoration:none;color:var(--color-img-secondary)}
.hidden{display:none}
.picture{display:flex;align-items:center;justify-content:center;width:55%;user-select:none;z-index:0}
.picture svg{width:100%}
.picture svg .st10,.picture svg .st11,.picture svg .st12,.picture svg .st13,.picture svg .st14,.picture svg .st15,.picture svg .st16,.picture svg .st17,.picture svg .st3,.picture svg .st6,.picture svg .st9{stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10}
.picture svg .st0{fill:var(--color-bg-primary)}
.picture svg .st1{fill:url(#svg-background-gradient)}
.picture svg .st2{fill:var(--color-bg-secondary)}
.picture svg .st3{fill:var(--color-bg-primary);stroke:var(--color-img-primary);stroke-width:3.5}
.picture svg .st4{fill:var(--color-img-secondary)}
.picture svg .st5{fill:none;stroke:var(--color-img-secondary);stroke-width:4;stroke-linejoin:round;stroke-miterlimit:10}
.picture svg .st6{fill:var(--color-bg-primary);stroke:var(--color-img-primary);stroke-width:3}
.picture svg .st7{fill:var(--color-img-primary)}
.picture svg .st8{fill:none;stroke:var(--color-img-primary);stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:10}
.picture svg .st9{fill:none;stroke:var(--color-img-primary);stroke-width:3}
.picture svg .st10{fill:none;stroke:var(--color-img-primary);stroke-width:3.5}
.picture svg .st11{fill:none;stroke:var(--color-img-secondary);stroke-width:4}
.picture svg .st12{fill:var(--color-bg-primary);stroke:var(--color-img-primary);stroke-width:4}
.picture svg .st13{fill:none;stroke:var(--color-img-primary);stroke-width:4}
.picture svg .st14{fill:none;stroke:var(--color-img-secondary);stroke-width:4.5}
.picture svg .st15{fill:none;stroke:var(--color-img-secondary);stroke-width:5}
.picture svg .st16{fill:none;stroke:var(--color-img-primary);stroke-width:5}
.picture svg .st17{fill:var(--color-bg-primary);stroke:var(--color-img-details);stroke-width:3.5}
.picture svg .st19{fill:none;stroke:var(--color-img-details);stroke-width:2.5;stroke-linecap:round;stroke-miterlimit:10}
.picture svg .error-code{font:bold 40px sans-serif;fill:var(--color-img-details)}
@media (max-width:1024px){
:root{--font-size-small:11px;--font-size-normal:14px;--font-size-large:35px}
main{display:block;position:relative;padding-top:40px}
.content,.picture{width:100%}
.content{position:relative;margin:0 auto;z-index:1}
.title{width:100%}
.picture{position:absolute;top:0;left:0;z-index:0;opacity:.2;width:100%;height:100%;padding:0}
.picture svg{max-width:70%}
}
@media (max-width:600px){
.picture svg{max-width:100%}
}
</style>
</head>
<body>
<main>
<div class="content">
<h2 class="title" data-l10n>{{ message }}</h2>
<p data-l10n>{{ description }}</p>
<div class="subtitle if-not-found hidden">
<p><span data-l10n>Here's what might have happened</span>:</p>
<ul>
<li data-l10n>You may have mistyped the URL</li>
<li data-l10n>The site was moved</li>
<li data-l10n>It was never here</li>
</ul>
</div>
<p class="if-maybe-wrong-uri"><span data-l10n>Double-check the URL</span>. <a class="go-back hidden" data-l10n>Alternatively, go back</a></p>
{{ if show_details }}
<div class="details">
<p><span data-l10n>Request details</span>:</p>
<ul>
{{- if host }}<li><span><span data-l10n>Host</span>:</span> <code>{{ host }}</code></li>{{ end -}}
{{- if original_uri }}<li><span><span data-l10n>Original URI</span>:</span> <code>{{ original_uri }}</code></li>{{ end -}}
{{- if forwarded_for }}<li><span><span data-l10n>Forwarded for</span>:</span> <code>{{ forwarded_for }}</code></li>{{ end -}}
{{- if namespace }}<li><span><span data-l10n>Namespace</span>:</span> <code>{{ namespace }}</code></li>{{ end -}}
{{- if ingress_name }}<li><span><span data-l10n>Ingress name</span>:</span> <code>{{ ingress_name }}</code></li>{{ end -}}
{{- if service_name }}<li><span><span data-l10n>Service name</span>:</span> <code>{{ service_name }}</code></li>{{ end -}}
{{- if service_port }}<li><span><span data-l10n>Service port</span>:</span> <code>{{ service_port }}</code></li>{{ end -}}
{{- if request_id }}<li><span><span data-l10n>Request ID</span>:</span> <code>{{ request_id }}</code></li>{{ end -}}
<li><span><span data-l10n>Timestamp</span>:</span> <code>{{ now.Unix }}</code></li>
</ul>
</div>
{{ end }}
</div>
<div class="picture">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 480" x="0px" y="0px" xml:space="preserve">
<rect y="0" class="st0" width="600" height="480"></rect>
<radialgradient id="svg-background-gradient" cx="328.1394" cy="306.3561" r="219.5134" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:var(--color-bg-secondary)"></stop>
<stop offset="0.5002" style="stop-color:var(--color-bg-secondary)"></stop>
<stop offset="1" style="stop-color:var(--color-bg-primary)"></stop>
</radialgradient>
<rect x="95.2" y="35.7" class="st1" width="460" height="271.4"></rect>
<ellipse class="st2" cx="289.7" cy="352.3" rx="69.5" ry="13.9"></ellipse>
<ellipse class="st2" cx="180.5" cy="396.3" rx="51.2" ry="9.5"></ellipse>
<ellipse class="st2" cx="381.3" cy="418.3" rx="40.8" ry="6.4"></ellipse>
<path class="st3" d="M551.1,285.8H527c-2.3,0-4.1-1.8-4.1-4.1v-30c0-2.3,1.8-4.1,4.1-4.1h24.1c2.3,0,4.1,1.8,4.1,4.1v30 C555.2,284,553.4,285.8,551.1,285.8z"></path>
<circle class="st3" cx="539.1" cy="266.7" r="10.3"></circle>
<path class="st4" d="M265.6,343.3c-5,0-9,4-9,9h18C274.6,347.3,270.6,343.3,265.6,343.3z"></path>
<line class="st5" x1="272.7" y1="328.1" x2="272.7" y2="352.3"></line>
<path class="st4" d="M307,343.3c-5,0-9,4-9,9h18C316,347.3,311.9,343.3,307,343.3z"></path>
<line class="st5" x1="314.1" y1="328.1" x2="314.1" y2="352.3"></line>
<path class="st6" d="M380.7,422.6l-37.6-6.4c-1.5-0.3-2.5-1.5-2.2-2.9l4.6-26.8c0.2-1.4,1.6-2.2,3-2l37.6,6.4 c1.5,0.3,2.5,1.5,2.2,2.9l-4.6,26.8C383.6,422,382.2,422.9,380.7,422.6z"></path>
<path class="st6" d="M344.6,391.5l0.8-4.5c0.3-1.7,1.6-2.8,3.1-2.5l37.6,6.4c1.5,0.3,2.4,1.7,2.1,3.4l-0.8,4.5L344.6,391.5z"></path>
<circle class="st7" cx="349" cy="388.4" r="1"></circle>
<circle class="st7" cx="353.1" cy="389.1" r="1"></circle>
<circle class="st7" cx="357.1" cy="389.8" r="1"></circle>
<line class="st8" x1="360.4" y1="402.8" x2="367.4" y2="412.7"></line>
<line class="st8" x1="368.8" y1="404.3" x2="359" y2="411.2"></line>
<path class="st6" d="M166.4,401.4l-36.6-10.8c-1.5-0.4-2.3-1.8-1.9-3.1l7.7-26.1c0.4-1.3,1.8-2,3.3-1.6l36.6,10.8 c1.5,0.4,2.3,1.8,1.9,3.1l-7.7,26.1C169.3,401.1,167.9,401.8,166.4,401.4z"></path>
<path class="st6" d="M134.2,366.2l1.3-4.4c0.5-1.6,2-2.6,3.4-2.1l36.6,10.8c1.5,0.4,2.2,2,1.7,3.6l-1.3,4.4L134.2,366.2z"></path>
<circle class="st7" cx="138.9" cy="363.7" r="1"></circle>
<circle class="st7" cx="142.9" cy="364.8" r="1"></circle>
<circle class="st7" cx="146.9" cy="366" r="1"></circle>
<path class="st6" d="M220.9,399.3l-38-3.9c-1.5-0.2-2.5-1.3-2.4-2.7l2.8-27.1c0.1-1.4,1.4-2.3,2.9-2.2l38,3.9 c1.5,0.2,2.5,1.3,2.4,2.7l-2.8,27.1C223.6,398.5,222.4,399.5,220.9,399.3z"></path>
<path class="st6" d="M188.6,400.9l-38.1,2.8c-1.5,0.1-2.7-0.9-2.8-2.3l-2-27.1c-0.1-1.4,1-2.6,2.5-2.7l38.1-2.8 c1.5-0.1,2.7,0.9,2.8,2.3l2,27.1C191.2,399.6,190.1,400.8,188.6,400.9z"></path>
<path class="st9" d="M146.1,379.4l-0.3-4.5c-0.1-1.7,0.9-3.1,2.4-3.2l38.1-2.8c1.5-0.1,2.8,1.1,2.9,2.8l0.3,4.5L146.1,379.4z"></path>
<circle class="st7" cx="149.6" cy="375.3" r="1"></circle>
<circle class="st7" cx="153.7" cy="375" r="1"></circle>
<circle class="st7" cx="157.8" cy="374.7" r="1"></circle>
<line class="st8" x1="164.1" y1="386.6" x2="173.3" y2="394.4"></line>
<line class="st8" x1="172.7" y1="385.9" x2="164.8" y2="395.1"></line>
<path class="st10" d="M539.1,267.8c0,96.1-51.7,97.6-67.6,98.6c-28.1,1.8-76.3-14.4-63-25.6c13.3-11.2,53.8-10.3,59.3-4.3 c4,4.3,6.1,16.6-49.9,15.8c-29.4-0.4-51-8.4-60.8-32.1"></path>
<path class="st11" d="M184.1,262.5c17.8,9,28.4-2.4,28.4-2.4"></path>
<ellipse class="st0" cx="289.7" cy="170.7" rx="77.1" ry="21.7"></ellipse>
<path class="st12" d="M366.8,308.7c0,12.1-34.5,21.8-77.1,21.8c-42.6,0-77.1-9.8-77.1-21.8V170.7c0,12.1,34.5,21.8,77.1,21.8 c42.6,0,77.1-9.8,77.1-21.8V308.7z"></path>
<path class="st13" d="M212.6,170.7c0-12.1,34.5-21.8,77.1-21.8c42.6,0,77.1,9.8,77.1,21.8"></path>
<path class="st13" d="M366.8,216.7c0,12.1-34.5,21.8-77.1,21.8c-42.6,0-77.1-9.8-77.1-21.8"></path>
<path class="st13" d="M366.8,262.7c0,12.1-34.5,21.8-77.1,21.8c-42.6,0-77.1-9.8-77.1-21.8"></path>
<path class="st11" d="M384.2,279.8c-6.2-18.9-25.1-18.7-25.1-18.7"></path>
<path class="st14" d="M378,288.7c0,0,0-6.3,5.6-8.8c0,0,1.6,0.5,3.3,1.3"></path>
<path class="st15" d="M384.2,279.8"></path>
<circle class="st4" cx="319" cy="254.8" r="4.2"></circle>
<circle class="st4" cx="257.2" cy="255.4" r="4.2"></circle>
<line class="st16" x1="182.4" y1="284.4" x2="179" y2="229.2"></line>
<polygon class="st17" points="191.3,144 153.6,146.3 128.7,174.8 131,212.7 159.3,238 196.9,235.6 221.8,207.2 219.5,169.2" style="fill:var(--color-bg-sign)"></polygon>
<text class="error-code" x="125" y="220" transform="rotate(-5)">{{ code }}</text>
<line class="st14" x1="183.2" y1="255.9" x2="175.9" y2="258.8"></line>
<line class="st14" x1="184.7" y1="260.4" x2="175.8" y2="263"></line>
<line class="st14" x1="185.4" y1="265.4" x2="176.9" y2="267.2"></line>
<ellipse class="st11" cx="287.7" cy="269" rx="4.4" ry="6.7"></ellipse>
<path class="st6" d="M405.5,316l-37.8,5.5c-1.5,0.2-2.8-0.7-3-2.1l-3.9-26.9c-0.2-1.4,0.8-2.6,2.3-2.8l37.8-5.5 c1.5-0.2,2.8,0.7,3,2.1l3.9,26.9C407.9,314.5,407,315.7,405.5,316z"></path>
<path class="st6" d="M361.5,297.6l-0.7-4.5c-0.2-1.7,0.7-3.1,2.2-3.4l37.8-5.5c1.5-0.2,2.8,0.9,3.1,2.6l0.7,4.5L361.5,297.6z"></path>
<circle class="st7" cx="364.7" cy="293.3" r="1"></circle>
<circle class="st7" cx="368.8" cy="292.7" r="1"></circle>
<circle class="st7" cx="372.9" cy="292.1" r="1"></circle>
<line class="st19" x1="380" y1="303.4" x2="389.7" y2="310.6"></line>
<line class="st19" x1="388.5" y1="302.2" x2="381.3" y2="311.9"></line>
<path class="st6" d="M204.8,355.2l-28.4,25.5c-1.1,1-2.7,1-3.6-0.1l-18.2-20.3c-0.9-1-0.8-2.6,0.3-3.6l28.4-25.5 c1.1-1,2.7-1,3.6,0.1l18.2,20.3C206.1,352.6,205.9,354.2,204.8,355.2z"></path>
<path class="st9" d="M158,364.1l-3-3.4c-1.1-1.3-1.1-3,0-4l28.4-25.5c1.1-1,2.9-0.8,4,0.5l3,3.4L158,364.1z"></path>
<circle class="st7" cx="158.3" cy="358.7" r="1"></circle>
<circle class="st7" cx="161.3" cy="356" r="1"></circle>
<circle class="st7" cx="164.4" cy="353.2" r="1"></circle>
<line class="st8" x1="176.7" y1="358.8" x2="188.7" y2="359.4"></line>
<line class="st8" x1="183" y1="353.1" x2="182.4" y2="365.1"></line>
<path class="st6" d="M219.9,344l14.8,35.2c0.6,1.4,0,2.9-1.2,3.4l-25.1,10.5c-1.3,0.5-2.7-0.1-3.3-1.5l-14.8-35.2 c-0.6-1.4,0-2.9,1.2-3.4l25.1-10.5C217.8,341.9,219.3,342.6,219.9,344z"></path>
<path class="st9" d="M213,391.1l-4.2,1.8c-1.6,0.7-3.2,0.1-3.8-1.3l-14.8-35.2c-0.6-1.4,0.2-3,1.7-3.6l4.2-1.8L213,391.1z"></path>
<circle class="st7" cx="208" cy="389.1" r="1"></circle>
<circle class="st7" cx="206.4" cy="385.3" r="1"></circle>
<circle class="st7" cx="204.8" cy="381.5" r="1"></circle>
<line class="st8" x1="214.1" y1="371.7" x2="218.6" y2="360.6"></line>
<line class="st8" x1="210.8" y1="363.9" x2="221.9" y2="368.4"></line>
<path class="st14" d="M394.1,287.1c-0.7-1.6-3.9-4.5-7.2-5.9"></path>
<path class="st6" d="M419.7,413.7l-37.8,5.2c-1.5,0.2-2.8-0.7-3-2.1l-3.7-27c-0.2-1.4,0.8-2.6,2.3-2.8l37.8-5.2 c1.5-0.2,2.8,0.7,3,2.1l3.7,27C422.2,412.2,421.2,413.5,419.7,413.7z"></path>
<path class="st6" d="M375.9,394.8l-0.6-4.5c-0.2-1.7,0.7-3.1,2.2-3.3l37.8-5.2c1.5-0.2,2.8,0.9,3.1,2.6l0.6,4.5L375.9,394.8z"></path>
<circle class="st7" cx="379.2" cy="390.6" r="1"></circle>
<circle class="st7" cx="383.3" cy="390" r="1"></circle>
<circle class="st7" cx="387.4" cy="389.5" r="1"></circle>
<line class="st8" x1="394.4" y1="400.9" x2="404" y2="408.2"></line>
<line class="st8" x1="402.9" y1="399.7" x2="395.6" y2="409.4"></line>
<polygon class="st17" points="361,62.2 346.5,104.9 364.7,107.8 347.6,141.8 382,99.7 363.5,93.5 385,63.8 "></polygon>
<polygon class="st17" points="396.5,101.6 374.8,122.8 384.1,130.2 363.6,145.4 396.4,130.6 388,121.2 409.5,109.9 "></polygon>
<line class="st14" x1="384.7" y1="281.7" x2="386" y2="290.6"></line>
</svg>
</div>
</main>
<script>
Array.prototype.forEach.call(document.getElementsByClassName('if-not-found'), function ($el) {
$el.style.display = "{{ code }}" === "404" ? 'block' : 'none';
});
Array.prototype.forEach.call(document.getElementsByClassName('if-maybe-wrong-uri'), function ($el) {
$el.style.display = ["401", "403", "404", "418", "505"].includes("{{ code }}") ? 'block' : 'none';
});
Array.prototype.forEach.call(document.getElementsByClassName('go-back'), function ($el) {
if (document.referrer !== '' || history.length > 1) {
$el.setAttribute('href', '#back-to-the-future');
$el.addEventListener('click', function (event) {
history.back();
event.preventDefault();
return false;
}, false);
$el.style.display = 'inline-block'; // show the element
} else {
$el.style.display = 'none'; // hide the element
}
});
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
</html>

View File

@ -63,39 +63,39 @@
<div class="details">
<table>
{{- if host }}<tr>
<td class="name">Host</td>
<td class="name" data-l10n>Host</td>
<td class="value">{{ host }}</td>
</tr>{{ end -}}
{{- if original_uri }}<tr>
<td class="name">Original URI</td>
<td class="name" data-l10n>Original URI</td>
<td class="value">{{ original_uri }}</td>
</tr>{{ end -}}
{{- if forwarded_for }}<tr>
<td class="name">Forwarded for</td>
<td class="name" data-l10n>Forwarded for</td>
<td class="value">{{ forwarded_for }}</td>
</tr>{{ end -}}
{{- if namespace }}<tr>
<td class="name">Namespace</td>
<td class="name" data-l10n>Namespace</td>
<td class="value">{{ namespace }}</td>
</tr>{{ end -}}
{{- if ingress_name }}<tr>
<td class="name">Ingress name</td>
<td class="name" data-l10n>Ingress name</td>
<td class="value">{{ ingress_name }}</td>
</tr>{{ end -}}
{{- if service_name }}<tr>
<td class="name">Service name</td>
<td class="name" data-l10n>Service name</td>
<td class="value">{{ service_name }}</td>
</tr>{{ end -}}
{{- if service_port }}<tr>
<td class="name">Service port</td>
<td class="name" data-l10n>Service port</td>
<td class="value">{{ service_port }}</td>
</tr>{{ end -}}
{{- if request_id }}<tr>
<td class="name">Request ID</td>
<td class="name" data-l10n>Request ID</td>
<td class="value">{{ request_id }}</td>
</tr>{{ end -}}
<tr>
<td class="name">Timestamp</td>
<td class="name" data-l10n>Timestamp</td>
<td class="value">{{ now.Unix }}</td>
</tr>
</table>
@ -103,6 +103,18 @@
{{ end }}
</div>
</div>
<script>
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}

272
templates/connection.html Normal file
View File

@ -0,0 +1,272 @@
<!DOCTYPE html>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="robots" content="noindex, nofollow"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>{{ code }} | {{ message }}</title>
<link rel="preconnect" href="https://fonts.gstatic.com"/>
<link href="https://fonts.googleapis.com/css2?family=Red+Hat+Display:wght@500&family=Fira+Mono&family=Ubuntu&display=swap" rel="stylesheet"/>
<style>
/** Idea author: https://github.com/186526/CloudflareCustomErrorPage */
:root{--color-bg-primary:#fff;--color-text-primary:#000;--color-text-secondary:#575958;--font-size-primary:56px;--font-size-secondary:20px;--ui-card-color-bg:#f2f2f2;--color-text-ok:#137333;--color-bg-ok:#e6f4ea;--color-text-error:#c5221f;--color-bg-error:#fce8e6;--color-text-warning:#b05a00;--color-bg-warning:#fef7e0;--icon-size:48px}
@media (prefers-color-scheme:dark){
:root{--color-bg-primary:#111;--color-text-primary:rgba(255, 255, 255, 0.86);--color-text-secondary:rgba(255, 255, 255, 0.4);--ui-card-color-bg:rgba(40, 40, 40, 0.73);--color-bg-ok:#07220f;--color-bg-error:#270501;--color-bg-warning:#392605}
}
body{margin:2rem 2rem;font-family:'Red Hat Display',Ubuntu,Roboto,'Noto Sans SC',sans-serif;color:var(--color-text-primary);background-color:var(--color-bg-primary)}
header{margin-left:1rem}
header .error-code{font-size:var(--font-size-primary);line-height:var(--font-size-primary);font-family:'Fira Mono',Ubuntu,monospace;font-weight:400;margin:0 0 0 10px}
header .error-description{font-family:Ubuntu,Roboto,'Noto Sans SC',sans-serif;font-size:var(--font-size-secondary);color:var(--color-text-secondary);margin:0 0 0 10px}
code{font-family:'Fira Mono',monospace}
.status{margin-top:2.5rem;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:center;align-items:center}
.card{background-color:var(--ui-card-color-bg);padding:2rem;margin:1rem 1rem;min-height:3rem;border-radius:9px;flex-grow:1}
.arrows svg{fill:var(--color-text-secondary)}
.icon svg{width:var(--icon-size);height:auto;fill:var(--color-text-primary)}
.card.ok{background-color:var(--color-bg-ok)}.card.ok .status-text{color:var(--color-text-ok)}.card.ok svg{fill:var(--color-text-ok)}
.card.error{background-color:var(--color-bg-error)}.card.error .status-text{color:var(--color-text-error)}.card.error svg{fill:var(--color-text-error)}
.card.warning{background-color:var(--color-bg-warning)}.card.warning .status-text{color:var(--color-text-warning)}.card.warning svg{fill:var(--color-text-warning)}
.card main{font-size:calc(var(--font-size-secondary) + .1rem)}
.card .status-text,.reason p{margin:0;font-family:Ubuntu,Roboto,Noto Sans SC,sans-serif}
.reason p{line-height:125%}
a{text-decoration:none;color:#1967d2}
.reason{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline}
.reason>*{display:block;margin:1rem;flex-grow:1;max-width:40%}
.reason h2{font-size:calc(var(--font-size-secondary) + .2rem);margin:0 0 .6em 0;font-weight:550}
footer{margin:1rem;color:var(--color-text-secondary);font-size:0}
/* {{ if show_details }} */
footer .details{margin-top:20px}
footer .details ul{padding:0}
footer .details code,footer .details span{font-size:calc(var(--font-size-secondary) - .6rem)}
footer .details code{padding-left:7px}
/* {{ end }} */
@media screen and (max-width:820px){
.arrows{display:none}
}
@media screen and (max-width:480px){
.reason>*{max-width:100%}
/* {{ if show_details }} */
footer .details code,footer .details span{font-size:calc(var(--font-size-secondary) - .3rem)}
/* {{ end }} */
}
@media screen and (min-width:768px){
body{margin:8% 10%}
header>*{display:inline-block;margin-left:1%}
}
</style>
</head>
<body>
<header>
<h1 class="error-code">{{ code }}</h1>
<p class="error-description">{{ message }}</p>
</header>
<div class="status">
<div class="card warning" id="client-status-card">
<i class="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.89-2-2-2zm0 14H5V8h14v10z"/>
</svg>
</i>
<main data-l10n>Your Client</main>
<p class="status-text" data-l10n>Unknown</p>
</div>
<div class="arrows">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" fill="#000000">
<defs>
<symbol id="arrows-horizontal" viewBox="0 0 24 24">
<rect fill="none" height="24" width="24" x="0"/>
<polygon points="7.41,13.41 6,12 2,16 6,20 7.41,18.59 5.83,17 21,17 21,15 5.83,15"/>
<polygon points="16.59,10.59 18,12 22,8 18,4 16.59,5.41 18.17,7 3,7 3,9 18.17,9"/>
</symbol>
</defs>
<use href="#arrows-horizontal"/>
</svg>
</div>
<div class="card ok" id="network-status-card">
<i class="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6m0-2C9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96C18.67 6.59 15.64 4 12 4z"/>
</svg>
</i>
<main data-l10n>Network</main>
<p class="status-text" data-l10n>Working</p>
</div>
<div class="arrows">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" fill="#000000">
<use href="#arrows-horizontal" />
</svg>
</div>
<div class="card warning" id="server-status-card">
<i class="icon">
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<path d="M0 0h24v24H0V0z" fill="none"/>
<path d="M19 15v4H5v-4h14m1-2H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-6c0-.55-.45-1-1-1zM7 18.5c-.82 0-1.5-.67-1.5-1.5s.68-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM19 5v4H5V5h14m1-2H4c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h16c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1zM7 8.5c-.82 0-1.5-.67-1.5-1.5S6.18 5.5 7 5.5s1.5.68 1.5 1.5S7.83 8.5 7 8.5z"/>
</svg>
</i>
<main data-l10n>Web Server</main>
<p class="status-text" data-l10n>Unknown</p>
</div>
</div>
<div class="reason">
<div class="what-happened">
<h2 data-l10n>What happened?</h2>
<p class="description" data-l10n>{{ description }}</p>
</div>
<div class="what-can-i-do">
<h2 data-l10n>What can I do?</h2>
<p class="description" data-l10n>Please try again in a few minutes</p>
</div>
</div>
</body>
<footer>
{{ if show_details }}
<div class="details">
<ul>
{{- if host }}<li><span><span data-l10n>Host</span>:</span> <code>{{ host }}</code></li>{{ end -}}
{{- if original_uri }}<li><span><span data-l10n>Original URI</span>:</span> <code>{{ original_uri }}</code></li>{{ end -}}
{{- if forwarded_for }}<li><span><span data-l10n>Forwarded for</span>:</span> <code>{{ forwarded_for }}</code></li>{{ end -}}
{{- if namespace }}<li><span><span data-l10n>Namespace</span>:</span> <code>{{ namespace }}</code></li>{{ end -}}
{{- if ingress_name }}<li><span><span data-l10n>Ingress name</span>:</span> <code>{{ ingress_name }}</code></li>{{ end -}}
{{- if service_name }}<li><span><span data-l10n>Service name</span>:</span> <code>{{ service_name }}</code></li>{{ end -}}
{{- if service_port }}<li><span><span data-l10n>Service port</span>:</span> <code>{{ service_port }}</code></li>{{ end -}}
{{- if request_id }}<li><span><span data-l10n>Request ID</span>:</span> <code>{{ request_id }}</code></li>{{ end -}}
<li><span><span data-l10n>Timestamp</span>:</span> <code>{{ now.Unix }}</code></li>
</ul>
</div>
{{ end }}
</footer>
<script>
const errorCode = parseInt(`{{ code }}`, 10);
if (typeof errorCode !== 'undefined' && !isNaN(errorCode)) {
/**
* @param {HTMLElement} $card
* @param { {isOk?: boolean, isWarning?: boolean, isError?: boolean} } state
* @param {string} statusText
*/
const setCardState = function ($card, state, statusText) {
const okClass = 'ok', warnClass = 'warning', errClass = 'error',
$statusText = $card.querySelectorAll('.status-text');
switch (true) {
case state.isOk === true:
$card.classList.remove(errClass, warnClass);
$card.classList.add(okClass);
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
break;
case state.isWarning === true:
$card.classList.remove(okClass, errClass);
$card.classList.add(warnClass);
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
break;
case state.isError === true:
$card.classList.remove(okClass, warnClass);
$card.classList.add(errClass);
$statusText.forEach(($statusText) => $statusText.innerText = statusText);
break;
}
};
/**
* @param { {whatHappened?: string, whatToDo?: string} } reasons
*/
const setReasons = function (reasons) {
const descSelector = '.description';
Array.prototype.forEach.call(document.getElementsByClassName('what-happened'), ($el) => {
if (typeof reasons.whatHappened === 'string' && reasons.whatHappened.length > 0) {
Array.prototype.forEach.call($el.querySelectorAll(descSelector), ($desc) => $desc.innerText = reasons.whatHappened);
} else {
$el.remove();
}
});
Array.prototype.forEach.call(document.getElementsByClassName('what-can-i-do'), ($el) => {
if (typeof reasons.whatToDo === 'string' && reasons.whatToDo.length > 0) {
Array.prototype.forEach.call($el.querySelectorAll(descSelector), ($desc) => $desc.innerText = reasons.whatToDo);
} else {
$el.remove();
}
});
};
/**
* @param {string} text
*/
const setErrorDescription = function (text) {
Array.prototype.forEach.call(document.getElementsByClassName('error-description'), function ($el) {
$el.innerHTML = text;
});
};
const message = `{{ message }}`.trim(), cards = {
$client: document.getElementById('client-status-card'),
$network: document.getElementById('network-status-card'),
$server: document.getElementById('server-status-card'),
};
let whatToDo = 'Please try again in a few minutes';
switch (true) {
case errorCode >= 400 && errorCode <= 499:
switch (errorCode) {
case 400: case 405: case 411: case 413: whatToDo = 'Please try to change the request method, headers, payload, or URL'; break;
case 401: case 403: case 407: whatToDo = 'Please check your authorization data'; break;
case 404: whatToDo = 'Please double-check the URL and try again'; break;
case 409: case 410: case 418: whatToDo = '¯\\_(ツ)_/¯'; break;
}
setErrorDescription(`<span data-l10n>${message}</span> (<span data-l10n>client-side error</span>)`);
setCardState(cards.$client, {isError: true}, message)
setCardState(cards.$network, {isOk: true}, 'Working')
setCardState(cards.$server, {isOk: true}, 'Working')
break;
case errorCode >= 500 && errorCode <= 599:
setErrorDescription(`<span data-l10n>${message}</span> (<span data-l10n>server-side error</span>)`);
setCardState(cards.$client, {isOk: true}, 'Working')
setCardState(cards.$network, {isOk: true}, 'Working')
setCardState(cards.$server, {isError: true}, message)
break;
default:
setErrorDescription(message);
setCardState(cards.$client, {isWarning: true}, 'Unknown')
setCardState(cards.$network, {isOk: true}, 'Working')
setCardState(cards.$server, {isWarning: true}, 'Unknown')
break;
}
setReasons({whatHappened: `{{ description }}`.trim(), whatToDo: whatToDo.trim()});
} else {
console.warn('Cannot parse the error code:', errorCode);
}
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
</html>

View File

@ -9,7 +9,8 @@
<meta name="robots" content="noindex, nofollow" />
<title>{{ code }}: {{ message }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap" rel="stylesheet">
<style>
html,body {background-color:#1a1a1a;color:#fff;font-family:'Open Sans',sans-serif;height:100vh;margin:0;font-size:0}
.container {height:100vh;align-items:center;display:flex;justify-content:center;position:relative}
@ -33,7 +34,7 @@
<body>
<div class="container">
<div class="wrap">
<svg class="ghost" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="127.433px" height="132.743px" viewBox="0 0 127.433 132.743" enable-background="new 0 0 127.433 132.743" xml:space="preserve">
<svg class="ghost" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="127.433px" height="132.743px" viewBox="0 0 127.433 132.743" xml:space="preserve">
<path fill="#FFF6F4" d="M116.223,125.064c1.032-1.183,1.323-2.73,1.391-3.747V54.76c0,0-4.625-34.875-36.125-44.375 s-66,6.625-72.125,44l-0.781,63.219c0.062,4.197,1.105,6.177,1.808,7.006c1.94,1.811,5.408,3.465,10.099-0.6 c7.5-6.5,8.375-10,12.75-6.875s5.875,9.75,13.625,9.25s12.75-9,13.75-9.625s4.375-1.875,7,1.25s5.375,8.25,12.875,7.875 s12.625-8.375,12.625-8.375s2.25-3.875,7.25,0.375s7.625,9.75,14.375,8.125C114.739,126.01,115.412,125.902,116.223,125.064z"></path>
<circle fill="#1a1a1a" cx="86.238" cy="57.885" r="6.667"></circle>
<circle fill="#1a1a1a" cx="40.072" cy="57.885" r="6.667"></circle>
@ -46,49 +47,49 @@
<path fill="#FCEFED" stroke="#FEEBE6" stroke-miterlimit="10" d="M116.279,55.814c-0.021-0.286-2.323-28.744-30.221-41.012 c-7.806-3.433-15.777-5.173-23.691-5.173c-16.889,0-30.283,7.783-37.187,15.067c-9.229,9.736-13.84,26.712-14.191,30.259 l-0.748,62.332c0.149,2.133,1.389,6.167,5.019,6.167c1.891,0,4.074-1.083,6.672-3.311c4.96-4.251,7.424-6.295,9.226-6.295 c1.339,0,2.712,1.213,5.102,3.762c4.121,4.396,7.461,6.355,10.833,6.355c2.713,0,5.311-1.296,7.942-3.962 c3.104-3.145,5.701-5.239,8.285-5.239c2.116,0,4.441,1.421,7.317,4.473c2.638,2.8,5.674,4.219,9.022,4.219 c4.835,0,8.991-2.959,11.27-5.728l0.086-0.104c1.809-2.2,3.237-3.938,5.312-3.938c2.208,0,5.271,1.942,9.359,5.936 c0.54,0.743,3.552,4.674,6.86,4.674c1.37,0,2.559-0.65,3.531-1.932l0.203-0.268L116.279,55.814z M114.281,121.405 c-0.526,0.599-1.096,0.891-1.734,0.891c-2.053,0-4.51-2.82-5.283-3.907l-0.116-0.136c-4.638-4.541-7.975-6.566-10.82-6.566 c-3.021,0-4.884,2.267-6.857,4.667l-0.086,0.104c-1.896,2.307-5.582,4.999-9.725,4.999c-2.775,0-5.322-1.208-7.567-3.59 c-3.325-3.528-6.03-5.102-8.772-5.102c-3.278,0-6.251,2.332-9.708,5.835c-2.236,2.265-4.368,3.366-6.518,3.366 c-2.772,0-5.664-1.765-9.374-5.723c-2.488-2.654-4.29-4.395-6.561-4.395c-2.515,0-5.045,2.077-10.527,6.777 c-2.727,2.337-4.426,2.828-5.37,2.828c-2.662,0-3.017-4.225-3.021-4.225l0.745-62.163c0.332-3.321,4.767-19.625,13.647-28.995 c3.893-4.106,10.387-8.632,18.602-11.504c-0.458,0.503-0.744,1.165-0.744,1.898c0,1.565,1.269,2.833,2.833,2.833 c1.564,0,2.833-1.269,2.833-2.833c0-1.355-0.954-2.485-2.226-2.764c4.419-1.285,9.269-2.074,14.437-2.074 c7.636,0,15.336,1.684,22.887,5.004c26.766,11.771,29.011,39.047,29.027,39.251V121.405z"></path>
</svg>
<p class="shadowFrame">
<svg version="1.1" class="shadow" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="61px" y="20px" width="122.436px" height="39.744px" viewBox="0 0 122.436 39.744" enable-background="new 0 0 122.436 39.744" xml:space="preserve">
<svg class="shadow" xmlns="http://www.w3.org/2000/svg" x="61px" y="20px" width="122.436px" height="39.744px" viewBox="0 0 122.436 39.744" xml:space="preserve">
<ellipse fill="#262626" cx="61.128" cy="19.872" rx="49.25" ry="8.916"></ellipse>
</svg>
</p>
<h3>Error {{ code }}</h3>
<p class="description">{{ description }}</p>
<h3><span data-l10n>Error</span> {{ code }}</h3>
<p class="description" data-l10n>{{ description }}</p>
{{ if show_details }}
<div class="details">
<table>
{{- if host }}<tr>
<td class="name">Host</td>
<td class="name" data-l10n>Host</td>
<td class="value">{{ host }}</td>
</tr>{{ end -}}
{{- if original_uri }}<tr>
<td class="name">Original URI</td>
<td class="name" data-l10n>Original URI</td>
<td class="value">{{ original_uri }}</td>
</tr>{{ end -}}
{{- if forwarded_for }}<tr>
<td class="name">Forwarded for</td>
<td class="name" data-l10n>Forwarded for</td>
<td class="value">{{ forwarded_for }}</td>
</tr>{{ end -}}
{{- if namespace }}<tr>
<td class="name">Namespace</td>
<td class="name" data-l10n>Namespace</td>
<td class="value">{{ namespace }}</td>
</tr>{{ end -}}
{{- if ingress_name }}<tr>
<td class="name">Ingress name</td>
<td class="name" data-l10n>Ingress name</td>
<td class="value">{{ ingress_name }}</td>
</tr>{{ end -}}
{{- if service_name }}<tr>
<td class="name">Service name</td>
<td class="name" data-l10n>Service name</td>
<td class="value">{{ service_name }}</td>
</tr>{{ end -}}
{{- if service_port }}<tr>
<td class="name">Service port</td>
<td class="name" data-l10n>Service port</td>
<td class="value">{{ service_port }}</td>
</tr>{{ end -}}
{{- if request_id }}<tr>
<td class="name">Request ID</td>
<td class="name" data-l10n>Request ID</td>
<td class="value">{{ request_id }}</td>
</tr>{{ end -}}
<tr>
<td class="name">Timestamp</td>
<td class="name" data-l10n>Timestamp</td>
<td class="value">{{ now.Unix }}</td>
</tr>
</table>
@ -96,6 +97,18 @@
{{ end }}
</div>
</div>
<script>
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}

View File

@ -9,8 +9,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow" />
<title>{{ message }}</title>
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<style>
/** Idea author: https://codepen.io/robinselmer */
html, body {
@ -145,23 +145,35 @@
<body>
<div class="overlay"></div>
<div class="terminal">
<h1>Error <span class="error_code">{{ code }}</span></h1>
<p class="output">{{ description }}.</p>
<p class="output">Good luck.</p>
<h1><span data-l10n>Error</span> <span class="error_code">{{ code }}</span></h1>
<p class="output" data-l10n>{{ description }}.</p>
<p class="output"><span data-l10n>Good luck</span>.</p>
{{ if show_details }}
<div class="details">
{{- if host }}<p class="output small">Host: <code>{{ host }}</code></p>{{ end -}}
{{- if original_uri }}<p class="output small">Original URI: <code>{{ original_uri }}</code></p>{{ end -}}
{{- if forwarded_for }}<p class="output small">Forwarded for: <code>{{ forwarded_for }}</code></p>{{ end -}}
{{- if namespace }}<p class="output small">Namespace: <code>{{ namespace }}</code></p>{{ end -}}
{{- if ingress_name }}<p class="output small">Ingress name: <code>{{ ingress_name }}</code></p>{{ end -}}
{{- if service_name }}<p class="output small">Service name: <code>{{ service_name }}</code></p>{{ end -}}
{{- if service_port }}<p class="output small">Service port: <code>{{ service_port }}</code></p>{{ end -}}
{{- if request_id }}<p class="output small">Request ID: <code>{{ request_id }}</code></p>{{ end -}}
<p class="output small">Timestamp: <code>{{ now.Unix }}</code></p>
{{- if host }}<p class="output small"><span data-l10n>Host</span>: <code>{{ host }}</code></p>{{ end -}}
{{- if original_uri }}<p class="output small"><span data-l10n>Original URI</span>: <code>{{ original_uri }}</code></p>{{ end -}}
{{- if forwarded_for }}<p class="output small"><span data-l10n>Forwarded for</span>: <code>{{ forwarded_for }}</code></p>{{ end -}}
{{- if namespace }}<p class="output small"><span data-l10n>Namespace</span>: <code>{{ namespace }}</code></p>{{ end -}}
{{- if ingress_name }}<p class="output small"><span data-l10n>Ingress name</span>: <code>{{ ingress_name }}</code></p>{{ end -}}
{{- if service_name }}<p class="output small"><span data-l10n>Service name</span>: <code>{{ service_name }}</code></p>{{ end -}}
{{- if service_port }}<p class="output small"><span data-l10n>Service port</span>: <code>{{ service_port }}</code></p>{{ end -}}
{{- if request_id }}<p class="output small"><span data-l10n>Request ID</span>: <code>{{ request_id }}</code></p>{{ end -}}
<p class="output small"><span data-l10n>Timestamp</span>: <code>{{ now.Unix }}</code></p>
</div>
{{ end }}
</div>
<script>
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}

View File

@ -33,7 +33,7 @@
<div class="code">
{{ code }}
</div>
<div class="message">
<div class="message" data-l10n>
{{ message }}
</div>
</div>
@ -41,39 +41,39 @@
<div class="details">
<table>
{{- if host }}<tr>
<td class="name">Host</td>
<td class="name" data-l10n>Host</td>
<td class="value">{{ host }}</td>
</tr>{{ end -}}
{{- if original_uri }}<tr>
<td class="name">Original URI</td>
<td class="name" data-l10n>Original URI</td>
<td class="value">{{ original_uri }}</td>
</tr>{{ end -}}
{{- if forwarded_for }}<tr>
<td class="name">Forwarded for</td>
<td class="name" data-l10n>Forwarded for</td>
<td class="value">{{ forwarded_for }}</td>
</tr>{{ end -}}
{{- if namespace }}<tr>
<td class="name">Namespace</td>
<td class="name" data-l10n>Namespace</td>
<td class="value">{{ namespace }}</td>
</tr>{{ end -}}
{{- if ingress_name }}<tr>
<td class="name">Ingress name</td>
<td class="name" data-l10n>Ingress name</td>
<td class="value">{{ ingress_name }}</td>
</tr>{{ end -}}
{{- if service_name }}<tr>
<td class="name">Service name</td>
<td class="name" data-l10n>Service name</td>
<td class="value">{{ service_name }}</td>
</tr>{{ end -}}
{{- if service_port }}<tr>
<td class="name">Service port</td>
<td class="name" data-l10n>Service port</td>
<td class="value">{{ service_port }}</td>
</tr>{{ end -}}
{{- if request_id }}<tr>
<td class="name">Request ID</td>
<td class="name" data-l10n>Request ID</td>
<td class="value">{{ request_id }}</td>
</tr>{{ end -}}
<tr>
<td class="name">Timestamp</td>
<td class="name" data-l10n>Timestamp</td>
<td class="value">{{ now.Unix }}</td>
</tr>
</table>
@ -81,6 +81,18 @@
{{ end }}
</div>
</div>
<script>
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}

View File

@ -12,7 +12,9 @@
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<style>
html,body {background-color:#fff;color:#636b6f;font-family:'Nunito',sans-serif;font-weight:100;height:100vh;margin:0;font-size:0}
:root {--color-bg-primary:#fff;--color-text-primary:#636b6f;--color-text-secondary:#777}
@media (prefers-color-scheme: dark) {:root {--color-bg-primary:#222526;--color-text-primary:#fff;--color-text-secondary:#999}}
html,body {background-color:var(--color-bg-primary);color:var(--color-text-primary);font-family:'Nunito',sans-serif;font-weight:100;height:100vh;margin:0;font-size:0}
.full-height {height:100vh}
.flex-center {align-items:center;display:flex;justify-content:center}
.position-ref {position:relative}
@ -20,7 +22,7 @@
.message {font-size:18px;text-align:center;padding:10px}
/* {{ if show_details }} */
.details table {width:100%;border-collapse:collapse;box-sizing:border-box;margin-top:20px}
.details td {font-size:11px;color:#777}
.details td {font-size:11px;color:var(--color-text-secondary)}
.details td.name {text-align:right;padding-right:.6em;width:50%;border-right:2px solid;border-color:#aaa}
.details td.value {text-align:left;padding-left:.6em;font-family:'Lucida Console','Courier New',monospace}
/* {{ end }} */
@ -33,7 +35,7 @@
<div class="code">
{{ code }}
</div>
<div class="message">
<div class="message" data-l10n>
{{ message }}
</div>
</div>
@ -41,39 +43,39 @@
<div class="details">
<table>
{{- if host }}<tr>
<td class="name">Host</td>
<td class="name" data-l10n>Host</td>
<td class="value">{{ host }}</td>
</tr>{{ end -}}
{{- if original_uri }}<tr>
<td class="name">Original URI</td>
<td class="name" data-l10n>Original URI</td>
<td class="value">{{ original_uri }}</td>
</tr>{{ end -}}
{{- if forwarded_for }}<tr>
<td class="name">Forwarded for</td>
<td class="name" data-l10n>Forwarded for</td>
<td class="value">{{ forwarded_for }}</td>
</tr>{{ end -}}
{{- if namespace }}<tr>
<td class="name">Namespace</td>
<td class="name" data-l10n>Namespace</td>
<td class="value">{{ namespace }}</td>
</tr>{{ end -}}
{{- if ingress_name }}<tr>
<td class="name">Ingress name</td>
<td class="name" data-l10n>Ingress name</td>
<td class="value">{{ ingress_name }}</td>
</tr>{{ end -}}
{{- if service_name }}<tr>
<td class="name">Service name</td>
<td class="name" data-l10n>Service name</td>
<td class="value">{{ service_name }}</td>
</tr>{{ end -}}
{{- if service_port }}<tr>
<td class="name">Service port</td>
<td class="name" data-l10n>Service port</td>
<td class="value">{{ service_port }}</td>
</tr>{{ end -}}
{{- if request_id }}<tr>
<td class="name">Request ID</td>
<td class="name" data-l10n>Request ID</td>
<td class="value">{{ request_id }}</td>
</tr>{{ end -}}
<tr>
<td class="name">Timestamp</td>
<td class="name" data-l10n>Timestamp</td>
<td class="value">{{ now.Unix }}</td>
</tr>
</table>
@ -81,6 +83,18 @@
{{ end }}
</div>
</div>
<script>
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}

View File

@ -0,0 +1,398 @@
<!DOCTYPE html>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow"/>
<title>{{ message }}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito+Sans" rel="stylesheet">
<style>
/** Codepen: https://codepen.io/kdbkapsere/pen/oNXLbqQ */
:root {
--color-bg-primary: #fff;
--color-text-primary: #0e0620;
--color-ui-bg-primary: #0e0620;
--color-ui-bg-inverted: #fff;
}
@media (prefers-color-scheme: dark) {
:root {
--color-bg-primary: #212121;
--color-text-primary: #fafafa;
--color-ui-bg-primary: #fafafa;
--color-ui-bg-inverted: #212121;
}
}
html,
body {
height: 100%;
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
font-family: 'Nunito Sans', sans-serif;
margin: 0;
padding: 0;
font-size: 0;
}
body {
align-items: center;
display: flex;
justify-content: center;
height: 100vh;
}
main {
width: 100%;
max-width: 1140px;
display: flex;
justify-content: space-between;
}
.picture, .content {
box-sizing: border-box;
width: 50%;
}
.content {
padding: 0 40px;
}
svg .dark {
stroke: var(--color-ui-bg-primary);
}
svg .fill-dark {
fill: var(--color-ui-bg-primary);
}
svg .fill-light {
fill: var(--color-ui-bg-inverted);
}
h1 {
font-size: 150px;
margin: 15px 0;
font-weight: bold;
}
h2 {
font-size: 32px;
font-weight: bold;
}
p {
font-size: 16px;
}
/* {{ if show_details }} */
.details {
list-style: none;
padding-left: 0;
opacity: .7;
}
.details li span {
font-size: 14px;
font-weight: bold;
}
.details li code {
font-size: 14px;
font-weight: normal;
padding-left: 7px;
}
/* {{ end }} */
@media screen and (max-width: 768px) {
main {
display: block;
}
.picture, .content {
width: 100%;
text-align: center;
}
.content {
padding: 0 20px;
}
.picture svg {
max-width: 60%;
}
}
</style>
</head>
<body>
<main>
<div class="picture">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
<g>
<defs>
<clipPath id="GlassClip">
<path
d="M380.857,346.164c-1.247,4.651-4.668,8.421-9.196,10.06c-9.332,3.377-26.2,7.817-42.301,3.5 s-28.485-16.599-34.877-24.192c-3.101-3.684-4.177-8.66-2.93-13.311l7.453-27.798c0.756-2.82,3.181-4.868,6.088-5.13 c6.755-0.61,20.546-0.608,41.785,5.087s33.181,12.591,38.725,16.498c2.387,1.682,3.461,4.668,2.705,7.488L380.857,346.164z"/>
</clipPath>
<clipPath id="cordClip">
<rect width="800" height="600"/>
</clipPath>
</defs>
<g id="planet">
<circle fill="none" stroke-width="3" stroke-miterlimit="10" cx="572.859" cy="108.803"
r="90.788" class="dark" />
<circle id="craterBig" fill="none" stroke-width="3" stroke-miterlimit="10" cx="548.891"
cy="62.319" r="13.074" class="dark"/>
<circle id="craterSmall" fill="none" stroke-width="3" stroke-miterlimit="10" cx="591.743"
cy="158.918" r="7.989" class="dark"/>
<path id="ring" fill="none" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10"
class="dark"
d="M476.562,101.461c-30.404,2.164-49.691,4.221-49.691,8.007c0,6.853,63.166,12.408,141.085,12.408s141.085-5.555,141.085-12.408c0-3.378-15.347-4.988-40.243-7.225"/>
<path id="ringShadow" opacity="0.5" fill="none" class="dark" stroke-width="3"
stroke-linecap="round" stroke-miterlimit="10"
d="M483.985,127.43c23.462,1.531,52.515,2.436,83.972,2.436c36.069,0,68.978-1.19,93.922-3.149"/>
</g>
<g id="stars">
<g id="starsBig">
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="518.07" y1="245.375" x2="518.07" y2="266.581"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="508.129" y1="255.978" x2="528.01" y2="255.978"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="154.55" y1="231.391" x2="154.55" y2="252.598"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="144.609" y1="241.995" x2="164.49" y2="241.995"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="320.135" y1="132.746" x2="320.135" y2="153.952"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="310.194" y1="143.349" x2="330.075" y2="143.349"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="200.67" y1="483.11" x2="200.67" y2="504.316"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="210.611" y1="493.713" x2="190.73" y2="493.713"/>
</g>
</g>
<g id="starsSmall">
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="432.173" y1="380.52" x2="432.173" y2="391.83"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="426.871" y1="386.175" x2="437.474" y2="386.175"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="489.555" y1="299.765" x2="489.555" y2="308.124"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="485.636" y1="303.945" x2="493.473" y2="303.945"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="231.468" y1="291.009" x2="231.468" y2="299.369"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="227.55" y1="295.189" x2="235.387" y2="295.189"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="244.032" y1="547.539" x2="244.032" y2="555.898"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="247.95" y1="551.719" x2="240.113" y2="551.719"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="186.359" y1="406.967" x2="186.359" y2="415.326"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="190.277" y1="411.146" x2="182.44" y2="411.146"/>
</g>
<g>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="480.296" y1="406.967" x2="480.296" y2="415.326"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" x1="484.215" y1="411.146" x2="476.378" y2="411.146"/>
</g>
</g>
<g id="circlesBig">
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="588.977" cy="255.978" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="450.066" cy="320.259" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="168.303" cy="353.753" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="429.522" cy="201.185" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="200.67" cy="176.313" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="133.343" cy="477.014" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="283.521" cy="568.033" r="7.952"/>
<circle fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-miterlimit="10" cx="413.618" cy="482.387" r="7.952"/>
</g>
<g id="circlesSmall">
<circle class="fill-dark" cx="549.879" cy="296.402" r="2.651"/>
<circle class="fill-dark" cx="253.29" cy="229.24" r="2.651"/>
<circle class="fill-dark" cx="434.824" cy="263.931" r="2.651"/>
<circle class="fill-dark" cx="183.708" cy="544.176" r="2.651"/>
<circle class="fill-dark" cx="382.515" cy="530.923" r="2.651"/>
<circle class="fill-dark" cx="130.693" cy="305.608" r="2.651"/>
<circle class="fill-dark" cx="480.296" cy="477.014" r="2.651"/>
</g>
</g>
<g id="spaceman" clip-path="url(cordClip)">
<path id="cord" fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M273.813,410.969c0,0-54.527,39.501-115.34,38.218c-2.28-0.048-4.926-0.241-7.841-0.548c-68.038-7.178-134.288-43.963-167.33-103.87c-0.908-1.646-1.793-3.3-2.654-4.964c-18.395-35.511-37.259-83.385-32.075-118.817"/>
<path id="backpack" class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M338.164,454.689l-64.726-17.353c-11.086-2.972-17.664-14.369-14.692-25.455l15.694-58.537c3.889-14.504,18.799-23.11,33.303-19.221l52.349,14.035c14.504,3.889,23.11,18.799,19.221,33.303l-15.694,58.537C360.647,451.083,349.251,457.661,338.164,454.689z"/>
<g id="antenna">
<line class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" x1="323.396" y1="236.625"
x2="295.285" y2="353.753"/>
<circle class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" cx="323.666" cy="235.617"
r="6.375"/>
</g>
<g id="armR">
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M360.633,363.039c1.352,1.061,4.91,5.056,5.824,6.634l27.874,47.634c3.855,6.649,1.59,15.164-5.059,19.02l0,0c-6.649,3.855-15.164,1.59-19.02-5.059l-5.603-9.663"/>
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M388.762,434.677c5.234-3.039,7.731-8.966,6.678-14.594c2.344,1.343,4.383,3.289,5.837,5.793c4.411,7.596,1.829,17.33-5.767,21.741c-7.596,4.411-17.33,1.829-21.741-5.767c-1.754-3.021-2.817-5.818-2.484-9.046C375.625,437.355,383.087,437.973,388.762,434.677z"/>
</g>
<g id="armL">
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M301.301,347.66c-1.702,0.242-5.91,1.627-7.492,2.536l-47.965,27.301c-6.664,3.829-8.963,12.335-5.134,18.999h0c3.829,6.664,12.335,8.963,18.999,5.134l9.685-5.564"/>
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M241.978,395.324c-3.012-5.25-2.209-11.631,1.518-15.977c-2.701-0.009-5.44,0.656-7.952,2.096c-7.619,4.371-10.253,14.09-5.883,21.71c4.371,7.619,14.09,10.253,21.709,5.883c3.03-1.738,5.35-3.628,6.676-6.59C252.013,404.214,245.243,401.017,241.978,395.324z"/>
</g>
<g id="body">
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M353.351,365.387c-7.948,1.263-16.249,0.929-24.48-1.278c-8.232-2.207-15.586-6.07-21.836-11.14c-17.004,4.207-31.269,17.289-36.128,35.411l-1.374,5.123c-7.112,26.525,8.617,53.791,35.13,60.899l0,0c26.513,7.108,53.771-8.632,60.883-35.158l1.374-5.123C371.778,395.999,365.971,377.536,353.351,365.387z"/>
<path fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M269.678,394.912L269.678,394.912c26.3,20.643,59.654,29.585,93.106,25.724l2.419-0.114"/>
</g>
<g id="legs">
<g id="legR">
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M312.957,456.734l-14.315,53.395c-1.896,7.07,2.299,14.338,9.37,16.234l0,0c7.07,1.896,14.338-2.299,16.234-9.37l17.838-66.534C333.451,455.886,323.526,457.387,312.957,456.734z"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" x1="304.883" y1="486.849"
x2="330.487" y2="493.713"/>
</g>
<g id="legL">
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M296.315,452.273L282,505.667c-1.896,7.07-9.164,11.265-16.234,9.37l0,0c-7.07-1.896-11.265-9.164-9.37-16.234l17.838-66.534C278.993,441.286,286.836,447.55,296.315,452.273z"/>
<line fill="none" class="dark" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" x1="262.638" y1="475.522"
x2="288.241" y2="482.387"/>
</g>
</g>
<g id="head">
<ellipse transform="matrix(0.259 -0.9659 0.9659 0.259 -51.5445 563.2371)"
class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10" cx="341.295" cy="315.211"
rx="61.961" ry="60.305"/>
<path id="headStripe" fill="none" class="dark" stroke-width="3"
stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"
d="M330.868,261.338c-7.929,1.72-15.381,5.246-21.799,10.246"/>
<path class="dark fill-light" stroke-width="3" stroke-linecap="round"
stroke-linejoin="round" stroke-miterlimit="10"
d="M380.857,346.164c-1.247,4.651-4.668,8.421-9.196,10.06c-9.332,3.377-26.2,7.817-42.301,3.5s-28.485-16.599-34.877-24.192c-3.101-3.684-4.177-8.66-2.93-13.311l7.453-27.798c0.756-2.82,3.181-4.868,6.088-5.13c6.755-0.61,20.546-0.608,41.785,5.087s33.181,12.591,38.725,16.498c2.387,1.682,3.461,4.668,2.705,7.488L380.857,346.164z"/>
<g clip-path="url(#GlassClip)">
<polygon id="glassShine" fill="none" class="dark" stroke-width="3"
stroke-miterlimit="10"
points="278.436,375.599 383.003,264.076 364.393,251.618 264.807,364.928 "/>
</g>
</g>
</g>
</g>
</svg>
</div>
<div class="content">
<h1>{{ code }}</h1>
<h2><span data-l10n>UH OH</span>! <span data-l10n>{{ message }}</span></h2>
<p data-l10n>{{ description }}</p>
{{ if show_details }}
<ul class="details">
{{- if host }}<li><span><span data-l10n>Host</span>:</span> <code>{{ host }}</code></li>{{ end -}}
{{- if original_uri }}<li><span><span data-l10n>Original URI</span>:</span> <code>{{ original_uri }}</code></li>{{ end -}}
{{- if forwarded_for }}<li><span><span data-l10n>Forwarded for</span>:</span> <code>{{ forwarded_for }}</code></li>{{ end -}}
{{- if namespace }}<li><span><span data-l10n>Namespace</span>:</span> <code>{{ namespace }}</code></li>{{ end -}}
{{- if ingress_name }}<li><span><span data-l10n>Ingress name</span>:</span> <code>{{ ingress_name }}</code></li>{{ end -}}
{{- if service_name }}<li><span><span data-l10n>Service name</span>:</span> <code>{{ service_name }}</code></li>{{ end -}}
{{- if service_port }}<li><span><span data-l10n>Service port</span>:</span> <code>{{ service_port }}</code></li>{{ end -}}
{{- if request_id }}<li><span><span data-l10n>Request ID</span>:</span> <code>{{ request_id }}</code></li>{{ end -}}
<li><span><span data-l10n>Timestamp</span>:</span> <code>{{ now.Unix }}</code></li>
</ul>
{{ end }}
</div>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"
integrity="sha512-H6cPm97FAsgIKmlBA4s774vqoN24V5gSQL4yBTDOY2su2DeXZVhQPxFK4P6GPdnZqM9fg1G3cMv5wD7e6cFLZQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
/** @var {object} gsap is a library for building high-performance animations */
if (typeof gsap === 'object') {
gsap.set("svg", {visibility: "visible"});
gsap.to("#headStripe", {y: 0.5, rotation: 1, yoyo: true, repeat: -1, ease: "sine.inOut", duration: 1});
gsap.to("#spaceman", {y: 0.5, rotation: 1, yoyo: true, repeat: -1, ease: "sine.inOut", duration: 1});
gsap.to("#craterSmall", {x: -3, yoyo: true, repeat: -1, duration: 1, ease: "sine.inOut"});
gsap.to("#craterBig", {x: 3, yoyo: true, repeat: -1, duration: 1, ease: "sine.inOut"});
gsap.to("#planet", {rotation: -2, yoyo: true, repeat: -1, duration: 1, ease: "sine.inOut", transformOrigin: "50% 50%"});
gsap.to("#starsBig g", {rotation: "random(-30,30)", transformOrigin: "50% 50%", yoyo: true, repeat: -1, ease: "sine.inOut"});
gsap.fromTo("#starsSmall g", {scale: 0, transformOrigin: "50% 50%"}, {scale: 1, transformOrigin: "50% 50%", yoyo: true, repeat: -1, stagger: 0.1});
gsap.to("#circlesSmall circle", {y: -4, yoyo: true, duration: 1, ease: "sine.inOut", repeat: -1});
gsap.to("#circlesBig circle", {y: -2, yoyo: true, duration: 1, ease: "sine.inOut", repeat: -1});
gsap.set("#glassShine", {x: -68});
gsap.to("#glassShine", {x: 80, duration: 2, rotation: -30, ease: "expo.inOut", transformOrigin: "50% 50%", repeat: -1, repeatDelay: 8, delay: 2});
} else {
console.warn('gsap library is not initialized (network error?)')
}
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
</html>

281
templates/matrix.html Normal file
View File

@ -0,0 +1,281 @@
<!DOCTYPE html>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{{ message }} ({{ code }})</title>
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<style>
:root{--matrix-glyph-size:15px;--matrix-glyph-font-size:15px;--matrix-glyph-front-color:rgba(255, 255, 255, 0.8);--matrix-glyph-tail-color:#0f0;--matrix-overlay-color:rgba(0, 0, 0, 0.12)}
body,html{margin:0;padding:0;background-color:#000;height:100vh}
#matrix{display:block;position:fixed;width:100vw;height:100vh}
.container{align-items:center;display:flex;justify-content:center;position:absolute;top:0;left:0;width:100vw;height:100vh;z-index:1}
.container .message{background-color:rgba(0,0,0,.85);border:2px solid var(--matrix-glyph-tail-color);padding:15px 20px;margin:0 20px;font-family:Inconsolata,Helvetica,sans-serif;text-align:center;font-size:0;color:var(--matrix-glyph-tail-color);text-shadow:1px 0 2px var(--matrix-glyph-tail-color),-1px 0 2px var(--matrix-glyph-tail-color);box-shadow:1px 0 5px var(--matrix-glyph-tail-color),-1px 0 2px var(--matrix-glyph-tail-color);max-width:640px}
.container .message h1{margin:0;font-size:52px}
.container .message p{margin:.3em 0 0 0;font-size:17px;color:var(--matrix-glyph-front-color)}
/* {{ if show_details }} */
.container .details{margin-top:20px}
.container .details ul{padding:0}
.container .details code,.container .details span{font-size:11px}
.container .details code{padding-left:7px}
/* {{ end }} */
.hidden {display:none}
@media screen and (max-width:820px){
:root{--matrix-glyph-size:10px;--matrix-glyph-font-size:10px}
.container .message h1{font-size:38px}
.container .message p{font-size:13px}
/* {{ if show_details }} */
.container .details code,.container .details span{font-size:11px}
/* {{ end }} */
}
</style>
</head>
<body>
<div class="container">
<ul id="matrix-words" class="hidden">
<li>{{ code }}</li>
<li>{{ message }}</li>
<li>{{ description }}</li>
<li>{{ code }} {{ message }}</li>
</ul>
<div class="message">
<h1>{{ code }}: <span data-l10n>{{ message }}</span></h1>
<p data-l10n>{{ description }}</p>
{{ if show_details }}
<div class="details">
<ul>
{{- if host }}<li><span><span data-l10n>Host</span>:</span> <code>{{ host }}</code></li>{{ end -}}
{{- if original_uri }}<li><span><span data-l10n>Original URI</span>:</span> <code>{{ original_uri }}</code></li>{{ end -}}
{{- if forwarded_for }}<li><span><span data-l10n>Forwarded for</span>:</span> <code>{{ forwarded_for }}</code></li>{{ end -}}
{{- if namespace }}<li><span><span data-l10n>Namespace</span>:</span> <code>{{ namespace }}</code></li>{{ end -}}
{{- if ingress_name }}<li><span><span data-l10n>Ingress name</span>:</span> <code>{{ ingress_name }}</code></li>{{ end -}}
{{- if service_name }}<li><span><span data-l10n>Service name</span>:</span> <code>{{ service_name }}</code></li>{{ end -}}
{{- if service_port }}<li><span><span data-l10n>Service port</span>:</span> <code>{{ service_port }}</code></li>{{ end -}}
{{- if request_id }}<li><span><span data-l10n>Request ID</span>:</span> <code>{{ request_id }}</code></li>{{ end -}}
<li><span><span data-l10n>Timestamp</span>:</span> <code>{{ now.Unix }}</code></li>
</ul>
</div>
{{ end }}
</div>
</div>
<canvas id="matrix"></canvas>
<script>
'use strict';
/**
* @param {HTMLCanvasElement} $canvas
* @constructor
*/
const Matrix = function ($canvas) {
const symbols = 'ラドクリフマラソンわたしワタシんょンョたばこタバコとうきょうトウキョウ '.split('');
/**
* @return {string}
*/
const getRandomSymbol = function () {
return symbols[Math.floor(Math.random() * symbols.length)];
}
const ctx = $canvas.getContext('2d');
ctx.globalCompositeOperation = 'lighter'; // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
this.redrawInterval = 90; // fade oud speed
this.glyphSize = 0;
this.rowsCapacity = 0;
this.columnsCapacity = 0;
/**
* @return {void}
*/
this.init = () => {
$canvas.width = $canvas.clientWidth;
$canvas.height = $canvas.clientHeight;
this.glyphSize = parseInt(getComputedStyle($canvas).getPropertyValue('--matrix-glyph-size'), 10);
this.rowsCapacity = Math.ceil($canvas.clientHeight / this.glyphSize);
this.columnsCapacity = Math.ceil($canvas.clientWidth / this.glyphSize);
};
/**
* @param {string} symbol
* @param {number} row
* @param {number} column
* @param {string} color
*/
const drawSymbol = (symbol, row, column, color) => {
if (row > this.rowsCapacity || column > this.columnsCapacity) {
return;
}
ctx.fillStyle = color;
ctx.font = getComputedStyle($canvas).getPropertyValue('--matrix-glyph-font-size') + ' monospace';
if (symbol.length > 1) {
symbol = symbol.charAt(0); // only one char is allowed
}
let xOffset = 0, charCode = symbol.charCodeAt(0);
if (charCode >= 33 && charCode <= 126) { // is ascii
xOffset = this.glyphSize / 5;
}
ctx.fillText(symbol, (column * this.glyphSize) + xOffset, row * this.glyphSize);
};
/**
* @param {number} column
* @param {number} speed Lowest = fastest, largest = slowest
* @param {string?} text
* @param {number?} offset
*/
const drawLine = (column, speed, text, offset) => {
let cursor = 0;
const tailColor = getComputedStyle($canvas).getPropertyValue('--matrix-glyph-tail-color'),
frontColor = getComputedStyle($canvas).getPropertyValue('--matrix-glyph-front-color');
const handler = window.setInterval(() => {
if (column > this.columnsCapacity) {
return window.clearInterval(handler);
}
if (cursor <= this.rowsCapacity) {
let symbol = getRandomSymbol();
if (typeof text === 'string' && typeof offset === 'number') {
if (cursor >= offset && text.length >= cursor - offset) {
symbol = text.charAt(cursor - offset);
}
}
if (typeof symbol === 'string' && symbol !== ' ') {
const prev = cursor;
window.setTimeout(() => { // redraw with a green color
drawSymbol(symbol, prev, column, tailColor);
}, speed / 1.3);
drawSymbol(symbol, cursor, column, frontColor); // white color first
}
cursor++;
} else {
window.clearInterval(handler);
}
}, speed);
};
/**
* @return {void}
*/
this.redraw = () => {
ctx.fillStyle = getComputedStyle($canvas).getPropertyValue('--matrix-overlay-color');
ctx.fillRect(0, 0, $canvas.clientWidth, $canvas.clientHeight);
};
let redrawIntervalHandler = undefined, dropsIntervalHandler = undefined;
/**
* @param {HTMLUListElement?} $linesList
*/
this.run = ($linesList) => {
if (redrawIntervalHandler === undefined) {
redrawIntervalHandler = window.setInterval(this.redraw, this.redrawInterval);
}
if (dropsIntervalHandler === undefined) {
const fn = () => {
const randomColumn = Math.floor(Math.random() * (this.columnsCapacity + 1)),
minSpeed = 200, maxSpeed = 50,
randomSpeed = Math.floor(Math.random() * (maxSpeed - minSpeed + 1)) + minSpeed;
const list = [];
let line = undefined, offset = undefined;
if ($linesList !== undefined) {
Array.prototype.forEach.call($linesList.querySelectorAll('li'), $li => {
const text = $li.innerText.trim();
if (text.length > 0) {
list.push(text);
}
});
if (list.length > 0 && Math.random() > 0.4) {
line = list[Math.floor(Math.random() * list.length)];
offset = Math.floor(Math.random() * line.length);
if (offset <= 5) {
offset *= 3;
}
}
}
drawLine(randomColumn, randomSpeed, line, offset);
if (dropsIntervalHandler !== undefined) {
window.clearInterval(dropsIntervalHandler);
dropsIntervalHandler = undefined;
}
dropsIntervalHandler = window.setInterval(fn, ((minSpeed + maxSpeed) / 2 * this.rowsCapacity) / this.columnsCapacity / 0.5);
};
fn();
}
};
/**
* @return {void}
*/
this.stop = () => {
if (redrawIntervalHandler !== undefined) {
window.clearInterval(redrawIntervalHandler);
redrawIntervalHandler = undefined;
}
if (dropsIntervalHandler !== undefined) {
window.clearInterval(dropsIntervalHandler);
dropsIntervalHandler = undefined;
}
};
if (typeof ResizeObserver === 'function') {
(new ResizeObserver(this.init)).observe($canvas);
} else {
this.init();
}
};
(new Matrix(document.getElementById('matrix'))).run(document.getElementById('matrix-words'));
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--
Error {{ code }}: {{ message }}
Description: {{ description }}
-->
</html>

View File

@ -130,7 +130,7 @@
<div class="container-center">
<div>
<h1>{{ code }}</h1>
<h2>{{ description }}</h2>
<h2 data-l10n>{{ description }}</h2>
</div>
</div>
@ -174,6 +174,17 @@
window.addEventListener('beforeunload', function (/** @param BeforeUnloadEvent event */ event) {
window.clearInterval(flickerInterval);
});
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--

View File

@ -1 +1,39 @@
# TODO: Write docs
# Templates
Creating templates is a very simple operation, even for those who know nothing at all about [Go Template](https://pkg.go.dev/text/template). All you should know is:
- The template should be one page. Without additional `css` or `js` files (but you can load them from the CDN or another GitHub repositories using [jsdelivr.com](https://www.jsdelivr.com/), for example)
- Don't forget to include `<meta name="robots" content="noindex, nofollow" />` tag in the header
- You can use a special "placeholders" (wrapped in `{{` and `}}`) for the rendering error code, message and others (see details below)
## Supported signatures
### Error page & request data
| Signature | Description | Example |
|--------------------------------------|---------------------------------------------------------------|----------------------------------------------|
| `{{ code }}` | Error page code | `404` |
| `{{ message }}` | Error code message | `Not found` |
| `{{ description }}` | Error code description | `The server can not find the requested page` |
| `{{ original_uri }}` | `X-Original-URI` header value | `/foo1/bar2` |
| `{{ namespace }}` | `X-Namespace` header value | `foo` |
| `{{ ingress_name }}` | `X-Ingress-Name` header value | `bar` |
| `{{ service_name }}` | `X-Service-Name` header value | `baz` |
| `{{ service_port }}` | `X-Service-Port` header value | `8080` |
| `{{ request_id }}` | `X-Request-ID` header value | `12AB34CD56EF78` |
| `{{ forwarded_for }}` | `X-Forwarded-For` header value | `203.0.113.195, 70.41.3.18` |
| `{{ host }}` | `Host` header value | `example.com` |
| `{{ now.Unix }}` | Current timestamp (e.g. in Unix format) | `1643621927` |
| `{{ hostname }}` | OS hostname | `ab12cd34ef56` |
| `{{ version }}` | Application version | `2.5.0` |
| `{{ if show_details }}...{{ end }}` | Logical operator (server started with "show details" option?) | |
| `{{ if hide_details }}...{{ end }}` | Same as above, but inverted | |
| `{{ if l10n_enabled }}...{{ end }}` | Logical operator (l10n is enabled?) | |
| `{{ if l10n_disabled }}...{{ end }}` | Same as above, but inverted | |
### Modifiers
| Signature | Description | Example |
|------------------------------------|--------------------------------|-------------------------------------|
| <code>{{ ... &#124; json }}</code> | Convert value into json-string | <code>{{ code &#124; json }}</code> |
| <code>{{ ... &#124; int }}</code> | Convert value into integer | <code>{{ code &#124; int }}</code> |

View File

@ -72,60 +72,63 @@
<body>
<div class="flex-center full-height">
<div>
<span id="error_text">{{ code }}: {{ message }}</span>
<div id="error_text">
<span class="source">{{ code }}: <span data-l10n>{{ message }}</span></span>
<span class="target"></span>
</div>
{{ if show_details }}
<div class="hidden" id="details">
<table>
{{- if host }}
<tr>
<td class="name">Host:</td>
<td class="name"><span data-l10n>Host</span>:</td>
<td class="value">{{ host }}</td>
</tr>
{{ end -}}
{{- if original_uri }}
<tr>
<td class="name">Original URI:</td>
<td class="name"><span data-l10n>Original URI</span>:</td>
<td class="value">{{ original_uri }}</td>
</tr>
{{ end -}}
{{- if forwarded_for }}
<tr>
<td class="name">Forwarded for:</td>
<td class="name"><span data-l10n>Forwarded for</span>:</td>
<td class="value">{{ forwarded_for }}</td>
</tr>
{{ end -}}
{{- if namespace }}
<tr>
<td class="name">Namespace:</td>
<td class="name"><span data-l10n>Namespace</span>:</td>
<td class="value">{{ namespace }}</td>
</tr>
{{ end -}}
{{- if ingress_name }}
<tr>
<td class="name">Ingress name:</td>
<td class="name"><span data-l10n>Ingress name</span>:</td>
<td class="value">{{ ingress_name }}</td>
</tr>
{{ end -}}
{{- if service_name }}
<tr>
<td class="name">Service name:</td>
<td class="name"><span data-l10n>Service name</span>:</td>
<td class="value">{{ service_name }}</td>
</tr>
{{ end -}}
{{- if service_port }}
<tr>
<td class="name">Service port:</td>
<td class="name"><span data-l10n>Service port</span>:</td>
<td class="value">{{ service_port }}</td>
</tr>
{{ end -}}
{{- if request_id }}
<tr>
<td class="name">Request ID:</td>
<td class="name"><span data-l10n>Request ID</span>:</td>
<td class="value">{{ request_id }}</td>
</tr>
{{ end -}}
<tr>
<td class="name">Timestamp:</td>
<td class="name"><span data-l10n>Timestamp</span>:</td>
<td class="value">{{ now.Unix }}</td>
</tr>
</table>
@ -137,24 +140,74 @@
<script>
'use strict';
const $errorText = document.getElementById('error_text'),
text = $errorText.innerText,
characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=+<>,./?[{()}]!@#$%^&*~`\|'.split('');
let progress = 0;
/**
* @param {HTMLElement} $el
*/
const Shuffle = function ($el) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=+<>,./?[{()}]!@#$%^&*~`\|'.split(''),
$source = $el.querySelector('.source'), $target = $el.querySelector('.target');
const scrambleInterval = window.setInterval(function () {
let newText = text;
let cursor = 0, scrambleInterval = undefined, cursorDelayInterval = undefined, cursorInterval = undefined;
for (let i = 0; i < text.length; i++) {
if (i >= progress) {
newText = newText.substr(0, i) +
characters[Math.round(Math.random() * (characters.length - 1))] +
newText.substr(i + 1);
/**
* @param {Number} len
* @return {string}
*/
const getRandomizedString = function (len) {
let s = '';
for (let i = 0; i < len; i++) {
s += chars[Math.floor(Math.random() * chars.length)];
}
}
$errorText.innerText = newText;
}, 450 / 60);
return s;
};
this.start = function () {
$source.style.display = 'none';
$target.style.display = 'block';
scrambleInterval = window.setInterval(() => {
if (cursor <= $source.innerText.length) {
$target.innerText = $source.innerText.substring(0, cursor) + getRandomizedString($source.innerText.length - cursor);
}
}, 450 / 30);
cursorDelayInterval = window.setTimeout(() => {
cursorInterval = window.setInterval(() => {
if (cursor > $source.innerText.length - 1) {
this.stop();
}
cursor++;
}, 70);
}, 350);
};
this.stop = function () {
$source.style.display = 'block';
$target.style.display = 'none';
$target.innerText = '';
cursor = 0;
if (scrambleInterval !== undefined) {
window.clearInterval(scrambleInterval);
scrambleInterval = undefined;
}
if (cursorInterval !== undefined) {
window.clearInterval(cursorInterval);
cursorInterval = undefined;
}
if (cursorDelayInterval !== undefined) {
window.clearInterval(cursorDelayInterval);
cursorDelayInterval = undefined;
}
};
};
(new Shuffle(document.getElementById('error_text'))).start();
// {{ if show_details }}
window.setTimeout(function () {
@ -162,16 +215,16 @@
}, 550);
// {{ end }}
window.setTimeout(function () {
let revealInterval = window.setInterval(function () {
if (progress < text.length) {
progress++;
} else {
window.clearInterval(revealInterval);
window.clearInterval(scrambleInterval);
}
}, 70);
}, 350);
// {{ if l10n_enabled }}
if (navigator.language.substring(0, 2).toLowerCase() !== 'en') {
((s, p) => { // localize the page (details here - https://github.com/tarampampam/error-pages/tree/master/l10n)
s.src = 'https://cdn.jsdelivr.net/gh/tarampampam/error-pages@2/l10n/l10n.min.js'; // '../l10n/l10n.js';
s.async = s.defer = true;
s.addEventListener('load', () => p.removeChild(s));
p.appendChild(s);
})(document.createElement('script'), document.body);
}
// {{ end }}
</script>
</body>
<!--

View File

@ -0,0 +1,13 @@
GET http://{{ host }}:{{ port }}/502.html
X-Foo: foo
bar: BAR
Baz_blah: baz Baz
NonEx: skip
HTTP/* 200
[Asserts]
header "X-Foo" == "foo"
header "Bar" == "BAR"
header "Baz_blah" == "baz Baz"
header "NonEx" not exists