From 8a68ece2cc9476031548453126ef60e4e687d73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rald=20Cro=C3=ABs?= Date: Mon, 3 Jul 2023 15:10:05 +0200 Subject: [PATCH 01/12] Update maintainers guidelines --- docs/content/contributing/maintainers-guidelines.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/content/contributing/maintainers-guidelines.md b/docs/content/contributing/maintainers-guidelines.md index 049bd92e8..9f6fc5cd3 100644 --- a/docs/content/contributing/maintainers-guidelines.md +++ b/docs/content/contributing/maintainers-guidelines.md @@ -70,7 +70,7 @@ but we can suggest you start with activities such as: ## Communicating -- All of our maintainers are added to Slack #traefik-maintainers channel that belongs to Traefik labs workspace. +- All of our maintainers are added to the Traefik Maintainers Discord server that belongs to Traefik labs. Having the team in one place helps us to communicate effectively. You can reach Traefik core developers directly, which offers the possibility to discuss issues, pull requests, enhancements more efficiently @@ -83,13 +83,13 @@ but we can suggest you start with activities such as: activities related to the reported issues and PR’s, other important project-related announcements. -- At 5:00 PM CET every day we review all the created issues that have been reported, +- At 2:15pm CET every Monday and Thursday we review all the created issues that have been reported, assign them the appropriate *[labels](maintainers.md#labels)* and prioritize them based on the severity of the problem. The process is called *[issue triaging](https://github.com/traefik/contributors-guide/blob/master/issue_triage.md)*. Each of the maintainers is welcome to join the meeting. - For that purpose, we use a dedicated Discord server - where you are invited once you have become the official maintainer. + For that purpose, we use the Traefik Maintainers Discord server + where you are invited once you have become an official maintainer. ## Maintainers Activity From aaa763b7afe7f3ad571e63942cd0b2f654227c34 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 10 Jul 2023 13:48:05 +0200 Subject: [PATCH 02/12] Upgrade docs build stack --- docs/check.Dockerfile | 14 ++++++-------- docs/content/https/acme.md | 2 +- docs/content/migration/v1-to-v2.md | 4 ++-- docs/content/providers/docker.md | 2 ++ docs/scripts/verify.sh | 9 ++++----- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/check.Dockerfile b/docs/check.Dockerfile index 92321d109..d33a46af3 100644 --- a/docs/check.Dockerfile +++ b/docs/check.Dockerfile @@ -1,7 +1,8 @@ -FROM alpine:3.14 as alpine +FROM alpine:3.18 as alpine RUN apk --no-cache --no-progress add \ build-base \ + gcompat \ libcurl \ libxml2-dev \ libxslt-dev \ @@ -13,8 +14,8 @@ RUN apk --no-cache --no-progress add \ ruby-json \ zlib-dev -RUN gem install nokogiri --version 1.13.3 --no-document -- --use-system-libraries -RUN gem install html-proofer --version 3.19.3 --no-document -- --use-system-libraries +RUN gem install nokogiri --version 1.15.3 --no-document -- --use-system-libraries +RUN gem install html-proofer --version 5.0.7 --no-document -- --use-system-libraries # After Ruby, some NodeJS YAY! RUN apk --no-cache --no-progress add \ @@ -22,12 +23,9 @@ RUN apk --no-cache --no-progress add \ nodejs \ npm -# To handle 'not get uid/gid' -RUN npm config set unsafe-perm true - RUN npm install --global \ - markdownlint@0.22.0 \ - markdownlint-cli@0.26.0 + markdownlint@0.29.0 \ + markdownlint-cli@0.35.0 # Finally the shell tools we need for later # tini helps to terminate properly all the parallelized tasks when sending CTRL-C diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index 1392092bb..f59142156 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -11,7 +11,7 @@ Automatic HTTPS You can configure Traefik to use an ACME provider (like Let's Encrypt) for automatic certificate generation. !!! warning "Let's Encrypt and Rate Limiting" - Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits). These last up to __one week__, and can not be overridden. + Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits). These last up to **one week**, and can not be overridden. When running Traefik in a container this file should be persisted across restarts. If Traefik requests new certificates each time it starts up, a crash-looping container can quickly reach Let's Encrypt's ratelimits. diff --git a/docs/content/migration/v1-to-v2.md b/docs/content/migration/v1-to-v2.md index 8d93e48f3..849f42b4c 100644 --- a/docs/content/migration/v1-to-v2.md +++ b/docs/content/migration/v1-to-v2.md @@ -23,7 +23,7 @@ feature by feature, of how the configuration looked like in v1, and how it now l - convert `acme.json` file from v1 to v2 format. - migrate the static configuration contained in the file `traefik.toml` to a Traefik v2 file. -## Frontends and Backends Are Dead...
... Long Live Routers, Middlewares, and Services +## Frontends and Backends Are Dead, Long Live Routers, Middlewares, and Services During the transition from v1 to v2, a number of internal pieces and components of Traefik were rewritten and reorganized. As such, the combination of core notions such as frontends and backends has been replaced with the combination of [routers](../routing/routers/index.md), [services](../routing/services/index.md), and [middlewares](../middlewares/overview.md). @@ -542,7 +542,7 @@ To apply a redirection: ## Strip and Rewrite Path Prefixes With the new core notions of v2 (introduced earlier in the section -["Frontends and Backends Are Dead... Long Live Routers, Middlewares, and Services"](#frontends-and-backends-are-dead-long-live-routers-middlewares-and-services)), +["Frontends and Backends Are Dead, Long Live Routers, Middlewares, and Services"](#frontends-and-backends-are-dead-long-live-routers-middlewares-and-services)), transforming the URL path prefix of incoming requests is configured with [middlewares](../middlewares/overview.md), after the routing step with [router rule `PathPrefix`](../routing/routers/index.md#rule). diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index a1472d245..50cfd2a2a 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -254,7 +254,9 @@ services: _Required, Default="unix:///var/run/docker.sock"_ + See the sections [Docker API Access](#docker-api-access) and [Docker Swarm API Access](#docker-api-access_1) for more information. + ??? example "Using the docker.sock" diff --git a/docs/scripts/verify.sh b/docs/scripts/verify.sh index 44835ce79..24eeb4271 100755 --- a/docs/scripts/verify.sh +++ b/docs/scripts/verify.sh @@ -17,12 +17,11 @@ find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \ -name "*.html" -print0 \ | xargs -0 -r -P "${NUMBER_OF_CPUS}" -I '{}' \ htmlproofer \ - --check-html \ + --checks \ --check_external_hash \ - --alt_ignore="/traefikproxy-vertical-logo-color.svg/" \ - --http_status_ignore="0,500,501,503" \ - --file_ignore="/404.html/" \ - --url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/,/hetzner.com/,/docs.github.com/,/njal.la/,/www.wedos.com/,/www.reg.ru/,/www.godaddy.com/,/internetbs.net/" \ + --ignore_status_codes="0,500,501,503" \ + --ignore_files="/404.html/" \ + --ignore_urls="/https://groups.google.com\/a\/traefik.io\/forum\/#!forum\/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/,/hetzner.com/,/docs.github.com/,/njal.la/,/www.wedos.com/,/www.reg.ru/,/www.godaddy.com/,/internetbs.net/" \ '{}' 1>/dev/null ## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration From 2df5defd36f301f1aac58082efa0d93ca2623c04 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 18 Jul 2023 18:22:55 +0200 Subject: [PATCH 03/12] chore: fix PyYAML version --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 3c638f98c..8274f4d68 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -32,7 +32,7 @@ Pygments==2.11.2 pymdown-extensions==7.0 pyparsing==2.4.7 python-dateutil==2.8.2 -PyYAML==6.0 +PyYAML==6.0.1 pyyaml-env-tag==0.1 requests==2.25.1 retrying==1.3.3 From 00048a83511b4eedb05cd0e9e6134e560860330a Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 18 Jul 2023 18:50:05 +0200 Subject: [PATCH 04/12] fix: integration test with Go v1.20.6 --- integration/https_test.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/integration/https_test.go b/integration/https_test.go index 19983faeb..e5009e287 100644 --- a/integration/https_test.go +++ b/integration/https_test.go @@ -1140,6 +1140,7 @@ func (s *HTTPSSuite) TestWithDomainFronting(c *check.C) { desc string hostHeader string serverName string + expectedError bool expectedContent string expectedStatusCode int }{ @@ -1161,6 +1162,7 @@ func (s *HTTPSSuite) TestWithDomainFronting(c *check.C) { desc: "Spaces after the host header", hostHeader: "site3.www.snitest.com ", serverName: "site3.www.snitest.com", + expectedError: true, expectedContent: "server3", expectedStatusCode: http.StatusOK, }, @@ -1175,6 +1177,7 @@ func (s *HTTPSSuite) TestWithDomainFronting(c *check.C) { desc: "Spaces after the servername and host header", hostHeader: "site3.www.snitest.com ", serverName: "site3.www.snitest.com ", + expectedError: true, expectedContent: "server3", expectedStatusCode: http.StatusOK, }, @@ -1223,7 +1226,11 @@ func (s *HTTPSSuite) TestWithDomainFronting(c *check.C) { req.Host = test.hostHeader err = try.RequestWithTransport(req, 500*time.Millisecond, &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true, ServerName: test.serverName}}, try.StatusCodeIs(test.expectedStatusCode), try.BodyContains(test.expectedContent)) - c.Assert(err, checker.IsNil) + if test.expectedError { + c.Assert(err, checker.NotNil) + } else { + c.Assert(err, checker.IsNil) + } } } From 48de3b02309a8f2227c3fff59d0e5f5f2612a2bc Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Wed, 19 Jul 2023 13:34:05 +0300 Subject: [PATCH 05/12] Add support for RISC-V --- .goreleaser.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.goreleaser.yml b/.goreleaser.yml index 9194b4a1e..9892a4747 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -27,6 +27,7 @@ builds: - arm64 - ppc64le - s390x + - riscv64 goarm: - '7' - '6' From e29da5ad659077682f255c000da30dd98a7ccf92 Mon Sep 17 00:00:00 2001 From: Massimiliano D <126668030+mdeliatf@users.noreply.github.com> Date: Wed, 19 Jul 2023 16:56:05 +0200 Subject: [PATCH 06/12] Updates the Hub tooltip content using a web component and adds an option to disable Hub button --- cmd/traefik/traefik.go | 4 + .../reference/static-configuration/cli-ref.md | 3 + .../reference/static-configuration/env-ref.md | 3 + .../reference/static-configuration/file.toml | 1 + .../reference/static-configuration/file.yaml | 1 + pkg/config/static/static_config.go | 7 +- pkg/version/version.go | 19 +-- webui/src/components/_commons/NavBar.vue | 116 ++++++------------ .../src/statics/hub-logo-horizontal-clear.png | Bin 2687 -> 0 bytes .../src/statics/hub-logo-horizontal-dark.png | Bin 2874 -> 0 bytes .../traefiklabs-hub-button-app/main-v1.js | 3 + .../traefiklabs-hub-button-app/main-v1.js.map | 1 + webui/src/store/core/mutations.js | 1 + 13 files changed, 67 insertions(+), 92 deletions(-) delete mode 100644 webui/src/statics/hub-logo-horizontal-clear.png delete mode 100644 webui/src/statics/hub-logo-horizontal-dark.png create mode 100644 webui/src/statics/traefiklabs-hub-button-app/main-v1.js create mode 100644 webui/src/statics/traefiklabs-hub-button-app/main-v1.js.map diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index 2c198abf1..d9607347e 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -205,6 +205,10 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err log.WithoutContext().Warn("Traefik Pilot has been removed.") } + if staticConfiguration.API != nil { + version.DisableDashboardAd = staticConfiguration.API.DisableDashboardAd + } + // Plugins pluginBuilder, err := createPluginBuilder(staticConfiguration) diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index e9385b08b..fbc3eb389 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -45,6 +45,9 @@ Activate dashboard. (Default: ```true```) `--api.debug`: Enable additional endpoints for debugging and profiling. (Default: ```false```) +`--api.disabledashboardad`: +Disable ad in the dashboard. (Default: ```false```) + `--api.insecure`: Activate API directly on the entryPoint named traefik. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index 184c4202b..9f59741ce 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -45,6 +45,9 @@ Activate dashboard. (Default: ```true```) `TRAEFIK_API_DEBUG`: Enable additional endpoints for debugging and profiling. (Default: ```false```) +`TRAEFIK_API_DISABLEDASHBOARDAD`: +Disable ad in the dashboard. (Default: ```false```) + `TRAEFIK_API_INSECURE`: Activate API directly on the entryPoint named traefik. (Default: ```false```) diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index ca95739c9..a4698a6f5 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -265,6 +265,7 @@ insecure = true dashboard = true debug = true + disabledashboardad = false [metrics] [metrics.prometheus] diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index c3b6e830c..3d2ee7c88 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -292,6 +292,7 @@ api: insecure: true dashboard: true debug: true + disabledashboardad: false metrics: prometheus: buckets: diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 9bdb43730..e3419fd7a 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -104,9 +104,10 @@ type ServersTransport struct { // API holds the API configuration. type API struct { - Insecure bool `description:"Activate API directly on the entryPoint named traefik." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` - Dashboard bool `description:"Activate dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty" export:"true"` - Debug bool `description:"Enable additional endpoints for debugging and profiling." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"` + Insecure bool `description:"Activate API directly on the entryPoint named traefik." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` + Dashboard bool `description:"Activate dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty" export:"true"` + Debug bool `description:"Enable additional endpoints for debugging and profiling." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"` + DisableDashboardAd bool `description:"Disable ad in the dashboard." json:"disableDashboardAd,omitempty" toml:"disableDashboardAd,omitempty" yaml:"disableDashboardAd,omitempty" export:"true"` // TODO: Re-enable statistics // Statistics *types.Statistics `description:"Enable more detailed statistics." json:"statistics,omitempty" toml:"statistics,omitempty" yaml:"statistics,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"` } diff --git a/pkg/version/version.go b/pkg/version/version.go index 49b4f9e1e..d9ede515f 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -22,7 +22,8 @@ var ( BuildDate = "I don't remember exactly" // StartDate holds the start date of traefik. StartDate = time.Now() - // UUID instance uuid. + // DisableDashboardAd disables ad in the dashboard. + DisableDashboardAd = false ) // Handler expose version routes. @@ -37,14 +38,16 @@ func (v Handler) Append(router *mux.Router) { router.Methods(http.MethodGet).Path("/api/version"). HandlerFunc(func(response http.ResponseWriter, request *http.Request) { v := struct { - Version string - Codename string - StartDate time.Time `json:"startDate"` - UUID string `json:"uuid,omitempty"` + Version string + Codename string + StartDate time.Time `json:"startDate"` + UUID string `json:"uuid,omitempty"` + DisableDashboardAd bool `json:"disableDashboardAd,omitempty"` }{ - Version: Version, - Codename: Codename, - StartDate: StartDate, + Version: Version, + Codename: Codename, + StartDate: StartDate, + DisableDashboardAd: DisableDashboardAd, } if err := templatesRenderer.JSON(response, http.StatusOK, v); err != nil { diff --git a/webui/src/components/_commons/NavBar.vue b/webui/src/components/_commons/NavBar.vue index 854ff8ea1..4e1a02d46 100644 --- a/webui/src/components/_commons/NavBar.vue +++ b/webui/src/components/_commons/NavBar.vue @@ -30,12 +30,9 @@
-
- -
-

Extend your capabilities to API Management

- -
+
+ +
@@ -89,14 +86,41 @@ export default { }, name () { return config.productName + }, + disableDashboardAd () { + return this.coreVersion.disableDashboardAd + } + }, + data () { + return { + hasHubButtonComponent: false } }, methods: { - ...mapActions('core', { getVersion: 'getVersion' }), - getHubLogoSrc (isDarkMode) { - return isDarkMode - ? 'statics/hub-logo-horizontal-dark.png' - : 'statics/hub-logo-horizontal-clear.png' + ...mapActions('core', { getVersion: 'getVersion' }) + }, + watch: { + disableDashboardAd (newValue) { + if (!newValue && customElements.get('hub-button-app') === undefined) { + const hubButtonScript = document.createElement('script') + hubButtonScript.async = true + hubButtonScript.onerror = () => { + const hubButtonScriptLocal = document.createElement('script') + hubButtonScriptLocal.async = true + hubButtonScriptLocal.onload = () => { + this.hasHubButtonComponent = customElements.get('hub-button-app') !== undefined + } + // Sources: https://github.com/traefik/traefiklabs-hub-button-app + hubButtonScriptLocal.src = 'statics/traefiklabs-hub-button-app/main-v1.js' + document.head.appendChild(hubButtonScriptLocal) + } + hubButtonScript.onload = () => { + this.hasHubButtonComponent = customElements.get('hub-button-app') !== undefined + } + // Sources: https://github.com/traefik/traefiklabs-hub-button-app + hubButtonScript.src = 'https://traefik.github.io/traefiklabs-hub-button-app/main-v1.js' + document.head.appendChild(hubButtonScript) + } } }, created () { @@ -164,11 +188,6 @@ export default { font-weight: 600; } - .btn-hub { - color: #dedede; - background: #5f6572; - } - .q-item { padding: 0; } @@ -178,69 +197,4 @@ export default { align-items: flex-start; } - .tooltip { - display: inline-block; - - .content { - display: flex; - align-items: center; - visibility: hidden; - font-size: 16px; - padding: 20px; - border-radius: 16px; - background-color: #fff; - box-shadow: 0 0 6px rgba(0,0,0,0.16), 0 0 6px rgba(0,0,0,0.23); - - /* Position the tooltip text */ - position: absolute; - z-index: 1; - top: 90%; - left: -5%; - - /* Fade in tooltip */ - opacity: 0; - transition: opacity 0.3s; - - &::after { - content: ""; - position: absolute; - top: -10px; - left: 22%; - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-bottom: 10px solid #fff; - } - - p { - align-self: baseline; - color: var(--q-color-primary); - font-weight: bold; - margin: 0 20px 0 0; - max-width: 180px; - } - - img { - margin: 0 20px; - } - } - - &.is-dark-mode .content { - background-color: #262626; - box-shadow: 0 0 6px rgba(10,18,36,0.16), 0 0 6px rgba(10,18,36,0.23); - - &::after { - border-bottom: 10px solid #262626; - } - - p { - color: #fff; - } - } - - &:hover .content { - visibility: visible; - opacity: 1; - } - } - diff --git a/webui/src/statics/hub-logo-horizontal-clear.png b/webui/src/statics/hub-logo-horizontal-clear.png deleted file mode 100644 index 9fdabf2afa62276f35dd6794d3a5391507907657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2687 zcmZvec|6mPAIE3poO6!pn~-B^Xe3AZ#%!*cdvhf|N+wq%XF1lgxstQyzH-JSid;2? z?~t? zVkYuZhjRRs+fb&cdCTilz#40ALp#r2e{S?gx*u<8z;MTJ!0(~)P!jcFaTk*xIGX?F zIcMOw9_7IoR}8d`AM!=KcWqg=VfT6a?iX>~Tzb0-!+D^KI-*)8k@q$d47-g4D#jyq zvSzuWD=rP1{25od?fG*92)B3l`xT+}wsNFJqdSYUNtBI!?_ybENo!1(%zUC+9#}yU z6Zx+0+orbA>7P3lR@;z~p!^#PHK2t@z>7&byaO`8{9Lc`tnohnFZiq(UDKoeROWgc z9F+wzdjmQ7+S<<=EucSB>w&x`8e>cMtO+e@UTgfe;|Fle39fDG$ltk;AX2WAp&0cZ z@|RxfX?U#$HJ!pC;pd2O)70rA*vmusgJk;FKa&=h<;9{4Sd#UKR=U>5_kG`aM7&$D zwD`f|$t>$TF+UjGrF#}4A@+}8X&2kZLWU~O{>mRJjSG{LVK!nd_Kxyai?ou-t zxEg4(+MYy(k%u_#{p!$pq{W75+bNpoj#`igIAt-#UlP_!5lMi;%FfP45|EkbWY2hp zOD6VGxs*9QdtVMl71KKV3G8}CxF2YGl7w?=IN<4Y(BbwxMy3@3$hLP8H09vYSZ>0> z4?d&pc~lmEPsvF)*=dTQ+Nesp9L-O~iDL>*;?dSneeh1>cpCr_A=?IU3{|V=x*SYI z$C>I($tc0T9kF>Xcv_#t_2jG*hTxX+c z=b;v|qZiw)O(jT60x1|-(HPHjl77LXpBumCgG+}4%Htx(U5aJq9aDu;MV0T>nq|C# za5ks0jsyDFde4B1?YAC~CGAFLh|xTKDdyiDn6$cBjwHmG7KvvScv^^;d4Ac1S;JX+ z(YldNCz8TyvE^hX4uwL0=}9oovNHr6IL@1hDw^T#JU!Z=cDeLj2wPzA_qokR5U!{U zb`!a}L(Q^F=vV@Fra_JA zLpgFii16F<82gnyX|EdT=VD+q}IrY3RA2ZI-n}pC!{X(qL%EvG)oN#++(Wdp) z>1hX%Pyw2Y4qec=c=jEL0{ zat3h{J=Dv3Af)%S8=dA71|=mH1a-A)`aO|o{K@a=u#oP@zz*CjnJ`QZlF3oNQ^eCO zKiaU9p+cc-t$f%5qpiwnAmN-o5T4uYRiO@n70s4T>M5Q^(!s0g+Cn}M_)4k{S4Y#6 znDWmFB`9{s3Bh+K>a>m2O0XFUPz;7&CkU)buGfmRH{Yy%-JmAcOMntq>07KOA?NH~ zSv^;UW%Ic3tmjJS+HV(TlLp57ysd?^azc_9udZWbFqdZ@51yGG)?5DhGOM)snNsIe z(n(@HQJdw5nIjgjB2k{Z7qIMCSOuePu!9W0wMPTUC?JYJVB>c&`PKF3by)quQh9dG z;+uqhra|2Wf`m+xu|M>br+IF0Te$RufbDTZ+nx!Zs_?+JKX}y;D$M;2S7z(eqQzdl zpzOdkji3D1J)y_ox9TRScLJVe#FL(16x{Hr(-53f>77>uN`rAGYoYJHaBKa=01O_q zs!}(y8QPwzHG84~+^k!FueiAfNGXSZcAtw#KMI3)&sPT;1y=1)$)B1ho0k<+d-}>; zxfgc17Oub9C9$%xQF04{z4vplu)?bVm`OHM%=Z7A(07x=s?c!KpZX#akn zV`v4QQ1B$X)(=yCysnVbhRj0+qft>)c<__)x0H$8Ta%JFh1~&AJB&?0>gz$i=4DSj zB|?B9!RHGFwv!jSPAWAx`5kB>pGM6XM05#IOwUjI53ZQ+qijtp%P-5n1y+D`Cxv)t ze0dMUd4V|`H|q<=$wv*k!}Os5ZT2Y^=EL1->N_eXnxtx&Qp1CEUeyiZC>~3fxsj5q z!Zqj5%doO~3tz6;UZ;VInG``ehJexe66L^8q7BD--9Om(?^%9yjq%wow@sq-e`s@#KhYUK;oxRk(U?0ap3)C! z#N24^VJbq{7%wV$)(U=SpnmvlkPZ5@%&)6@d<)^)O(RTmVt?oqH3=56 zV%9oLIQ=j{EK%_&>u4SN*DH6ZX6a;=ZiQD_IKs!KzkGCOYQRdMkKNY947};Muj$e~ zS<%UR|0Gevl;9gfXtb-&6if6l77XsLjpoJinL-xgMUk4iw%D`oN8!63s%}yP`tQNErDJzK2=F{Q{y()`}YUy~&OY4_y rBGKu~#Id&Sk=_(lS3L(dKfeQz6sew!G2GfZeB?l;h87sQ0dVIZrAP6i diff --git a/webui/src/statics/hub-logo-horizontal-dark.png b/webui/src/statics/hub-logo-horizontal-dark.png deleted file mode 100644 index aff782355a0997237a7ce477c8bf4a8683d38940..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2874 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