diff --git a/.circleci/main.yml b/.circleci/main.yml
index 9bf48ebea00209fe975a64cc5d9a96acea86c684..b6be1d91464a0b74d61eee65785c21a5cf572740 100644
--- a/.circleci/main.yml
+++ b/.circleci/main.yml
@@ -228,23 +228,22 @@ jobs:
       - image: cimg/go:1.19.1-node
     parallelism: 4
     resource_class: 2xlarge+
-    environment:
-      GO_IPFS_DIST_URL: https://dist-ipfs-tech.ipns.cf-ipfs.com # TODO remove this line when https://github.com/protocol/bifrost-infra/issues/2300 is closed
     steps:
       - *make_out_dirs
       - attach_workspace:
           at: /tmp/circleci-workspace
       - restore_cache:
           keys:
-            - v1-interop-{{ .Branch }}-{{ .Revision }}
-            - v1-interop-{{ .Branch }}-
-            - v1-interop-
+            - v2-interop-{{ .Branch }}-{{ .Revision }}
+            - v2-interop-{{ .Branch }}-
+            - v2-interop-
       - run:
           name: Installing dependencies
           command: |
             npm init -y
-            npm install ipfs@^0.61.0
-            npm install ipfs-interop@^8.0.10
+            npm install ipfs@^0.66.0
+            npm install kubo-rpc-client@^3.0.1
+            npm install ipfs-interop@^10.0.1
             npm install mocha-circleci-reporter@0.0.3
           working_directory: ~/ipfs/kubo/interop
       - run:
@@ -261,7 +260,7 @@ jobs:
       - store_test_results:
           path: /tmp/test-results
       - save_cache:
-          key: v1-interop-{{ .Branch }}-{{ .Revision }}
+          key: v2-interop-{{ .Branch }}-{{ .Revision }}
           paths:
             - ~/ipfs/kubo/interop/node_modules
   go-ipfs-api:
@@ -294,7 +293,7 @@ jobs:
           command: go test -count=1 -v ./...
           working_directory: ~/ipfs/kubo/go-ipfs-api
       - save_cache:
-          key: v1-go-api-{{ checksum "~/ipfs/kubo/go-ipfs-api/go.sum" }}
+          key: v2-go-api-{{ checksum "~/ipfs/kubo/go-ipfs-api/go.sum" }}
           paths:
             - ~/go/pkg/mod
             - ~/.cache/go-build/
@@ -310,7 +309,7 @@ jobs:
       - run:
           name: Cloning
           command: |
-            git clone https://github.com/ipfs/go-ipfs-http-client.git
+            git clone https://github.com/ipfs/go-ipfs-http-client.git -b bump-for-rcmgr-last-push
             git -C go-ipfs-http-client log -1
       - restore_cache:
           keys:
@@ -330,8 +329,6 @@ jobs:
   ipfs-webui:
     executor: node-browsers
     resource_class: 2xlarge+
-    environment:
-      GO_IPFS_DIST_URL: https://dist-ipfs-tech.ipns.cf-ipfs.com # TODO remove this line when https://github.com/protocol/bifrost-infra/issues/2300 is closed
     steps:
       - *make_out_dirs
       - attach_workspace:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 997067ad803061c0cd2ceefc95ebf8b3247b982d..2994d7d1ad0cc79a303e023c89c5c3d4f5c7c412 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,6 +14,7 @@ jobs:
   prepare:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     runs-on: ubuntu-latest
+    timeout-minutes: 5
     env:
       TEST_NO_DOCKER: 1
       TEST_NO_FUSE: 1
@@ -40,12 +41,7 @@ jobs:
   ipfs-interop:
     needs: [prepare]
     runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        suites:
-          - 'exchange-files'
-          - 'files pin circuit ipns cid-version-agnostic ipns-pubsub pubsub'
-      fail-fast: false
+    timeout-minutes: 20
     defaults:
       run:
         shell: bash
@@ -70,19 +66,20 @@ jobs:
       - run: mkdir interop
       - run: |
           npm init -y
-          npm install ipfs@^0.61.0
-          npm install ipfs-interop@^8.0.10
+          npm install ipfs@^0.66.0
+          npm install kubo-rpc-client@^3.0.1
+          npm install ipfs-interop@^10.0.1
         working-directory: interop
-      - run: npx ipfs-interop -- -t node $(sed -e 's#[^ ]*#-f test/&.js#g' <<< '${{ matrix.suites }}')
+      - run: npx ipfs-interop -- -t node
         env:
           LIBP2P_TCP_REUSEPORT: false
           LIBP2P_ALLOW_WEAK_RSA_KEYS: 1
           IPFS_GO_EXEC: ${{ github.workspace }}/cmd/ipfs/ipfs
-          GO_IPFS_DIST_URL: https://dist-ipfs-tech.ipns.cf-ipfs.com # TODO: remove this line when https://github.com/protocol/bifrost-infra/issues/2300 is closed
         working-directory: interop
   go-ipfs-api:
     needs: [prepare]
     runs-on: ubuntu-latest
+    timeout-minutes: 5
     env:
       TEST_NO_DOCKER: 1
       TEST_NO_FUSE: 1
@@ -122,6 +119,7 @@ jobs:
   go-ipfs-http-client:
     needs: [prepare]
     runs-on: ubuntu-latest
+    timeout-minutes: 5
     env:
       TEST_NO_DOCKER: 1
       TEST_NO_FUSE: 1
@@ -145,6 +143,7 @@ jobs:
         with:
           repository: ipfs/go-ipfs-http-client
           path: go-ipfs-http-client
+          ref: bump-for-rcmgr-last-push
       - uses: protocol/cache-go-action@v1
         with:
           name: ${{ github.job }}
@@ -154,6 +153,7 @@ jobs:
   ipfs-webui:
     needs: [prepare]
     runs-on: ubuntu-latest
+    timeout-minutes: 20
     env:
       NO_SANDBOX: true
       LIBP2P_TCP_REUSEPORT: false
@@ -162,7 +162,6 @@ jobs:
       TRAVIS: 1
       GIT_PAGER: cat
       IPFS_CHECK_RCMGR_DEFAULTS: 1
-      GO_IPFS_DIST_URL: https://dist-ipfs-tech.ipns.cf-ipfs.com # TODO: remove this line when https://github.com/protocol/bifrost-infra/issues/2300 is closed
     defaults:
       run:
         shell: bash
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index e12af6b4e4117c3c27d52ff828177c4760ace680..c5c355fac3824d2291ee34c3d20d16c1bedf0abb 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -16,6 +16,7 @@ jobs:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     name: Analyze
     runs-on: ubuntu-latest
+    timeout-minutes: 20
 
     strategy:
       fail-fast: false
diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml
index 86c50bec7f127659f85994c62aafbd754ebe1108..23e29bf39e2c22537c8e1e87904f779af128f2ee 100644
--- a/.github/workflows/docker-build.yml
+++ b/.github/workflows/docker-build.yml
@@ -11,6 +11,7 @@ jobs:
   docker-build:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     runs-on: ubuntu-latest
+    timeout-minutes: 10
     env:
       IMAGE_NAME: ipfs/kubo
       WIP_IMAGE_TAG: wip
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index a7416e388f4673a42606abb1c5a0091fefba4abc..f798bb2022eb15043d82bb6fa1186c71d2aaf7b3 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -14,6 +14,7 @@ jobs:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     name: Push Docker image to Docker Hub
     runs-on: ubuntu-latest
+    timeout-minutes: 90
     env:
       IMAGE_NAME: ipfs/kubo
       LEGACY_IMAGE_NAME: ipfs/go-ipfs
diff --git a/.github/workflows/gobuild.yml b/.github/workflows/gobuild.yml
index 120e94693025259db2b94ca29b2b785090efaead..532d34590cec0ca5d21d7a24583f3355680439d7 100644
--- a/.github/workflows/gobuild.yml
+++ b/.github/workflows/gobuild.yml
@@ -14,6 +14,7 @@ jobs:
   gobuild:
     needs: [runner]
     runs-on: ${{ fromJSON(needs.runner.outputs.config).labels }}
+    timeout-minutes: 20
     env:
       TEST_NO_DOCKER: 1
       TEST_VERBOSE: 1
diff --git a/.github/workflows/golang-analysis.yml b/.github/workflows/golang-analysis.yml
index 958ece6686d96484bfdfec22ca9f92b4905bd2dc..1bc66900349e485f8e69829f42e65fc9710e60bb 100644
--- a/.github/workflows/golang-analysis.yml
+++ b/.github/workflows/golang-analysis.yml
@@ -11,6 +11,7 @@ jobs:
   unit:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     runs-on: ubuntu-latest
+    timeout-minutes: 10
     name: All
     steps:
       - uses: actions/checkout@v2
diff --git a/.github/workflows/golint.yml b/.github/workflows/golint.yml
index 9623ae4b60866286f24f793f13162ffda2b45f14..a6593582da78e06ebce2101c0d9fb1fe5e94ffc0 100644
--- a/.github/workflows/golint.yml
+++ b/.github/workflows/golint.yml
@@ -11,6 +11,7 @@ jobs:
   golint:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     runs-on: ubuntu-latest
+    timeout-minutes: 10
     env:
       TEST_NO_DOCKER: 1
       TEST_NO_FUSE: 1
diff --git a/.github/workflows/gotest.yml b/.github/workflows/gotest.yml
index 2c50fd3e5346187ff2cb04a5c302cd018ec8d770..8eb41a34dbd2fb94c857832045f08708bbf3bd35 100644
--- a/.github/workflows/gotest.yml
+++ b/.github/workflows/gotest.yml
@@ -11,6 +11,7 @@ jobs:
   gotest:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     runs-on: ubuntu-latest
+    timeout-minutes: 20
     env:
       TEST_NO_DOCKER: 1
       TEST_NO_FUSE: 1
diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml
index afb4d740d3fd968b48376b964becab5a378608fd..c8aef2256d0fd890b3c6c6073afbfc7986f63c8c 100644
--- a/.github/workflows/runner.yml
+++ b/.github/workflows/runner.yml
@@ -10,6 +10,7 @@ on:
 jobs:
   choose:
     runs-on: ubuntu-latest
+    timeout-minutes: 1
     outputs:
       config: ${{ steps.config.outputs.result }}
     steps:
diff --git a/.github/workflows/sharness.yml b/.github/workflows/sharness.yml
index 6241e3fe62b85972dad84bddf61f0730bc503ebe..8809f2a53088ed2701371aaed11d78419d6bf0ed 100644
--- a/.github/workflows/sharness.yml
+++ b/.github/workflows/sharness.yml
@@ -14,6 +14,7 @@ jobs:
   sharness:
     needs: [runner]
     runs-on: ${{ fromJSON(needs.runner.outputs.config).labels }}
+    timeout-minutes: 20
     defaults:
       run:
         shell: bash
@@ -55,9 +56,7 @@ jobs:
           make -O -j "$PARALLEL" \
             test_sharness \
             coverage/sharness_tests.coverprofile \
-            test/sharness/test-results/sharness.xml \
-            test/sharness/test-results/sharness.html \
-            test/sharness/test-results/sharness-html
+            test/sharness/test-results/sharness.xml
         working-directory: kubo
         env:
           TEST_NO_DOCKER: 0
@@ -87,6 +86,13 @@ jobs:
           echo "# Summary" >> $GITHUB_STEP_SUMMARY
           echo >> $GITHUB_STEP_SUMMARY
           cat kubo/test/sharness/test-results/summary.txt >> $GITHUB_STEP_SUMMARY
+      - name: Generate one-page HTML report
+        uses: pl-strflt/junit-xml-to-html@v1
+        if: failure() || success()
+        with:
+          mode: no-frames
+          input: kubo/test/sharness/test-results/sharness.xml
+          output: kubo/test/sharness/test-results/sharness.html
       - name: Upload one-page HTML report to S3
         id: one-page
         uses: pl-strflt/tf-aws-gh-runner/.github/actions/upload-artifact@main
@@ -100,6 +106,13 @@ jobs:
         with:
           name: sharness.html
           path: kubo/test/sharness/test-results/sharness.html
+      - name: Generate full HTML report
+        uses: pl-strflt/junit-xml-to-html@v1
+        if: failure() || success()
+        with:
+          mode: frames
+          input: kubo/test/sharness/test-results/sharness.xml
+          output: kubo/test/sharness/test-results/sharness-html
       - name: Upload full HTML report to S3
         id: full
         uses: pl-strflt/tf-aws-gh-runner/.github/actions/upload-artifact@main
diff --git a/.github/workflows/sync-release-assets.yml b/.github/workflows/sync-release-assets.yml
index da3ca9582b51b737be9e6758bfd660b50625b140..f2527d47c460110e88e860f539fb1d68218dfb86 100644
--- a/.github/workflows/sync-release-assets.yml
+++ b/.github/workflows/sync-release-assets.yml
@@ -13,6 +13,7 @@ jobs:
   sync-github-and-dist-ipfs-tech:
     if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
     runs-on: "ubuntu-latest"
+    timeout-minutes: 5
     steps:
       - uses: ipfs/download-ipfs-distribution-action@v1
       - uses: ipfs/start-ipfs-daemon-action@v1
diff --git a/.github/workflows/testground-on-push.yml b/.github/workflows/testground-on-push.yml
deleted file mode 100644
index 7b55dbdee3bc4b5929235344790ea14083874927..0000000000000000000000000000000000000000
--- a/.github/workflows/testground-on-push.yml
+++ /dev/null
@@ -1,38 +0,0 @@
----
-name: Testground PR Checker
-
-on:
-  workflow_dispatch:
-  push:
-
-
-jobs:
-  testground:
-    if: github.repository == 'ipfs/kubo' || github.event_name == 'workflow_dispatch'
-    runs-on: ubuntu-latest
-    name: ${{ matrix.composition_file }}
-    strategy:
-      matrix:
-        include:
-          - backend_addr: ci.testground.ipfs.team
-            backend_proto: https
-            plan_directory: testplans/bitswap
-            composition_file: testplans/bitswap/_compositions/small-k8s.toml
-          - backend_addr: ci.testground.ipfs.team
-            backend_proto: https
-            plan_directory: testplans/bitswap
-            composition_file: testplans/bitswap/_compositions/medium-k8s.toml
-          - backend_addr: ci.testground.ipfs.team
-            backend_proto: https
-            plan_directory: testplans/bitswap
-            composition_file: testplans/bitswap/_compositions/large-k8s.toml
-    steps:
-      - uses: actions/checkout@v2
-      - name: testground run
-        uses: testground/testground-github-action@v1
-        timeout-minutes: 5
-        with:
-          backend_addr: ${{ matrix.backend_addr }}
-          backend_proto: ${{ matrix.backend_proto }}
-          plan_directory: ${{ matrix.plan_directory }}
-          composition_file: ${{ matrix.composition_file }}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1b5a5769fc366044002e3e5e3842db75921e1aa2..16e72bcb150fb07c8949bbb9c022d0674b510fc0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 # Kubo Changelogs
 
+- [v0.19](docs/changelogs/v0.19.md)
 - [v0.18](docs/changelogs/v0.18.md)
 - [v0.17](docs/changelogs/v0.17.md)
 - [v0.16](docs/changelogs/v0.16.md)
diff --git a/README.md b/README.md
index e734fef6642e7ce8516b846c336eac82cd36a3c2..94e5e42af15a7b33939eec497630e3406c8f3e4e 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,7 @@ Kubo was the first IPFS implementation and is the most widely used one today. Im
 Featureset
 - Runs an IPFS-Node as a network service
 - [Command Line Interface](https://docs.ipfs.tech/reference/kubo/cli/) to IPFS-Nodes
-- Local [Web2-to-Web3 HTTP Gateway functionality](https://github.com/ipfs/specs/tree/main/http-gateways#readme) 
+- Local [Web2-to-Web3 HTTP Gateway functionality](https://github.com/ipfs/specs/tree/main/http-gateways#readme)
 - HTTP RPC API (`/api/v0`) to access and control the daemon
 - IPFS's internal Webgui can be used to manage the Kubo nodes
 
@@ -381,7 +381,6 @@ Some places to get you started on the codebase:
 - libp2p
   - libp2p: https://github.com/libp2p/go-libp2p
   - DHT: https://github.com/libp2p/go-libp2p-kad-dht
-  - PubSub: https://github.com/libp2p/go-libp2p-pubsub
 - [IPFS : The `Add` command demystified](https://github.com/ipfs/kubo/tree/master/docs/add-code-flow.md)
 
 ### Map of Implemented Subsystems
diff --git a/Rules.mk b/Rules.mk
index f7e962549c8fcd885377d1e5804614e187176c8c..3d3d9c13951cdc65d2ab26def28da7cd656f683d 100644
--- a/Rules.mk
+++ b/Rules.mk
@@ -118,7 +118,7 @@ help:
 	@echo '  all          - print this help message'
 	@echo '  build        - Build binary at ./cmd/ipfs/ipfs'
 	@echo '  nofuse       - Build binary with no fuse support'
-	@echo '  install      - Build binary and install into $$GOPATH/bin'
+	@echo '  install      - Build binary and install into $$GOBIN'
 #	@echo '  dist_install - TODO: c.f. ./cmd/ipfs/dist/README.md'
 	@echo ''
 	@echo 'CLEANING TARGETS:'
diff --git a/assets/README.md b/assets/README.md
index 02af2f19ca0ac0ccb298d0d5634632db8a210895..b342d080101ab407fedbb8ee407397a620373565 100644
--- a/assets/README.md
+++ b/assets/README.md
@@ -3,13 +3,3 @@
 This directory contains the go-ipfs assets:
 
 * Getting started documentation (`init-doc`).
-* Directory listing HTML template (`dir-index-html`).
-
-## Re-generating
-
-Edit the source files and use `go generate` from within the
-assets directory:
-
-```
-go generate .
-```
diff --git a/assets/assets.go b/assets/assets.go
index 37cbbfad5db87a82d9a652ce44391081b7e866a8..00792d511d317cea2c3a6e9f49b8553df40538ce 100644
--- a/assets/assets.go
+++ b/assets/assets.go
@@ -1,30 +1,22 @@
-//go:generate npm run build --prefix ./dir-index-html/
 package assets
 
 import (
 	"embed"
 	"fmt"
-	"io"
-	"io/fs"
 	gopath "path"
-	"strconv"
 
 	"github.com/ipfs/kubo/core"
 	"github.com/ipfs/kubo/core/coreapi"
 
-	"github.com/cespare/xxhash"
 	cid "github.com/ipfs/go-cid"
 	"github.com/ipfs/go-libipfs/files"
 	options "github.com/ipfs/interface-go-ipfs-core/options"
 	"github.com/ipfs/interface-go-ipfs-core/path"
 )
 
-//go:embed init-doc dir-index-html/dir-index.html dir-index-html/knownIcons.txt
+//go:embed init-doc
 var Asset embed.FS
 
-// AssetHash a non-cryptographic hash of all embedded assets
-var AssetHash string
-
 // initDocPaths lists the paths for the docs we want to seed during --init
 var initDocPaths = []string{
 	gopath.Join("init-doc", "about"),
@@ -36,32 +28,6 @@ var initDocPaths = []string{
 	gopath.Join("init-doc", "ping"),
 }
 
-func init() {
-	sum := xxhash.New()
-	err := fs.WalkDir(Asset, ".", func(path string, d fs.DirEntry, err error) error {
-		if err != nil {
-			return err
-		}
-
-		if d.IsDir() {
-			return nil
-		}
-
-		file, err := Asset.Open(path)
-		if err != nil {
-			return err
-		}
-		defer file.Close()
-		_, err = io.Copy(sum, file)
-		return err
-	})
-	if err != nil {
-		panic("error creating asset sum: " + err.Error())
-	}
-
-	AssetHash = strconv.FormatUint(sum.Sum64(), 32)
-}
-
 // SeedInitDocs adds the list of embedded init documentation to the passed node, pins it and returns the root key
 func SeedInitDocs(nd *core.IpfsNode) (cid.Cid, error) {
 	return addAssetList(nd, initDocPaths)
diff --git a/assets/dag-index-html/README.md b/assets/dag-index-html/README.md
deleted file mode 100644
index de38a9504a1e64cde41e609d2dbbda9a652174bd..0000000000000000000000000000000000000000
--- a/assets/dag-index-html/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# dag-index-html
-
-> HTML representation for non-UnixFS DAGs such as DAG-CBOR.
diff --git a/assets/dag-index-html/index.go b/assets/dag-index-html/index.go
deleted file mode 100644
index 214b06a38226d8282b406bf828603e5d7b496e1d..0000000000000000000000000000000000000000
--- a/assets/dag-index-html/index.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package dagindexhtml
-
-import "html/template"
-
-// TODO: DagIndexTemplate - replace static CSS with shared one with ../dir-index-html
-
-// DagIndexTemplate is HTML-based template for non-UnixFS DAGs when request was
-// made with Accept: text/html (web browsers).
-var DagIndexTemplate = template.Must(template.New("redirect").Parse(`<!DOCTYPE html>
-<html lang="en">
-<head>
-  <meta charset="utf-8" />
-  <meta name="description" content="Content-addressed data on IPFS">
-  <meta property="og:title" content="Data on IPFS">
-  <meta property="og:description" content="{{ .Path }}">
-  <meta property="og:type" content="website">
-  <meta property="og:image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-  <meta name="twitter:title" content="{{ .Path }}">
-  <meta name="twitter:description" content="Content-addressed data hosted on the distributed, decentralized web using IPFS">
-  <meta name="twitter:card" content="summary_large_image">
-  <meta name="twitter:image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-  <meta name="twitter:creator" content="@ipfs">
-  <meta name="twitter:site" content="@ipfs">
-  <meta name="image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-  <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlo89/56ZQ/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUjDu1lo89/6mhTP+zrVP/nplD/5+aRK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHNiIS6Wjz3/ubFY/761W/+vp1D/urRZ/8vDZf/GvmH/nplD/1BNIm8AAAAAAAAAAAAAAAAAAAAAAAAAAJaPPf+knEj/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf+tpk7/nplD/wAAAAAAAAAAAAAAAJaPPf+2rVX/vrVb/761W/++tVv/vrVb/6+nUP+6tFn/y8Nl/8vDZf/Lw2X/y8Nl/8G6Xv+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/761W/+vp1D/urRZ/8vDZf/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf++tVv/vrVb/761W/++tVv/vbRa/5aPPf+emUP/y8Nl/8vDZf/Lw2X/y8Nl/8vDZf+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/5qTQP+inkb/op5G/6KdRv/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/sqlS/56ZQ//LxWb/0Mlp/9DJaf/Kw2X/oJtE/7+3XP/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf+9tFr/mJE+/7GsUv/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+xrFL/nplD/8vDZf+emUP/AAAAAAAAAACWjz3/op5G/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+inkb/nplD/wAAAAAAAAAAAAAAAKKeRv+3slb/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+1sFX/op5G/wAAAAAAAAAAAAAAAAAAAAAAAAAAop5GUKKeRv/Nxmf/0cpq/9HKav/Rymr/0cpq/83GZ/+inkb/op5GSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G16KeRv/LxWb/y8Vm/6KeRv+inkaPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G/6KeRtcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/n8AAPgfAADwDwAAwAMAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAwAMAAPAPAAD4HwAA/n8AAA==" />
-  <title>{{ .Path }}</title>
-  <style>
-  /* Source - fileicons.org */.ipfs-_blank {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWBJREFUeNqEUj1LxEAQnd1MVA4lyIEWx6UIKEGUExGsbC3tLfwJ/hT/g7VlCnubqxXBwg/Q4hQP/LhKL5nZuBsvuGfW5MGyuzM7jzdvVuR5DgYnZ+f99ai7Vt5t9K9unu4HLweI3qWYxI6PDosdy0fhcntxO44CcOBzPA7mfEyuHwf7ntQk4jcnywOxIlfxOCNYaLVgb6cXbkTdhJXq2SIlNMC0xIqhHczDbi8OVzpLSUa0WebRfmigLHqj1EcPZnwf7gbDIrYVRyEinurj6jTBHyI7pqVrFQqEbt6TEmZ9v1NRAJNC1xTYxIQh/MmRUlmFQE3qWOW1nqB2TWk1/3tgJV0waVvkFIEeZbHq4ElyKzAmEXOx6gnEVJuWBzmkRJBRPYGZBDsVaOlpSgVJE2yVaAe/0kx/3azBRO0VsbMFZE3CDSZKweZfYIVg+DZ6v7h9GDVOwZPw/PoxKu/fAgwALbDAXf7DdQkAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-_page {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNpsUztv01AYPfdhOy/XTZ80VV1VoCqlA2zQqUgwMEErWBALv4GJDfEDmOEHsFTqVCTExAiiSI2QEKJKESVFFBWo04TESRzfy2c7LY/kLtf2d8+555zvM9NaI1ora5svby9OnbUEBxgDlIKiWjXQeLy19/X17sEtcPY2rtHS96/Hu0RvXXLz+cUzM87zShsI29DpHCYt4E6Box4IZzTnbDx7V74GjhOSfwgE0H2638K9h08A3iHGVbjTw7g6YmAyw/BgecHNGGJjvfQhIfmfIFDAXJpjuugi7djIFVI4P0plctgJQ0xnFe5eOO02OwEp2VkhSCnC8WOCdqgwnzFx4/IyppwRVN+XYXsecqZA1pB48ekAnw9/4GZx3L04N/GoTwEjX4cNH5vlPfjtAIYp8cWrQutxrC5Mod3VsXVTMFSqtaE+gl9dhaUxE2tXZiF7nYiiatJ3v5s8R/1yOCNLOuwjkELiTbmC9dJHpIaGASsDkoFQGJQwHWMcHWJYOmUj1OjvQotuytt5nHMLEGkCyx6QU384jwkUAd2sxJbS/QShZtg/8rHzzQOzSaFhxQrA6YgQMQHojCUlgnCAAvKFBoXXaHfArSCZDE0gyWJgFIKmvUFKO4MUNIk2a4+hODtDUVuJ/J732AKS6ZtImdTyAQQB3bZN8l9t75IFh0JMUdVKsohsUPqRgnka0tYgggYpCHkKGTsHI5NOMojB4iTICCepvX53AIEfQta1iUCmoTiBmdEri2RgddKFhuJoqb/af/yw/d3zTNM6UkaOfis62aUgddAbnz+rXuPY+Vnzjt9/CzAAbmLjCrfBiRgAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-aac {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNp0Uk1PE0EYftruVlvAUkhVEPoBcsEoLRJBY01MPHjCs3cvogcT/4qJJN5NvHhoohcOnPw4YEGIkCh+oLGBKm3Z7nZ3dme2vjOhTcjiJJvZzPvOM8/HG2q325Dr3kLp7Y1ibpIxjs4KhQBZfvV6s7K5Vb0bjeof5ZlcGysP1a51mifODybvzE8mzCbrAoTDIThMoGXZiZ4YSiurf+Z1XeuCqJ7Oj+sK3jQcNAmg8xkGQ71mYejcAB49vpmeuzJccl0+dUj6KIAvfHCPg3N+uAv4vg9BOxcCmfEzuP/genpmeqhEMgude10Jwm+DuUIyUdTlqu2byoMfX/dRermBeExHsTiWNi3+lMpzRwDki8zxCIATmzbevfmClukiP5NFhJgwkjeRTeLShdOoVJqnAgwkgCAZ6+UdLC9twjQZ8pdzioFkZBHY3q6B3l4dJEEEPOCeD4cYVH7Xsf15F+FImC775INAJBJSkVoWo0QY9YqgiR4ZZzRaGBkdwK3bFxGLRZUfB3Rm2x4x9CGtsUxH9QYkKICDFuLxKAozGZwdTqBRs2FbLlXbiPdECMCHadj/AaDXZNFqedCIvnRcS4UpRo7+hC5zUmw8Ope9wUFinvpmZ7NKt2RTmB4hKZo6n8qP4Oq1HBkKlVYAQBrUlziB0XQSif4YmQhksgNIJk9iaLhPaV9b/Um+uJSCdzyDbGZQRSkvjo+n4JNxubGUSsCj+ZCpODYjkGMAND2k7exUsfhkCd+29yguB88Wl7FW/o6tT7/gcXqAgGv7hhx1LWBireHVn79YP6ChQ3njb/eFlfWqGqT3H3ZlGIhGI2i2UO/U/wkwAAmoalcxlNA1AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-ai {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk5JREFUeNpsU01vElEUPTPzZqBAQaSFQiJYUmlKYhoTF41L3Tbu/Q/+AvsX3Bp/gPsuWLrqyqQ7TUxMtAvF1tYGoXwNw7wv7zwYgtKX3Lw379575p5z77O01ohW+/DVh8zj7aYKhflGdG9ZsGwLNydffgVfr19YHvsEa+Zu/nxndob5StQK+dyzvZzyw/gKlmMj7IygFM+xvNcanp4/t5dAomXHBy2UUBOO2MAl/B9/cPb6PULuoHx0WM0e3GvpUOxD3wZAJWutZqYUYmqpSg5OMgH3YQObL59W0/ullpryR3HegkKEqiWBSGV4R3vQ7sIhScTZFTpHx3A215B5sluVY/WWMg7+ATB/lcLsKpTonHzD+OMFEuTz8ikkt9Kwt9YJZB38cpBdoQAZJdLvCGByfoPB6Xdk90pYy6Xg3c/DaWwArg09DaG5lCsUFN0pckZAojdC8m4auBqaALuSgez7VB1RtDSUWOQvUaBLFUzJBMJ2DwmPgd1Jwm0WoSgJfjDvrTKxtwAIyEkAOQ5hU//Zdg5uowDlUNMnwZLW0sSuUuACYhwQRwFvJxupCjEYUUccOkoaKmdOlZnY1TkgAcXAhxhOwLsDsHoN3u4O5JTDfVCH6I9nfjId3gIgSUATFJk/hVevGtOMwS0XwQ3AzB/FrlKg8Q27I2javVoZrFgwD4qVipAEyMlnaFArzaj/D0DiMXlJAFQyK2r8fnMMRZp4lQ1MaSL5tU/1kqAkMCh2tYI+7+kh70cjPbr4bEZ51jZr8TJnB9PJXpz3V4ABAPOQVJn2Q60GAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-aiff {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAohJREFUeNpkU9tqE1EUXZmZpE3aTBLbJFPTtFURtSCthr7UCyKKFJ/9An3og6Ag/oXfoUj7og9asCBYKT6UIPHaWtpq7NU2aZK5z5wZ9xxMpMwZDuewz9prr32ZiO/7CNaDx3OLt6fOjBqGg/aKRCIInp8+KzfKH7fudnVF58nE16el+/yU2mBFSWZKpWJKVc0OgUBo02K4NDmU6o75Mx+Wdu9IUXFeiOA/pn1xHeYaugVDdzpbp91qGlAKGTx8dC19/Wpxhjnsxj/RRwk85hGJC9d1O6fneWAuoztDYSSLe9OT6SuXB2ccx73Z9uukwDwfls1g0xZIY/Ad/Gnyt/XVfbyYrSDRE8PExHB6/8B6QuaxIwRBFMt0iIAiMx+LCys8jfGJEUik2WpZOD2SQf9oDtVqQwopCAiY66FS/om3b75CVS2MlU7AJ2WiJBCZjZ2dJuRkDJZFwFAR7UCBja3fNfxY2YEoCtRCj9em3Tpds6FpJseGCBxS0GgYGBzqw62p84gnYnAI2CSbSbPhEpFAaE2zODaUAlWWwDoS5DheGqbWpVE/0CmqCY9qkEyINBceb2uADRNQ8bSWAVVzIFKomCQim+0luS4yKYlsHlRyZo7EsSEC23K5vAsXh/H92zZkuRvxeBS5nEx2yp2KqhxPoV5TYS/8CtdApylM9sZQKKSQzyeRTseRV2QoAzIYY8jme5DN9fI0dQoUIjANGydP9VM7PZw9p/AiBpNYrdbw/t0yTJqRtdU9UrfJCUMpSJIgbWzsYe51BcViHzLHeqCRqhZ1YX1tFwNfZBxS9O3NWkAcHqR606k/n/3coKAoV/Y7vQ/OYCZevlrmv3c0GsFh06u3/f4KMABvSWfDHmbK2gAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-avi {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm1JREFUeNpsU8tu00AUPXZcN0nzTpq2KQ3pAwkIAnWHqCoeexBb+AQ+ABZ8A2s+AIkdm266QUJIFWKBkHg1KpRHi5omJGkbJ3bGHj+4M1EQrTvSyGPPueeec++1EgQBxHp+/9mbyuriRZdxjJaiKBD3W+u1+p9a856max+gDO8ebT+WT20Ezi9NZi/crqadvn2MQBAGfpCOpqNru2937vxPIpY6Onjccx3Twck9MBiSU0ncfHirXFmZX3Md9wqCUwiEVN/zaQfHt0vfbBe5uQyuPVgpl5Zn11ybL4/i/lkICOw5niQRGQShoiqI6Bo43W2ub8n3hRtLZT7gTynk6gkCX9gAOxpAnxhHZDwC1/aI1EViJolu/QhKRMHZ1UX0Gr1USIEn5FPWHy+/wTokkrQOq2vBaHZBN4hmY9Jwfr4An/teiEB45ZZDwDiMhoExT0N+sYDCuUkkplLIlXP4/XEXdo+RUhdhBSSfUwtVTUG8MIHK9QVqI7D/uY6vr2pwmCPrkz+Tk9gwARWQ9WxppbXZhNnpw+ya4A5HZi6L4lIR8WyCcL6sTZiAWjWgAmpxkn5+kqTamK6WkCwmERmLDLvjB0ML9ikWXPLFuozYOap3L8HYN6DHdbS/d5CeTVBndBz87FCBLYkNTyIjBQemnIEsSY5lYrK1+UoWcToLMjEHAyIQ2BCBSx/NVh+ZUhrqmEqBebS3WyhdLg0zt/ugAaIklsSGLHCLa6zDMGhZ2HjyGsnpFPqNHnY2fmHv3R5SMymYbROszSQ2ROAY9qHiofvlxSc5xsKKqqnY3diRE9h4X5d/pzg7lnM4ivsrwADe9Wg/CQJgFAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-bmp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmZJREFUeNp0U+1rUlEY/13v9YV0vq2wttI5CdpL9aEGBZUDv0df668I6n+or0UQ/RuuD0EgVDAZrsKF4AR1a6COKW5qXvXec27PuVeda3bgcF6e8/ye5/d7niMZhgExnK9fbTrm5pbBGMZDkgCyq+VyhTUaT6Eo2ZHJePPWXJXRhez3B1yxmM/QdctXUSCgtV4Py4CvY3cky4e1x5DlLCaGbbzjXDcousG5OQe5HPRSCQPK4PpsEM/XH4WvhS4noeu3JwHGGRiULhsMoKZS4I0GtEIB9mgULJGA0+9DPBpBT7sffvf1W/Lg6OgJufw8C0CRGEXWazUwiiyFQjA8bsjVKjaJzovMD/Q5gxyJhG2cvyeXe2cAuADQNGBmBvLaGuTFRaDfh31lBTWi9pumjbK0B4JQul3vOQpM8JdskOLrdCvDcDjAsjtg5TIkoiKLaokMNR2cnZbqNAMycqG7XbHKR2fMzwO/dsxSwu0BiBJsNsv2LwAJAJCI5ux2gXYbqNetcz5PoORI1cDS0n8AxGW7A+zvEYBKZ2ZlcsEtJLbedMjePBaCTQMghx45ulyWkzxMVUQ2RMQhLfFO16YAqCrixPnm6iqKrRb2W23EfF4cUNSrHg90cr7hDyB33MTnSmUKALVs4uIlROjxg+AsPhGVl3fuIl2tIOB0Ya91gkOi9mxhAal0ekork1ic/kGLBORMxy2K1qS9V1ZQbNThIj2EGh+2tsyOnSai8r1UxMNIBB+LRTTULr4Uds0K1tU/uOLxIrmbNz8XXSrnASSpubG9fbKRyVh1n/zSw29t9oC1b47MfwUYAAUsLiWr4QUJAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-c {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcxJREFUeNqEUk1rE0EYfmZnkgoJCaGNCehuJTalhJZSUZB66a0HwXsP/Qn+FM+9+hty0LNYCr2I7UVLIW0Fc0hpQpSS7O7MrO9MspuvVV8YMnk/nn2e5x0WRRFMvP/w6WSz5jbi/9NxfP693Wp3DrJCnMW5d28P7a+IE15lufR8o1ZEStwPhkWHsWbrZ+eNEPxsuubEF6m0TBv2Q4liPofXuzveulttSqW2UwH+GjqC0horpSL2njU89+FyMwjlTlxOJMTa9ZQHzDQIjgwdom9zLzfXPc75kbnOAswBJTlC2XrqQRMLxhi442DgB4UFBhgPpm3B5pgBHNUUxQKAHs8pHf3TEuFMetM9IKr/i2mWMwC0SnuSFTG2YKyppwKYVdGO7TFhzBqGIenVeLCUtfURgErucx5ECKREKBU4d3B718PHz6cICGT/1Qs8qpQtGOdyhtGEARWDQFqQJSeDL98u4VbLaKw9IRAJPwjtoJGlVAoDQ800+fRFTTYXcjlcXN2g++s36p5Lzzlve1iEROa8BGH1EbrSAeqrjxEqicHQt8/YSDHMpaNs7wJAp9vvfb287idboAVkRAa5fBYXP9rxO4Mgf0xvPPdHgAEA8OoGd40i1j0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-cpp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfJJREFUeNqEUs9PE0EU/mZ2WgqpXX+QIDFdalVslh8NlAOQaOKFAwfvHvwT/FM8e/U/MOnBmwcj8WD0ACEGghIkbU0baaEthe3OTJ0ZWV26q37JZt68ee/b9733yGAwgMbL12/fz+azbnAPY2Nrt7Zfqz9JMrYZ+J4/e2pOFjiciRvXlgp5GzHonXk2o6S8V6k/TjBrM/xGA4MLyeOSPZ8jkx7D+uqCU3Amy1yIYizB36AlCSkwfjWDR4uu40yMl/s+XwjeWThQQ4Z6QNSnSkYykcDXasP4lmfvOZTSF9q8TDBEFPbN5bOqCglCCCxK0TvvZyIV4CIxbgpC+4gm/PUmFCIE8iJPyME/e8Lon9j4HvyHYLjKSwRCSEUgf9+15mFbx8QS6CZJMzJ9SlBCwX3fJDLG4PX7ykcwkmQmJtpEhWa7g1dvNlSwjwelebz7tAXLolh0p/Fxe9fErK2WDFGEgKjxfNjegX0lDTc/heNuF99/HGEslcKXwyoazWNDdlCr6+DoJgrBzdI0T9rYO6yg2zszMlaKM3Dv5OBzbuyZuzm1B16U4Nzz2f3cFOx0Gq12F9cztpExncsqYoaHpSIKtx0zJdVIFpHQ6py29muNk1uTN829o/6SHEnh80HFaE6NjmLnWxUJy1LyTltB3k8BBgBeEeQTiWRskAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-css {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNpsUktvUlEQ/u5DoCLl/RAKKKUvWmIxjYntQtcu3LvwJ/hTXLt16coFC2PsojEaMKZtCqFaTdGmjbS0CG3By+vei3OOBSGXSU7uzNyZ78z3zRF6vR6YvXzzPrMUCyf68bB9zO+VfpROn5hkOdfPPX/2lH/lfiLidztX5mN2jLGG0rKLENIE8liWpdzwP7HvqJqujmvudFU4bFY8Wk1FZsOBtKppd8YCDNu77CZevd3gflfTUFcUhP0ePLibiIR9rjSBpgwAfe4dVcV6dhtep4PH5msylGYLrzeybErcT85FYiH/CyPAf74gObC2vMhzsiRhPhpC6eQUM+EA1pJzILEnjRSuJsju7MJqsUCSRei6Dp3yXqcdGlHZ/rLPazQWGCn8+6YW4pAkEW0SjzUzanWlCa/LgcR0lNfovTEi6lcIkzesnM/R8RlN0INGp3h4DHoDsE5YRvQyiKiRSMzikRAOS2WoqoZWu41K7RwzlOOAVDMMMHhIGvFlRxJFrKYW0ep0IYgC3SDh4b1lTJjNfENsrazOAMAw680mPuW+8lFno1P4XDigRhOiwQAyJK7TbsNS/PaA7giAIAhYz2yRgBIfsVA8wIetPG6FAqhdNrC5u0f+TUyHgyMTDDToEt/ftQsEvW4EPG5OZcrvw0mlimarTXkPfpXPcNlQoGtjACgpryQXsPNtH/nvRXqBJpoKHMzGNkNB0Odls7LNyAYKpUq1dt1iuvB7fRDp9kr9D1xOFwkpoksXusmXaZWFn0coV89r/b6/AgwAkUENaQaRxswAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-dat {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfVJREFUeNqMU01PE1EUPe/Na0uptmlASg3MoiZgCA3hQ8PHAjbqwsS9C3+CP8W1W/+BSReyYUPwI4QAVkAgUEgIbVIg1FZb2pl5b3zv2cHBjsaTTOa+e989OffcGeK6LhTevFv+OJoZHPHOfrz/sl86KpWfhxnLe7lXL1/oN/MSZqonOXU/k0AA6lfNhEFIrlAsP2PMyPtr1AscLpyg5pbtIHErhqez4+awmc45nI8FEvwNaiQuBHqTcSxMjJhmX0/Osp1xr878FxWEzwMinxAzEA4xFIpnOjedHTKpYbxW4U2CP4j8uWxmUKsghMCgFI2mFe9QgHZj0Ba4yhFF+KvGJToIRLuPC/efnjD6+26wB1Lq/xgbSCBXKeWJG/OTdky8cWTdT3C9RmWSGk2XCLlWo4xTNbfN5qh7PpXM72GjZeHt0gpq9QbmH4whGb+NpU/reDQ7hcWVVXxvXOHxzCQopQEKXKEbL6o1ZIcy+LC5g62DY2zsHeC0fA4zndIrHOjvg2XbAQRSfsuy9XxC2qzi/H5B6/68W0AsGkW0KyJPBLbDO0fg3JX/CUM81i0bD6WKe6j9qOPJ3EMcF0tSNsFA6g6alqW+VtZBUL78Vtk+Oqne7U9rs5qOQCjSheJFBeFIFOfVujSUYu3rIc4uqxWv76cAAwCwbvRb3SgYxQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-dmg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNpsU01rE1EUPe9lkk47yWTStCmtNhFSWxos2EXVhSsRcasuxYV05V8Qf4DgD/AvCK5EV1oFI7iUBqmCNdDvppq2mWSSzEzy3vPOpFFq+uDNfR/3nnvueXeYUgrBWH1/9/NE7k5BKRnuRcfF2qdnmJq9DeF9tQ+2isuMsxXGWHh/a1mEVsPJSI5fSU3OPEj291IIlN49RXz0KqzEQjIeZS/L5Y/3wPGhDxIM/i/A7fZWgVG0t5EaG0ZUa0JGM8gvPrZmLt58QYwv91mfAqCIE0sAqgumBFITGQzpUYhuF0KfRa7waDyXXXolpVrsh/0tgSLDr5I+wUZo1UHCSkAficPzY6juFSmbRPrC/azjq+fkcO00gAqoU7B0ETKkfWbuCTjTYeq5oESAauexcTScX+ZACWFm0YQSLZKhHdr67+/wW0e0dgjYo3sCEXXybYtBDVSHLp2es3IpsILS24c42lkBg6DzRjgRzCDZ/xr0GNRJwwYiWgzt+hYMawleu0V3wbkT+kUirOc7IGJAz68R/Qak1BAlx3hqASPGBJRXpXOv58dkz3eAgQoOm4hyj57NgZm0MHvpBmK6QdUdg/DAg9cRkhicBSDaKJdeo1bdxmR2DtWDDUxl51HZ+QHTysD3XdQO95Gfv06aeGcAdBrY3Chi8lwO3768QWX7J5q1XWyVSxgajiOXLyBG2hzurRKV9lmt7ISNkkjo6HhNyjoK+2gXRsKE57ZIE2ot10Z1fz0Ue4ABVw3NMjnW14rInh8jTYywoTg3EOFpOM4mXNfH9PQUfGlrAwBOs3I8ljbtuMWhRWzIIPrkn+GcYcgIWEowbZ+0qB334/4IMADESjqbnHbH0gAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-doc {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAppJREFUeNpsU79PFEEU/mZ39vZu77g7DokcP04BBSUmiEKCSCxs7Ei00JAYO2NlTKyMrX+CJhaGwopSQ0dMtFEsbDRBgiZEQIF4IHcg+2t2Z8eZ5QDlnM1mZ9+8973vfe8NEUJArfSNhzPG0VIfeIiDRSDkw1cWVt3N8rhG6SdSO2Gvn8dfuueqZwuNZqk3Jxg7iNcIfBbgXD6ZC8u5qffzX8eoYeyDxC77uygKhcouovgVUQj1H4YB2ovNuD9+tTTU0zMVBmG/+C8AIYh8F361DL/yE5HnADKYlVdg6MDAmW7cuz5WGuw+PsWDYGAvbL8ECFUt4K7/AHd/I9c7BLaxinD2Ld5Zo7g78RLuRhlBS2cpWbGfStfhfwCEpK0nUjCbWuGsLciSOELPhkq/YgdY3l6HsLfRcLYf+pHNbH0JigEPkLAyMsiEJ7NrqQzM1i7wyhoMZqOhvQs6Z0ovXgdAJACRoulEg5HOwrOroKk0zOY2BDtVpTF0CU6kLkQJXa+BNEoG0lMSsBBKQXWNQktmoGcaYeSaQCIVWOvUYQAiWZFQtk5mSMoSzEILtBrTfEcviC5bwVwQmoh96wA0ic5dB57ngeoaTIPCdb34zDITYNLOOIeVSsW+dQC+7+NSWx6jJ4tY/rWNV7PfcGv0tBoPTM7M4eKJVgx2FTE9u4QPS6x+kHzfw/mOAjarW2hJG3hy8zIceweuY+PRtREMdzbjzcd5WBqPB6xeRGUMGRzHjWvMmxQ7tiOF1JBN6FiTd6Sy9RuFbHpX7MMMqOD088Ii+op5OUAO7jyeRGfBwrF8Cg8mXuDL4neMXzgFwhwZz+hf7a9d5yu3Z6DTPjVQIY9k7erO7Y63Lvc8ErEeyq6JaM6efjai4v4IMABI0DEPqPKkigAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-dotx {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAndJREFUeNpsU01rE1EUPTPzJk0y+WhMStW2qdVWxUVEQUF0I+4ELQiC7lz4N9z0T+hG9wrdZKUgLqulhrbSag1CKpT0g7RpYjqZmffle5NEKdMHlzfvvXvPPffcO4aUEno9f3Vt4dTp+BXOe+fB0u/NbVpv7h89NU1j1TCM8H7+xY9wJwPHZMbOjRadLAvE/2gToJTiTPx89k+OlVd/LT+0TPIPpO/SzyQk40xCMxBSZ9Z3CoAx5DOjeHT7SbE0XSpzwa8OWB9jINELolQg8AR0EgUKn1PIlIWpkUt4cPNxkTOU12trs8p95RiAXpqaztqou8q6SKQJJmZSqGwsodFsIJk1kcyLYv7IeafcLx4HUNkFF4jFTExMZ0B9DrfD4HUEusYhWs4GPEJg5wly/tBYRIOeDhpEwlS34xcyajdQr3UwOT2MlJOEBRuGNHWp9AQRVXDfQiFV/U5GBSiQ5p6ngBEa5z3fiIhC6g6IMDBwOdoHPkYnHPVyhN0tF7E4QSpr94CEOKELffq+y9Bq+DCJ7rWBoQQBVbPR2O6G4OlsLASJMtCZfQqm0NP5IVWnamdAkUxbyuIYtD7wWegb0YAzAVMkkI6NwPM9xEwHloyDGAmk7AKS9rAS0FKOdugbYeAHPu7OPEM+MY7q3hIKqTFQHmC3XcONc/fxdfMDrk/ew/edzyhvvTmBAddocVRqH3Frahau56qpZDho7+PnTgXffi/gbHYmLEvPSIQBp5JU62sYz13G609zKBXvoOMdYn2zgm7Xg2MVML/4Eu3uPgxhk2gXmNl8v/i2pcXTP8tKdTEcbWLZqDQXwu/l6pfwbEnSGsT9FWAA4mdHv2/9YJ4AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-dwg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAoFJREFUeNpsU0tPE2EUPfOg006hD4rQh8WgbCSwkKgbF2owujaCiQsXxpX+D6MmbtXEsHCLmIAbE6NLo8YlGIxREIshIqVl+mQ6j8/zFVCb4UtuZua795577rl3FCEE5Bl79vPd5LHYiOP7cH1AUWi85ytmvlas1bJ9E5ryBntH3BpuP/X9i7ovkluuiE8N9SDepaLpCcRCCqa/VDCaMuIjSWP25Upl6n+QDoCz6Yh7KKzh3sI2LuUimPtRRyaqodj0MDloYiITSTi+mH29Wu0AUf9CsZPJoW5czJl48LmCc5kIKo5Al67B9gUGYxrun+5NnMlFZ+GKiQADj2a7AquseLIvjMv5KMaSBu4sWVir+3i8VIVKYSby0UTdFU8Znu8AYBHQgVOJEN5uOXi4UsdawwU0FSf6TaSoyw6DRvukPkgGWpDKy4F8a3jImCrqFDFn6rhKPR4VGnhvOTAY3WLcjifcQAsqRfhUc/Gq1MKNbBh9nIAMDjEppocxs9HCMktfGTCwP/oOBkUKNk/qF3pDYC6Ktk8RfWzyaaoKrqdDaBDwya8W1m0/CPCR3kFy7CcnmWQRUJqcRJFUKtTnPCeR71LwoeYF92CYyVnCFZpCTrRtCv5to2St8SOrKxiPqEEA4fkYT+mI0rdoeUiH1XZVuQPpsIKqw2QmfifTsnOABiWySlH9uU0Hh2MqjsZV5LtpPSoGeN9rKnhBX7ehoOSLIIPfnGONXGMMWN7xUfVldYDbjM3mrh5HCDgS17DhHgDQcIU+XbBxnDTn1x1UuQcJ9iv7l5Q5e1zLGri92EDJFnoAgHtcfr6wbbVXUqq193+0z97n3UJt1+d51n7aHwEGAAHXJoAuZNlzAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-dxf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo5JREFUeNpsU0trE1EYPfNMmtdoH2kDNmJbaVFcaBVFpAsREQpFwY0bu3HjQnTj1mVd+ANcuC3qQixmry6E0kWFVIQ+bKy2tbFJm3emyXTujGca+4DkwsedfLnn3POd77uS67rw1vC79ek7fZEzpu3AYUqS9tKQGZPLpa3VXP0uFCmJ/8t9OLC3q/uJbcs5bkIybvdHoMsSbLKENRmvU2WcNnTjRFD7ML1WGSPJHI6sA4KRWMAWVDPxLYex3iCmfpuIh1QsFSyMxQO4GvXHHwOJ6XWSyIck8v6HQsnjAxFc7vTj2VwBg4aG78VdBHQFCk+dbVcxMdwev9gTSEC455sIBOu2KLsoJFzqasP9vjCeDBlYqzn4VXXwarGKZN7Crd5QfLDT/7KpBM84c9fFUFjFp2wdk6smflRsKKqMa7EgfJJ3Ac2OKlit2pEmBTQfngdpnupoU7BUtRGiiTe7fXiRqmK+KuDn6TpvYogmBRJcrOwIJLIWxmM+dOsyLKryQAaJpjJ1/AxrGO3SqdZt7kKZJrzJWBg5piHENuY8vV6e0UOye1TyftvC5l+gZB8SHJTwpSx4q4JeTUKaxhXoR57h7Rn+3iFolJ3xvPhab6HgJG/pJ7jsNP4sUX+jZiCgEsWd/DjH5IrSYpBUAr0yHpzSoXKOP25a6OBhndh0zcX1qIYM2RIbu6i0KiHD5B/GTMHG03kTGpEL7H80wHFOWwhqDZ+SpkBOtCDYJDhZE4gRcKNbYynAqbCMbXpwpVPFbEng0aKJGbYzK1p4wIegLlcEPmdt+DjXbzcsxFlCynRwwVAwW6hjqeg0Zt521SYCWCJvbe0Un29UDx7Hgrs3IEitHXkw3jOv2fl92D8BBgAJeyqBh90ENQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-eps {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNp0U01vElEUPfMFCEVArdoSqEA0KV246UJdUJM2Lo2JK/9FjXu3utJqTNz4D9worrsQExbFpAFT0TYp0CZ8pIAiyMfMvBnvm2Foa9uX3Lw7c98979x77hNM0wRf7ufPsq7Z2SQYw2QJAkDxQalUZa3WI8hy3gmZr15bu+z8kILBkCeRCJi6bufKMji0NhwiCQR6iitdatTvQ5LyOLLEiWcYukm3m4Zhmbq1BX13FyoxuH7xAlbvpqKRK1fT0PWbRwEmDEyiy1QVg/V1GO02tO1tKLEY2PIy3KEAlmJRDLXb0TeZL+n9g4MHlLJ5HIBuYnSzXq+DlcsQLk/D9Hoh1WrIUjlPcpsYGQzS3LWoaBhvKeXWMQCDA1D9pt8PaXERUjwOjEZQFhZQp9L2yERiqYRCkPt/z58ogTGqHQLE1BLgUmC6XGD5AlipBIFKkbhanKHGYLBDqQ4ZED0OAbfLlo8OIxwGvhVgyTHlA3xkomjH/gegBgDURMv6faDbBZpN+/tHkUApkdTA/PwZAPxntwdUyjYA/+ZMqJHjLgM9iv/6zRt2GgMaIE21aVIjnSm0DGPfmhzyde0UAE2Dj+p7urKCPvkZku9eJILOSMUnkvVhIo7GYIB3xSKYdhoA1erXGVKXpvFxZwdBonnD68PQ7YEwM4O4xwMPxc8RYE87g4FIcz+kvfmnA0YzIJIy77/m0OCqsTkkCTysKPjJG3viLei63Gm3kCO6UWqcMejjxecMPmxsoFKtYop6UNirYL9Wtc5OHqzznIXHq1na7OfMJROcK8a6O7MjW7nfzZdrd7jzT4ABACh3NGsh3GcdAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-exe {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo1JREFUeNp0k8tPE1EUxr+ZzvRJO62lUAQaKIQ0FVJFjBBdoIkrDDHuXJi4NnHtX+HCjW408Q/QmHTRaCRRohIJifgiiBICTQu29mHfnc7MHc+MlECKdxZz595zf+c737nD6boOYzxJLC6Nhwej7e/24HkO779s7G6mMjcEwfKZ21+/d+em+RbagaFev28qEpZwzKg3ZckqCPH1nfS8hScIdyhBe6JqTG3PfyTTeLrwFhvbKdy9/xi5QglXL0yGJsKDccZY7LDIAwWHpSferWBh+RN8ni4UylVER8MY6PHj0uSpUK0hxzfTmWsUtnoEwO3rer64jEyxim6/Hy67DXaHExvJX3jw7CX8XjfORUdDlOohhU4fAVjILCPbm9V1yIqK2FgYt+ZmsZcv4lH8Nb5upXD7+hVMjIRQa8qeDg8UTYPU5cTcxSk4nS709XTD53ZhpD+IYMAPj+TBz93fZiz5oHV4AP1fGdlyHZIkIZkrI7GyhnK9CZXy+Aig6p1+HQAY003AcF8AVtGGfLWG9XTO4MLZ5cL0WAixoT4zVmPHADSiMo3hzHA/xgeDWFjbNg8H3A7kKnX0koEcPdTu/ylgRGZgOjNv38zoSXC8BZJDRKOlwGEV0VJVGM0y4joAPO1spXbx6sNHeD1uRIYGUCxVSRlDt1fC8rfvcDnsmJ+dOaLgoAs6AVLZPJJ7WdhEkUyT8GJpBflSBcVKDTvpDBw2GzQqQT1OgaZqUOhtFQUTUKnVTVWNpgy51YLVKph7sqKYkA4A1ScEfT66vm5kC3+ofh6Xz59FQ5bpkvE4QW3M5Apoyorhl9ABIKnFgNdTOh2NkJG6WSf9eRBJtmFwLDJmriUzeaOkYvvcXwEGAIVNH6cDA1DkAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-flv {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsUl1PE0EUPbssLYUCXdpaC9gWoSTgAyFigiRGY+KjvuuTr/4A44MP/gx/gMYfwIsan0RjIjGiJIZgSIGFIoXSD0t3Z3dnd70zpITazuZmJzP3nnvumaMEQQCx3jx69SV3a3KWMxetpSgKxP3m242Do43SQy2k/YRydvds67n8a63k+FRSn7l/bdg5tdsAuM3he/5weDC8vLdqPLgIIpba2niux52mg//DqlsYSg3iztO7mczN3DJ3+ByCLgCBH4hOFEF7cDpzPCRyOpaeLGXSc2PL3HbnW3XaRQCPEgWI2MsRVAVqrwbX9bHxbhOKpiJ/bzpDOr2k68V2BtRNzMtqDEqPejY/4zSGjb54BM0mQ8k4xsDoIMauXxnqYOD7PmwScP31d0SS/eAuh1lrolFpIBQNQw2pqJdqsAlIceB1AJCIkkE/FZskXDQVRXw6IYHiE0nBEcaPXSSvJnGwWkQXAE4acAhbxPMJpOdHweoMhc9b2F8zwKizbdlyPLVH7QLg+JKBYzoorxzjz3oRzUoToaEw9KyO8XQW5AE5jrFT6AbAYVVNxCZ0Ka3So+DSTAoDiej5ywTySbls1OEDobhFlMcXxrHw+AbINEjNXgb7y6BndLhk8cRkHHbD7g4gEhiJFxsdhrDqaamBaDKKerGGSKwPI9kR9EZCaNA5ubE7A5s8IFhsrxQkgJhZoa/06xC5xRz2v+3BOjFlbqcGlquxsondT9vY+2pAJdeZR6fI355CgQCN2A4O1w7gkQ7cdLUOAKdhV6uFSv3kd/n8mT68eC8dKWLnY4FsfeZQh7nVVt0/AQYAsf5g+SvepeQAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-gif {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmVJREFUeNp0U0tPE1EU/trplAqlL0laiw40xASByEJIZFGVnSvj1j+gWxNXJq7VrbrwF7h10cSNhMRHojEuACVBKmH6SJQyJeXRxzzv9dyZPiCtN5lMe8853znf953xcc4hztDzZ1+C6fQMHAfd4/MBFG+p6h/n4OAeAoGNToi/eOm+A50LKRaLh6amoty2vVpZdotNXccMEK3LwZxa2bsDSdrAqePv/mLM5tSdMwYBYqyvw9zdhUn/L59P4OGtG8qlZCoH254/DdCdQBCxqZu+ugqnWoW9swN5ehp2NotgIo6bGQWGtaS8+vQ5V9a0u5S+1gfABEilAqdUgm98HDwUQkDT8JXoPPq+BoM5kCYmFT9jryn1+hkAt7heBx8dhbSwACmTAUwTgdlZ/CVKJaLnI1GD8TikZiPSR8Gxib8chH95mZTxgwWHwH7+gFMswqcokIRbjMO2HDCnZ1VvArpjEmnKZc8+cZJJYGsLsMiZ8AgwEqaY6Mb6RQR33JFhGECzCRyfAFXNu9v+RVNRZWIMuDJNuYMAaDycUFGhCOgtuAtFVDA83G5A8TrFDw+F5QMAxAKJJxz2xnW3RPJGbm+rCyjotZetH4DGzaSSeDA3h4Zl4R0JOEZWTpIzF4n/m995bNdqZwB6m0gFft3Ak6vz+KYWwFsGlqIxXItEcDt1ARMEtKdVgZb+fwA0G2C2hXM0ZTZNRcSf0b1pmXi7uYnjI+Lfanm5fRQsK8BIxKcrK7i/uIgP+Tw+FlREqHN5fx/vyU4uHBE6UO4gDWqk/JFaLuMxcXeFk6TuJ90V0HOk1in7J8AAjmgkPfjU+isAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-h {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAbRJREFUeNqMUk1Lw0AQnf0woK0ttVqp0hwqVCl+UBERT94F7x78Cf4Uz179DT14F8WbYHtRkBYRLNqDtdaPZLObuLs1NGlXcWDJZGbey+x7QUEQgIqT07PL5WKhHL5H46J+22q22vsWpbWwdnR4oJ80LNiz2czGUjENhvj4ctIE4Wrj8XmPUlKL9nCYcOFzE9j1OKSTCdjdrtiLdr7KhVgzEvwW6krC92E6k4Kd9bJt57JV5vFK2KfRQRV+RAMkzxglYI1RaDy2dW1rpWRjQo5VGicYIorWVooFvQVCCAjG8Omw1MgG8AM0uSBUDSnCfk/IGCHwf3DCD/7UhOLBrFkDuep/hDUSSCv1iYo4rIfqGwmUSNJjfYbBcQKhZw0aBMA4B48LwBhBt/cON80HmM9NQ6fXg/Wlku4TwmNWDzaQqzHG+0PSKod5cH5Vh2RiAhYKc8DlV1UPSyuFMGygVlMg1/P6BC6DqXQK8jNZDXAYA1f21V34wMXYFaiyVw0rJyzLgs3VMkxOjGtix/V0XWChZ0cI2i/dzvXdfTd0Qf91BMPrhyNzgKfOmxaWypqaDXHfAgwAtCL8XOfF47gAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-hpp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAehJREFUeNqEUk1v00AUHK/XKf1yZdESVRBXjRSRFqMQVBA5Ic5I3DnwE/gpnLnyG3LgXglx4UDDLZS0RWkDLiRxSusk9u6GXSembmLgWZbX7+2bnZl92mg0goo3b3ffO/ncdvyfjHef6q2Dlvs8Q2ktzr16+SL60jhhZ69bO8X8ClLC7w9XdKJVG8fuM0r1WrJG4gXjgqU1D0MGc2kBTytl+7a9XmWcl1IB/hZKEhccq5aJJ/e3bTu7Wg1CVo7rNLlRhUh4oMnXoDoyhoHGyWmUe+QUbELIa7W8CjAFlMzdzeckCwFN06ATAn8QmDMMMGlMuwWucpoCHNe4jBkAMenjYvRPTyi53JvuwX8AplleAeBcRFrH6rXIxLim9I/pi3QA1RhKaYxdjkN8IwalCMIwWs9ljMkh0wzk+9M7w179C3LZNXxve2h+c3Hu91HeKmD/6zHOLnw83ilB1/V0CeqU3Q81LC/O41b2Btx2N2JVP2riR8eTUxmi0TzBwrKZMsqMoz8MsDh/DWuWhUBKURLKxQIeOMWoptYPnS1c+INZBkwISomOSsmBZS7B+3WOzZvrKGzkMAiGqNy7g+LmRkRfekBnANy2163PZXrSbrQ6vch19Xz8fPDHyL39QzkHBKedXjfu+y3AAGU37INBJto1AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-html {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmBJREFUeNqEUktPE1EU/mY605a+hhZTBNKRDApNrWIRA4nEBUZdmCgLNi4MK5f+FNdu3bFv1J1EXODCR1JJSMTwpqUP6NiCpe10Zjz3hj5Mm3iSybl37jnf+c53jmDbNpi9eb+6Ftcisea909bWNzNb6dwzSXKkhIt/r14+515qBqmDA8HpqKagh53XaopblpIbe+knDpFAhPab2Dw0TKvRK7lmNODzePBgZlK9oUWSpmVNdpIU8T+jaMsyMaD4MDcZVa+NhJMN00w0n6V2nN3yQgdHWZag+LzYPTomIAtT0THVtPGanmb/BbjwLFkvn2IttYGYplKyDzsHh7gdmyAWfh5zVq0Guhg4RAHFUhmfvq3j134aXo8bd+ITnMFOOovU5jbGRoZwNxFn1cxuAIcDW/sZDjA/c4u+BNxOJyxqaenpI3z88gMfPn9Hv98HQZS6RazW6kjExvFi8TGdDSy/W0Emf4LS6R8sv11BmfzSwkPcm74Jo9Ei0GZgmkw8QCOao8OXcaz/5vSZnPdnp3ApqBBLkWJE0Ci7ASzbIhCLLQ1E0iOkBDh9NpUgiUejo8oNuJwyn0YPABtn51UYFFivG3yBGCNZkuDtc/MW+ZQI3OrYpBaARCKufk3B5XIiWyhiL5ODp8+FfFHH+KiKSqWKUL8fC/NznGlPBmz+24dZjKnD0CJDcMoyW0SqXuMtHBFw7rhIAD1ErNUNafxKBNevapwu65NpEQ4FqXIA+RMd6VwBP3cPSERb6gLIFIq61+UqGWaFdcrVt/lmAuWjAi2aiMFwmOYuIJ/N6M28vwIMAMoNDyg4rcU9AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-ics {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhRJREFUeNqEUkFPE0EU/mZ2dra7bLNpi2AxQFKalkJrohICiYkXPagXrx78Df4K48GDBzmQePLMhUODNxQ5ciEkJVqDtJGmMWrCATRbd2ecoS5u3aovmezsvu9973vfPiKlhI4XL7c2r5YL81LIELEghLA3u/udxmHnPmfGW/Wuv+LpwwdneRYBx7PeWK0wOYYhcXxyckGV1fdbnbuMsXcklqPRJQxFMKz4RxDCtVO4s3xlRjWoB0FYjlQPEEBieChwKCRGMx5uLtaKs1P5ei8IKlGa/YkXMXYtlTEDlsnw/mMXhBJcqxSK6vlcpa4PEpCooUyIqs5M6hG1o2CUwqA091cFcYLf/sjzcX75EiQIojI9779CTYR4jwTBf+r7GAwh0AxCiL6JMT/04vQ79u8aI2O/7Jzg69o6Go8ewycUahtBpADhHKLnK/eVbkMdtROWIv80NQ2sPhncA9Htwn+9hZG0rY6DzFwJl+7dhs0ZstUy8rduwPS/wd/ehmi3kwq4zTHiWUgXp+EuL8FvNvFl5Rn4xAS86iyI2kY3n0Mv48ByrOQmancdi8I0Kcj3U5iuA29xAelKCUHrEIayzltagG2E4IwkFaQgSC6lYI09iN0d8It5uNV5nG5sgJdKYC0G8WoTOZvBISFNEBxnsuzD3GX4vfDsszzqAu0jkJQDedCGbB6AWg54pYbPo+NGVPdTgAEAqQq70PytIL0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-iso {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjlJREFUeNp0kstrU0EUxr/k5qbJzdPYpGkpsUJoA2q1oLjTdiGiIC5cuXHlxv9BEOrStTvBnQvRrSAIsejCrlqpsURq2hCJNQ+TNLm5uc/x3MmzJh34mDNnvvnNzOE4GGOwx8+t9XQkfn0VE0Y5/7Z+kHm+dvOhtd3P9c/xwNZh7nWaMYtNUmX/Fct/vlN7/8J5aRRgyzm8xzpRDjGE2aVH4VTqdnoUYg/XkEhmy+Cx3DhA5tMzdFolvg5Mx3Fx9SmH0JIg79Zo3j4GADMIokJTKtjbfAKXU4Y/2NvSfyH75TFOxa9Cmr0XnlPFl5ReOQ6wNMDsoFX6AElqQlNV1KsOuNwS/AGFjEUIDhmn5+/DMM16/9igBowAzFKIswPJr6MjlxFP3sV04gaP7RzMPe6xvWM1gNUBM2UKYlBau3QghGphg29J3gDlLLilWNdD3gkvIIDRhD9yGe2mCV0V4HFXuCxT5Dlv8Dz3sIkAs03FalDxBMQSt9BRBMhNncuO7dyU28c9tnf8C/Q0ZtR4GImeQSj8APLRH772BWcgiFODffCv/t8H9tO0v3RjV7VqkeeXLlzDfvYjj88uXhl4JwIsrYxmLY/M1gYclIvGE9jZfNPrSCD3/QgLyeWTADV6wW9AryIcCkB0u1Aq/oCPumlufoF72vIheaLDr4wCLIOqrYnULA14PSoqpSJEAUilZrD77Sv3LK+cI0+Be8cAbbmAOrob0agtD491LYfkoqvnyZLsWRkA/gkwABL4S3L78XYyAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-java {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjxJREFUeNp8U01v00AUnNiOEyepQyhQobRBSlVIoRCBEPTAjQsSEneE+An8FM5cuXLNoQduIAE3qopKNJAIIppA2jrOR93aa6/N8yZuUxyxkrXr3ffmzczbTQRBgHC83nj3ca28dD36nx6fvnzrNNrdp4oibyUmey9fPBezEgWVFuYLdyvlPGaMY4fl1aRS+9pqP5ElAkmcnknRwuO+Nyt5u/ETYfyj9WrpZnmpxn2/Ok1Swn/GvtnH5k4TLue4kNfxoFoprRQv1TzOb8cAIu3+ZD7oD/Hm7XuxzqRUNDtdkuLiTmW5tFxceBXlnXgQTAORSMt2oGezUJJJrK9dFWdEH7Ik4dB29LiESeUEJXd7/dAT3L+1ivlCHr8NEzutXTBvbJPPSdO/AH5wysChwM/1HzCGlmAzOrKxu2eCud6Z2Jke2MwThpUXL6Nn2ZAVFTlNw70bK0iRnGAq9qwHtOmTRpsx1NsHyKRVnNPnoMoK9kc2BjbD4vk5JGV5NkBoEPM4FFnCteJFWOS4ntHEfphQyKaFTWFLw704AJ26ZFx/ZEEi3YyY0O1Dmr4EKTUHA8hUnS6siI0DEHLYog+b28RCRuNXR/iQUpPUEQ+NVht6Lodnjx+GXYgDSFRnq97Ed2pXSlXhUSeGhxYc5sKlNXM5DGLR2TMwfZVPAIi+otGNWy1fEZUKeo4qc4ysI+F8VksLIJfYcD9QYgB/DNPMptWBlsnBIS86xmDMTBo/PWd0LB6VZfdEbJT3V4ABAA5HIzlv9dtdAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-jpeg,.ipfs-jpg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8luUlEY/s4dmMpkWxRopGJNNbiwhk1tItbGtXHr0hcwmvgOdWld6Bu4coXumtREE3ZKu8FgOlC1kIoXtC3jPfdc/8PUIpzkBM7wf+f/hsts24YczuerGUc0moBlYTAYA+i8sbdXtAzjITRtq39kr73s/Gr9DTUYPOeamwvYnHdrdR0SnDebuCbswJGqpX+Uf92Hqm7hzFAG/4TgNr1uCwEJ0trcBC8U0Kb1/PQkHt9JxSLnL6TB+Y2zAIMOJBGLXmtsbEAYBsx8HnqCGKVScAX8uHf5EpqmGXv18VO6VDEe0PXsKABN8+AAgiabmYFNNJTDQ2RUFc8+Z9G0OPR4PKYwvKari0MAgiY/OQGCAajhMNR4nDZMaInrKBGl70SPMScck1NQG3X/CAWLE3/dAWV5hRRVIJxOWNksrP19sFgMqqAebUGYHMI6teq0A9oTVAhqu2sfbYYjsL7lCZ3683gA70T3TK7/B4BNoO020GwB9TpwfAz8LgMtWn/NkV8EHgoB81c7nYwCyBZlEVkHcqMTKFnkmehJTOPvEfCnKi0fAyADJKfXC/h83TaZTJjaa5lANLpOFqAXtlEAorAwO9u5syT5UxLfU0e3o1FMu1x4u7ODYq02BKAMAVSrSNLrK1MhLPj8mNF0vFm+C1ZvwKBwXXE4AGn1WAASazESwUW3BzUSMeJ2o1Aq4sPurvQYSRLwlhRR6mSaYyi0WlpAJrFRx3ouh5/lMt5lv8BLwXp0M4lSpYL17e2uK5wP6lj/c2ZPn2RI+YT8fDvqoyegVLyfG5kBKaQQOfvF2pLc+ifAABiQH3PEc1i/AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-js {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUQ5ODY5Q0NGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUQ5ODY5Q0RGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRDk4NjlDQUYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFRDk4NjlDQkYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoT8zQ8AAAJdSURBVHjadFNbTxNREP52t7S0bktbKFAvTUVaw60YqkExUTD6oD74qC/yD/wp/gh885XEEI0RAyYQUiMpIBGMkYR6o23abi+73e2uc04v1LROMtnZPTPffvPNHMGyLDB7sbJ2ciUSli3U35smkK9t7x9v7n2dD/g8KUkUwWqeP3vKz23NxJGzgwOx0RC6mSgIo+WKuvP56MeUzy2nJEk8PWsGJVVTuhWbpgmHw47FB7d98Wg4mVWK52o1sxOg3Va3PmFp+Q2PdUquaFUM9/vw+O6cP3bxwm46Xwh1ALR3/vL1e+hGjcc9koScUsTSq3coVDQsXJ3wzo5HEs3clgZNMTVdx1T0Ep7cn6//QRQwMhzA6uZHLD5cIFEFSKIU+G8LK+tb0KsGZKcTJoEyP08AbpcLy6sbPKdQrigdAGaDwWxsDH1uGbliCYIgcM8WFPg8Mq5Pjzdyu4jYbCE44EepXMHuwXe+A8x3KKYxYsjvbUzmlPGpBmYdgI1oYjSMbL4Ao1YXMkcM2Dd2xnbAamPQAqg1GORLZdycmYTdJqFKk2DPR3fmwI4zBDrg9RADqxPAbPBif2WTSB584/3/TGegEOit+DRcvQ4OZJi1LgwIQKVCg2i6nb1I7H3Br3QWqT9pBAP9uDY5xjdSM3RqxeoUkfVnEOW8UkLykERTNXjkM7h3Iw6NNvHw6JjuhAhVrba0+QeALozcI9nQR0VvNxJc/ZmxCNGvIBQcpDG6udA22kyW29HC72wu8yG579ZoiSYuR/ly2+y9CA4NceWLmo717T1i5ULqJNtapL8CDACskxPFZRxLwQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-key {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlZJREFUeNpsU11PE0EUPbM7u/2AtJUWU6qiiSYYo5EmmPDCD9AH46sx8cEnja/+CB989z+Y+MKPgMiDsYQACcbaWBBogYD92t2Zud7ZlQZsbzKZ3bl3zj3n3IwgItjYeDO3MlWme0bjUth8e8/fO2tHzx3XqUEk50uft+Ndnhdmc3SlfNPkVZT8Cy600DoIISvVfKYtlvfX1p66XmoIYsMZdjJQWvEFbbsC/S5g2QhSkKUK7rx6OzvzqLpsovAhaAxA3DUBQn2TUFsl7KwTfm4Z9DoO5LW7uPXi9Wxpfn7ZKF09vyPxX2iWcNRkKGZz0mQWKoNs8AVB6x1yRY2pYnc2LLofuXTxMgAlmlXIfngCxNxEzM+DPv6NQa2BygLgZyX6JT83ngHTN5GAL0WSoUQkSQnXkyBh/k0GegTAaldM20sTKvet+yyhIZApECamL0jUSe3oFChx3TopM4TeEQP2gc6BgGIwb4KGNXRhCkMGxgg2kJeybRiZM45D8W61qEAknSmpHStBhywu0nFVupSCTAcM4ECwqapv+NQ6LS9JGALoMIIoPYDjZiEL1xHtbyO39AQUDaA7R1AH23DSeSA4hv5RG/VAhxomPYP8sw9A4TaC9iHkjUWmrtGvbyC18BLe3GP0m3WW4I5hEBEnPIStXzyuFIxb4EkMEJ79Qa/xHbKxCdM7xeCwzUZOjgEwnuzt7qLz6T3cySmQP43uzjeIiTJM6io6W19B/NLCKMVGCzkCoLR/0lrfOI2fNy/huKC1FTsK/rbGNeMRC8dHpHByfu+vAAMAL/0jvAVZQl0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-less {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjZERjZENTJGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjZERjZENTNGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGNkRGNkQ1MEYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNkRGNkQ1MUYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pl1w97IAAAJhSURBVHjahJNLbxJRFMf/wPAIMIxMkUI7tS0VYqlGDLGhjdKkqyZ24cJFN925de+XcONHaHRj4k7TND6SGo1VWwmp2kSLhlqMDbQ87gzPYcY7k4GgoJ6bmdw598zvnvM/95pUVYVma+svcovx8yMnFZHAMJPJBJfDzq5vpX6+/vD5qo/z7DOMBdo/d26t6jFMJ3iY51jBz4M+LP6wxEw40Gy23qYzB3HO7fpmpZCOmfEfa7Xb4NxOrC4lvbPToe2yKE3K1PdPwNOtHdx79ESfq4qKkijB5/XgevIyHxEC24USmewDqD2ABxubaLRkfW6zMqjWGlh7/ByyAtxYnOPnL0Q2+gGGmKRaw8zUBJaTiS5QOO1FJnuIAM8hciaIWHgi8NcSNt+loVDY8JBXh2ojJAR1HbTSNFMUpV8Dxcjg0nSYBrtBxdLbqI1iheCUh9XXNGurAwCdEkb9QyBSFam9TDfoPZ1LUg1BH28IiwEARTVAQOzcFKRaHZpLoa9avY6L1Gfs0c32t4PU6W2lWsV8LAorw0Cs1nXftYWE3qZGqwWHzYp2zzlgetuolVFvtiDLbRRKFTAWCxx2G/KlMtXFhWPqOzsWHJwBx7rxKv2R7mwFz3lw9/5DLC/M4Us2RwV0g3U58XJnF7dvrsBOoX0Abbej/DFKRMKI30fTVGC32WA2m5H9cQQvhYi0vE/7Wdgczn6ARA9QPBrBszcp/XvpyqxebzQ0Tlsq6llxLhe9bD4cFMr9XdjLHpLv+SLGBYHAYiVu1kNOpAaRTWbCejgiw0zGhFGSK1aw+zXbvfK/BBgAPwADAs5GpGsAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-logo {background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 553 235.3'%3E%3Cdefs%3E%3C/defs%3E%3Cpath fill='%23ffffff' d='M239 63h17.8v105H239V63zm35.6 0h36.3c7.9 0 14.5.9 19.6 2.6s9.2 4.1 12.1 7.1a24.45 24.45 0 0 1 6.2 10.2 40.75 40.75 0 0 1 1.8 12.1 45.69 45.69 0 0 1-1.8 12.9 26.58 26.58 0 0 1-6.2 10.8 30.59 30.59 0 0 1-12.1 7.3c-5.1 1.8-11.5 2.7-19.3 2.7h-19.1V168h-17.5V63zm36.2 51a38.37 38.37 0 0 0 11.1-1.3 16.3 16.3 0 0 0 6.8-3.7 13.34 13.34 0 0 0 3.5-5.8 29.75 29.75 0 0 0 1-7.6 25.68 25.68 0 0 0-1-7.7 12 12 0 0 0-3.6-5.5 17.15 17.15 0 0 0-6.9-3.4 41.58 41.58 0 0 0-10.9-1.2h-18.5V114h18.5zm119.9-51v15.3h-49.2V108h46.3v15.4h-46.3V168h-17.8V63h67zm26.2 72.9c.8 6.9 3.3 11.9 7.4 15s10.4 4.7 18.6 4.7a32.61 32.61 0 0 0 10.1-1.3 20.52 20.52 0 0 0 6.6-3.5 12 12 0 0 0 3.5-5.2 19.08 19.08 0 0 0 1-6.4 16.14 16.14 0 0 0-.7-4.9 12.87 12.87 0 0 0-2.6-4.5 16.59 16.59 0 0 0-5.1-3.6 35 35 0 0 0-8.2-2.4l-13.4-2.5a89.76 89.76 0 0 1-14.1-3.7 33.51 33.51 0 0 1-10.4-5.8 22.28 22.28 0 0 1-6.3-8.8 34.1 34.1 0 0 1-2.1-12.7 26 26 0 0 1 11.3-22.4 36.35 36.35 0 0 1 12.6-5.6 65.89 65.89 0 0 1 15.8-1.8c7.2 0 13.3.8 18.2 2.5a34.46 34.46 0 0 1 11.9 6.5 28.21 28.21 0 0 1 6.9 9.3 42.1 42.1 0 0 1 3.2 11l-16.8 2.6c-1.4-5.9-3.7-10.2-7.1-13.1s-8.7-4.3-16.1-4.3a43.9 43.9 0 0 0-10.5 1.1 19.47 19.47 0 0 0-6.8 3.1 11.63 11.63 0 0 0-3.7 4.6 14.08 14.08 0 0 0-1.1 5.4c0 4.6 1.2 8 3.7 10.3s6.9 4 13.2 5.3l14.5 2.8c11.1 2.1 19.2 5.6 24.4 10.5s7.8 12.1 7.8 21.4a31.37 31.37 0 0 1-2.4 12.3 25.27 25.27 0 0 1-7.4 9.8 36.58 36.58 0 0 1-12.4 6.6 56 56 0 0 1-17.3 2.4c-13.4 0-24-2.8-31.6-8.5s-11.9-14.4-12.6-26.2h18z'/%3E%3Cpath fill='%23469ea2' d='M30.3 164l84 48.5 84-48.5V67l-84-48.5-84 48.5v97z'/%3E%3Cpath fill='%236acad1' d='M105.7 30.1l-61 35.2a18.19 18.19 0 0 1 0 3.3l60.9 35.2a14.55 14.55 0 0 1 17.3 0l60.9-35.2a18.19 18.19 0 0 1 0-3.3L123 30.1a14.55 14.55 0 0 1-17.3 0zm84 48.2l-61 35.6a14.73 14.73 0 0 1-8.6 15l.1 70a15.57 15.57 0 0 1 2.8 1.6l60.9-35.2a14.73 14.73 0 0 1 8.6-15V79.9a20 20 0 0 1-2.8-1.6zm-150.8.4a15.57 15.57 0 0 1-2.8 1.6v70.4a14.38 14.38 0 0 1 8.6 15l60.9 35.2a15.57 15.57 0 0 1 2.8-1.6v-70.4a14.38 14.38 0 0 1-8.6-15L38.9 78.7z'/%3E%3Cpath fill='%23469ea2' d='M114.3 29l75.1 43.4v86.7l-75.1 43.4-75.1-43.4V72.3L114.3 29m0-10.3l-84 48.5v97l84 48.5 84-48.5v-97l-84-48.5z'/%3E%3Cpath fill='%23469ea2' d='M114.9 132h-1.2A15.66 15.66 0 0 1 98 116.3v-1.2a15.66 15.66 0 0 1 15.7-15.7h1.2a15.66 15.66 0 0 1 15.7 15.7v1.2a15.66 15.66 0 0 1-15.7 15.7zm0 64.5h-1.2a15.65 15.65 0 0 0-13.7 8l14.3 8.2 14.3-8.2a15.65 15.65 0 0 0-13.7-8zm83.5-48.5h-.6a15.66 15.66 0 0 0-15.7 15.7v1.2a15.13 15.13 0 0 0 2 7.6l14.3-8.3V148zm-14.3-89a15.4 15.4 0 0 0-2 7.6v1.2a15.66 15.66 0 0 0 15.7 15.7h.6V67.2L184.1 59zm-69.8-40.3L100 26.9a15.73 15.73 0 0 0 13.7 8.1h1.2a15.65 15.65 0 0 0 13.7-8l-14.3-8.3zM44.6 58.9l-14.3 8.3v16.3h.6a15.66 15.66 0 0 0 15.7-15.7v-1.2a16.63 16.63 0 0 0-2-7.7zM30.9 148h-.6v16.2l14.3 8.3a15.4 15.4 0 0 0 2-7.6v-1.2A15.66 15.66 0 0 0 30.9 148z'/%3E%3Cpath fill='%23083b54' fill-opacity='0.15' d='M114.3 213.2v-97.1l-84-48.5v97.1z'/%3E%3Cpath fill='%23083b54' fill-opacity='0.05' d='M198.4 163.8v-97l-84 48.5v97.1z'/%3E%3C/svg%3E%0A");background-repeat:no-repeat;background-size:contain}.ipfs-mid {background-repeat:no-repeat;background-size:contain}.ipfs-mkv {background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M7.5 91.1V71.2h6.1l3.6 13.5 3.6-13.5h6.1V91h-3.8V75.4l-4 15.6h-3.9l-4-15.6V91H7.5zm23.5 0V71.2h4V80l8.2-8.8h5.4L41.1 79l8 12.1h-5.2l-5.5-9.3-3.4 3.3v6h-4zm25.2 0L49 71.3h4.4L58.5 86l4.9-14.7h4.3l-7.2 19.8h-4.3z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain}.ipfs-mov {background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M6.1 91.1V71.2h6.1l3.6 13.5 3.6-13.5h6.1V91h-3.8V75.4l-4 15.6h-3.9l-4-15.6V91H6.1zm22.6-9.8c0-2 .3-3.7.9-5.1.5-1 1.1-1.9 1.9-2.7.8-.8 1.7-1.4 2.6-1.8 1.2-.5 2.7-.8 4.3-.8 3 0 5.3.9 7.1 2.7 1.8 1.8 2.7 4.3 2.7 7.6 0 3.2-.9 5.7-2.6 7.5-1.8 1.8-4.1 2.7-7.1 2.7s-5.4-.9-7.1-2.7c-1.8-1.8-2.7-4.3-2.7-7.4zm4.1-.2c0 2.2.5 4 1.6 5.1 1 1.2 2.4 1.7 4 1.7s2.9-.6 4-1.7c1-1.2 1.6-2.9 1.6-5.2 0-2.3-.5-4-1.5-5.1-1-1.1-2.3-1.7-4-1.7s-3 .6-4 1.7c-1.1 1.2-1.7 3-1.7 5.2zm23.6 10l-7.2-19.8h4.4L58.7 86l4.9-14.7h4.3l-7.2 19.8h-4.3z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain}.ipfs-mp3 {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra7XWxpSsFYIbVQf9REFBHkYBRIPJh4wrN3DsZ4MPGP8b/wUCIHEw5EY0w04o9ILcREGmwVgaXbbXdnd2bXNxPahGyczebtzrz3ve99740WRRHkWn5cebu4cH6SMY7e0jRAHr9c3WxsVvcemmbys9yT6+uHJ8oaPefypdPDD5Ymh5w26wMkEho8JtDtuEOZFCrvN/4uJZNGH0T59D58X/C27aFNAL3Xthmsww5GCyN4+uzu+OLtQsUPxPQx6ZMAoQjBAw7O+bEVCMMQgqygs+LFs1h+dGd8bna0QmXO9OL6JYgwAvOFZKKoy3V44CgNfv7Yx8oLH+lUEgvzF8Ydhz+n41snAGRG5gUEwClzhHdvttFxfNyYK0EnJozKK5eGcf1qHo1GOxtjwI+pfvm4g/W1qtJgerYE2SXJSIL9+W0jk0mCShAxDXgQKgbNXxZq35vQKCiKQkSUXdc1+gcch1FHGPmKuIgBCdc66qJQHMG9+1NIpUylxxHtuW6gEiTIu+N4yjdWgty0yTmdNjFzcwKjY0MU7MLt+IjoSad16FoIx3b/A0DZ7FYXnsdpAjUMDOjI5zPgfoBsRodhhGhZHfBBU/nGAGRtxWIOg5lT2NtrI5dL0SB5KJzLodloqXaOEatPGztKq5gG3S5DNjuAK5NjKJfPYKI0okBkSdemCiSgS/rkQNLSePtxBj4LSCwfFtE0krqqX7ZVMnu9XlMXy2l7ME0dzA3iANQyY6vWxC61UY41zTyNcYh6/QCNXQvzi5dR39nHVq1BUyuMGAARsF6tbbe4iKD1r7Om5iFBdmW1SsDflLiuB6sX90+AAQDHAW7dW0YnzgAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-mp4 {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnBJREFUeNpsk99r01AUx79psrTrujVtbceabnZs4DYRHSoMh6Dgq77rn+AfoA/+If4Bok+C0CfxVRDBh+I2NqZzrpS1DVvbtU3SJPcm8SSlsJlecsn9dT73nO85V/B9H0H78OLdt/LDlQ1uMYybIAgI9n99OWxoe83nkiz9hDDae330JvxL48O51Xxm/enNtKPbVwAh0Ec6kYpXat9Pnl2GBC02HrjM5Y7h4P8+7FtIFVJ49OrxUnl7ucIdfhv+BIDv+fBcj7p/tXMPrs2RXVTw4OX2UnFTrXCbbY7tpMsA13FDSDAOQ4gJEGUJLs0PPh9CkESsPrmxxEz2lra3rnpAt3G6adgdQhBpmeLkFodNmsjpOPoXBrQTDcmFFNS7i3MRDzzPCw/vva8ikU+COQxm14BBhvJcHLGpGPTOAJxxeLbrRgAkYujBdH4G5oWJWXUW19YL4XqunAMFhnq1BqWYgaY1MAHASQOiU96zKzkU76mwehaOvx6h9uMv7KFN3RopL4oTAI4HRh4wSl399xla+00YbR3yrIzM9SzSqgJJnoKcklGrH08CcJjnBtLLCsSEGGpSWJvHtDKNoFippsJ0ulIsDDUCCATMlBQkNuahEyiZTcLsmFBKaQxaOk53TlHeKkM70AjAooCghBOk9sKtIvqtPqS4FBaRnJSRX8tj2DOh3lFB5Qw2ZNFK5LRo6w4sKt2ggAzywidAMN/9uIPSZglBLDO5FF3mRD3wHE9qVRvoHrUpfn+UEQK0/7ShtwboHJ6jdH8RZxSC57hSVETb7e5/2u0FxqPHJow+8iZ4lYY2QGu3idhIxO7Y7p8AAwALCGZKEPBGCgAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-mpg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNpsU0tPE1EU/ubRdlqmnUBboa0UeUQDiUGCC1+JmrhxoXt/gBvXJi74If4AV0Y3sNKF0YUaICqoIfjgVShEiGF4tDOdO/fOeOaSKtie5GZu7pzz3e/c7ztKGIaI4vn9p+/P3h4e4a6Pv6EoQBDiy7P5rc1P1Xt6XP8M5ejXo6UJ+dWbuemeTGdpvNdiNe9YvQLe4Bi4PmTpRmyq8m71rp74BxKF2twIHvAo+f/l1T2Yp0zceHizfOZa/xRnfBRhG4CQqAYioBWeXDyA8Di6ei1ceXC1XBwrTXHPH2vW6ccBBBMI6BsSUEQzakGL6xB0tvjyBxRNxdCtc2Xf8R9TyaWTDOg2TjfVdw6hqIoE9B2GxkEDWlLH7s4ette2kSp0oDRezrQwCIIA3oGHr0/mKMmE53qo23W4+w5S+Q5ohob9X3tgHgO8ULQACC7gMx9mKQP30EW6mEHpYi8xcJEdzMucjfkKcrTfmqmiFYBxCF/Id+gayKJwoQjHdrA5v4HK7Cq44KjZNWpagaqp7QACks0H9znW365ia24DzoEDozOJbH8eVtGShXHTwNracnsG7q6LzsEuaAlNPm9h7DSSVjLyCMkppDI+GS2StQWA1RlKo0X56n2X+6QHkmkDakxF9WMVqWyK+s/BrthYfvWz1Ug+zUDcjMPMm0h3pxEjFma3CbIuCud7oMc0LL1ZgmElpGJtW3B+15HIGNITrMYIlOH7i0U41NrInREylYbu4R5qQbQBaAh95fVKZCnpQCnb9DrWZyrRERS6NDeUw+yHaXh7rt4C4B8y+9vkwn7kwKNRpDoa9aiFKBYnF+RcREqQ2e1m3R8BBgAy9kz9ysCE6QAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-odf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAi5JREFUeNp0UktrU0EU/mbu3FfE1KRRUpWYheALNBURUVy7cy9UkO6KW/+Lbt0IPsFui4gLBbUqFaUuXETUKCYa0jS5yZ2ZO557b5MmTXpgmDPnfOc7jznMGINYPi0de5UvmpORxpjE/kbNqW005DVu8TWw1H758ZfkFgNgJmtyxSPRjJIj0QTW/RDiYGXGb7Dl32/eXrVsd0gSCx9miqC0ooCdp69g5Q/h6OLN0ty5ynIkwzMwUwh2FwMdcbDiCZQXlkqFCpEoPT/wih1YjLInANcD+/Ua9bu3wJlGvrBZCmet2+S6ME5g4oGlZ9A/I70XCDhhDexPNTFmswJBwcnuXkF86VSNZxVu0ukLSGnBcqlnN4HoCQIaIuIv7LUooMOgQ7q75LAAb59B9gCBHSKgqemRr94mMKmD24CfM8nb7THYGQNLpAkUkcb66JyGBFFEWRVL57gFEH5qj8Lxwca2qS3EZaugmzAw24dR/XQgwtsCSBjPIdWbUoE2UJLBnV8Ac/ciWHsK9/glWLnD6K2vgPszsOdOQdfeQ1c/ThKoTgDn9A3KUED/52d45xchZsvorD6Bf/Z60riV3Q9Z/0bbGU1uopYGkfERSQ3VbsMwl0qlqoIARmSoPYXWy0dor79LfBMEEd8jGs/uQ3Yl7PJFNFbuEXiV2riCf88fovXhBbo/vqP3t02/ZYmJFqTkzY160Go9uEMbFK8hR/NrdXtFuUVmnmySVGgO4v4LMAAjRgmO+SJJiQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-ods {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAetJREFUeNqMUj1IHEEU/i7u7Z23e8tGgneGQPw3hZDkkhQiSuwMQREba4uUgpVlCrvEQhurkCoWqcQQ0oTAaYKNqJygGEwgHCSB6Knn7eXcdX/GmdHVPWYFP3gw78173/vmvYkQQsAwNvckq96UnyIEh7/d4t7uUd/8y+85P+bXSX4grkhI6nJYPW7LrXpBK2YxiSoShhu4Buq1NPofDeqdrZ3Z4cl7D4J3UtA5VyVAlmJoru9Af2ZAp1lcCQ3nqgiuKmbY3l/BH+MnHM9GVLP0Ww3KNA33CQoQQnL834Fj74PUGkANEIkCSSsa8gQqgYTIcB0PVsXB318GInRiCVWCkpRFAs+j5gKlA4t29Ggh4d0t04FKt9PQqF4UFgumSEA8ApeaElilWbYRVy/lsns/N1QBkxtENF4jxPxcgcB1CZVOrvMteK5IQDtJJIGh++PcX9iYwWjXK37+vP0WdYk0Ht99jtX8JywWFkQChw4tc+cZcvlF7rMze+ubbxN40fMalRMDP/6twaiUeK7wlZ0TD0a5hLTWxo2d45KKprqHKJslTsy209s2wnMFBTYNZjc/oLt9gPvLOx+hxVJIKS2YW5pCbSyJTGMK775O8VyBwDJd2LTDl/X5i8v3S7NVw9vJb51tITDEUwEGANCx2/rXEEFFAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-odt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAepJREFUeNqMkz1II1EQx/+7Ca6JkqyYiJ8cKEpAQbBQFDm0sVOsFBS9wt5KOTgEG5twxVlZ+XEnKNiIghYKxx5nwEpIIXaiSAgKGmMi0d23u8+3T7OaZJEMLG9mmPnN/w1vBUopLPNNhRWXHOyDg0nx82TiJtZPlPVoNpftc2cTotcHtxx06kdXpSQ/BvzKESZzIDmAz6y+NojOjpDMZiqRPIgNoFyWM8DrKUV7axO+gcp4g7AzmquAdVNqOgL2z2I4id1B0wgeygOyt/rLL5buLwAIDgA9dY+L+DkuDQOCrkMgBsRglcMOqAGwIstMg8AkGsuZMNUMRMkLqE+QGloglvlA7uIOAKvZajR0qJkUj/XHe0BTIclVKKlrfKsj9qA8gA6wqSJzPaXlr7ky//tdLEUfawsBjExUFGVWbT7AxSa42H2LMfODmvd3wKb7RAMLYwM8nts8xJ/pEe7/3PmP2eGv3D+9usb35W0bINoA7RmjXSHsH0f5Z/mUSZ0Ir2JmsBtD80s8/rGyzWsLFTD5yUQCbfUBHl9d38LvkdDTXIuHVBo0k+bbt06qO+yAPGXwe/cA4wO9PN44jKDG70GougIzi2tQ00ms7/3lpwnBBgjZ37Kkd1Shht5XzBIFl/ufFtniT/lFgAEAU//g6kvdGBMAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-otp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcJJREFUeNqMkssvA1EUxr+ZjkdbrfFKVD12ErYSRELY2fkH+BMsLcQaSwsrSzZi47EjJEQkEhYkFlhYSVtFpdqOqpk717l3jKZmiC+5mZlzv/s795wzCuccQncz3YeRBj4KHz0/RrOZe2NsZPP20o255zQ3EAxzEAC+6uzTw13G4TFQAakA/CWtIYbY0KBOrx7IvwDQqlHV1o3YxKTOvyAUvfQCfqmA3e4ikyS/zRAKvOot7eoSHEgZIHrCfQAfBqBaKQQDKScQAExd8emBANg+2U2CvNMkkgSqBmrCxFB8mujeoJBWwEqARcssKTAJEGrmaGrjqK1zvNknH4BtyxKl2VUpRxmj5W+x73q9AEaZrR/ND1EJluIpS3i9JQiA+a+hSq8HwJjTsLrRaWitPTCOlhEZn5N75sM1qigmlN+dB3u++Qao5W4TtbEXXIsiszGL4PA00itTsu6XnQWo0TjMTAJqfMDx/ryBJcaVzSNSH4fW0Q+rkIf5rsjRiid7yyN7uoXS3Zn0egE0NiORAN9bQ017D1Lri7CLlP2EDr3Rf7C/itzV2bfXA/igLDaRixfngFhSCooH2xVPCWBlwKcAAwBX1suA6te+hAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-ots {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfZJREFUeNqMUk1rE1EUPS8zmabJdDKB2glEwY9ExJYiBUEQpV25qgtBXfgbpEtXuujKf+AfEKRddOdOGHClbYVCvyKWaijT2mhjphk7Sd7Me76ZONp0EsiBYWbOvfe88+69hHOOAE9f3zTVnDKNHvhlsfqPw/rM0ovyWsRFdXJEpDIyRnSlVz0KSkmvabaJeXSJBEhgAJzTDNybmtUnS5Pmg/lrN07H5NM/f13FoMgpXDSuhiIiK3Qi6LUugX7FAbaPPsJqfIHHKCStqRsXVFPQuZgD9BBxjikSiRq41AAkgCQBzVf0+BWEBX7GBm0xgHHUqk1UbBuEcIydzyCZlOI9YEGuDxwduCCitS3Xh3viCZ4jrcq4PJ6DLHd67tjtuAAXib54dCPVEfQ5XIcik/0/2iDeOYz3ceCxrisMi904y0XiMQFfkB7lg6xFHwFxEqUMV0anUNBLWKm8xd3i4zBWOzmASx0UsiW831mA59Xjm+h7HCOygduXHqJatzA7Poey9QnXjTuoVD/j/sRcmDOWLgqnLC5A2wwST+Pn8T629lahSCo291bwu9XA7vcy3m2+gTaUR14thrk9BXasbdiOjSe3nmPpwys0xSi/HpbDd3bIQC6dx/q3ZbRb/j8BEi3Po5cTJpHI9CBNDEa++GyDBN9/BBgAwfDlCVUQaNAAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-ott {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdFJREFUeNqMU89r02AYfpJ0iVm7EqhVOxw7dDBEdpiCE1RoEZRddvUgbIex/Rs7eehppyF4LOzQu4MxwYp0HgShIuwwUVSCVtl0s13afl+SzzcpyZYmyF74eN583/s+PO+PSEIIeJZdrtQVI19Cgmk/Ph39bpllXq82g7sgLxVcyKNZpIx8Uj5u5zSjc9Gov8ZihCRC8D+7On4JczevGeTGSEIC4ctKJtB1DTPXi1iCCEkIm1EFlC2Em0iwtWfinXkIzjiO0jljtDC5TtflGIGUQMB+mfja/oPv2Rx9MMjpMdJxOXyXTwkcwIkewfqQ1QtQNB385zcI14FrtQexsSb6SRysZ4Fbf+F6eHwATc9gJGNAm5iCTL5n/LCVRGADNoeaGoHqyaXj5gqQlTODovcwNk5Aj6wXqV8eCo7EDhMonEHpW+dZC7gUG98D3geo7vkb01h9cAvPdt76OGy1xntUd3bjUxAk3+l2sHJ/FgtrT0MUJNfDSm0bjQ/72Hzxxo+NK+h3B7XRNO4UrwymQtMIkdTBU0m+sBOayLsn8Ka78mQDjx/e87HXPkb1+UsfP37+AmZ1fP/suknBb6nefVQXjl06TxMlJfWKNWr+Kv8TYAAkUueexJF47QAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-pdf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNp0U0trU0EYPTP35qYxaW6TlDapNKWGbgo2FkF8rARB6rboXusf0F/hyq2U4krFqugqSBeuAyL4SERBstHa0iR9JKZJ7mvu+M0tqZGkH3x8987jzDnnm2FSSqh4ns0VU1ybFzj674Wa3uWiWbfsFQb+jrGj8Xvbm0HlvYVRxhJprpmTlGmum+OMm5uNPZNbtjk3l82ey8++8oW4Jv/H/wdA456g2kvH99FyHNiuAz2dwflbN8YW8zMK5Go/CMfQkAhpGsyQgRCtlpE4jIULyC9fHzu7MPPEl/5ib6WOE0JJNRiHHg6j86mMjw/2gG4bkbY4PW4Yj2j64skA5FTHdaEMPiAJszt1sK0d4suJmY4k0+IDDGRfqmh0u5gejQc+fG8eYCIahRQCEfgQnIuhEkgtONE+dGxYxEDj1DhiEycZ+1YXdUpHCqTMJIYyEES5aXXQsi2kYlGEia5GtHVKn+amPBeCutPgfLALPuVu+xDVPw2EQyFEjHDghbpYNm1yKVVnYjTOerepn4E6XQmLGSPkPkOXWATMSDcjQEkAaqOu6+i/rccALtFL53LI3r0Nq1ZD4/MXZJaWYFer+PXiJc6s3IEgY3+uPYZHTAcAHM+DTE8gnM1CSyaCulv+GrRy8uYyElcu4XfhLVpkpNtn/DGA5Uu0abFH36WnzzCayWAkmYJvWeCkfb9SwY+NDbSoOx4bYqJF8rZqVRRXV/HhzWtUSmWwmWl0RmN4v76OUqGASrmMOkntSHF8MOs954dT08W248wzYsJDOujRBAaqqikTpRo/qqd0/dv97c3Lat9fAQYA4z8bX9nTsb8AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-php {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhNJREFUeNqMkltrE0EUx//ZbDaXNrvZzdIkbYOXGgxYQlCK2IIY6EufxGdB8Av44AdR8AP44JOPBR+Ego0PClUKTTXQSmkTYtOkmubSJrQ1e3H2yJSEJNIDs3PmP+f89pyZcdm2DcdWvn7LzkxFHmCIra7nm9ulg8yLZ09yXON55Dgjt1PM2iPs0+aW/frdh8bzV2/SvQBnCLiEqcFxLKSSodlrU9leiGPihWePBkgeEZO6ShC2dCAZNuf6ADb+ldQ5PUPx4BCFcgXfdwq4Ph1Dtd5CZi4Nw7SQiMdCXkl6yVIy/QBWgcU+yx/XsLK2cdHndqlK/lZxH/OpJO7fnsWY3z/YAq+g0TmHpoUH2vB5PXi8RD9Fo10aAmDJTgWyIuOupmK38rsPcOvqJO33XWEvwLJsmKxHRVEwf/MKWl/yUMf8mIloWN8rw+sP0D6PHQmYuzGNgCRiMZVA17IQV4OIaTI8buH/AJMFd02Tkp05PO4jnWvc57EDAINt7u1X8Pb9KgI+Lxbv3cFR8xjx6AQ+b+Txs/qL9KePlih2CMBCq92hg2qzt1AoV7H5YxdhdqhHzRbgcpFeqdUplpvQW4FhmAixZ/sws4BoWCM/qmsE5XqE3dDQCrqGAYWdejqZgK6GUD8+IV9VghBFN1RZJv3sT5diBwC15gncggCPJKF0WCPN8dun55jQdVpz3Ynl9leAAQAJhiGatD9AOgAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-png {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsU9tOE1EUXXPp0CAUWmJbC04xBANNTF+kKhG8fID6aqL/gPEj9E0lIf6Dj30HL03wxQtVIC0QKrWxNG1Dk9Z2Oj1zxn1m0oIZTnIyZ8/ee+211z5Hsm0bYg29fLGpxWIJWBYGS5IA8ncKhT9Wvf4Yqprtu+w3q85X7f9QxseD/pmZMZsxN9fnc5JNw0ACGGv6tPSvyvEDKEoWZ5Y8OHHObKpucw4B0t3agnl4CJPs2YkQVu4s61ORaBqMJc8CDBiIRhhVM9bXYdVqYAcH8M3NgS0tQQsFcfdKHEbvlr6WyaR/V6uPKPy7B4DT7lUq4MUipMlJ2MPDUKtVfKZ2nn/5BoNbkONxXeb8LYXe/A9AJLNWCxgdhZJagDI9DZg9qIkEytRSkdqTSFQtGILSbgc8LViM+tc0yPfukzIyOJ359k9YR0eQdB2KmBbpwXoM3Dod1SkD+scpEapCI5DdpsJhIJcjajQZagcjI+5oLe4VkeQnyiZgdIH2X6BJ7dSqQLfrggjw0AQwP+/GegCIHppNoFAgEMO1RZKo7BQgRi3yN05cnwdA0BQMAgF3C6pnbuNg92M9AFT1diSCh6kb+FGvo2MxnBB9ocZxp4Mns1cde213B81e7xwAcl4jkaa0IUSjUdLJwkL0Ej6VSvArCt7l81iku6GrKnYEU89VJlSJRmR0Dax+fI9suYxSo4HlWIw6M3FBlnD9YhiXabyOsOeIqG7TzDeIYo6EDGp+ZPb2kKKqH8h+mkxiI5/D1/19J3bwYPvPWXq2skkiJVxesqt0XzghpKM8nRVV2Lv2q9eLIvSfAAMAaacnllcFBmYAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-ppt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAkhJREFUeNpsU11rE0EUPTM7ySZpmzT9DNamWAtFfSiCigr+AxF9zKtv/hvf/Aki+FEi6ov4ItWHPGiwiBUKoUqqTUJImmR3M7Mz3t0kNe1m4LIwc+65595zlxljEJzdR5uf5nLmsvZx6gSvtd9W9bjhF7jg5dH9nRc/wq8YXaTSJptb0xklx7IZoKUEz1zJ2DUU69/37vFYrDxegJ9U0lC+AoIIVGg9CL+vIObP48KDQn7x0sWiVnJrnEDg7KGk+i/Ac4iUM/R7BsmrSSxtXMfa3X7el8+Kjf3KfUJ+iRJQw4w0Tc8BRyWGRAZY3rBR/VlC+XED2ayDhZyXl03+hNA3TxNQshlGLAnE44zCIL1goXZwiMNvB1i6zbC0KuAsxNITWwgNMYPeLVJiFEO9ArjHAivrAjNzBr4f4vwIgdGD4YUACsZCE8AtYGWT5jCsGQw5wEYJzP/pj5RwYTA1b07eQmfZ8P0sgdaM2FlYwWkMgMpl6NQAO33GKM0wsQWflkh1uqGVmVWblsiDkQyqxwfag35SqcktaEWTUTHYNx4iGU/C29+BvX4Lpu/C7zYgFjegSY63WySsHyXwpYHU00ieu0bAOuJbBTArBkiXKiaAmTzcvRJUV9E8rOgqBwqlY8ASs/AadbRLb8CzeTjVClqft6FdB17tL7yeCbFRBYoLr6vR/PiSEl5BZJaBD0/R2nkOZqfQ2fsKt+0SEQ+GLSIEUvJm+6jbah2+pS2aon+4g/afd4SYJVuA7vvXdC/IHQtSoTnK+yfAAIEaId1m+vudAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-psd {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAqxJREFUeNpsU01ME0EYfbtdKKWGtoItRWgJHApCBE2I0YuoiSaaeDJeOJh41YN3TfTixcRwMfEk8eDJGA+Eg0YTTRRMg02KKFooCBbTlkJLS7f7P+u3K9Xo8iWT3Zn55s173/uGM00TVlwZfzJztD92iKO5ouvQGQPHcQDN380vlDPr65fdLj4Oa41i9sFt+ytgN7o7woGOrqgvvpLBaF8vWj1NUAwGTVNRM3mf5vU/zaU+XySQuTqIFXz9hxmGLkoS7r+YxvVnrzGzlgXPDOzUZPT4m3Dt/KlIuH9oUjXYEHZZ/wOgGQZi4TZcGI5hLb+FO++TSOSKcLtcMA0dI0EPrp4+HtnfG5skiUecDGwQE2MjAwiGWlFVNDz+tIyCokJhPKYSX7Gdz2I01hOJdnY9rJ/7UwPGTEiqjtbmJtw4MYx78S/4Wa3h5UoOYwPdIOp2Xi/t18rlFgcDw6o+ydiWVRwOBnCpL0oOAMmNEhLZIgSeoxwGSWcERon/M9DoBknTIdNQNAMnO4PIVGpIFXcwndlA2OtGc4MAxml27p4AIulWSIa9QVadiYSoJxhqBJivKgh5ad3k9gaw6JdlDaqq7q5wINY4F22HaLHSDZQkBW72O9cBYFEviBIURQH7a7MN0uDisUW12ZZcaGlmdq4DwCqeTo1zNtZuW7hUqGIw7MNqSUS2ImNsKEpSdEwt5lGhfQdAkQBEoub3NNrDJfAIeBuRrcrY5xGQ2RFJAjl00I8PCckJUCB9q1URBnk38XEJEuk41tmGwZAf66s1VOh2keqwoUnYpFxHH4iKIixkN3HzVQKP3iQR/5GDKMuYmE3h+fx3MHqh1sMafztHLuiCg0FAk0uFdLqcpGY5QEXbTC/j7mIaVjc18DxufUtBJ/vcggs+3ijVz/0SYABsJHPUtu/OYwAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-py {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlVJREFUeNpsUktvEmEUPTPzTUFmgJK2UqXQFG3pA6OBLrQxamJcaYwuu3Dp0l9iXLvVtRuDpgt3JIYaTVSaxtRHsJq2xEJBHgXmifebMhECXzKZme+ee+65516h2+2Cn2cb2VwyHl12//vP2/zOQaF4uD7GWN69e/LogfNm7kUsPBFaXYwHMeK0OlpQEJApHJTuykzK98dE98O0bLM/UNgr4v32Dj1fwSQRt9dSsfmZcMa0rIv9ODaqYrPVxuPnL1Cu1aEbJu7fvIZUIo4bqeVYRzcyv/8c3SPYpwECt/dmu4ON3Ed4TymI+hQc1ZqoE+F+uQLDsnHlwkKMscJTgl4eJOi9fxZLePNhGx6ZQRRFqH4VjZaGSv0Y6cQcJLpra0ZguIWegqDiw7lYBBZV6xiGk9DQDLzK5bEyF4Hi9VLMsoYI7J6Es5PjeHjnOl5ubqHaaJGBEkzbxplQAKIgDmBHekDTgI+qKKqKLvNApgmEgyquLs1CoFn2Y4cIeLJpkjoCLkWnUSIF3JxISIUsCjAoxhWNJLBIJs3YeXj/08oYZkOKY65HllE/bkMmY504YUd40HUq2JSSyW6iVPmLiXE/ZMYQCU+hXK3h1toqdNN0sEObyKtqtDQ6kXDwcadDS2TBryp4nX2HxXjsJK6bDnZIAZem6Tp5YMMmicn5OC4lztNWtvB9cg+hQABtWjKL2jH/T3GgBcYDXEE6mcDM6SlaJAGMWkivLBC54ZgniZaDHSI4rNSqn7/t1vgkGJPwZXffSeCjk2iUWz9+nSTQN8e6ef8EGAClUi/qoiOc3wAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-qt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNpsU8tu00AUPU5sp41NkzRxpfSZqi0VIIQqEEJUZYXECvbwCWxYsuBD+ABUFrDrCnWBQEJdIWigBSr6pqRJ1ebhxrE9M7aZmSrQ4o505fHMnXPPPWdGiaIIYrx89GKpNDdxmXkU3aEoCsT+z8W1Sm21+jCpJctQTvaerj+TX7WbnJ+0cpfuX8mQtn8GgJ4AZtIFY2Hz3foDVRcgyt+cRHcS0IARh+D/8G0PpmVi7smd0dLs+AIjwTVEiANEYYQwCHlEZyJgIQKfoX84g9uPZ0cHZ4YWmE9nuufU0wABCSSImMsWEgqSuoqA/39/swZFTWLy7vQo7dDnfPvWWQa8GuOV3IYLJXmyzDzG2/ChZ3pwbHdQ267BKJoYuj7SF2MQhiF8LuDK/Gf0DKTBKINz1IbTbEMzU1ANDW7LAfEIQKIgBsBFlAx6LYOz6MAcvoDCtAVGGPKlAiIu/F55F33FDA6W93EOAOMaMOl7biKPwRtD8Foetj5sYPfTDtxjl1f3Ubo5jkQieQ4ACSUD2iE4XDpAdbUiW9D7UsiN9WNkZgxajwbd0LGzt3keAJPUc1N5SVeENT0Ao2BKV6QzwlZeRBSKAYhe3aYHcZWn7l1EfjyPypcK9LQGa8qCvW9j9+MvaasQOHaRhGWdhsNLR8hwodYWf6B4tYjDjSOovRqq32rSYq/lytw4A77o1V2ERiAtzY5kkUrrsH+3QF2KY87ArTtQuQ6nAf4x6FCV1D001+vYersBM2vA4y1Rm2D7/Rac/TZIw4d/6MrcGAPf9htN0miJh7Lyuoyvr8rQeP9iVJcrSKgJ+TrFcyYebXTP/RFgAFQobmIOBxbsAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-rar {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNpsUktPE1EU/u68OgylZXi0hZACQU1LEKKCMcat7jTRnQsXxsQtv4E/4M74P1iriUaNCw1FgxpjCJQKKAU60+m8mJnrmSll4XCTc8+959zz3e88GOcc8aq9evChOHl/lvMoubvWX/z4+BwTlbvw7bXdg8b7h6LE1gGW+O88CRMt4XTlR6/rYxce5Xv3jlHH19fPkBu+gWy5mlcFb3Wn/umeKOEMJF5C7xCFbtA9dRXjFoYKGiTRAlPGUV1aKU9O3VwNQ74A8DQAIZxqAuAhBPIMFYpQVAVB4CPSZjEzv1weH5tbDQN+JQ2Abu488mnzIbAAA3o/VK2PwDJo7r5Fy7ZRuvi4PFS6+qIXdVYD8Jg6BUcuOD8BozSLlRWyicgVKkTMQWwUlFF0Ooe5FIPk57BD7G0SiywyjD8bCDyHsOkeeeR3SUxEkROmU6BfQYFJMHfhWXV8efkUrb13VPMTsrcTQSzxZ/+n0GVA6EGbSGdgG9vo15fg2nFgbO8k70SRdd+mahDT81vUxTZRlJBRMsjq89C0EXCvSf7TIBZ136YZUJEiE7LgJ2dN01BZuE0dkIhxE7KcQTK1QUj+cwAEyrPZ+IydzRoyah+mLy2isbWBweESJEnB9q+1RM9Ub9GQOWkABg8HjRr2d9Yh0hTlBlRsfn+D4vg0BvUC9rZqECUJuk7Tzr1zahCYlB6HJAREPwfbbMBzLBzsbUKVI0qBgQkc+SxgWUYaIAqOpKwKXJ6bgGlaaDV/YvHaFNrtDsKTfVSrJeqIg/bRNwjclFIALeP3saybhu8SC4VBHwnhBXXIKocYRXD9QzBi4Xgchmkd9+L+CTAAMqwy+ZzluBgAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-rb {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAixJREFUeNqEUktvElEU/mag5f2yJhXLwxIt0kiqsVEXujP+A925cu1Pce3WtXVtYuJCF7KtTY0NrVQIpRVKeXTkMcO9F8+9ZVooJJ5kcmbmfOe733fO1YbDIWS8+/g1dycVX7W/xyO3vdsuVKqvnE7HZ230783rlyo7bVBicSGyfjsVwozomVbIPe/c+FmsPHfoRKJd1HT7hXHBZjVbA4aA14NnD9bC2VR8gwuxPi5Sx39Cp+M0XUP0ahhP1jLhW7HFD4zze3b93ILtXYyyVKlR8/5hFbnvO9gtlrGSjOF+OpXkYviWyo8mCS4R6bqO4p86vm3v4fC4DrPfw4unj1XN6JvBaQtjChzUXK43sVU4wNFJA43Tv/B73edQwTmfIhAjCVL6UdPAj1IVFSKhCdAcAI9rnjBiAjtBYEu3GEeh1sKJ0YXR68sVIujzIhzwY8DEBHZqiLRKkicQDfvABxaiQTc4Y/C65pCOXwcjcmlvJgHtlwi4epYifiQWgmoLZwPW6HQG07LgcOgKO0UglAKOTt/E+09fwAiUWU7QAE9xUK3jbvomsispZVHMVEDSZdHo9rCZ/4VIMKAu0XGjpU7d2S8hk0pCELHEzrjKnCQOYJoD+Dxu1RyiwUm5LaMDo9NFt2cqDLvY4oQFp/QpfT/MrmI5FkWebt+NpWto0j2QmQkOjZ9hpwhqjXZzM/+7LU+cc7lRrjXh8/lVLRK5ovLWXglOsiOxdt8/AQYAzv8qbmu6vgEAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-rtf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAe5JREFUeNqEU01PE0EYfnZmd5FSvgLYFuwWt9EgHyEaox68eDJevHvwJ/hTPHv1N/QgZ2NC4g3kUAQKFKGhjVKqRrvbnRlnht262FHfy+y8877PPM8z71pCCKh4/ebt+rJfXEz26Vjf2mnsN5rPKKWbVpx7+eK5Xu2kyMtNTd5d8MdhiJ9BOO7atFI9ajy1UyAqSPIRMR6ZmoNehNHMMB7fX/UWvEKFMbYKE8DfQnAhwRmmJkbx6M6S5+WmK2Evup2c9yUk2nnKA0XVcSiGXAe1k5beP1i+4RFCXqnPywB/AKVzK34RjHNYlgVKCH50w7EBBogbTa/AVM5SgBdn0gc2AMDjPsbFPz2xye9asweS6n+NTbG8BCCfUtLjff2WoVnVpAH6z6hMUtJE3EykYfpF4vUiL3QNS7FMeSAQRBHW3r1Hq91B+VoBQRji4+ExFsvz6Hz7jm7Yw5OH92AcJKW9G4SoHhzhy/lXbB98Qmm2oCXN5WawsV2TACEoJXqwTKOsb3BtR2ucmZxANpPB8JUhyPnHWDaDpfJ1eZFALzJJ4MKO5MEtv4TSXB7V/br8iQLMz+almRZWbvoo5q9qRlxwewCgeXbe3qrVO5ZkUD/9jJGRLPaOm6COi92TU1DbxYe9umRD0DrrtJO+XwIMABWp9nS+FgaoAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-sass {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDNDMTBBM0JGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDNDMTBBM0NGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowM0MxMEEzOUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowM0MxMEEzQUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Po72XUcAAAJcSURBVHjahFJdTxNBFD1bykc/ttvdtttWGgI0bYrUgDZoNYqRJ014kMRXHvwB/hQTH/wFhMREJfFBQxBjhMRIFEQSCAlQxKYGggiU3e3HbnfX2bFt1EU9k9m9mblz5p4zlzFNExYmpue/jmTSZw5PZAl1MAwDT0c7O72wvPdudeNakPNtOZ0tsM7cvzdOc5yN5LDAsTFRAJks/kC2PxFRVe39Si6f4byez62EpAEH/gNN18F53Ri/Ocxf7OtdLMpKT42s/ZPg1cISJp/P0tg0TBzLCoK8D7eHh4RkLLJ4cCz12AjMXwgez8yhqtVo3NbqRKlcxcSL16gZwJ2Ry8KVc8kZO0HdTKlURn+8G6PD2SZhLMQj96WAiMAh2RXFYKI78lcJcx9WYBCycICnpNbojUWpD5Y0C4Zh2D0w6hWc70uQZC+IWfQZrXF0IsHvY+meBd08haAhoVMMQFJKWF7PNZM+klhRyogGhbqxOIXAMOtEwGAqDqVcgbVkkE+5UsEAWavf0az2t0ZqvK2qabh6IU3joizDwTgwej1LdVfJXkdbK8mt2QkayO99A0/0trQ46I1lVcX+UREhnsP34yLp1AD1xibBMuntpzU8mJyi3Tc1O4+l9U06n7x8Q/8PHz1DrrALt8tlr0CrkbJMHTop9Sk5sLa1g8L+ARJdnShKClY3tunN69t5iGLYTlCtakjFY7gxNABdN3B37BaqqoYT8pyX0in4ORbRkIA46YlDRbUTbBZ2Jb/Pw4qiKFnapcpPo9pdbrg8DjAOBsFgELJmsGs7eWkkc5bu/xBgAHkWC6UPADTOAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-scss {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RkM4QjYyNDVGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RkM4QjYyNDZGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGQzhCNjI0M0YxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGQzhCNjI0NEYxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pkf1yeMAAAJbSURBVHjahFNdTxNBFD0tLULpB91uodVWPmorUIxo0VSiNSExMYYHE33l0Ud/in+C+OSjYgjRGDBRCKJIUkIEWi0WKlja0ul22+5219lJ26gLeiezuXvn7rnnnrlrUFUVms3Mvd2bjIyezRVLBA0zGAzo6jhjm1te+7EU37rFO+w7JlMbtG+ePJ5mOaZmci/nsPl6ONBtw18WDQc9tZq0sp7YjTisXV/NFKRpRvzHpHodDqsF03djzuvDg6vHJWFAprF/Arxe/oins6+YryoqCiUBvNOO+7FrXMjnWc0WyIAOQP0N4Nn8IqqSzPx2swllsYqZl28gK8DDyRvcxKXQvB6gISYpiwgH+jEVi7YAfW4nEqk0PJwDofNejAX7Pae2sPhhHQoF63U5Gai2Bn1epoPWmmaKoug1UBoMrgwHabIVVCx2jdrKFwm67TZ2plldPQGg2cK5HheIUMbaZqKV9In6giDCy3MNYXECgKI2gICxoQAEsQItpNCHWKngMo01arTY/jFIzbutShJuXh1Fm9FImYiM7tTtKOtbO+toN9Nc+fQ5SGUOIVYl7HzPIH2YRZ0y2KZ+sVzBHn2v1mpMGx0DTaR3nzfwfGEJdybGkdo/wEigDyvxLzg4yiESvojZhfd49OAeLJ2degaSLIPOO6vwgiYaaRErTRREEdn8MeJbSVZ5M7nLdNExqFLaQwEfFfACQn1+HBWKSKb3MT4Sgstuh9vVDa+bQ4DORE6o6RlspzMk9TOPfr+fiLJCLFYr3TZSKNcI7+aJwWQmPM+TkqRg49tu65f/JcAAMwMas6WUKd8AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-sql {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAh5JREFUeNp8kctrE1EUxr+ZyXMkoa1NBROaSkpTBE23PhZ25cql2y5duvAPUdGFS1FxIRRBXZlFQ9GVdDENIhGJxkDsw2mneZnM83ruNZlOmNoDhzlzz3d/9zv3Sowx8Ch/qlYK2XM3cEJsbH0+qjV/rd6/u6aN18b7RMFT+9aosP/Ex+0ae/puw7j36PlKEMAzctKJ3aGFamMHjV0d+wcGitkMrpWWp6hVIciEk2MAOwbUWjosx0UiFoWqJpGMx5DNzODq5aIPoa82AWBg/lyKLMH1PMp/a9XvLXLzG1cuFlBaWpiKxaIPSLY6CaC93ggQjyiQZRkeQSzLRovGaPciWLt5faSWEBoh6KBvOhiaNga0+Y9pwaFxvu7rfp8F5pWDt+qNMp2IijHGwddWCvN+33/CoAOP5nVdT9SdoQ1JkggiQ6Yvr7V60+9z7akA2gfH9cRF8hO5F5Ve4lQAF9uuK+qFsylkzsQxrcaQm04hdWkR83Mzfp9rQ3fAFzu9Ph6+WMfjl6/pGBdb2jbKmx8QlRjWy5vkyhUZBPgOeGNHN9AbDLGUz6He2hVj3Ll9C8/evsdgaMK0HV8bcmDTU0UUBYXcedR+NLGnH0I3jvDk1Rsy46FP4C/1BtrdntCGHNiOAzWZgEKQ5Qt5lIqLojbaXSQTcRy2OwT4SZqk0IYAOgkVWUE+lxX/zb0DpFNpkTzmZmfFtzewhHYcfwUYAMZmVaZQlLFHAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-tga {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra725K22ILRGipb22pMG6JcSEQTbUIwnozxpBcvepeEP0KPogcT/wlNT17kIKbEmChFUYKGVtL0R2gLtNCl3Z1Z3+zSAlonmezOe/O+973vvZEsy4JYnqdPMu6RkSQYQ29JEkB+PZcrslrtPhQl23VZc8/tr9I1yMHg0EA8HrBM04lVFAhoY38fSSDQVN3pfKV8G7KcxZHl6v1xblqU3eLc3p2VFZjr6+gQgwsnhzGTuq6Nhs6kYZqXjwL0GFhEl3U60OfnwWs1GGtrUKNRsKkpeIIBpKIRtI1J7cX7hXRhc/MOhXw5DkCZGG2zXAajzFIoBMvng1ypIKOqmP30GW3OIEcimovzlxRy5RgAFwDEAIODkCcmIMdiQLsNdWwMZdJlg8pzEUt1aBhKq3XinxKYqF9yQbqRIqsMy+0Gyy47bKgUWXSLtDENE5wdtuqQATm50F1VnPbRGeEw8HXZbiV8fsDvI9ldju9vADAyihLEbrWAZhOoVp3z6iqBUiB1A4nEfwCEsbkL/M4TgE5n5jDx+oTEzp1d8m9tC8H6MaAB0imzx0NU/WKUYE+loEyawDBo2ui6TGfT6ANAxrvx87gYCGCxXEKVJvCWFsG3eh1vN/J4OD6Od4UC8o0G3TX7TGLHwI9iEQmvF9X6Fh7F4/iYy+GcLOMSlfEgGsP0qdNOmX0BiGKpVkV1bw/1nW2b/gCpf1PTcI+Y7eg6ps+G4bG4PR99SjAVo9HE4q+fKNE0vl5awuSohjeijbRefVjAtUgEQRK7Yhi9OKn7nKWZxxlSPWl3QwgnaIrW8QMhD542vUbx/W49m7sq4v4IMABOqi3Ej7bAEAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-tgz {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU1trE0EYPbMzSTfdtInFtkkpiaXVWou2FRUEn/so6JugL/oH/Af+B1988if40jcFERQURNBSQdDWlLQN2lsue8neZsZvc7FoOrDszM75znfOmVmmtUYyvry++36yfOeS1qqzDtvH2P76ApPlW3Drb2sHex/uccHWAdbZX30kO2+B3siN3zhTnHuQ66+95i423jzFzOVljBdKOZNHazvVT7e5wF+SZBj9iZJ+3J11mbW2kR8T4LwFli5i4fqTUvnczTUp9RLtDhKgJx0q4dEwWAxrREKICHEsoYYXMXvlcWmquLgmY71yCkG/c0AkARgLMZpnMDMpGNzEYe0dGp6HwvmHpbHC1Wf9MnFCkHQOyYEPzSJwQ2B65Tm5NZG3Fshim6wbMNJn4bpHowMKtIqo2COgR2IcAptwjvcgo6i77igjEmVDqbY8xQJ1VwRULhiBI6+G9Zf3cbTziuzIDkmHSNqECTFgQScEcYuc2NA8TcdYwXD+GkK/TYVN+u72WrIudiAD8o6oAR2RRCmQMjis3CIy1iSpPySCXhFTXeyAgh4BR+JVw8pauLi0Cp4yCX9A90FQhnSBYtnF/k+Q+HYam9itfIZB3QvT8zj8XSW5EhNTs9ivbSLwPUzPLNPJBIMEKnaQYg6aB9+RGR5F5VsNgnNKXMI1NdJGG5WfHzFVLJ7k8c8xUngpVodlDSGbFYj8Y4yMpOG09lHf3yIFPzA3fwHZTAQVtU4JUTeFDrdgDdlI8wAz5Qy2KxswReI7QODZcOr0ZH3q2hIDBI7zq16tuk3FNPxAI4wN+pkoccYoE4YJU5EdUtM4Qst26v26PwIMAKj3P/2YUKgYAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-tiff {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmRJREFUeNp0UktPE1EU/qYzHWstlrYJNcWUElyUJsaNGh9B0g1Lo0v9Ey78EbrVxBhXuHShm25YGBJRQpAYBDEWpaEPEhksdVpbyjzveO4MfZDCTWbauefc736PIziOA77OPH2yJCcSGdg2uksQAKofFou/7VrtASRpvVNynj13f6XOhjg8HAlMTIQdy/LO+v3uYUPTkAHCTb+cK+0pdyGK6+hbvu4/xiyHbncYAwfR19ZgbG/DoO9LsSgeTd9JXoxfyMG2rvQDdBlwIZauQ5ufh12twioU4E+nYU1NIRCNIDs+Bt28mXzx8VNuZ796j9q/DgAwomwqClilAmF0FE4wCInAlkjO4y+r0JgNX2os6XPYS2q/cQyAcQatFjA0BPH6NYipccAwIGUy2CVJFZInkKlyJAqx3T4/IMGmJkeWIWSz5KgI5pdhb3yDXS5DSCYh8rTID8s0wexeVD0GtMd85KkkefFxUfE47M1NokbJkByEQl6tL+ouAI+MUwbFhnYbaJKc/Sqg0x4H4eDRGDA56fUOABA9/GsCpaIHwr8FOhQ823O5RfW66tUGADhNy3RNRDjcN41HLxdQ8J6jYTsOQLfOJBK4f+s2/uoathoNGKT1MtFeVHZxdWTEZfEq/wMKl3rCJOIzTV6ADs2R5ulYDDNkYjp0DhrF+zCVgkw31+v1UxjQZkNV0SADd2o1MIuc9gmY+/kLxb0/UFoHePd9A1qzeUoKpilx9xcLWzgg+u/zeVfuQqkM9bCN1ysrWKXxdtPgvScwUAm58XZ52W16QyPtifRUzi588GbEi1ztHPsvwAC4uC9qhnsZvwAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-txt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeJJREFUeNp8UrtOG1EQPfsyXiyzBguIJSyChZBBEFCKpKHLo6egpErNn8CHgH8gkZIiTSIXLhJAWCgkoMgRMSiRBSK29z4y9+I1d/HCrFb3MTPnnjkzlpQSynY+fP70fGF2gQuByCz6lfdd9Uurfvrrjes6762eb3tzQ69uFJwPsqOPC+MBEmxxphi4tlU5OGmsOzaBWLc+O9oIIVhScidkyGZ8vH62nHtSKlaI4cse6TjAfSaFBBcco0EWqyvzubmpyQrj/FXk75cQaSEMeMXU8xykPA/Hjd/6/LRcyjEpt2i7HAe4A2TeLZWKUOJaVLxj27j813EHGKCXaAJExu/4BOdiAED08riQD2riOrexyRoYc3CvsAbLGAAjZga7vgZG23WMCdBvoxKJc36TRBlMiaa2JByjNqqD8qkYc1pjDK7abey+/YhrWlfKswhpiCR96aEU9o5+QE3g2ovVWDm2Sc22bBQm8vrVpbkS9r+doPr1EOWZaQ0yFoxg2PcREosEAI4uvZhJpzFMP+cSXRbq+043RManez+tNWKMI6GN0g0Z04HFR+NoNC/0yx717efZOSbzY3AcR4Op2AGA5p/W31r9e0vNgSrh9OwCrpeCkqvZuqTybnpRqx/r2CjvvwADAJC/7lzAzQmwAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-wav {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApFJREFUeNpsU1tPE0EYPXtpKbX0wqUQKVQMFdIXQBNCQBs06KP+B8ODGh+Mf4b/4IsGE54kxhcMBrkp7YOQgBRvSKG73fvsrt8Otoask0xmd+b7zpxzvm8E3/cRjPkniyulW0NFy2JoDkEAguOlpXJ9p3L8MBqVl4O9YHxae8pXuRlcGO7KPLhfTDVUqwUgigJMy4Whm6lEXHjxYf3XnByRN0QB/2KaH7btMlUxoRJAcyqKhdOaht7+DJ49n+2cvTnwynXcsb+kLwJ4rgfmMDDGWqvneXCZS9ND7mov5h9ND85M9y86Dpto5rUkuJ4Py3YDJpy6QGJPayqB+Njf+43XL220t0cwOZkfrNXsBUqZugDA6CbLdAiAwaek1ZU9LmP8Rh6S78GsGxjOp9FdzKJaVZIhBgGASzK21w/wbrnCk8euX+EMAjaaZuPHdwUdHVFYluuGPGCORwwYjg5rqOwccRk+3Ux0IEvntmsNG4ZmUayL/wAwKHUNfZfTKN0ZRaw9Cof8qJ/pMAyHy5KkAMTksSEJtnMenM7EMVMawbejMzJRh67bXEYiIXEAVTW50SEAhzqwfqrBcXx4VOhYm4RsNgHbsJFOyZTsQ1MN+hcohoUlkFiMT+TQFpMwXOjGpXgE+XwGk1N5pFJtKNCequgYGupCRBbCDOp0KBJc4VoP3dyBONW8uydBgBHUThqQKCk3mEZ/LoUG+RBioJO7VarAwEAntjYPiUUW9Hh4b2R7k9j98hN37xWx8fGAt3eIAdVMLn+uUv+b2KReSCZjZJiB9bV9jIz2ofr1BKvvd7G9dRC80lae0HzOt+cWVnrSKDrMJykifwNBpCgE/UAllEXufmDu8Zlffvvm8XSQ90eAAQA0pF7c08o4PAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-wmv {background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M9.1 91.1L4.7 72.5h3.9l2.8 12.8 3.4-12.8h4.5l3.3 13 2.9-13h3.8l-4.6 18.6h-4L17 77.2l-3.7 13.9H9.1zm22.1 0V72.5h5.7l3.4 12.7 3.4-12.7h5.7v18.6h-3.5V76.4l-3.7 14.7h-3.7l-3.7-14.7v14.7h-3.6zm26.7 0l-6.7-18.6h4.1l4.8 13.8 4.6-13.8h4L62 91.1h-4.1z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain}.ipfs-xls {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmxJREFUeNpsU0trFEEQ/mamZ3Y2+0zIC2MmITEkUYgERFQErx5E8KTi1b/h79A/4SW3nCNeYggBYZVEMU/y3N3Z7M7OTD/G6lk2ruw20zRdU/XV91VVG0mSQK/3n1a/jky6d6Xs3G8WXS+Pw5N6LXjLLGuna/78oZKerGsYKtrDE16uJGL1L9gEOOcYd2dL1fNwrbL//aXN7J1efPMmkUqEFAk0A0VZNbFEaQCBscIkXj975y3NLq9xye8PBkAniHOFph+j2eC4rsdoB4LsFubGl/Hq8RtvYWpxTQi52o1jvWiGYaRZL0/auDgOkC/Z8BYL2Pqxidp1FZkhoDxpeaXA/Ujuj/4HoOxKKjiOiek7RUShRNQWaNYFQuMafrYCxiw4ozZKfqbYJ0EvRdl1DQyyTs8XCNTA6UELMwvDyLpZWIZNNlNLlQOK2LMJRJ+5AkuZ1S7CFFzJzk56GnUjQWlYkqCoBWFbonEVYcLLA4dNnB624GQsDBWIgfZJEgxkoChzSFWvn4VpQemDm2VwXQsXJwF1h6c+gxlQ5jgSiEUEt0wdIe7tMES+nEG2aCLiJMOIIWIr9e0DEELAMUrwRuchVAyTKimUwO75Jm6VF3Bv7imOaj+xd7UFKVS/BPJF1b/E4tgTrE49J60O5kceoNqowiuuYKa8ghHXA48U9MT2AQgyRvTThE30bQiaSGa4yLMJNFo+Dq/2cHt4CYlwyFf2S6BHwwrMw/avDbR5C1k7h1YQ4KH3Amf+AcZyEbZPv9CItzQD1l9EbtYOjv74v/d3O9RMPTDrsEwGIWN8q2yk7XNYRs9JrRv3V4ABADSGR6eQ0/NQAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-xlsx {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8tqFEEUPVXdPY/ueWZIoiYZiSYKYhJc6EbduHOhgijo3t/wH1z6B0JAhOyMILhxo4kJGk1ASTAxwWF0Mpp5dHc9vFUzYwidaoqmq+8959xzbzGtNcx69PTS26ETmQtS9r4Hy/xv7MW7jV+th5yzVcaYPX/++It9u4NAv+CVR6tBUUTqMJsDcRzjZOZM8W9ZLKx+/XDb4e5/kH5In0lpIYWGUaC0YTZnBCAEKoVR3L36oDo7NbsglZwbqD6iQKOXFMcKUVfBkBAoQhlD5xxMDp/HrSv3q1JgYW3z0x0KXzkCYJaRZljru23aHWTzLiamAyytv0O9UYdf5PArqlppBfMUfu4oALErqZBKcUxMFRCHEp0DgW5Lo4N9NIN1dF0XXsVFOUyPJTzo+WBANDidjp8tgHGG3c0DnJ4uIRf4cOCBaW5KjY8xkZL72xpJ9QcFz5bVqHUJGHZL2YtNmKi06YCyiVFb4s/vEKMTAf1p4edOG6mMi1zR6wEpdUwX+vLDtkCzHoK7ptcM6ayLmGajvtex4PliyoIkFRjmUEASelB2rXQRSfjUCT9PlWpmW21iTGzCAyEkUixPRqXhe2V4zKczbdmybgkpJ0cGOuA6Y2MTCsKoi5HsNK7N3MN+uwYaWbxYfoLLkzdxcew6lrYWaZhm8PHHG3zffp1UwJSHz9vvkU8PodbcQYYYS5lxYkxTkGdVDQdV1Js1qPgYD6JIuIE7gsXVefIhIuM05k7dwMbeMmh87a18ufIMaVYyprrJLgje2Nr+1tzYXANnDnr3zRhHj37Vvy2wpXHtNAd5/wQYAD6WMuT2CwoVAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-xml {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAilJREFUeNqMks1PE0EYxh+g3W2t1G0sEqyISynUFJsSOShNwCamiYZED3LgIkcuxoN/iCZePZiYGD2aGD+i0F5KMChxlVaakAK2ykcAt+WzdLu7zkxo3WZL4pu8mXfmeeY3885ug67roPFh5nvc62m9hjoR+5LMp7MrkYf370qVtco+VtCUFpbj+jGR+JbWn76OyQ8ePwsZATQb8R/hanZgINgj9IqeuBFCw1Kt9OMBnNWCs24XwkG/QKYUEiGjVAPQof/rq0783pShET3ULQo8xz0iS5FaANmrHQH2DoqY+DSLSz6RzecWlnD9ymU47LYjd4O5BXqDTG4FM3NpTEkpdJ5rw0AowLRMbhUfp58gTOaD/UHmNQPI6YmvKWRX1zESHUJ/oBs2nmPa+Mgw0ZIM3tZyGoJwygzQNB2jNyJIZX7iB0lpPoM70UGmPX8zCU+rG8NDVxHwdiC5mKsPUFUN/gvtLLf39sFzVqaN3YrC6TjBauqhXhNA1TQoqloV7Da+pjZq1FsXUCamF29j6LvYhf3iISamZ3Fv9DZevouhRzzPfOG+3hpA9U9UyioOlTJ7pFeTCQS6RGzIebyf+oz5pSzWtmSW1EO9phvQ00slBRt/8qR3DoWdXbiczUiTzd52D+tdLmyTB14mx1rMAKVcRpEATjrsuElee/HXGmnFRyBOGD30C/nEDjNgs7CDpsYmnHG3YPegBCvHs9oYfm8nG9dJa5X4K8AAQzQX4KSN3wcAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-yml {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdxJREFUeNqMUl1rE0EUPbM7m5Y0Zptu21AwWwhYpfSDFh+kvvRd8N0Hf4I/xWdf/Q158F0QoQ+CVsFKaLSQpt/dpmvztTOzzky6cetOpWcZZvbO3MO5514SxzEU3r57/3GpWllM/tP4sL3TarROXuSo/SWJvX71Uu80Cfhlr/T4UdWFAVfdnmsTUtvdP35OUyQKVnJgXDBTcj9icAsTeLax7j/052qM81UjwW1QJXEhMF0qYnN90fdnvdogYmvJPU0/VBApD4hcDrWRcyikfB17srzgW7b9Rh1vEvxDlI4tVytaBSEEtmWh0xsUMwpwnWjqAlcxogiHd1wiQyCu87iI/+sJtf6+NXsgpd7FWCMB50KvkYMGMbLdZgLlfj+K9K4+FnFQ2x7WntIs50AbmiGwLILt+k+EvzvSNIHzdigdJ/AmXQRhiHv5POSwYmG+cqPVo0HqDxj8uTK2vn1Hfa+JmdIkvtZ/4fOPXU3WPDpFeNWVyUKryCiIGMN4zsH98gym3CIcOTwT+XHdXrdQQHAZotE8kBPpSqPNHtBOr48HUmLOcXRJT9dWNMGYJFby91pHOAvaykSaITg+bwefdhrteDRTMSwyrFCgI88E056Hy+4Ah2cXQZL3R4ABALUe7fqXWFN6AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-zip {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm9JREFUeNpsk0tv00AUhc+MY6dOmgeFJg1FoVVpUWlFC0s2IFF1jxBbhKj4BSxYdscPYcEmQmIDq0gsERIViy4TpD7VFzF1Ho5je2a4thOqNhlp5Mz4zudzzp0wpRTC8fPrk0/TC6+fDtYicLH97T1Kc2vQDcs+rH3eUAxVznn0fn1DRM8E+iOdv5ct3XmZG6yVlNj6solUbgVTt0q5FGtX6vXqC6VklTE+KAO/OODHSIQPRQpsXC+kkEz2ELA0ystv84tLzyucsbWByisAGf+QAS2CCDRRLMJMmxC+i8C4jdLCm/zM7OOKFGptcO6/BTpJ0yeQB0Y+mfKQuZZG0jQgeRbW8Xdomobs9LN8scc+UPHNy4Dwq8IljotIIQEm59/RoSyM1CKkXKZNBm7kIVgyM6wgAnSgRK9vqQfHPiMFDHqyFVsLR9Cm0o4YzoAASrSjCelQfRPb1Vc4qn0EY5L2W9GEaBLcxQgFHpGbkMIDJ69e+wjJ8VXqRgKid0r7ftQdxkRs9SqA2kgAm14SSIQh9uhuLGPMnKJs/5KquL1x0N0RCsizigoDaLqBdHoMiyvrlBsHVx1wphD4BCewoqxGKKDwAgtOy8JufYuk+5golGGaGZwc1sIGoDz3AOPZSVLaHgVwydoJDM1H4DbQODughB3YpOD44HfoHgnu4e7So0uAi0stHLJ3Aud8B9bpHu6vPoSu9TtDl6tUuoFiIYOgu0+158MKmOxomtyD3Qi/3MTR7i8K0EDG1GHO5DE3X4DvNahZlJOwEkOATvdPc2//hx3mXJ5lFJaF8K8bStd0YGfnOJbMGex21x6c+yfAAOlIPDJzr7cLAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}body {color:#34373f;font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;font-size:14px;line-height:1.43;margin:0;word-break:break-all;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}a {color:#117eb3;text-decoration:none}a:hover {color:#00b0e9;text-decoration:underline}a:active,a:visited {color:#00b0e9}strong {font-weight:700}table {border-collapse:collapse;border-spacing:0;max-width:100%;width:100%}table:last-child {border-bottom-left-radius:3px;border-bottom-right-radius:3px}tr:first-child td {border-top:0}tr:nth-of-type(even) {background-color:#f7f8fa}td {border-top:1px solid #d9dbe2;padding:.65em;vertical-align:top}#page-header {align-items:center;background:#0b3a53;border-bottom:4px solid #69c4cd;color:#fff;display:flex;font-size:1.12em;font-weight:500;justify-content:space-between;padding:0 1em}#page-header a {color:#69c4cd}#page-header a:active {color:#9ad4db}#page-header a:hover {color:#fff}#page-header-logo {height:2.25em;margin:.7em .7em .7em 0;width:7.15em}#page-header-menu {align-items:center;display:flex;margin:.65em 0}#page-header-menu div {margin:0 .6em}#page-header-menu div:last-child {margin:0 0 0 .6em}#page-header-menu svg {fill:#69c4cd;height:1.8em;margin-top:.125em}#page-header-menu svg:hover {fill:#fff}.menu-item-narrow {display:none}#content {border:1px solid #d9dbe2;border-radius:4px;margin:1em}#content-header {background-color:#edf0f4;border-bottom:1px solid #d9dbe2;border-top-left-radius:3px;border-top-right-radius:3px;padding:.7em 1em}.type-icon,.type-icon>* {width:1.15em}.no-linebreak {white-space:nowrap}.ipfs-hash {color:#7f8491;font-family:monospace}@media only screen and (max-width:500px) {.menu-item-narrow {display:inline}.menu-item-wide {display:none}}@media print {#page-header {display:none}#content-header,.ipfs-hash,body {color:#000}#content-header {border-bottom:1px solid #000}#content {border:1px solid #000}a,a:visited {color:#000;text-decoration:underline}a[href]:after {content:" (" attr(href) ")"}tr {page-break-inside:avoid}tr:nth-of-type(even) {background-color:transparent}td {border-top:1px solid #000}}@-ms-viewport {width:device-width}.d-flex {display:flex}.flex-wrap {flex-flow:wrap}.flex-shrink-1 {flex-shrink:1}.ml-auto {margin-left:auto}.table-responsive {display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
-  </style>
-</head>
-<body>
-  <div id="page-header">
-	<div id="page-header-logo" class="ipfs-logo">&nbsp;</div>
-	<div id="page-header-menu">
-	<div class="menu-item-wide"><a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About IPFS</a></div>
-	<div class="menu-item-wide"><a href="https://ipfs.tech#install" target="_blank" rel="noopener noreferrer">Install IPFS</a></div>
-	<div class="menu-item-narrow"><a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About</a></div>
-	<div class="menu-item-narrow"><a href="https://ipfs.tech#install" target="_blank" rel="noopener noreferrer">Install</a></div>
-	<div>
-	<a href="https://github.com/ipfs/kubo/issues/new/choose" target="_blank" rel="noopener noreferrer" title="Report a bug">
-	<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.4 21"><circle cx="7.5" cy="4.8" r="1"/><circle cx="11.1" cy="4.8" r="1"/><path d="M12.7 8.4c-0.5-1.5-1.9-2.5-3.5-2.5 -1.6 0-3 1-3.5 2.5H12.7z"/><path d="M8.5 9.7H5c-0.5 0.8-0.7 1.7-0.7 2.7 0 2.6 1.8 4.8 4.2 5.2V9.7z"/><path d="M13.4 9.7H9.9v7.9c2.4-0.4 4.2-2.5 4.2-5.2C14.1 11.4 13.9 10.5 13.4 9.7z"/><circle cx="15.7" cy="12.9" r="1"/><circle cx="15.1" cy="15.4" r="1"/><circle cx="15.3" cy="10.4" r="1"/><circle cx="2.7" cy="12.9" r="1"/><circle cx="3.3" cy="15.4" r="1"/><circle cx="3.1" cy="10.4" r="1"/></svg>
-	</a>
-	</div>
-	</div>
-  </div>
-  <div id="content">
-	<div id="content-header">
-	  <p>CID: <code translate="no">{{.CID}}</code><br/>
-	  Codec: <code translate="no">{{.CodecName}} ({{.CodecHex}})</code></p>
-	</div>
-    <div class="table-responsive">
-    <table>
-      <tr>
-        <td>
-	  <p><strong><a href="?format=json" rel="nofollow">Preview as JSON</a></strong><br/><small>(<code>application/json</code>)</small></p>
-        </td>
-      </tr>
-      <tr>
-        <td>
-	  <p>Or download as:
-	  <ul>
-	  <li><a href="?format=raw" rel="nofollow">Raw Block</a> (no conversion)</li>
-	  <li><a href="?format=dag-json" rel="nofollow">Valid DAG-JSON</a> (specs at <a href="https://ipld.io/specs/codecs/dag-json/spec/" target="_blank" rel="noopener noreferrer">IPLD</a> and <a href="https://www.iana.org/assignments/media-types/application/vnd.ipld.dag-json" target="_blank" rel="noopener noreferrer">IANA</a>)</li>
-	  <li><a href="?format=dag-cbor" rel="nofollow">Valid DAG-CBOR</a> (specs at <a href="https://ipld.io/specs/codecs/dag-cbor/spec/" target="_blank" rel="noopener noreferrer">IPLD</a> and <a href="https://www.iana.org/assignments/media-types/application/vnd.ipld.dag-cbor" target="_blank" rel="noopener noreferrer">IANA</a>)</li>
-	  </ul>
-	  </p>
-        </td>
-      </tr>
-    </table>
-    </div>
-  </div>
-</body>
-</html>`))
-
-type DagIndexTemplateData struct {
-	Path      string
-	CID       string
-	CodecName string
-	CodecHex  string
-}
diff --git a/assets/dir-index-html/README.md b/assets/dir-index-html/README.md
deleted file mode 100644
index 3dd45eb59056a469b28c6b6e7b7f90db2e0d95e8..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# dir-index-html
-
-> Directory listing HTML for HTTP gateway
-
-![](https://user-images.githubusercontent.com/157609/88379209-ce6f0600-cda2-11ea-9620-20b9237bb441.png)
-
-## Updating
-
-When making updates to the directory listing page template, please note the following:
-
-1. Make your changes to the (human-friendly) source documents in the `src` directory and run `npm run build`
-3. Before testing or releasing, go to the top-level `./assets` directory and make sure to run the `go generate .` script to update the bindata version
-
-## Testing
-
-1. Make sure you have [Go](https://golang.org/dl/) installed
-2. Start the test server, which lives in its own directory:
-
-```bash
-> cd test
-> go run .
-```
-This will listen on [`localhost:3000`](http://localhost:3000/) and reload the template every time you refresh the page.
-
-If you get a "no such file or directory" error upon trying `go run .`, make sure you ran `npm run build` to generate the minified artifact that the test is looking for.
-
diff --git a/assets/dir-index-html/dir-index.html b/assets/dir-index-html/dir-index.html
deleted file mode 100644
index d861cb6570016da839666e5a751cd6982f8251c2..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/dir-index.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE html>
-{{ $root := . }}
-<html lang="en">
-<head>
-<meta charset="utf-8" />
-<meta name="description" content="A directory of content-addressed files hosted on IPFS">
-<meta property="og:title" content="Files on IPFS">
-<meta property="og:description" content="{{ .Path }}">
-<meta property="og:type" content="website">
-<meta property="og:image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-<meta name="twitter:title" content="{{ .Path }}">
-<meta name="twitter:description" content="A directory of files hosted on the distributed, decentralized web using IPFS">
-<meta name="twitter:card" content="summary_large_image">
-<meta name="twitter:image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-<meta name="twitter:creator" content="@ipfs">
-<meta name="twitter:site" content="@ipfs">
-<meta name="image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlo89/56ZQ/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUjDu1lo89/6mhTP+zrVP/nplD/5+aRK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHNiIS6Wjz3/ubFY/761W/+vp1D/urRZ/8vDZf/GvmH/nplD/1BNIm8AAAAAAAAAAAAAAAAAAAAAAAAAAJaPPf+knEj/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf+tpk7/nplD/wAAAAAAAAAAAAAAAJaPPf+2rVX/vrVb/761W/++tVv/vrVb/6+nUP+6tFn/y8Nl/8vDZf/Lw2X/y8Nl/8G6Xv+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/761W/+vp1D/urRZ/8vDZf/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf++tVv/vrVb/761W/++tVv/vbRa/5aPPf+emUP/y8Nl/8vDZf/Lw2X/y8Nl/8vDZf+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/5qTQP+inkb/op5G/6KdRv/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/sqlS/56ZQ//LxWb/0Mlp/9DJaf/Kw2X/oJtE/7+3XP/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf+9tFr/mJE+/7GsUv/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+xrFL/nplD/8vDZf+emUP/AAAAAAAAAACWjz3/op5G/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+inkb/nplD/wAAAAAAAAAAAAAAAKKeRv+3slb/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+1sFX/op5G/wAAAAAAAAAAAAAAAAAAAAAAAAAAop5GUKKeRv/Nxmf/0cpq/9HKav/Rymr/0cpq/83GZ/+inkb/op5GSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G16KeRv/LxWb/y8Vm/6KeRv+inkaPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G/6KeRtcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/n8AAPgfAADwDwAAwAMAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAwAMAAPAPAAD4HwAA/n8AAA==" />
-<title>{{ .Path }}</title>
-<style>
-/* Source - fileicons.org */.ipfs-_blank {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWBJREFUeNqEUj1LxEAQnd1MVA4lyIEWx6UIKEGUExGsbC3tLfwJ/hT/g7VlCnubqxXBwg/Q4hQP/LhKL5nZuBsvuGfW5MGyuzM7jzdvVuR5DgYnZ+f99ai7Vt5t9K9unu4HLweI3qWYxI6PDosdy0fhcntxO44CcOBzPA7mfEyuHwf7ntQk4jcnywOxIlfxOCNYaLVgb6cXbkTdhJXq2SIlNMC0xIqhHczDbi8OVzpLSUa0WebRfmigLHqj1EcPZnwf7gbDIrYVRyEinurj6jTBHyI7pqVrFQqEbt6TEmZ9v1NRAJNC1xTYxIQh/MmRUlmFQE3qWOW1nqB2TWk1/3tgJV0waVvkFIEeZbHq4ElyKzAmEXOx6gnEVJuWBzmkRJBRPYGZBDsVaOlpSgVJE2yVaAe/0kx/3azBRO0VsbMFZE3CDSZKweZfYIVg+DZ6v7h9GDVOwZPw/PoxKu/fAgwALbDAXf7DdQkAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-_page {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNpsUztv01AYPfdhOy/XTZ80VV1VoCqlA2zQqUgwMEErWBALv4GJDfEDmOEHsFTqVCTExAiiSI2QEKJKESVFFBWo04TESRzfy2c7LY/kLtf2d8+555zvM9NaI1ora5svby9OnbUEBxgDlIKiWjXQeLy19/X17sEtcPY2rtHS96/Hu0RvXXLz+cUzM87zShsI29DpHCYt4E6Box4IZzTnbDx7V74GjhOSfwgE0H2638K9h08A3iHGVbjTw7g6YmAyw/BgecHNGGJjvfQhIfmfIFDAXJpjuugi7djIFVI4P0plctgJQ0xnFe5eOO02OwEp2VkhSCnC8WOCdqgwnzFx4/IyppwRVN+XYXsecqZA1pB48ekAnw9/4GZx3L04N/GoTwEjX4cNH5vlPfjtAIYp8cWrQutxrC5Mod3VsXVTMFSqtaE+gl9dhaUxE2tXZiF7nYiiatJ3v5s8R/1yOCNLOuwjkELiTbmC9dJHpIaGASsDkoFQGJQwHWMcHWJYOmUj1OjvQotuytt5nHMLEGkCyx6QU384jwkUAd2sxJbS/QShZtg/8rHzzQOzSaFhxQrA6YgQMQHojCUlgnCAAvKFBoXXaHfArSCZDE0gyWJgFIKmvUFKO4MUNIk2a4+hODtDUVuJ/J732AKS6ZtImdTyAQQB3bZN8l9t75IFh0JMUdVKsohsUPqRgnka0tYgggYpCHkKGTsHI5NOMojB4iTICCepvX53AIEfQta1iUCmoTiBmdEri2RgddKFhuJoqb/af/yw/d3zTNM6UkaOfis62aUgddAbnz+rXuPY+Vnzjt9/CzAAbmLjCrfBiRgAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-aac {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNp0Uk1PE0EYftruVlvAUkhVEPoBcsEoLRJBY01MPHjCs3cvogcT/4qJJN5NvHhoohcOnPw4YEGIkCh+oLGBKm3Z7nZ3dme2vjOhTcjiJJvZzPvOM8/HG2q325Dr3kLp7Y1ibpIxjs4KhQBZfvV6s7K5Vb0bjeof5ZlcGysP1a51mifODybvzE8mzCbrAoTDIThMoGXZiZ4YSiurf+Z1XeuCqJ7Oj+sK3jQcNAmg8xkGQ71mYejcAB49vpmeuzJccl0+dUj6KIAvfHCPg3N+uAv4vg9BOxcCmfEzuP/genpmeqhEMgude10Jwm+DuUIyUdTlqu2byoMfX/dRermBeExHsTiWNi3+lMpzRwDki8zxCIATmzbevfmClukiP5NFhJgwkjeRTeLShdOoVJqnAgwkgCAZ6+UdLC9twjQZ8pdzioFkZBHY3q6B3l4dJEEEPOCeD4cYVH7Xsf15F+FImC775INAJBJSkVoWo0QY9YqgiR4ZZzRaGBkdwK3bFxGLRZUfB3Rm2x4x9CGtsUxH9QYkKICDFuLxKAozGZwdTqBRs2FbLlXbiPdECMCHadj/AaDXZNFqedCIvnRcS4UpRo7+hC5zUmw8Ope9wUFinvpmZ7NKt2RTmB4hKZo6n8qP4Oq1HBkKlVYAQBrUlziB0XQSif4YmQhksgNIJk9iaLhPaV9b/Um+uJSCdzyDbGZQRSkvjo+n4JNxubGUSsCj+ZCpODYjkGMAND2k7exUsfhkCd+29yguB88Wl7FW/o6tT7/gcXqAgGv7hhx1LWBireHVn79YP6ChQ3njb/eFlfWqGqT3H3ZlGIhGI2i2UO/U/wkwAAmoalcxlNA1AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-ai {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk5JREFUeNpsU01vElEUPTPzZqBAQaSFQiJYUmlKYhoTF41L3Tbu/Q/+AvsX3Bp/gPsuWLrqyqQ7TUxMtAvF1tYGoXwNw7wv7zwYgtKX3Lw379575p5z77O01ohW+/DVh8zj7aYKhflGdG9ZsGwLNydffgVfr19YHvsEa+Zu/nxndob5StQK+dyzvZzyw/gKlmMj7IygFM+xvNcanp4/t5dAomXHBy2UUBOO2MAl/B9/cPb6PULuoHx0WM0e3GvpUOxD3wZAJWutZqYUYmqpSg5OMgH3YQObL59W0/ullpryR3HegkKEqiWBSGV4R3vQ7sIhScTZFTpHx3A215B5sluVY/WWMg7+ATB/lcLsKpTonHzD+OMFEuTz8ikkt9Kwt9YJZB38cpBdoQAZJdLvCGByfoPB6Xdk90pYy6Xg3c/DaWwArg09DaG5lCsUFN0pckZAojdC8m4auBqaALuSgez7VB1RtDSUWOQvUaBLFUzJBMJ2DwmPgd1Jwm0WoSgJfjDvrTKxtwAIyEkAOQ5hU//Zdg5uowDlUNMnwZLW0sSuUuACYhwQRwFvJxupCjEYUUccOkoaKmdOlZnY1TkgAcXAhxhOwLsDsHoN3u4O5JTDfVCH6I9nfjId3gIgSUATFJk/hVevGtOMwS0XwQ3AzB/FrlKg8Q27I2javVoZrFgwD4qVipAEyMlnaFArzaj/D0DiMXlJAFQyK2r8fnMMRZp4lQ1MaSL5tU/1kqAkMCh2tYI+7+kh70cjPbr4bEZ51jZr8TJnB9PJXpz3V4ABAPOQVJn2Q60GAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-aiff {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAohJREFUeNpkU9tqE1EUXZmZpE3aTBLbJFPTtFURtSCthr7UCyKKFJ/9An3og6Ag/oXfoUj7og9asCBYKT6UIPHaWtpq7NU2aZK5z5wZ9xxMpMwZDuewz9prr32ZiO/7CNaDx3OLt6fOjBqGg/aKRCIInp8+KzfKH7fudnVF58nE16el+/yU2mBFSWZKpWJKVc0OgUBo02K4NDmU6o75Mx+Wdu9IUXFeiOA/pn1xHeYaugVDdzpbp91qGlAKGTx8dC19/Wpxhjnsxj/RRwk85hGJC9d1O6fneWAuoztDYSSLe9OT6SuXB2ccx73Z9uukwDwfls1g0xZIY/Ad/Gnyt/XVfbyYrSDRE8PExHB6/8B6QuaxIwRBFMt0iIAiMx+LCys8jfGJEUik2WpZOD2SQf9oDtVqQwopCAiY66FS/om3b75CVS2MlU7AJ2WiJBCZjZ2dJuRkDJZFwFAR7UCBja3fNfxY2YEoCtRCj9em3Tpds6FpJseGCBxS0GgYGBzqw62p84gnYnAI2CSbSbPhEpFAaE2zODaUAlWWwDoS5DheGqbWpVE/0CmqCY9qkEyINBceb2uADRNQ8bSWAVVzIFKomCQim+0luS4yKYlsHlRyZo7EsSEC23K5vAsXh/H92zZkuRvxeBS5nEx2yp2KqhxPoV5TYS/8CtdApylM9sZQKKSQzyeRTseRV2QoAzIYY8jme5DN9fI0dQoUIjANGydP9VM7PZw9p/AiBpNYrdbw/t0yTJqRtdU9UrfJCUMpSJIgbWzsYe51BcViHzLHeqCRqhZ1YX1tFwNfZBxS9O3NWkAcHqR606k/n/3coKAoV/Y7vQ/OYCZevlrmv3c0GsFh06u3/f4KMABvSWfDHmbK2gAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-avi {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm1JREFUeNpsU8tu00AUPXZcN0nzTpq2KQ3pAwkIAnWHqCoeexBb+AQ+ABZ8A2s+AIkdm266QUJIFWKBkHg1KpRHi5omJGkbJ3bGHj+4M1EQrTvSyGPPueeec++1EgQBxHp+/9mbyuriRZdxjJaiKBD3W+u1+p9a856max+gDO8ebT+WT20Ezi9NZi/crqadvn2MQBAGfpCOpqNru2937vxPIpY6Onjccx3Twck9MBiSU0ncfHirXFmZX3Md9wqCUwiEVN/zaQfHt0vfbBe5uQyuPVgpl5Zn11ybL4/i/lkICOw5niQRGQShoiqI6Bo43W2ub8n3hRtLZT7gTynk6gkCX9gAOxpAnxhHZDwC1/aI1EViJolu/QhKRMHZ1UX0Gr1USIEn5FPWHy+/wTokkrQOq2vBaHZBN4hmY9Jwfr4An/teiEB45ZZDwDiMhoExT0N+sYDCuUkkplLIlXP4/XEXdo+RUhdhBSSfUwtVTUG8MIHK9QVqI7D/uY6vr2pwmCPrkz+Tk9gwARWQ9WxppbXZhNnpw+ya4A5HZi6L4lIR8WyCcL6sTZiAWjWgAmpxkn5+kqTamK6WkCwmERmLDLvjB0ML9ikWXPLFuozYOap3L8HYN6DHdbS/d5CeTVBndBz87FCBLYkNTyIjBQemnIEsSY5lYrK1+UoWcToLMjEHAyIQ2BCBSx/NVh+ZUhrqmEqBebS3WyhdLg0zt/ugAaIklsSGLHCLa6zDMGhZ2HjyGsnpFPqNHnY2fmHv3R5SMymYbROszSQ2ROAY9qHiofvlxSc5xsKKqqnY3diRE9h4X5d/pzg7lnM4ivsrwADe9Wg/CQJgFAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-bmp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmZJREFUeNp0U+1rUlEY/13v9YV0vq2wttI5CdpL9aEGBZUDv0df668I6n+or0UQ/RuuD0EgVDAZrsKF4AR1a6COKW5qXvXec27PuVeda3bgcF6e8/ye5/d7niMZhgExnK9fbTrm5pbBGMZDkgCyq+VyhTUaT6Eo2ZHJePPWXJXRhez3B1yxmM/QdctXUSCgtV4Py4CvY3cky4e1x5DlLCaGbbzjXDcousG5OQe5HPRSCQPK4PpsEM/XH4WvhS4noeu3JwHGGRiULhsMoKZS4I0GtEIB9mgULJGA0+9DPBpBT7sffvf1W/Lg6OgJufw8C0CRGEXWazUwiiyFQjA8bsjVKjaJzovMD/Q5gxyJhG2cvyeXe2cAuADQNGBmBvLaGuTFRaDfh31lBTWi9pumjbK0B4JQul3vOQpM8JdskOLrdCvDcDjAsjtg5TIkoiKLaokMNR2cnZbqNAMycqG7XbHKR2fMzwO/dsxSwu0BiBJsNsv2LwAJAJCI5ux2gXYbqNetcz5PoORI1cDS0n8AxGW7A+zvEYBKZ2ZlcsEtJLbedMjePBaCTQMghx45ulyWkzxMVUQ2RMQhLfFO16YAqCrixPnm6iqKrRb2W23EfF4cUNSrHg90cr7hDyB33MTnSmUKALVs4uIlROjxg+AsPhGVl3fuIl2tIOB0Ya91gkOi9mxhAal0ekork1ic/kGLBORMxy2K1qS9V1ZQbNThIj2EGh+2tsyOnSai8r1UxMNIBB+LRTTULr4Uds0K1tU/uOLxIrmbNz8XXSrnASSpubG9fbKRyVh1n/zSw29t9oC1b47MfwUYAAUsLiWr4QUJAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-c {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcxJREFUeNqEUk1rE0EYfmZnkgoJCaGNCehuJTalhJZSUZB66a0HwXsP/Qn+FM+9+hty0LNYCr2I7UVLIW0Fc0hpQpSS7O7MrO9MspuvVV8YMnk/nn2e5x0WRRFMvP/w6WSz5jbi/9NxfP693Wp3DrJCnMW5d28P7a+IE15lufR8o1ZEStwPhkWHsWbrZ+eNEPxsuubEF6m0TBv2Q4liPofXuzveulttSqW2UwH+GjqC0horpSL2njU89+FyMwjlTlxOJMTa9ZQHzDQIjgwdom9zLzfXPc75kbnOAswBJTlC2XrqQRMLxhi442DgB4UFBhgPpm3B5pgBHNUUxQKAHs8pHf3TEuFMetM9IKr/i2mWMwC0SnuSFTG2YKyppwKYVdGO7TFhzBqGIenVeLCUtfURgErucx5ECKREKBU4d3B718PHz6cICGT/1Qs8qpQtGOdyhtGEARWDQFqQJSeDL98u4VbLaKw9IRAJPwjtoJGlVAoDQ800+fRFTTYXcjlcXN2g++s36p5Lzzlve1iEROa8BGH1EbrSAeqrjxEqicHQt8/YSDHMpaNs7wJAp9vvfb287idboAVkRAa5fBYXP9rxO4Mgf0xvPPdHgAEA8OoGd40i1j0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-cpp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfJJREFUeNqEUs9PE0EU/mZ2WgqpXX+QIDFdalVslh8NlAOQaOKFAwfvHvwT/FM8e/U/MOnBmwcj8WD0ACEGghIkbU0baaEthe3OTJ0ZWV26q37JZt68ee/b9733yGAwgMbL12/fz+azbnAPY2Nrt7Zfqz9JMrYZ+J4/e2pOFjiciRvXlgp5GzHonXk2o6S8V6k/TjBrM/xGA4MLyeOSPZ8jkx7D+uqCU3Amy1yIYizB36AlCSkwfjWDR4uu40yMl/s+XwjeWThQQ4Z6QNSnSkYykcDXasP4lmfvOZTSF9q8TDBEFPbN5bOqCglCCCxK0TvvZyIV4CIxbgpC+4gm/PUmFCIE8iJPyME/e8Lon9j4HvyHYLjKSwRCSEUgf9+15mFbx8QS6CZJMzJ9SlBCwX3fJDLG4PX7ykcwkmQmJtpEhWa7g1dvNlSwjwelebz7tAXLolh0p/Fxe9fErK2WDFGEgKjxfNjegX0lDTc/heNuF99/HGEslcKXwyoazWNDdlCr6+DoJgrBzdI0T9rYO6yg2zszMlaKM3Dv5OBzbuyZuzm1B16U4Nzz2f3cFOx0Gq12F9cztpExncsqYoaHpSIKtx0zJdVIFpHQ6py29muNk1uTN829o/6SHEnh80HFaE6NjmLnWxUJy1LyTltB3k8BBgBeEeQTiWRskAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-css {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNpsUktvUlEQ/u5DoCLl/RAKKKUvWmIxjYntQtcu3LvwJ/hTXLt16coFC2PsojEaMKZtCqFaTdGmjbS0CG3By+vei3OOBSGXSU7uzNyZ78z3zRF6vR6YvXzzPrMUCyf68bB9zO+VfpROn5hkOdfPPX/2lH/lfiLidztX5mN2jLGG0rKLENIE8liWpdzwP7HvqJqujmvudFU4bFY8Wk1FZsOBtKppd8YCDNu77CZevd3gflfTUFcUhP0ePLibiIR9rjSBpgwAfe4dVcV6dhtep4PH5msylGYLrzeybErcT85FYiH/CyPAf74gObC2vMhzsiRhPhpC6eQUM+EA1pJzILEnjRSuJsju7MJqsUCSRei6Dp3yXqcdGlHZ/rLPazQWGCn8+6YW4pAkEW0SjzUzanWlCa/LgcR0lNfovTEi6lcIkzesnM/R8RlN0INGp3h4DHoDsE5YRvQyiKiRSMzikRAOS2WoqoZWu41K7RwzlOOAVDMMMHhIGvFlRxJFrKYW0ep0IYgC3SDh4b1lTJjNfENsrazOAMAw680mPuW+8lFno1P4XDigRhOiwQAyJK7TbsNS/PaA7giAIAhYz2yRgBIfsVA8wIetPG6FAqhdNrC5u0f+TUyHgyMTDDToEt/ftQsEvW4EPG5OZcrvw0mlimarTXkPfpXPcNlQoGtjACgpryQXsPNtH/nvRXqBJpoKHMzGNkNB0Odls7LNyAYKpUq1dt1iuvB7fRDp9kr9D1xOFwkpoksXusmXaZWFn0coV89r/b6/AgwAkUENaQaRxswAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-dat {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfVJREFUeNqMU01PE1EUPe/Na0uptmlASg3MoiZgCA3hQ8PHAjbqwsS9C3+CP8W1W/+BSReyYUPwI4QAVkAgUEgIbVIg1FZb2pl5b3zv2cHBjsaTTOa+e989OffcGeK6LhTevFv+OJoZHPHOfrz/sl86KpWfhxnLe7lXL1/oN/MSZqonOXU/k0AA6lfNhEFIrlAsP2PMyPtr1AscLpyg5pbtIHErhqez4+awmc45nI8FEvwNaiQuBHqTcSxMjJhmX0/Osp1xr878FxWEzwMinxAzEA4xFIpnOjedHTKpYbxW4U2CP4j8uWxmUKsghMCgFI2mFe9QgHZj0Ba4yhFF+KvGJToIRLuPC/efnjD6+26wB1Lq/xgbSCBXKeWJG/OTdky8cWTdT3C9RmWSGk2XCLlWo4xTNbfN5qh7PpXM72GjZeHt0gpq9QbmH4whGb+NpU/reDQ7hcWVVXxvXOHxzCQopQEKXKEbL6o1ZIcy+LC5g62DY2zsHeC0fA4zndIrHOjvg2XbAQRSfsuy9XxC2qzi/H5B6/68W0AsGkW0KyJPBLbDO0fg3JX/CUM81i0bD6WKe6j9qOPJ3EMcF0tSNsFA6g6alqW+VtZBUL78Vtk+Oqne7U9rs5qOQCjSheJFBeFIFOfVujSUYu3rIc4uqxWv76cAAwCwbvRb3SgYxQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-dmg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNpsU01rE1EUPe9lkk47yWTStCmtNhFSWxos2EXVhSsRcasuxYV05V8Qf4DgD/AvCK5EV1oFI7iUBqmCNdDvppq2mWSSzEzy3vPOpFFq+uDNfR/3nnvueXeYUgrBWH1/9/NE7k5BKRnuRcfF2qdnmJq9DeF9tQ+2isuMsxXGWHh/a1mEVsPJSI5fSU3OPEj291IIlN49RXz0KqzEQjIeZS/L5Y/3wPGhDxIM/i/A7fZWgVG0t5EaG0ZUa0JGM8gvPrZmLt58QYwv91mfAqCIE0sAqgumBFITGQzpUYhuF0KfRa7waDyXXXolpVrsh/0tgSLDr5I+wUZo1UHCSkAficPzY6juFSmbRPrC/azjq+fkcO00gAqoU7B0ETKkfWbuCTjTYeq5oESAauexcTScX+ZACWFm0YQSLZKhHdr67+/wW0e0dgjYo3sCEXXybYtBDVSHLp2es3IpsILS24c42lkBg6DzRjgRzCDZ/xr0GNRJwwYiWgzt+hYMawleu0V3wbkT+kUirOc7IGJAz68R/Qak1BAlx3hqASPGBJRXpXOv58dkz3eAgQoOm4hyj57NgZm0MHvpBmK6QdUdg/DAg9cRkhicBSDaKJdeo1bdxmR2DtWDDUxl51HZ+QHTysD3XdQO95Gfv06aeGcAdBrY3Chi8lwO3768QWX7J5q1XWyVSxgajiOXLyBG2hzurRKV9lmt7ISNkkjo6HhNyjoK+2gXRsKE57ZIE2ot10Z1fz0Ue4ABVw3NMjnW14rInh8jTYywoTg3EOFpOM4mXNfH9PQUfGlrAwBOs3I8ljbtuMWhRWzIIPrkn+GcYcgIWEowbZ+0qB334/4IMADESjqbnHbH0gAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-doc {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAppJREFUeNpsU79PFEEU/mZ39vZu77g7DokcP04BBSUmiEKCSCxs7Ei00JAYO2NlTKyMrX+CJhaGwopSQ0dMtFEsbDRBgiZEQIF4IHcg+2t2Z8eZ5QDlnM1mZ9+8973vfe8NEUJArfSNhzPG0VIfeIiDRSDkw1cWVt3N8rhG6SdSO2Gvn8dfuueqZwuNZqk3Jxg7iNcIfBbgXD6ZC8u5qffzX8eoYeyDxC77uygKhcouovgVUQj1H4YB2ovNuD9+tTTU0zMVBmG/+C8AIYh8F361DL/yE5HnADKYlVdg6MDAmW7cuz5WGuw+PsWDYGAvbL8ECFUt4K7/AHd/I9c7BLaxinD2Ld5Zo7g78RLuRhlBS2cpWbGfStfhfwCEpK0nUjCbWuGsLciSOELPhkq/YgdY3l6HsLfRcLYf+pHNbH0JigEPkLAyMsiEJ7NrqQzM1i7wyhoMZqOhvQs6Z0ovXgdAJACRoulEg5HOwrOroKk0zOY2BDtVpTF0CU6kLkQJXa+BNEoG0lMSsBBKQXWNQktmoGcaYeSaQCIVWOvUYQAiWZFQtk5mSMoSzEILtBrTfEcviC5bwVwQmoh96wA0ic5dB57ngeoaTIPCdb34zDITYNLOOIeVSsW+dQC+7+NSWx6jJ4tY/rWNV7PfcGv0tBoPTM7M4eKJVgx2FTE9u4QPS6x+kHzfw/mOAjarW2hJG3hy8zIceweuY+PRtREMdzbjzcd5WBqPB6xeRGUMGRzHjWvMmxQ7tiOF1JBN6FiTd6Sy9RuFbHpX7MMMqOD088Ii+op5OUAO7jyeRGfBwrF8Cg8mXuDL4neMXzgFwhwZz+hf7a9d5yu3Z6DTPjVQIY9k7erO7Y63Lvc8ErEeyq6JaM6efjai4v4IMABI0DEPqPKkigAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-dotx {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAndJREFUeNpsU01rE1EUPTPzJk0y+WhMStW2qdVWxUVEQUF0I+4ELQiC7lz4N9z0T+hG9wrdZKUgLqulhrbSag1CKpT0g7RpYjqZmffle5NEKdMHlzfvvXvPPffcO4aUEno9f3Vt4dTp+BXOe+fB0u/NbVpv7h89NU1j1TCM8H7+xY9wJwPHZMbOjRadLAvE/2gToJTiTPx89k+OlVd/LT+0TPIPpO/SzyQk40xCMxBSZ9Z3CoAx5DOjeHT7SbE0XSpzwa8OWB9jINELolQg8AR0EgUKn1PIlIWpkUt4cPNxkTOU12trs8p95RiAXpqaztqou8q6SKQJJmZSqGwsodFsIJk1kcyLYv7IeafcLx4HUNkFF4jFTExMZ0B9DrfD4HUEusYhWs4GPEJg5wly/tBYRIOeDhpEwlS34xcyajdQr3UwOT2MlJOEBRuGNHWp9AQRVXDfQiFV/U5GBSiQ5p6ngBEa5z3fiIhC6g6IMDBwOdoHPkYnHPVyhN0tF7E4QSpr94CEOKELffq+y9Bq+DCJ7rWBoQQBVbPR2O6G4OlsLASJMtCZfQqm0NP5IVWnamdAkUxbyuIYtD7wWegb0YAzAVMkkI6NwPM9xEwHloyDGAmk7AKS9rAS0FKOdugbYeAHPu7OPEM+MY7q3hIKqTFQHmC3XcONc/fxdfMDrk/ew/edzyhvvTmBAddocVRqH3Frahau56qpZDho7+PnTgXffi/gbHYmLEvPSIQBp5JU62sYz13G609zKBXvoOMdYn2zgm7Xg2MVML/4Eu3uPgxhk2gXmNl8v/i2pcXTP8tKdTEcbWLZqDQXwu/l6pfwbEnSGsT9FWAA4mdHv2/9YJ4AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-dwg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAoFJREFUeNpsU0tPE2EUPfOg006hD4rQh8WgbCSwkKgbF2owujaCiQsXxpX+D6MmbtXEsHCLmIAbE6NLo8YlGIxREIshIqVl+mQ6j8/zFVCb4UtuZua795577rl3FCEE5Bl79vPd5LHYiOP7cH1AUWi85ytmvlas1bJ9E5ryBntH3BpuP/X9i7ovkluuiE8N9SDepaLpCcRCCqa/VDCaMuIjSWP25Upl6n+QDoCz6Yh7KKzh3sI2LuUimPtRRyaqodj0MDloYiITSTi+mH29Wu0AUf9CsZPJoW5czJl48LmCc5kIKo5Al67B9gUGYxrun+5NnMlFZ+GKiQADj2a7AquseLIvjMv5KMaSBu4sWVir+3i8VIVKYSby0UTdFU8Znu8AYBHQgVOJEN5uOXi4UsdawwU0FSf6TaSoyw6DRvukPkgGWpDKy4F8a3jImCrqFDFn6rhKPR4VGnhvOTAY3WLcjifcQAsqRfhUc/Gq1MKNbBh9nIAMDjEppocxs9HCMktfGTCwP/oOBkUKNk/qF3pDYC6Ktk8RfWzyaaoKrqdDaBDwya8W1m0/CPCR3kFy7CcnmWQRUJqcRJFUKtTnPCeR71LwoeYF92CYyVnCFZpCTrRtCv5to2St8SOrKxiPqEEA4fkYT+mI0rdoeUiH1XZVuQPpsIKqw2QmfifTsnOABiWySlH9uU0Hh2MqjsZV5LtpPSoGeN9rKnhBX7ehoOSLIIPfnGONXGMMWN7xUfVldYDbjM3mrh5HCDgS17DhHgDQcIU+XbBxnDTn1x1UuQcJ9iv7l5Q5e1zLGri92EDJFnoAgHtcfr6wbbVXUqq193+0z97n3UJt1+d51n7aHwEGAAHXJoAuZNlzAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-dxf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo5JREFUeNpsU0trE1EYPfNMmtdoH2kDNmJbaVFcaBVFpAsREQpFwY0bu3HjQnTj1mVd+ANcuC3qQixmry6E0kWFVIQ+bKy2tbFJm3emyXTujGca+4DkwsedfLnn3POd77uS67rw1vC79ek7fZEzpu3AYUqS9tKQGZPLpa3VXP0uFCmJ/8t9OLC3q/uJbcs5bkIybvdHoMsSbLKENRmvU2WcNnTjRFD7ML1WGSPJHI6sA4KRWMAWVDPxLYex3iCmfpuIh1QsFSyMxQO4GvXHHwOJ6XWSyIck8v6HQsnjAxFc7vTj2VwBg4aG78VdBHQFCk+dbVcxMdwev9gTSEC455sIBOu2KLsoJFzqasP9vjCeDBlYqzn4VXXwarGKZN7Crd5QfLDT/7KpBM84c9fFUFjFp2wdk6smflRsKKqMa7EgfJJ3Ac2OKlit2pEmBTQfngdpnupoU7BUtRGiiTe7fXiRqmK+KuDn6TpvYogmBRJcrOwIJLIWxmM+dOsyLKryQAaJpjJ1/AxrGO3SqdZt7kKZJrzJWBg5piHENuY8vV6e0UOye1TyftvC5l+gZB8SHJTwpSx4q4JeTUKaxhXoR57h7Rn+3iFolJ3xvPhab6HgJG/pJ7jsNP4sUX+jZiCgEsWd/DjH5IrSYpBUAr0yHpzSoXKOP25a6OBhndh0zcX1qIYM2RIbu6i0KiHD5B/GTMHG03kTGpEL7H80wHFOWwhqDZ+SpkBOtCDYJDhZE4gRcKNbYynAqbCMbXpwpVPFbEng0aKJGbYzK1p4wIegLlcEPmdt+DjXbzcsxFlCynRwwVAwW6hjqeg0Zt521SYCWCJvbe0Un29UDx7Hgrs3IEitHXkw3jOv2fl92D8BBgAJeyqBh90ENQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-eps {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNp0U01vElEUPfMFCEVArdoSqEA0KV246UJdUJM2Lo2JK/9FjXu3utJqTNz4D9worrsQExbFpAFT0TYp0CZ8pIAiyMfMvBnvm2Foa9uX3Lw7c98979x77hNM0wRf7ufPsq7Z2SQYw2QJAkDxQalUZa3WI8hy3gmZr15bu+z8kILBkCeRCJi6bufKMji0NhwiCQR6iitdatTvQ5LyOLLEiWcYukm3m4Zhmbq1BX13FyoxuH7xAlbvpqKRK1fT0PWbRwEmDEyiy1QVg/V1GO02tO1tKLEY2PIy3KEAlmJRDLXb0TeZL+n9g4MHlLJ5HIBuYnSzXq+DlcsQLk/D9Hoh1WrIUjlPcpsYGQzS3LWoaBhvKeXWMQCDA1D9pt8PaXERUjwOjEZQFhZQp9L2yERiqYRCkPt/z58ogTGqHQLE1BLgUmC6XGD5AlipBIFKkbhanKHGYLBDqQ4ZED0OAbfLlo8OIxwGvhVgyTHlA3xkomjH/gegBgDURMv6faDbBZpN+/tHkUApkdTA/PwZAPxntwdUyjYA/+ZMqJHjLgM9iv/6zRt2GgMaIE21aVIjnSm0DGPfmhzyde0UAE2Dj+p7urKCPvkZku9eJILOSMUnkvVhIo7GYIB3xSKYdhoA1erXGVKXpvFxZwdBonnD68PQ7YEwM4O4xwMPxc8RYE87g4FIcz+kvfmnA0YzIJIy77/m0OCqsTkkCTysKPjJG3viLei63Gm3kCO6UWqcMejjxecMPmxsoFKtYop6UNirYL9Wtc5OHqzznIXHq1na7OfMJROcK8a6O7MjW7nfzZdrd7jzT4ABACh3NGsh3GcdAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-exe {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo1JREFUeNp0k8tPE1EUxr+ZzvRJO62lUAQaKIQ0FVJFjBBdoIkrDDHuXJi4NnHtX+HCjW408Q/QmHTRaCRRohIJifgiiBICTQu29mHfnc7MHc+MlECKdxZz595zf+c737nD6boOYzxJLC6Nhwej7e/24HkO779s7G6mMjcEwfKZ21+/d+em+RbagaFev28qEpZwzKg3ZckqCPH1nfS8hScIdyhBe6JqTG3PfyTTeLrwFhvbKdy9/xi5QglXL0yGJsKDccZY7LDIAwWHpSferWBh+RN8ni4UylVER8MY6PHj0uSpUK0hxzfTmWsUtnoEwO3rer64jEyxim6/Hy67DXaHExvJX3jw7CX8XjfORUdDlOohhU4fAVjILCPbm9V1yIqK2FgYt+ZmsZcv4lH8Nb5upXD7+hVMjIRQa8qeDg8UTYPU5cTcxSk4nS709XTD53ZhpD+IYMAPj+TBz93fZiz5oHV4AP1fGdlyHZIkIZkrI7GyhnK9CZXy+Aig6p1+HQAY003AcF8AVtGGfLWG9XTO4MLZ5cL0WAixoT4zVmPHADSiMo3hzHA/xgeDWFjbNg8H3A7kKnX0koEcPdTu/ylgRGZgOjNv38zoSXC8BZJDRKOlwGEV0VJVGM0y4joAPO1spXbx6sNHeD1uRIYGUCxVSRlDt1fC8rfvcDnsmJ+dOaLgoAs6AVLZPJJ7WdhEkUyT8GJpBflSBcVKDTvpDBw2GzQqQT1OgaZqUOhtFQUTUKnVTVWNpgy51YLVKph7sqKYkA4A1ScEfT66vm5kC3+ofh6Xz59FQ5bpkvE4QW3M5Apoyorhl9ABIKnFgNdTOh2NkJG6WSf9eRBJtmFwLDJmriUzeaOkYvvcXwEGAIVNH6cDA1DkAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-flv {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsUl1PE0EUPbssLYUCXdpaC9gWoSTgAyFigiRGY+KjvuuTr/4A44MP/gx/gMYfwIsan0RjIjGiJIZgSIGFIoXSD0t3Z3dnd70zpITazuZmJzP3nnvumaMEQQCx3jx69SV3a3KWMxetpSgKxP3m242Do43SQy2k/YRydvds67n8a63k+FRSn7l/bdg5tdsAuM3he/5weDC8vLdqPLgIIpba2niux52mg//DqlsYSg3iztO7mczN3DJ3+ByCLgCBH4hOFEF7cDpzPCRyOpaeLGXSc2PL3HbnW3XaRQCPEgWI2MsRVAVqrwbX9bHxbhOKpiJ/bzpDOr2k68V2BtRNzMtqDEqPejY/4zSGjb54BM0mQ8k4xsDoIMauXxnqYOD7PmwScP31d0SS/eAuh1lrolFpIBQNQw2pqJdqsAlIceB1AJCIkkE/FZskXDQVRXw6IYHiE0nBEcaPXSSvJnGwWkQXAE4acAhbxPMJpOdHweoMhc9b2F8zwKizbdlyPLVH7QLg+JKBYzoorxzjz3oRzUoToaEw9KyO8XQW5AE5jrFT6AbAYVVNxCZ0Ka3So+DSTAoDiej5ywTySbls1OEDobhFlMcXxrHw+AbINEjNXgb7y6BndLhk8cRkHHbD7g4gEhiJFxsdhrDqaamBaDKKerGGSKwPI9kR9EZCaNA5ubE7A5s8IFhsrxQkgJhZoa/06xC5xRz2v+3BOjFlbqcGlquxsondT9vY+2pAJdeZR6fI355CgQCN2A4O1w7gkQ7cdLUOAKdhV6uFSv3kd/n8mT68eC8dKWLnY4FsfeZQh7nVVt0/AQYAsf5g+SvepeQAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-gif {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmVJREFUeNp0U0tPE1EU/trplAqlL0laiw40xASByEJIZFGVnSvj1j+gWxNXJq7VrbrwF7h10cSNhMRHojEuACVBKmH6SJQyJeXRxzzv9dyZPiCtN5lMe8853znf953xcc4hztDzZ1+C6fQMHAfd4/MBFG+p6h/n4OAeAoGNToi/eOm+A50LKRaLh6amoty2vVpZdotNXccMEK3LwZxa2bsDSdrAqePv/mLM5tSdMwYBYqyvw9zdhUn/L59P4OGtG8qlZCoH254/DdCdQBCxqZu+ugqnWoW9swN5ehp2NotgIo6bGQWGtaS8+vQ5V9a0u5S+1gfABEilAqdUgm98HDwUQkDT8JXoPPq+BoM5kCYmFT9jryn1+hkAt7heBx8dhbSwACmTAUwTgdlZ/CVKJaLnI1GD8TikZiPSR8Gxib8chH95mZTxgwWHwH7+gFMswqcokIRbjMO2HDCnZ1VvArpjEmnKZc8+cZJJYGsLsMiZ8AgwEqaY6Mb6RQR33JFhGECzCRyfAFXNu9v+RVNRZWIMuDJNuYMAaDycUFGhCOgtuAtFVDA83G5A8TrFDw+F5QMAxAKJJxz2xnW3RPJGbm+rCyjotZetH4DGzaSSeDA3h4Zl4R0JOEZWTpIzF4n/m995bNdqZwB6m0gFft3Ak6vz+KYWwFsGlqIxXItEcDt1ARMEtKdVgZb+fwA0G2C2hXM0ZTZNRcSf0b1pmXi7uYnjI+Lfanm5fRQsK8BIxKcrK7i/uIgP+Tw+FlREqHN5fx/vyU4uHBE6UO4gDWqk/JFaLuMxcXeFk6TuJ90V0HOk1in7J8AAjmgkPfjU+isAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-h {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAbRJREFUeNqMUk1Lw0AQnf0woK0ttVqp0hwqVCl+UBERT94F7x78Cf4Uz179DT14F8WbYHtRkBYRLNqDtdaPZLObuLs1NGlXcWDJZGbey+x7QUEQgIqT07PL5WKhHL5H46J+22q22vsWpbWwdnR4oJ80LNiz2czGUjENhvj4ctIE4Wrj8XmPUlKL9nCYcOFzE9j1OKSTCdjdrtiLdr7KhVgzEvwW6krC92E6k4Kd9bJt57JV5vFK2KfRQRV+RAMkzxglYI1RaDy2dW1rpWRjQo5VGicYIorWVooFvQVCCAjG8Omw1MgG8AM0uSBUDSnCfk/IGCHwf3DCD/7UhOLBrFkDuep/hDUSSCv1iYo4rIfqGwmUSNJjfYbBcQKhZw0aBMA4B48LwBhBt/cON80HmM9NQ6fXg/Wlku4TwmNWDzaQqzHG+0PSKod5cH5Vh2RiAhYKc8DlV1UPSyuFMGygVlMg1/P6BC6DqXQK8jNZDXAYA1f21V34wMXYFaiyVw0rJyzLgs3VMkxOjGtix/V0XWChZ0cI2i/dzvXdfTd0Qf91BMPrhyNzgKfOmxaWypqaDXHfAgwAtCL8XOfF47gAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-hpp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAehJREFUeNqEUk1v00AUHK/XKf1yZdESVRBXjRSRFqMQVBA5Ic5I3DnwE/gpnLnyG3LgXglx4UDDLZS0RWkDLiRxSusk9u6GXSembmLgWZbX7+2bnZl92mg0goo3b3ffO/ncdvyfjHef6q2Dlvs8Q2ktzr16+SL60jhhZ69bO8X8ClLC7w9XdKJVG8fuM0r1WrJG4gXjgqU1D0MGc2kBTytl+7a9XmWcl1IB/hZKEhccq5aJJ/e3bTu7Wg1CVo7rNLlRhUh4oMnXoDoyhoHGyWmUe+QUbELIa7W8CjAFlMzdzeckCwFN06ATAn8QmDMMMGlMuwWucpoCHNe4jBkAMenjYvRPTyi53JvuwX8AplleAeBcRFrH6rXIxLim9I/pi3QA1RhKaYxdjkN8IwalCMIwWs9ljMkh0wzk+9M7w179C3LZNXxve2h+c3Hu91HeKmD/6zHOLnw83ilB1/V0CeqU3Q81LC/O41b2Btx2N2JVP2riR8eTUxmi0TzBwrKZMsqMoz8MsDh/DWuWhUBKURLKxQIeOMWoptYPnS1c+INZBkwISomOSsmBZS7B+3WOzZvrKGzkMAiGqNy7g+LmRkRfekBnANy2163PZXrSbrQ6vch19Xz8fPDHyL39QzkHBKedXjfu+y3AAGU37INBJto1AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-html {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmBJREFUeNqEUktPE1EU/mY605a+hhZTBNKRDApNrWIRA4nEBUZdmCgLNi4MK5f+FNdu3bFv1J1EXODCR1JJSMTwpqUP6NiCpe10Zjz3hj5Mm3iSybl37jnf+c53jmDbNpi9eb+6Ftcisea909bWNzNb6dwzSXKkhIt/r14+515qBqmDA8HpqKagh53XaopblpIbe+knDpFAhPab2Dw0TKvRK7lmNODzePBgZlK9oUWSpmVNdpIU8T+jaMsyMaD4MDcZVa+NhJMN00w0n6V2nN3yQgdHWZag+LzYPTomIAtT0THVtPGanmb/BbjwLFkvn2IttYGYplKyDzsHh7gdmyAWfh5zVq0Guhg4RAHFUhmfvq3j134aXo8bd+ITnMFOOovU5jbGRoZwNxFn1cxuAIcDW/sZDjA/c4u+BNxOJyxqaenpI3z88gMfPn9Hv98HQZS6RazW6kjExvFi8TGdDSy/W0Emf4LS6R8sv11BmfzSwkPcm74Jo9Ei0GZgmkw8QCOao8OXcaz/5vSZnPdnp3ApqBBLkWJE0Ci7ASzbIhCLLQ1E0iOkBDh9NpUgiUejo8oNuJwyn0YPABtn51UYFFivG3yBGCNZkuDtc/MW+ZQI3OrYpBaARCKufk3B5XIiWyhiL5ODp8+FfFHH+KiKSqWKUL8fC/NznGlPBmz+24dZjKnD0CJDcMoyW0SqXuMtHBFw7rhIAD1ErNUNafxKBNevapwu65NpEQ4FqXIA+RMd6VwBP3cPSERb6gLIFIq61+UqGWaFdcrVt/lmAuWjAi2aiMFwmOYuIJ/N6M28vwIMAMoNDyg4rcU9AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-ics {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhRJREFUeNqEUkFPE0EU/mZ2dra7bLNpi2AxQFKalkJrohICiYkXPagXrx78Df4K48GDBzmQePLMhUODNxQ5ciEkJVqDtJGmMWrCATRbd2ecoS5u3aovmezsvu9973vfPiKlhI4XL7c2r5YL81LIELEghLA3u/udxmHnPmfGW/Wuv+LpwwdneRYBx7PeWK0wOYYhcXxyckGV1fdbnbuMsXcklqPRJQxFMKz4RxDCtVO4s3xlRjWoB0FYjlQPEEBieChwKCRGMx5uLtaKs1P5ei8IKlGa/YkXMXYtlTEDlsnw/mMXhBJcqxSK6vlcpa4PEpCooUyIqs5M6hG1o2CUwqA091cFcYLf/sjzcX75EiQIojI9779CTYR4jwTBf+r7GAwh0AxCiL6JMT/04vQ79u8aI2O/7Jzg69o6Go8ewycUahtBpADhHKLnK/eVbkMdtROWIv80NQ2sPhncA9Htwn+9hZG0rY6DzFwJl+7dhs0ZstUy8rduwPS/wd/ehmi3kwq4zTHiWUgXp+EuL8FvNvFl5Rn4xAS86iyI2kY3n0Mv48ByrOQmancdi8I0Kcj3U5iuA29xAelKCUHrEIayzltagG2E4IwkFaQgSC6lYI09iN0d8It5uNV5nG5sgJdKYC0G8WoTOZvBISFNEBxnsuzD3GX4vfDsszzqAu0jkJQDedCGbB6AWg54pYbPo+NGVPdTgAEAqQq70PytIL0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-iso {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjlJREFUeNp0kstrU0EUxr/k5qbJzdPYpGkpsUJoA2q1oLjTdiGiIC5cuXHlxv9BEOrStTvBnQvRrSAIsejCrlqpsURq2hCJNQ+TNLm5uc/x3MmzJh34mDNnvvnNzOE4GGOwx8+t9XQkfn0VE0Y5/7Z+kHm+dvOhtd3P9c/xwNZh7nWaMYtNUmX/Fct/vlN7/8J5aRRgyzm8xzpRDjGE2aVH4VTqdnoUYg/XkEhmy+Cx3DhA5tMzdFolvg5Mx3Fx9SmH0JIg79Zo3j4GADMIokJTKtjbfAKXU4Y/2NvSfyH75TFOxa9Cmr0XnlPFl5ReOQ6wNMDsoFX6AElqQlNV1KsOuNwS/AGFjEUIDhmn5+/DMM16/9igBowAzFKIswPJr6MjlxFP3sV04gaP7RzMPe6xvWM1gNUBM2UKYlBau3QghGphg29J3gDlLLilWNdD3gkvIIDRhD9yGe2mCV0V4HFXuCxT5Dlv8Dz3sIkAs03FalDxBMQSt9BRBMhNncuO7dyU28c9tnf8C/Q0ZtR4GImeQSj8APLRH772BWcgiFODffCv/t8H9tO0v3RjV7VqkeeXLlzDfvYjj88uXhl4JwIsrYxmLY/M1gYclIvGE9jZfNPrSCD3/QgLyeWTADV6wW9AryIcCkB0u1Aq/oCPumlufoF72vIheaLDr4wCLIOqrYnULA14PSoqpSJEAUilZrD77Sv3LK+cI0+Be8cAbbmAOrob0agtD491LYfkoqvnyZLsWRkA/gkwABL4S3L78XYyAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-java {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjxJREFUeNp8U01v00AUnNiOEyepQyhQobRBSlVIoRCBEPTAjQsSEneE+An8FM5cuXLNoQduIAE3qopKNJAIIppA2jrOR93aa6/N8yZuUxyxkrXr3ffmzczbTQRBgHC83nj3ca28dD36nx6fvnzrNNrdp4oibyUmey9fPBezEgWVFuYLdyvlPGaMY4fl1aRS+9pqP5ElAkmcnknRwuO+Nyt5u/ETYfyj9WrpZnmpxn2/Ok1Swn/GvtnH5k4TLue4kNfxoFoprRQv1TzOb8cAIu3+ZD7oD/Hm7XuxzqRUNDtdkuLiTmW5tFxceBXlnXgQTAORSMt2oGezUJJJrK9dFWdEH7Ik4dB29LiESeUEJXd7/dAT3L+1ivlCHr8NEzutXTBvbJPPSdO/AH5wysChwM/1HzCGlmAzOrKxu2eCud6Z2Jke2MwThpUXL6Nn2ZAVFTlNw70bK0iRnGAq9qwHtOmTRpsx1NsHyKRVnNPnoMoK9kc2BjbD4vk5JGV5NkBoEPM4FFnCteJFWOS4ntHEfphQyKaFTWFLw704AJ26ZFx/ZEEi3YyY0O1Dmr4EKTUHA8hUnS6siI0DEHLYog+b28RCRuNXR/iQUpPUEQ+NVht6Lodnjx+GXYgDSFRnq97Ed2pXSlXhUSeGhxYc5sKlNXM5DGLR2TMwfZVPAIi+otGNWy1fEZUKeo4qc4ysI+F8VksLIJfYcD9QYgB/DNPMptWBlsnBIS86xmDMTBo/PWd0LB6VZfdEbJT3V4ABAA5HIzlv9dtdAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-jpeg,.ipfs-jpg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8luUlEY/s4dmMpkWxRopGJNNbiwhk1tItbGtXHr0hcwmvgOdWld6Bu4coXumtREE3ZKu8FgOlC1kIoXtC3jPfdc/8PUIpzkBM7wf+f/hsts24YczuerGUc0moBlYTAYA+i8sbdXtAzjITRtq39kr73s/Gr9DTUYPOeamwvYnHdrdR0SnDebuCbswJGqpX+Uf92Hqm7hzFAG/4TgNr1uCwEJ0trcBC8U0Kb1/PQkHt9JxSLnL6TB+Y2zAIMOJBGLXmtsbEAYBsx8HnqCGKVScAX8uHf5EpqmGXv18VO6VDEe0PXsKABN8+AAgiabmYFNNJTDQ2RUFc8+Z9G0OPR4PKYwvKari0MAgiY/OQGCAajhMNR4nDZMaInrKBGl70SPMScck1NQG3X/CAWLE3/dAWV5hRRVIJxOWNksrP19sFgMqqAebUGYHMI6teq0A9oTVAhqu2sfbYYjsL7lCZ3683gA70T3TK7/B4BNoO020GwB9TpwfAz8LgMtWn/NkV8EHgoB81c7nYwCyBZlEVkHcqMTKFnkmehJTOPvEfCnKi0fAyADJKfXC/h83TaZTJjaa5lANLpOFqAXtlEAorAwO9u5syT5UxLfU0e3o1FMu1x4u7ODYq02BKAMAVSrSNLrK1MhLPj8mNF0vFm+C1ZvwKBwXXE4AGn1WAASazESwUW3BzUSMeJ2o1Aq4sPurvQYSRLwlhRR6mSaYyi0WlpAJrFRx3ouh5/lMt5lv8BLwXp0M4lSpYL17e2uK5wP6lj/c2ZPn2RI+YT8fDvqoyegVLyfG5kBKaQQOfvF2pLc+ifAABiQH3PEc1i/AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-js {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUQ5ODY5Q0NGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUQ5ODY5Q0RGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRDk4NjlDQUYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFRDk4NjlDQkYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoT8zQ8AAAJdSURBVHjadFNbTxNREP52t7S0bktbKFAvTUVaw60YqkExUTD6oD74qC/yD/wp/gh885XEEI0RAyYQUiMpIBGMkYR6o23abi+73e2uc04v1LROMtnZPTPffvPNHMGyLDB7sbJ2ciUSli3U35smkK9t7x9v7n2dD/g8KUkUwWqeP3vKz23NxJGzgwOx0RC6mSgIo+WKuvP56MeUzy2nJEk8PWsGJVVTuhWbpgmHw47FB7d98Wg4mVWK52o1sxOg3Va3PmFp+Q2PdUquaFUM9/vw+O6cP3bxwm46Xwh1ALR3/vL1e+hGjcc9koScUsTSq3coVDQsXJ3wzo5HEs3clgZNMTVdx1T0Ep7cn6//QRQwMhzA6uZHLD5cIFEFSKIU+G8LK+tb0KsGZKcTJoEyP08AbpcLy6sbPKdQrigdAGaDwWxsDH1uGbliCYIgcM8WFPg8Mq5Pjzdyu4jYbCE44EepXMHuwXe+A8x3KKYxYsjvbUzmlPGpBmYdgI1oYjSMbL4Ao1YXMkcM2Dd2xnbAamPQAqg1GORLZdycmYTdJqFKk2DPR3fmwI4zBDrg9RADqxPAbPBif2WTSB584/3/TGegEOit+DRcvQ4OZJi1LgwIQKVCg2i6nb1I7H3Br3QWqT9pBAP9uDY5xjdSM3RqxeoUkfVnEOW8UkLykERTNXjkM7h3Iw6NNvHw6JjuhAhVrba0+QeALozcI9nQR0VvNxJc/ZmxCNGvIBQcpDG6udA22kyW29HC72wu8yG579ZoiSYuR/ly2+y9CA4NceWLmo717T1i5ULqJNtapL8CDACskxPFZRxLwQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-key {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlZJREFUeNpsU11PE0EUPbM7u/2AtJUWU6qiiSYYo5EmmPDCD9AH46sx8cEnja/+CB989z+Y+MKPgMiDsYQACcbaWBBogYD92t2Zud7ZlQZsbzKZ3bl3zj3n3IwgItjYeDO3MlWme0bjUth8e8/fO2tHzx3XqUEk50uft+Ndnhdmc3SlfNPkVZT8Cy600DoIISvVfKYtlvfX1p66XmoIYsMZdjJQWvEFbbsC/S5g2QhSkKUK7rx6OzvzqLpsovAhaAxA3DUBQn2TUFsl7KwTfm4Z9DoO5LW7uPXi9Wxpfn7ZKF09vyPxX2iWcNRkKGZz0mQWKoNs8AVB6x1yRY2pYnc2LLofuXTxMgAlmlXIfngCxNxEzM+DPv6NQa2BygLgZyX6JT83ngHTN5GAL0WSoUQkSQnXkyBh/k0GegTAaldM20sTKvet+yyhIZApECamL0jUSe3oFChx3TopM4TeEQP2gc6BgGIwb4KGNXRhCkMGxgg2kJeybRiZM45D8W61qEAknSmpHStBhywu0nFVupSCTAcM4ECwqapv+NQ6LS9JGALoMIIoPYDjZiEL1xHtbyO39AQUDaA7R1AH23DSeSA4hv5RG/VAhxomPYP8sw9A4TaC9iHkjUWmrtGvbyC18BLe3GP0m3WW4I5hEBEnPIStXzyuFIxb4EkMEJ79Qa/xHbKxCdM7xeCwzUZOjgEwnuzt7qLz6T3cySmQP43uzjeIiTJM6io6W19B/NLCKMVGCzkCoLR/0lrfOI2fNy/huKC1FTsK/rbGNeMRC8dHpHByfu+vAAMAL/0jvAVZQl0AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-less {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjZERjZENTJGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjZERjZENTNGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGNkRGNkQ1MEYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNkRGNkQ1MUYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pl1w97IAAAJhSURBVHjahJNLbxJRFMf/wPAIMIxMkUI7tS0VYqlGDLGhjdKkqyZ24cJFN925de+XcONHaHRj4k7TND6SGo1VWwmp2kSLhlqMDbQ87gzPYcY7k4GgoJ6bmdw598zvnvM/95pUVYVma+svcovx8yMnFZHAMJPJBJfDzq5vpX6+/vD5qo/z7DOMBdo/d26t6jFMJ3iY51jBz4M+LP6wxEw40Gy23qYzB3HO7fpmpZCOmfEfa7Xb4NxOrC4lvbPToe2yKE3K1PdPwNOtHdx79ESfq4qKkijB5/XgevIyHxEC24USmewDqD2ABxubaLRkfW6zMqjWGlh7/ByyAtxYnOPnL0Q2+gGGmKRaw8zUBJaTiS5QOO1FJnuIAM8hciaIWHgi8NcSNt+loVDY8JBXh2ojJAR1HbTSNFMUpV8Dxcjg0nSYBrtBxdLbqI1iheCUh9XXNGurAwCdEkb9QyBSFam9TDfoPZ1LUg1BH28IiwEARTVAQOzcFKRaHZpLoa9avY6L1Gfs0c32t4PU6W2lWsV8LAorw0Cs1nXftYWE3qZGqwWHzYp2zzlgetuolVFvtiDLbRRKFTAWCxx2G/KlMtXFhWPqOzsWHJwBx7rxKv2R7mwFz3lw9/5DLC/M4Us2RwV0g3U58XJnF7dvrsBOoX0Abbej/DFKRMKI30fTVGC32WA2m5H9cQQvhYi0vE/7Wdgczn6ARA9QPBrBszcp/XvpyqxebzQ0Tlsq6llxLhe9bD4cFMr9XdjLHpLv+SLGBYHAYiVu1kNOpAaRTWbCejgiw0zGhFGSK1aw+zXbvfK/BBgAPwADAs5GpGsAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-logo {background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 553 235.3'%3E%3Cdefs%3E%3C/defs%3E%3Cpath fill='%23ffffff' d='M239 63h17.8v105H239V63zm35.6 0h36.3c7.9 0 14.5.9 19.6 2.6s9.2 4.1 12.1 7.1a24.45 24.45 0 0 1 6.2 10.2 40.75 40.75 0 0 1 1.8 12.1 45.69 45.69 0 0 1-1.8 12.9 26.58 26.58 0 0 1-6.2 10.8 30.59 30.59 0 0 1-12.1 7.3c-5.1 1.8-11.5 2.7-19.3 2.7h-19.1V168h-17.5V63zm36.2 51a38.37 38.37 0 0 0 11.1-1.3 16.3 16.3 0 0 0 6.8-3.7 13.34 13.34 0 0 0 3.5-5.8 29.75 29.75 0 0 0 1-7.6 25.68 25.68 0 0 0-1-7.7 12 12 0 0 0-3.6-5.5 17.15 17.15 0 0 0-6.9-3.4 41.58 41.58 0 0 0-10.9-1.2h-18.5V114h18.5zm119.9-51v15.3h-49.2V108h46.3v15.4h-46.3V168h-17.8V63h67zm26.2 72.9c.8 6.9 3.3 11.9 7.4 15s10.4 4.7 18.6 4.7a32.61 32.61 0 0 0 10.1-1.3 20.52 20.52 0 0 0 6.6-3.5 12 12 0 0 0 3.5-5.2 19.08 19.08 0 0 0 1-6.4 16.14 16.14 0 0 0-.7-4.9 12.87 12.87 0 0 0-2.6-4.5 16.59 16.59 0 0 0-5.1-3.6 35 35 0 0 0-8.2-2.4l-13.4-2.5a89.76 89.76 0 0 1-14.1-3.7 33.51 33.51 0 0 1-10.4-5.8 22.28 22.28 0 0 1-6.3-8.8 34.1 34.1 0 0 1-2.1-12.7 26 26 0 0 1 11.3-22.4 36.35 36.35 0 0 1 12.6-5.6 65.89 65.89 0 0 1 15.8-1.8c7.2 0 13.3.8 18.2 2.5a34.46 34.46 0 0 1 11.9 6.5 28.21 28.21 0 0 1 6.9 9.3 42.1 42.1 0 0 1 3.2 11l-16.8 2.6c-1.4-5.9-3.7-10.2-7.1-13.1s-8.7-4.3-16.1-4.3a43.9 43.9 0 0 0-10.5 1.1 19.47 19.47 0 0 0-6.8 3.1 11.63 11.63 0 0 0-3.7 4.6 14.08 14.08 0 0 0-1.1 5.4c0 4.6 1.2 8 3.7 10.3s6.9 4 13.2 5.3l14.5 2.8c11.1 2.1 19.2 5.6 24.4 10.5s7.8 12.1 7.8 21.4a31.37 31.37 0 0 1-2.4 12.3 25.27 25.27 0 0 1-7.4 9.8 36.58 36.58 0 0 1-12.4 6.6 56 56 0 0 1-17.3 2.4c-13.4 0-24-2.8-31.6-8.5s-11.9-14.4-12.6-26.2h18z'/%3E%3Cpath fill='%23469ea2' d='M30.3 164l84 48.5 84-48.5V67l-84-48.5-84 48.5v97z'/%3E%3Cpath fill='%236acad1' d='M105.7 30.1l-61 35.2a18.19 18.19 0 0 1 0 3.3l60.9 35.2a14.55 14.55 0 0 1 17.3 0l60.9-35.2a18.19 18.19 0 0 1 0-3.3L123 30.1a14.55 14.55 0 0 1-17.3 0zm84 48.2l-61 35.6a14.73 14.73 0 0 1-8.6 15l.1 70a15.57 15.57 0 0 1 2.8 1.6l60.9-35.2a14.73 14.73 0 0 1 8.6-15V79.9a20 20 0 0 1-2.8-1.6zm-150.8.4a15.57 15.57 0 0 1-2.8 1.6v70.4a14.38 14.38 0 0 1 8.6 15l60.9 35.2a15.57 15.57 0 0 1 2.8-1.6v-70.4a14.38 14.38 0 0 1-8.6-15L38.9 78.7z'/%3E%3Cpath fill='%23469ea2' d='M114.3 29l75.1 43.4v86.7l-75.1 43.4-75.1-43.4V72.3L114.3 29m0-10.3l-84 48.5v97l84 48.5 84-48.5v-97l-84-48.5z'/%3E%3Cpath fill='%23469ea2' d='M114.9 132h-1.2A15.66 15.66 0 0 1 98 116.3v-1.2a15.66 15.66 0 0 1 15.7-15.7h1.2a15.66 15.66 0 0 1 15.7 15.7v1.2a15.66 15.66 0 0 1-15.7 15.7zm0 64.5h-1.2a15.65 15.65 0 0 0-13.7 8l14.3 8.2 14.3-8.2a15.65 15.65 0 0 0-13.7-8zm83.5-48.5h-.6a15.66 15.66 0 0 0-15.7 15.7v1.2a15.13 15.13 0 0 0 2 7.6l14.3-8.3V148zm-14.3-89a15.4 15.4 0 0 0-2 7.6v1.2a15.66 15.66 0 0 0 15.7 15.7h.6V67.2L184.1 59zm-69.8-40.3L100 26.9a15.73 15.73 0 0 0 13.7 8.1h1.2a15.65 15.65 0 0 0 13.7-8l-14.3-8.3zM44.6 58.9l-14.3 8.3v16.3h.6a15.66 15.66 0 0 0 15.7-15.7v-1.2a16.63 16.63 0 0 0-2-7.7zM30.9 148h-.6v16.2l14.3 8.3a15.4 15.4 0 0 0 2-7.6v-1.2A15.66 15.66 0 0 0 30.9 148z'/%3E%3Cpath fill='%23083b54' fill-opacity='0.15' d='M114.3 213.2v-97.1l-84-48.5v97.1z'/%3E%3Cpath fill='%23083b54' fill-opacity='0.05' d='M198.4 163.8v-97l-84 48.5v97.1z'/%3E%3C/svg%3E%0A");background-repeat:no-repeat;background-size:contain}.ipfs-mid {background-repeat:no-repeat;background-size:contain}.ipfs-mkv {background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M7.5 91.1V71.2h6.1l3.6 13.5 3.6-13.5h6.1V91h-3.8V75.4l-4 15.6h-3.9l-4-15.6V91H7.5zm23.5 0V71.2h4V80l8.2-8.8h5.4L41.1 79l8 12.1h-5.2l-5.5-9.3-3.4 3.3v6h-4zm25.2 0L49 71.3h4.4L58.5 86l4.9-14.7h4.3l-7.2 19.8h-4.3z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain}.ipfs-mov {background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M6.1 91.1V71.2h6.1l3.6 13.5 3.6-13.5h6.1V91h-3.8V75.4l-4 15.6h-3.9l-4-15.6V91H6.1zm22.6-9.8c0-2 .3-3.7.9-5.1.5-1 1.1-1.9 1.9-2.7.8-.8 1.7-1.4 2.6-1.8 1.2-.5 2.7-.8 4.3-.8 3 0 5.3.9 7.1 2.7 1.8 1.8 2.7 4.3 2.7 7.6 0 3.2-.9 5.7-2.6 7.5-1.8 1.8-4.1 2.7-7.1 2.7s-5.4-.9-7.1-2.7c-1.8-1.8-2.7-4.3-2.7-7.4zm4.1-.2c0 2.2.5 4 1.6 5.1 1 1.2 2.4 1.7 4 1.7s2.9-.6 4-1.7c1-1.2 1.6-2.9 1.6-5.2 0-2.3-.5-4-1.5-5.1-1-1.1-2.3-1.7-4-1.7s-3 .6-4 1.7c-1.1 1.2-1.7 3-1.7 5.2zm23.6 10l-7.2-19.8h4.4L58.7 86l4.9-14.7h4.3l-7.2 19.8h-4.3z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain}.ipfs-mp3 {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra7XWxpSsFYIbVQf9REFBHkYBRIPJh4wrN3DsZ4MPGP8b/wUCIHEw5EY0w04o9ILcREGmwVgaXbbXdnd2bXNxPahGyczebtzrz3ve99740WRRHkWn5cebu4cH6SMY7e0jRAHr9c3WxsVvcemmbys9yT6+uHJ8oaPefypdPDD5Ymh5w26wMkEho8JtDtuEOZFCrvN/4uJZNGH0T59D58X/C27aFNAL3Xthmsww5GCyN4+uzu+OLtQsUPxPQx6ZMAoQjBAw7O+bEVCMMQgqygs+LFs1h+dGd8bna0QmXO9OL6JYgwAvOFZKKoy3V44CgNfv7Yx8oLH+lUEgvzF8Ydhz+n41snAGRG5gUEwClzhHdvttFxfNyYK0EnJozKK5eGcf1qHo1GOxtjwI+pfvm4g/W1qtJgerYE2SXJSIL9+W0jk0mCShAxDXgQKgbNXxZq35vQKCiKQkSUXdc1+gcch1FHGPmKuIgBCdc66qJQHMG9+1NIpUylxxHtuW6gEiTIu+N4yjdWgty0yTmdNjFzcwKjY0MU7MLt+IjoSad16FoIx3b/A0DZ7FYXnsdpAjUMDOjI5zPgfoBsRodhhGhZHfBBU/nGAGRtxWIOg5lT2NtrI5dL0SB5KJzLodloqXaOEatPGztKq5gG3S5DNjuAK5NjKJfPYKI0okBkSdemCiSgS/rkQNLSePtxBj4LSCwfFtE0krqqX7ZVMnu9XlMXy2l7ME0dzA3iANQyY6vWxC61UY41zTyNcYh6/QCNXQvzi5dR39nHVq1BUyuMGAARsF6tbbe4iKD1r7Om5iFBdmW1SsDflLiuB6sX90+AAQDHAW7dW0YnzgAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-mp4 {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnBJREFUeNpsk99r01AUx79psrTrujVtbceabnZs4DYRHSoMh6Dgq77rn+AfoA/+If4Bok+C0CfxVRDBh+I2NqZzrpS1DVvbtU3SJPcm8SSlsJlecsn9dT73nO85V/B9H0H78OLdt/LDlQ1uMYybIAgI9n99OWxoe83nkiz9hDDae330JvxL48O51Xxm/enNtKPbVwAh0Ec6kYpXat9Pnl2GBC02HrjM5Y7h4P8+7FtIFVJ49OrxUnl7ucIdfhv+BIDv+fBcj7p/tXMPrs2RXVTw4OX2UnFTrXCbbY7tpMsA13FDSDAOQ4gJEGUJLs0PPh9CkESsPrmxxEz2lra3rnpAt3G6adgdQhBpmeLkFodNmsjpOPoXBrQTDcmFFNS7i3MRDzzPCw/vva8ikU+COQxm14BBhvJcHLGpGPTOAJxxeLbrRgAkYujBdH4G5oWJWXUW19YL4XqunAMFhnq1BqWYgaY1MAHASQOiU96zKzkU76mwehaOvx6h9uMv7KFN3RopL4oTAI4HRh4wSl399xla+00YbR3yrIzM9SzSqgJJnoKcklGrH08CcJjnBtLLCsSEGGpSWJvHtDKNoFippsJ0ulIsDDUCCATMlBQkNuahEyiZTcLsmFBKaQxaOk53TlHeKkM70AjAooCghBOk9sKtIvqtPqS4FBaRnJSRX8tj2DOh3lFB5Qw2ZNFK5LRo6w4sKt2ggAzywidAMN/9uIPSZglBLDO5FF3mRD3wHE9qVRvoHrUpfn+UEQK0/7ShtwboHJ6jdH8RZxSC57hSVETb7e5/2u0FxqPHJow+8iZ4lYY2QGu3idhIxO7Y7p8AAwALCGZKEPBGCgAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-mpg {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNpsU0tPE1EU/ubRdlqmnUBboa0UeUQDiUGCC1+JmrhxoXt/gBvXJi74If4AV0Y3sNKF0YUaICqoIfjgVShEiGF4tDOdO/fOeOaSKtie5GZu7pzz3e/c7ztKGIaI4vn9p+/P3h4e4a6Pv6EoQBDiy7P5rc1P1Xt6XP8M5ejXo6UJ+dWbuemeTGdpvNdiNe9YvQLe4Bi4PmTpRmyq8m71rp74BxKF2twIHvAo+f/l1T2Yp0zceHizfOZa/xRnfBRhG4CQqAYioBWeXDyA8Di6ei1ceXC1XBwrTXHPH2vW6ccBBBMI6BsSUEQzakGL6xB0tvjyBxRNxdCtc2Xf8R9TyaWTDOg2TjfVdw6hqIoE9B2GxkEDWlLH7s4ette2kSp0oDRezrQwCIIA3oGHr0/mKMmE53qo23W4+w5S+Q5ohob9X3tgHgO8ULQACC7gMx9mKQP30EW6mEHpYi8xcJEdzMucjfkKcrTfmqmiFYBxCF/Id+gayKJwoQjHdrA5v4HK7Cq44KjZNWpagaqp7QACks0H9znW365ia24DzoEDozOJbH8eVtGShXHTwNracnsG7q6LzsEuaAlNPm9h7DSSVjLyCMkppDI+GS2StQWA1RlKo0X56n2X+6QHkmkDakxF9WMVqWyK+s/BrthYfvWz1Ug+zUDcjMPMm0h3pxEjFma3CbIuCud7oMc0LL1ZgmElpGJtW3B+15HIGNITrMYIlOH7i0U41NrInREylYbu4R5qQbQBaAh95fVKZCnpQCnb9DrWZyrRERS6NDeUw+yHaXh7rt4C4B8y+9vkwn7kwKNRpDoa9aiFKBYnF+RcREqQ2e1m3R8BBgAy9kz9ysCE6QAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-odf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAi5JREFUeNp0UktrU0EU/mbu3FfE1KRRUpWYheALNBURUVy7cy9UkO6KW/+Lbt0IPsFui4gLBbUqFaUuXETUKCYa0jS5yZ2ZO557b5MmTXpgmDPnfOc7jznMGINYPi0de5UvmpORxpjE/kbNqW005DVu8TWw1H758ZfkFgNgJmtyxSPRjJIj0QTW/RDiYGXGb7Dl32/eXrVsd0gSCx9miqC0ooCdp69g5Q/h6OLN0ty5ynIkwzMwUwh2FwMdcbDiCZQXlkqFCpEoPT/wih1YjLInANcD+/Ua9bu3wJlGvrBZCmet2+S6ME5g4oGlZ9A/I70XCDhhDexPNTFmswJBwcnuXkF86VSNZxVu0ukLSGnBcqlnN4HoCQIaIuIv7LUooMOgQ7q75LAAb59B9gCBHSKgqemRr94mMKmD24CfM8nb7THYGQNLpAkUkcb66JyGBFFEWRVL57gFEH5qj8Lxwca2qS3EZaugmzAw24dR/XQgwtsCSBjPIdWbUoE2UJLBnV8Ac/ciWHsK9/glWLnD6K2vgPszsOdOQdfeQ1c/ThKoTgDn9A3KUED/52d45xchZsvorD6Bf/Z60riV3Q9Z/0bbGU1uopYGkfERSQ3VbsMwl0qlqoIARmSoPYXWy0dor79LfBMEEd8jGs/uQ3Yl7PJFNFbuEXiV2riCf88fovXhBbo/vqP3t02/ZYmJFqTkzY160Go9uEMbFK8hR/NrdXtFuUVmnmySVGgO4v4LMAAjRgmO+SJJiQAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-ods {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAetJREFUeNqMUj1IHEEU/i7u7Z23e8tGgneGQPw3hZDkkhQiSuwMQREba4uUgpVlCrvEQhurkCoWqcQQ0oTAaYKNqJygGEwgHCSB6Knn7eXcdX/GmdHVPWYFP3gw78173/vmvYkQQsAwNvckq96UnyIEh7/d4t7uUd/8y+85P+bXSX4grkhI6nJYPW7LrXpBK2YxiSoShhu4Buq1NPofDeqdrZ3Z4cl7D4J3UtA5VyVAlmJoru9Af2ZAp1lcCQ3nqgiuKmbY3l/BH+MnHM9GVLP0Ww3KNA33CQoQQnL834Fj74PUGkANEIkCSSsa8gQqgYTIcB0PVsXB318GInRiCVWCkpRFAs+j5gKlA4t29Ggh4d0t04FKt9PQqF4UFgumSEA8ApeaElilWbYRVy/lsns/N1QBkxtENF4jxPxcgcB1CZVOrvMteK5IQDtJJIGh++PcX9iYwWjXK37+vP0WdYk0Ht99jtX8JywWFkQChw4tc+cZcvlF7rMze+ubbxN40fMalRMDP/6twaiUeK7wlZ0TD0a5hLTWxo2d45KKprqHKJslTsy209s2wnMFBTYNZjc/oLt9gPvLOx+hxVJIKS2YW5pCbSyJTGMK775O8VyBwDJd2LTDl/X5i8v3S7NVw9vJb51tITDEUwEGANCx2/rXEEFFAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-odt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAepJREFUeNqMkz1II1EQx/+7Ca6JkqyYiJ8cKEpAQbBQFDm0sVOsFBS9wt5KOTgEG5twxVlZ+XEnKNiIghYKxx5nwEpIIXaiSAgKGmMi0d23u8+3T7OaZJEMLG9mmPnN/w1vBUopLPNNhRWXHOyDg0nx82TiJtZPlPVoNpftc2cTotcHtxx06kdXpSQ/BvzKESZzIDmAz6y+NojOjpDMZiqRPIgNoFyWM8DrKUV7axO+gcp4g7AzmquAdVNqOgL2z2I4id1B0wgeygOyt/rLL5buLwAIDgA9dY+L+DkuDQOCrkMgBsRglcMOqAGwIstMg8AkGsuZMNUMRMkLqE+QGloglvlA7uIOAKvZajR0qJkUj/XHe0BTIclVKKlrfKsj9qA8gA6wqSJzPaXlr7ky//tdLEUfawsBjExUFGVWbT7AxSa42H2LMfODmvd3wKb7RAMLYwM8nts8xJ/pEe7/3PmP2eGv3D+9usb35W0bINoA7RmjXSHsH0f5Z/mUSZ0Ir2JmsBtD80s8/rGyzWsLFTD5yUQCbfUBHl9d38LvkdDTXIuHVBo0k+bbt06qO+yAPGXwe/cA4wO9PN44jKDG70GougIzi2tQ00ms7/3lpwnBBgjZ37Kkd1Shht5XzBIFl/ufFtniT/lFgAEAU//g6kvdGBMAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-otp {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcJJREFUeNqMkssvA1EUxr+ZjkdbrfFKVD12ErYSRELY2fkH+BMsLcQaSwsrSzZi47EjJEQkEhYkFlhYSVtFpdqOqpk717l3jKZmiC+5mZlzv/s795wzCuccQncz3YeRBj4KHz0/RrOZe2NsZPP20o255zQ3EAxzEAC+6uzTw13G4TFQAakA/CWtIYbY0KBOrx7IvwDQqlHV1o3YxKTOvyAUvfQCfqmA3e4ikyS/zRAKvOot7eoSHEgZIHrCfQAfBqBaKQQDKScQAExd8emBANg+2U2CvNMkkgSqBmrCxFB8mujeoJBWwEqARcssKTAJEGrmaGrjqK1zvNknH4BtyxKl2VUpRxmj5W+x73q9AEaZrR/ND1EJluIpS3i9JQiA+a+hSq8HwJjTsLrRaWitPTCOlhEZn5N75sM1qigmlN+dB3u++Qao5W4TtbEXXIsiszGL4PA00itTsu6XnQWo0TjMTAJqfMDx/ryBJcaVzSNSH4fW0Q+rkIf5rsjRiid7yyN7uoXS3Zn0egE0NiORAN9bQ017D1Lri7CLlP2EDr3Rf7C/itzV2bfXA/igLDaRixfngFhSCooH2xVPCWBlwKcAAwBX1suA6te+hAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-ots {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfZJREFUeNqMUk1rE1EUPS8zmabJdDKB2glEwY9ExJYiBUEQpV25qgtBXfgbpEtXuujKf+AfEKRddOdOGHClbYVCvyKWaijT2mhjphk7Sd7Me76ZONp0EsiBYWbOvfe88+69hHOOAE9f3zTVnDKNHvhlsfqPw/rM0ovyWsRFdXJEpDIyRnSlVz0KSkmvabaJeXSJBEhgAJzTDNybmtUnS5Pmg/lrN07H5NM/f13FoMgpXDSuhiIiK3Qi6LUugX7FAbaPPsJqfIHHKCStqRsXVFPQuZgD9BBxjikSiRq41AAkgCQBzVf0+BWEBX7GBm0xgHHUqk1UbBuEcIydzyCZlOI9YEGuDxwduCCitS3Xh3viCZ4jrcq4PJ6DLHd67tjtuAAXib54dCPVEfQ5XIcik/0/2iDeOYz3ceCxrisMi904y0XiMQFfkB7lg6xFHwFxEqUMV0anUNBLWKm8xd3i4zBWOzmASx0UsiW831mA59Xjm+h7HCOygduXHqJatzA7Poey9QnXjTuoVD/j/sRcmDOWLgqnLC5A2wwST+Pn8T629lahSCo291bwu9XA7vcy3m2+gTaUR14thrk9BXasbdiOjSe3nmPpwys0xSi/HpbDd3bIQC6dx/q3ZbRb/j8BEi3Po5cTJpHI9CBNDEa++GyDBN9/BBgAwfDlCVUQaNAAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-ott {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdFJREFUeNqMU89r02AYfpJ0iVm7EqhVOxw7dDBEdpiCE1RoEZRddvUgbIex/Rs7eehppyF4LOzQu4MxwYp0HgShIuwwUVSCVtl0s13afl+SzzcpyZYmyF74eN583/s+PO+PSEIIeJZdrtQVI19Cgmk/Ph39bpllXq82g7sgLxVcyKNZpIx8Uj5u5zSjc9Gov8ZihCRC8D+7On4JczevGeTGSEIC4ctKJtB1DTPXi1iCCEkIm1EFlC2Em0iwtWfinXkIzjiO0jljtDC5TtflGIGUQMB+mfja/oPv2Rx9MMjpMdJxOXyXTwkcwIkewfqQ1QtQNB385zcI14FrtQexsSb6SRysZ4Fbf+F6eHwATc9gJGNAm5iCTL5n/LCVRGADNoeaGoHqyaXj5gqQlTODovcwNk5Aj6wXqV8eCo7EDhMonEHpW+dZC7gUG98D3geo7vkb01h9cAvPdt76OGy1xntUd3bjUxAk3+l2sHJ/FgtrT0MUJNfDSm0bjQ/72Hzxxo+NK+h3B7XRNO4UrwymQtMIkdTBU0m+sBOayLsn8Ka78mQDjx/e87HXPkb1+UsfP37+AmZ1fP/suknBb6nefVQXjl06TxMlJfWKNWr+Kv8TYAAkUueexJF47QAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-pdf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNp0U0trU0EYPTP35qYxaW6TlDapNKWGbgo2FkF8rARB6rboXusf0F/hyq2U4krFqugqSBeuAyL4SERBstHa0iR9JKZJ7mvu+M0tqZGkH3x8987jzDnnm2FSSqh4ns0VU1ybFzj674Wa3uWiWbfsFQb+jrGj8Xvbm0HlvYVRxhJprpmTlGmum+OMm5uNPZNbtjk3l82ey8++8oW4Jv/H/wdA456g2kvH99FyHNiuAz2dwflbN8YW8zMK5Go/CMfQkAhpGsyQgRCtlpE4jIULyC9fHzu7MPPEl/5ib6WOE0JJNRiHHg6j86mMjw/2gG4bkbY4PW4Yj2j64skA5FTHdaEMPiAJszt1sK0d4suJmY4k0+IDDGRfqmh0u5gejQc+fG8eYCIahRQCEfgQnIuhEkgtONE+dGxYxEDj1DhiEycZ+1YXdUpHCqTMJIYyEES5aXXQsi2kYlGEia5GtHVKn+amPBeCutPgfLALPuVu+xDVPw2EQyFEjHDghbpYNm1yKVVnYjTOerepn4E6XQmLGSPkPkOXWATMSDcjQEkAaqOu6+i/rccALtFL53LI3r0Nq1ZD4/MXZJaWYFer+PXiJc6s3IEgY3+uPYZHTAcAHM+DTE8gnM1CSyaCulv+GrRy8uYyElcu4XfhLVpkpNtn/DGA5Uu0abFH36WnzzCayWAkmYJvWeCkfb9SwY+NDbSoOx4bYqJF8rZqVRRXV/HhzWtUSmWwmWl0RmN4v76OUqGASrmMOkntSHF8MOs954dT08W248wzYsJDOujRBAaqqikTpRo/qqd0/dv97c3Lat9fAQYA4z8bX9nTsb8AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-php {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhNJREFUeNqMkltrE0EUx//ZbDaXNrvZzdIkbYOXGgxYQlCK2IIY6EufxGdB8Av44AdR8AP44JOPBR+Ego0PClUKTTXQSmkTYtOkmubSJrQ1e3H2yJSEJNIDs3PmP+f89pyZcdm2DcdWvn7LzkxFHmCIra7nm9ulg8yLZ09yXON55Dgjt1PM2iPs0+aW/frdh8bzV2/SvQBnCLiEqcFxLKSSodlrU9leiGPihWePBkgeEZO6ShC2dCAZNuf6ADb+ldQ5PUPx4BCFcgXfdwq4Ph1Dtd5CZi4Nw7SQiMdCXkl6yVIy/QBWgcU+yx/XsLK2cdHndqlK/lZxH/OpJO7fnsWY3z/YAq+g0TmHpoUH2vB5PXi8RD9Fo10aAmDJTgWyIuOupmK38rsPcOvqJO33XWEvwLJsmKxHRVEwf/MKWl/yUMf8mIloWN8rw+sP0D6PHQmYuzGNgCRiMZVA17IQV4OIaTI8buH/AJMFd02Tkp05PO4jnWvc57EDAINt7u1X8Pb9KgI+Lxbv3cFR8xjx6AQ+b+Txs/qL9KePlih2CMBCq92hg2qzt1AoV7H5YxdhdqhHzRbgcpFeqdUplpvQW4FhmAixZ/sws4BoWCM/qmsE5XqE3dDQCrqGAYWdejqZgK6GUD8+IV9VghBFN1RZJv3sT5diBwC15gncggCPJKF0WCPN8dun55jQdVpz3Ynl9leAAQAJhiGatD9AOgAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-png {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsU9tOE1EUXXPp0CAUWmJbC04xBANNTF+kKhG8fID6aqL/gPEj9E0lIf6Dj30HL03wxQtVIC0QKrWxNG1Dk9Z2Oj1zxn1m0oIZTnIyZ8/ee+211z5Hsm0bYg29fLGpxWIJWBYGS5IA8ncKhT9Wvf4Yqprtu+w3q85X7f9QxseD/pmZMZsxN9fnc5JNw0ACGGv6tPSvyvEDKEoWZ5Y8OHHObKpucw4B0t3agnl4CJPs2YkQVu4s61ORaBqMJc8CDBiIRhhVM9bXYdVqYAcH8M3NgS0tQQsFcfdKHEbvlr6WyaR/V6uPKPy7B4DT7lUq4MUipMlJ2MPDUKtVfKZ2nn/5BoNbkONxXeb8LYXe/A9AJLNWCxgdhZJagDI9DZg9qIkEytRSkdqTSFQtGILSbgc8LViM+tc0yPfukzIyOJ359k9YR0eQdB2KmBbpwXoM3Dod1SkD+scpEapCI5DdpsJhIJcjajQZagcjI+5oLe4VkeQnyiZgdIH2X6BJ7dSqQLfrggjw0AQwP+/GegCIHppNoFAgEMO1RZKo7BQgRi3yN05cnwdA0BQMAgF3C6pnbuNg92M9AFT1diSCh6kb+FGvo2MxnBB9ocZxp4Mns1cde213B81e7xwAcl4jkaa0IUSjUdLJwkL0Ej6VSvArCt7l81iku6GrKnYEU89VJlSJRmR0Dax+fI9suYxSo4HlWIw6M3FBlnD9YhiXabyOsOeIqG7TzDeIYo6EDGp+ZPb2kKKqH8h+mkxiI5/D1/19J3bwYPvPWXq2skkiJVxesqt0XzghpKM8nRVV2Lv2q9eLIvSfAAMAaacnllcFBmYAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-ppt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAkhJREFUeNpsU11rE0EUPTM7ySZpmzT9DNamWAtFfSiCigr+AxF9zKtv/hvf/Aki+FEi6ov4ItWHPGiwiBUKoUqqTUJImmR3M7Mz3t0kNe1m4LIwc+65595zlxljEJzdR5uf5nLmsvZx6gSvtd9W9bjhF7jg5dH9nRc/wq8YXaTSJptb0xklx7IZoKUEz1zJ2DUU69/37vFYrDxegJ9U0lC+AoIIVGg9CL+vIObP48KDQn7x0sWiVnJrnEDg7KGk+i/Ac4iUM/R7BsmrSSxtXMfa3X7el8+Kjf3KfUJ+iRJQw4w0Tc8BRyWGRAZY3rBR/VlC+XED2ayDhZyXl03+hNA3TxNQshlGLAnE44zCIL1goXZwiMNvB1i6zbC0KuAsxNITWwgNMYPeLVJiFEO9ArjHAivrAjNzBr4f4vwIgdGD4YUACsZCE8AtYGWT5jCsGQw5wEYJzP/pj5RwYTA1b07eQmfZ8P0sgdaM2FlYwWkMgMpl6NQAO33GKM0wsQWflkh1uqGVmVWblsiDkQyqxwfag35SqcktaEWTUTHYNx4iGU/C29+BvX4Lpu/C7zYgFjegSY63WySsHyXwpYHU00ieu0bAOuJbBTArBkiXKiaAmTzcvRJUV9E8rOgqBwqlY8ASs/AadbRLb8CzeTjVClqft6FdB17tL7yeCbFRBYoLr6vR/PiSEl5BZJaBD0/R2nkOZqfQ2fsKt+0SEQ+GLSIEUvJm+6jbah2+pS2aon+4g/afd4SYJVuA7vvXdC/IHQtSoTnK+yfAAIEaId1m+vudAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-psd {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAqxJREFUeNpsU01ME0EYfbtdKKWGtoItRWgJHApCBE2I0YuoiSaaeDJeOJh41YN3TfTixcRwMfEk8eDJGA+Eg0YTTRRMg02KKFooCBbTlkJLS7f7P+u3K9Xo8iWT3Zn55s173/uGM00TVlwZfzJztD92iKO5ouvQGQPHcQDN380vlDPr65fdLj4Oa41i9sFt+ytgN7o7woGOrqgvvpLBaF8vWj1NUAwGTVNRM3mf5vU/zaU+XySQuTqIFXz9hxmGLkoS7r+YxvVnrzGzlgXPDOzUZPT4m3Dt/KlIuH9oUjXYEHZZ/wOgGQZi4TZcGI5hLb+FO++TSOSKcLtcMA0dI0EPrp4+HtnfG5skiUecDGwQE2MjAwiGWlFVNDz+tIyCokJhPKYSX7Gdz2I01hOJdnY9rJ/7UwPGTEiqjtbmJtw4MYx78S/4Wa3h5UoOYwPdIOp2Xi/t18rlFgcDw6o+ydiWVRwOBnCpL0oOAMmNEhLZIgSeoxwGSWcERon/M9DoBknTIdNQNAMnO4PIVGpIFXcwndlA2OtGc4MAxml27p4AIulWSIa9QVadiYSoJxhqBJivKgh5ad3k9gaw6JdlDaqq7q5wINY4F22HaLHSDZQkBW72O9cBYFEviBIURQH7a7MN0uDisUW12ZZcaGlmdq4DwCqeTo1zNtZuW7hUqGIw7MNqSUS2ImNsKEpSdEwt5lGhfQdAkQBEoub3NNrDJfAIeBuRrcrY5xGQ2RFJAjl00I8PCckJUCB9q1URBnk38XEJEuk41tmGwZAf66s1VOh2keqwoUnYpFxHH4iKIixkN3HzVQKP3iQR/5GDKMuYmE3h+fx3MHqh1sMafztHLuiCg0FAk0uFdLqcpGY5QEXbTC/j7mIaVjc18DxufUtBJ/vcggs+3ijVz/0SYABsJHPUtu/OYwAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-py {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlVJREFUeNpsUktvEmEUPTPzTUFmgJK2UqXQFG3pA6OBLrQxamJcaYwuu3Dp0l9iXLvVtRuDpgt3JIYaTVSaxtRHsJq2xEJBHgXmifebMhECXzKZme+ee+65516h2+2Cn2cb2VwyHl12//vP2/zOQaF4uD7GWN69e/LogfNm7kUsPBFaXYwHMeK0OlpQEJApHJTuykzK98dE98O0bLM/UNgr4v32Dj1fwSQRt9dSsfmZcMa0rIv9ODaqYrPVxuPnL1Cu1aEbJu7fvIZUIo4bqeVYRzcyv/8c3SPYpwECt/dmu4ON3Ed4TymI+hQc1ZqoE+F+uQLDsnHlwkKMscJTgl4eJOi9fxZLePNhGx6ZQRRFqH4VjZaGSv0Y6cQcJLpra0ZguIWegqDiw7lYBBZV6xiGk9DQDLzK5bEyF4Hi9VLMsoYI7J6Es5PjeHjnOl5ubqHaaJGBEkzbxplQAKIgDmBHekDTgI+qKKqKLvNApgmEgyquLs1CoFn2Y4cIeLJpkjoCLkWnUSIF3JxISIUsCjAoxhWNJLBIJs3YeXj/08oYZkOKY65HllE/bkMmY504YUd40HUq2JSSyW6iVPmLiXE/ZMYQCU+hXK3h1toqdNN0sEObyKtqtDQ6kXDwcadDS2TBryp4nX2HxXjsJK6bDnZIAZem6Tp5YMMmicn5OC4lztNWtvB9cg+hQABtWjKL2jH/T3GgBcYDXEE6mcDM6SlaJAGMWkivLBC54ZgniZaDHSI4rNSqn7/t1vgkGJPwZXffSeCjk2iUWz9+nSTQN8e6ef8EGAClUi/qoiOc3wAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-qt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNpsU8tu00AUPU5sp41NkzRxpfSZqi0VIIQqEEJUZYXECvbwCWxYsuBD+ABUFrDrCnWBQEJdIWigBSr6pqRJ1ebhxrE9M7aZmSrQ4o505fHMnXPPPWdGiaIIYrx89GKpNDdxmXkU3aEoCsT+z8W1Sm21+jCpJctQTvaerj+TX7WbnJ+0cpfuX8mQtn8GgJ4AZtIFY2Hz3foDVRcgyt+cRHcS0IARh+D/8G0PpmVi7smd0dLs+AIjwTVEiANEYYQwCHlEZyJgIQKfoX84g9uPZ0cHZ4YWmE9nuufU0wABCSSImMsWEgqSuoqA/39/swZFTWLy7vQo7dDnfPvWWQa8GuOV3IYLJXmyzDzG2/ChZ3pwbHdQ267BKJoYuj7SF2MQhiF8LuDK/Gf0DKTBKINz1IbTbEMzU1ANDW7LAfEIQKIgBsBFlAx6LYOz6MAcvoDCtAVGGPKlAiIu/F55F33FDA6W93EOAOMaMOl7biKPwRtD8Foetj5sYPfTDtxjl1f3Ubo5jkQieQ4ACSUD2iE4XDpAdbUiW9D7UsiN9WNkZgxajwbd0LGzt3keAJPUc1N5SVeENT0Ao2BKV6QzwlZeRBSKAYhe3aYHcZWn7l1EfjyPypcK9LQGa8qCvW9j9+MvaasQOHaRhGWdhsNLR8hwodYWf6B4tYjDjSOovRqq32rSYq/lytw4A77o1V2ERiAtzY5kkUrrsH+3QF2KY87ArTtQuQ6nAf4x6FCV1D001+vYersBM2vA4y1Rm2D7/Rac/TZIw4d/6MrcGAPf9htN0miJh7Lyuoyvr8rQeP9iVJcrSKgJ+TrFcyYebXTP/RFgAFQobmIOBxbsAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-rar {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNpsUktPE1EU/u68OgylZXi0hZACQU1LEKKCMcat7jTRnQsXxsQtv4E/4M74P1iriUaNCw1FgxpjCJQKKAU60+m8mJnrmSll4XCTc8+959zz3e88GOcc8aq9evChOHl/lvMoubvWX/z4+BwTlbvw7bXdg8b7h6LE1gGW+O88CRMt4XTlR6/rYxce5Xv3jlHH19fPkBu+gWy5mlcFb3Wn/umeKOEMJF5C7xCFbtA9dRXjFoYKGiTRAlPGUV1aKU9O3VwNQ74A8DQAIZxqAuAhBPIMFYpQVAVB4CPSZjEzv1weH5tbDQN+JQ2Abu488mnzIbAAA3o/VK2PwDJo7r5Fy7ZRuvi4PFS6+qIXdVYD8Jg6BUcuOD8BozSLlRWyicgVKkTMQWwUlFF0Ooe5FIPk57BD7G0SiywyjD8bCDyHsOkeeeR3SUxEkROmU6BfQYFJMHfhWXV8efkUrb13VPMTsrcTQSzxZ/+n0GVA6EGbSGdgG9vo15fg2nFgbO8k70SRdd+mahDT81vUxTZRlJBRMsjq89C0EXCvSf7TIBZ136YZUJEiE7LgJ2dN01BZuE0dkIhxE7KcQTK1QUj+cwAEyrPZ+IydzRoyah+mLy2isbWBweESJEnB9q+1RM9Ub9GQOWkABg8HjRr2d9Yh0hTlBlRsfn+D4vg0BvUC9rZqECUJuk7Tzr1zahCYlB6HJAREPwfbbMBzLBzsbUKVI0qBgQkc+SxgWUYaIAqOpKwKXJ6bgGlaaDV/YvHaFNrtDsKTfVSrJeqIg/bRNwjclFIALeP3saybhu8SC4VBHwnhBXXIKocYRXD9QzBi4Xgchmkd9+L+CTAAMqwy+ZzluBgAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-rb {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAixJREFUeNqEUktvElEU/mag5f2yJhXLwxIt0kiqsVEXujP+A925cu1Pce3WtXVtYuJCF7KtTY0NrVQIpRVKeXTkMcO9F8+9ZVooJJ5kcmbmfOe733fO1YbDIWS8+/g1dycVX7W/xyO3vdsuVKqvnE7HZ230783rlyo7bVBicSGyfjsVwozomVbIPe/c+FmsPHfoRKJd1HT7hXHBZjVbA4aA14NnD9bC2VR8gwuxPi5Sx39Cp+M0XUP0ahhP1jLhW7HFD4zze3b93ILtXYyyVKlR8/5hFbnvO9gtlrGSjOF+OpXkYviWyo8mCS4R6bqO4p86vm3v4fC4DrPfw4unj1XN6JvBaQtjChzUXK43sVU4wNFJA43Tv/B73edQwTmfIhAjCVL6UdPAj1IVFSKhCdAcAI9rnjBiAjtBYEu3GEeh1sKJ0YXR68sVIujzIhzwY8DEBHZqiLRKkicQDfvABxaiQTc4Y/C65pCOXwcjcmlvJgHtlwi4epYifiQWgmoLZwPW6HQG07LgcOgKO0UglAKOTt/E+09fwAiUWU7QAE9xUK3jbvomsispZVHMVEDSZdHo9rCZ/4VIMKAu0XGjpU7d2S8hk0pCELHEzrjKnCQOYJoD+Dxu1RyiwUm5LaMDo9NFt2cqDLvY4oQFp/QpfT/MrmI5FkWebt+NpWto0j2QmQkOjZ9hpwhqjXZzM/+7LU+cc7lRrjXh8/lVLRK5ovLWXglOsiOxdt8/AQYAzv8qbmu6vgEAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-rtf {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAe5JREFUeNqEU01PE0EYfnZmd5FSvgLYFuwWt9EgHyEaox68eDJevHvwJ/hTPHv1N/QgZ2NC4g3kUAQKFKGhjVKqRrvbnRlnht262FHfy+y8877PPM8z71pCCKh4/ebt+rJfXEz26Vjf2mnsN5rPKKWbVpx7+eK5Xu2kyMtNTd5d8MdhiJ9BOO7atFI9ajy1UyAqSPIRMR6ZmoNehNHMMB7fX/UWvEKFMbYKE8DfQnAhwRmmJkbx6M6S5+WmK2Evup2c9yUk2nnKA0XVcSiGXAe1k5beP1i+4RFCXqnPywB/AKVzK34RjHNYlgVKCH50w7EBBogbTa/AVM5SgBdn0gc2AMDjPsbFPz2xye9asweS6n+NTbG8BCCfUtLjff2WoVnVpAH6z6hMUtJE3EykYfpF4vUiL3QNS7FMeSAQRBHW3r1Hq91B+VoBQRji4+ExFsvz6Hz7jm7Yw5OH92AcJKW9G4SoHhzhy/lXbB98Qmm2oCXN5WawsV2TACEoJXqwTKOsb3BtR2ucmZxANpPB8JUhyPnHWDaDpfJ1eZFALzJJ4MKO5MEtv4TSXB7V/br8iQLMz+almRZWbvoo5q9qRlxwewCgeXbe3qrVO5ZkUD/9jJGRLPaOm6COi92TU1DbxYe9umRD0DrrtJO+XwIMABWp9nS+FgaoAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-sass {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDNDMTBBM0JGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDNDMTBBM0NGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowM0MxMEEzOUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowM0MxMEEzQUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Po72XUcAAAJcSURBVHjahFJdTxNBFD1bykc/ttvdtttWGgI0bYrUgDZoNYqRJ014kMRXHvwB/hQTH/wFhMREJfFBQxBjhMRIFEQSCAlQxKYGggiU3e3HbnfX2bFt1EU9k9m9mblz5p4zlzFNExYmpue/jmTSZw5PZAl1MAwDT0c7O72wvPdudeNakPNtOZ0tsM7cvzdOc5yN5LDAsTFRAJks/kC2PxFRVe39Si6f4byez62EpAEH/gNN18F53Ri/Ocxf7OtdLMpKT42s/ZPg1cISJp/P0tg0TBzLCoK8D7eHh4RkLLJ4cCz12AjMXwgez8yhqtVo3NbqRKlcxcSL16gZwJ2Ry8KVc8kZO0HdTKlURn+8G6PD2SZhLMQj96WAiMAh2RXFYKI78lcJcx9WYBCycICnpNbojUWpD5Y0C4Zh2D0w6hWc70uQZC+IWfQZrXF0IsHvY+meBd08haAhoVMMQFJKWF7PNZM+klhRyogGhbqxOIXAMOtEwGAqDqVcgbVkkE+5UsEAWavf0az2t0ZqvK2qabh6IU3joizDwTgwej1LdVfJXkdbK8mt2QkayO99A0/0trQ46I1lVcX+UREhnsP34yLp1AD1xibBMuntpzU8mJyi3Tc1O4+l9U06n7x8Q/8PHz1DrrALt8tlr0CrkbJMHTop9Sk5sLa1g8L+ARJdnShKClY3tunN69t5iGLYTlCtakjFY7gxNABdN3B37BaqqoYT8pyX0in4ORbRkIA46YlDRbUTbBZ2Jb/Pw4qiKFnapcpPo9pdbrg8DjAOBsFgELJmsGs7eWkkc5bu/xBgAHkWC6UPADTOAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-scss {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RkM4QjYyNDVGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RkM4QjYyNDZGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGQzhCNjI0M0YxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGQzhCNjI0NEYxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pkf1yeMAAAJbSURBVHjahFNdTxNBFD0tLULpB91uodVWPmorUIxo0VSiNSExMYYHE33l0Ud/in+C+OSjYgjRGDBRCKJIUkIEWi0WKlja0ul22+5219lJ26gLeiezuXvn7rnnnrlrUFUVms3Mvd2bjIyezRVLBA0zGAzo6jhjm1te+7EU37rFO+w7JlMbtG+ePJ5mOaZmci/nsPl6ONBtw18WDQc9tZq0sp7YjTisXV/NFKRpRvzHpHodDqsF03djzuvDg6vHJWFAprF/Arxe/oins6+YryoqCiUBvNOO+7FrXMjnWc0WyIAOQP0N4Nn8IqqSzPx2swllsYqZl28gK8DDyRvcxKXQvB6gISYpiwgH+jEVi7YAfW4nEqk0PJwDofNejAX7Pae2sPhhHQoF63U5Gai2Bn1epoPWmmaKoug1UBoMrgwHabIVVCx2jdrKFwm67TZ2plldPQGg2cK5HheIUMbaZqKV9In6giDCy3MNYXECgKI2gICxoQAEsQItpNCHWKngMo01arTY/jFIzbutShJuXh1Fm9FImYiM7tTtKOtbO+toN9Nc+fQ5SGUOIVYl7HzPIH2YRZ0y2KZ+sVzBHn2v1mpMGx0DTaR3nzfwfGEJdybGkdo/wEigDyvxLzg4yiESvojZhfd49OAeLJ2degaSLIPOO6vwgiYaaRErTRREEdn8MeJbSVZ5M7nLdNExqFLaQwEfFfACQn1+HBWKSKb3MT4Sgstuh9vVDa+bQ4DORE6o6RlspzMk9TOPfr+fiLJCLFYr3TZSKNcI7+aJwWQmPM+TkqRg49tu65f/JcAAMwMas6WUKd8AAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-sql {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAh5JREFUeNp8kctrE1EUxr+ZyXMkoa1NBROaSkpTBE23PhZ25cql2y5duvAPUdGFS1FxIRRBXZlFQ9GVdDENIhGJxkDsw2mneZnM83ruNZlOmNoDhzlzz3d/9zv3Sowx8Ch/qlYK2XM3cEJsbH0+qjV/rd6/u6aN18b7RMFT+9aosP/Ex+0ae/puw7j36PlKEMAzctKJ3aGFamMHjV0d+wcGitkMrpWWp6hVIciEk2MAOwbUWjosx0UiFoWqJpGMx5DNzODq5aIPoa82AWBg/lyKLMH1PMp/a9XvLXLzG1cuFlBaWpiKxaIPSLY6CaC93ggQjyiQZRkeQSzLRovGaPciWLt5faSWEBoh6KBvOhiaNga0+Y9pwaFxvu7rfp8F5pWDt+qNMp2IijHGwddWCvN+33/CoAOP5nVdT9SdoQ1JkggiQ6Yvr7V60+9z7akA2gfH9cRF8hO5F5Ve4lQAF9uuK+qFsylkzsQxrcaQm04hdWkR83Mzfp9rQ3fAFzu9Ph6+WMfjl6/pGBdb2jbKmx8QlRjWy5vkyhUZBPgOeGNHN9AbDLGUz6He2hVj3Ll9C8/evsdgaMK0HV8bcmDTU0UUBYXcedR+NLGnH0I3jvDk1Rsy46FP4C/1BtrdntCGHNiOAzWZgEKQ5Qt5lIqLojbaXSQTcRy2OwT4SZqk0IYAOgkVWUE+lxX/zb0DpFNpkTzmZmfFtzewhHYcfwUYAMZmVaZQlLFHAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-tga {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra725K22ILRGipb22pMG6JcSEQTbUIwnozxpBcvepeEP0KPogcT/wlNT17kIKbEmChFUYKGVtL0R2gLtNCl3Z1Z3+zSAlonmezOe/O+973vvZEsy4JYnqdPMu6RkSQYQ29JEkB+PZcrslrtPhQl23VZc8/tr9I1yMHg0EA8HrBM04lVFAhoY38fSSDQVN3pfKV8G7KcxZHl6v1xblqU3eLc3p2VFZjr6+gQgwsnhzGTuq6Nhs6kYZqXjwL0GFhEl3U60OfnwWs1GGtrUKNRsKkpeIIBpKIRtI1J7cX7hXRhc/MOhXw5DkCZGG2zXAajzFIoBMvng1ypIKOqmP30GW3OIEcimovzlxRy5RgAFwDEAIODkCcmIMdiQLsNdWwMZdJlg8pzEUt1aBhKq3XinxKYqF9yQbqRIqsMy+0Gyy47bKgUWXSLtDENE5wdtuqQATm50F1VnPbRGeEw8HXZbiV8fsDvI9ldju9vADAyihLEbrWAZhOoVp3z6iqBUiB1A4nEfwCEsbkL/M4TgE5n5jDx+oTEzp1d8m9tC8H6MaAB0imzx0NU/WKUYE+loEyawDBo2ui6TGfT6ANAxrvx87gYCGCxXEKVJvCWFsG3eh1vN/J4OD6Od4UC8o0G3TX7TGLHwI9iEQmvF9X6Fh7F4/iYy+GcLOMSlfEgGsP0qdNOmX0BiGKpVkV1bw/1nW2b/gCpf1PTcI+Y7eg6ps+G4bG4PR99SjAVo9HE4q+fKNE0vl5awuSohjeijbRefVjAtUgEQRK7Yhi9OKn7nKWZxxlSPWl3QwgnaIrW8QMhD542vUbx/W49m7sq4v4IMABOqi3Ej7bAEAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-tgz {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU1trE0EYPbMzSTfdtInFtkkpiaXVWou2FRUEn/so6JugL/oH/Af+B1988if40jcFERQURNBSQdDWlLQN2lsue8neZsZvc7FoOrDszM75znfOmVmmtUYyvry++36yfOeS1qqzDtvH2P76ApPlW3Drb2sHex/uccHWAdbZX30kO2+B3siN3zhTnHuQ66+95i423jzFzOVljBdKOZNHazvVT7e5wF+SZBj9iZJ+3J11mbW2kR8T4LwFli5i4fqTUvnczTUp9RLtDhKgJx0q4dEwWAxrREKICHEsoYYXMXvlcWmquLgmY71yCkG/c0AkARgLMZpnMDMpGNzEYe0dGp6HwvmHpbHC1Wf9MnFCkHQOyYEPzSJwQ2B65Tm5NZG3Fshim6wbMNJn4bpHowMKtIqo2COgR2IcAptwjvcgo6i77igjEmVDqbY8xQJ1VwRULhiBI6+G9Zf3cbTziuzIDkmHSNqECTFgQScEcYuc2NA8TcdYwXD+GkK/TYVN+u72WrIudiAD8o6oAR2RRCmQMjis3CIy1iSpPySCXhFTXeyAgh4BR+JVw8pauLi0Cp4yCX9A90FQhnSBYtnF/k+Q+HYam9itfIZB3QvT8zj8XSW5EhNTs9ivbSLwPUzPLNPJBIMEKnaQYg6aB9+RGR5F5VsNgnNKXMI1NdJGG5WfHzFVLJ7k8c8xUngpVodlDSGbFYj8Y4yMpOG09lHf3yIFPzA3fwHZTAQVtU4JUTeFDrdgDdlI8wAz5Qy2KxswReI7QODZcOr0ZH3q2hIDBI7zq16tuk3FNPxAI4wN+pkoccYoE4YJU5EdUtM4Qst26v26PwIMAKj3P/2YUKgYAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-tiff {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmRJREFUeNp0UktPE1EU/qYzHWstlrYJNcWUElyUJsaNGh9B0g1Lo0v9Ey78EbrVxBhXuHShm25YGBJRQpAYBDEWpaEPEhksdVpbyjzveO4MfZDCTWbauefc736PIziOA77OPH2yJCcSGdg2uksQAKofFou/7VrtASRpvVNynj13f6XOhjg8HAlMTIQdy/LO+v3uYUPTkAHCTb+cK+0pdyGK6+hbvu4/xiyHbncYAwfR19ZgbG/DoO9LsSgeTd9JXoxfyMG2rvQDdBlwIZauQ5ufh12twioU4E+nYU1NIRCNIDs+Bt28mXzx8VNuZ796j9q/DgAwomwqClilAmF0FE4wCInAlkjO4y+r0JgNX2os6XPYS2q/cQyAcQatFjA0BPH6NYipccAwIGUy2CVJFZInkKlyJAqx3T4/IMGmJkeWIWSz5KgI5pdhb3yDXS5DSCYh8rTID8s0wexeVD0GtMd85KkkefFxUfE47M1NokbJkByEQl6tL+ouAI+MUwbFhnYbaJKc/Sqg0x4H4eDRGDA56fUOABA9/GsCpaIHwr8FOhQ823O5RfW66tUGADhNy3RNRDjcN41HLxdQ8J6jYTsOQLfOJBK4f+s2/uoathoNGKT1MtFeVHZxdWTEZfEq/wMKl3rCJOIzTV6ADs2R5ulYDDNkYjp0DhrF+zCVgkw31+v1UxjQZkNV0SADd2o1MIuc9gmY+/kLxb0/UFoHePd9A1qzeUoKpilx9xcLWzgg+u/zeVfuQqkM9bCN1ysrWKXxdtPgvScwUAm58XZ52W16QyPtifRUzi588GbEi1ztHPsvwAC4uC9qhnsZvwAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-txt {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeJJREFUeNp8UrtOG1EQPfsyXiyzBguIJSyChZBBEFCKpKHLo6egpErNn8CHgH8gkZIiTSIXLhJAWCgkoMgRMSiRBSK29z4y9+I1d/HCrFb3MTPnnjkzlpQSynY+fP70fGF2gQuByCz6lfdd9Uurfvrrjes6762eb3tzQ69uFJwPsqOPC+MBEmxxphi4tlU5OGmsOzaBWLc+O9oIIVhScidkyGZ8vH62nHtSKlaI4cse6TjAfSaFBBcco0EWqyvzubmpyQrj/FXk75cQaSEMeMXU8xykPA/Hjd/6/LRcyjEpt2i7HAe4A2TeLZWKUOJaVLxj27j813EHGKCXaAJExu/4BOdiAED08riQD2riOrexyRoYc3CvsAbLGAAjZga7vgZG23WMCdBvoxKJc36TRBlMiaa2JByjNqqD8qkYc1pjDK7abey+/YhrWlfKswhpiCR96aEU9o5+QE3g2ovVWDm2Sc22bBQm8vrVpbkS9r+doPr1EOWZaQ0yFoxg2PcREosEAI4uvZhJpzFMP+cSXRbq+043RManez+tNWKMI6GN0g0Z04HFR+NoNC/0yx717efZOSbzY3AcR4Op2AGA5p/W31r9e0vNgSrh9OwCrpeCkqvZuqTybnpRqx/r2CjvvwADAJC/7lzAzQmwAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-wav {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApFJREFUeNpsU1tPE0EYPXtpKbX0wqUQKVQMFdIXQBNCQBs06KP+B8ODGh+Mf4b/4IsGE54kxhcMBrkp7YOQgBRvSKG73fvsrt8Otoask0xmd+b7zpxzvm8E3/cRjPkniyulW0NFy2JoDkEAguOlpXJ9p3L8MBqVl4O9YHxae8pXuRlcGO7KPLhfTDVUqwUgigJMy4Whm6lEXHjxYf3XnByRN0QB/2KaH7btMlUxoRJAcyqKhdOaht7+DJ49n+2cvTnwynXcsb+kLwJ4rgfmMDDGWqvneXCZS9ND7mov5h9ND85M9y86Dpto5rUkuJ4Py3YDJpy6QGJPayqB+Njf+43XL220t0cwOZkfrNXsBUqZugDA6CbLdAiAwaek1ZU9LmP8Rh6S78GsGxjOp9FdzKJaVZIhBgGASzK21w/wbrnCk8euX+EMAjaaZuPHdwUdHVFYluuGPGCORwwYjg5rqOwccRk+3Ux0IEvntmsNG4ZmUayL/wAwKHUNfZfTKN0ZRaw9Cof8qJ/pMAyHy5KkAMTksSEJtnMenM7EMVMawbejMzJRh67bXEYiIXEAVTW50SEAhzqwfqrBcXx4VOhYm4RsNgHbsJFOyZTsQ1MN+hcohoUlkFiMT+TQFpMwXOjGpXgE+XwGk1N5pFJtKNCequgYGupCRBbCDOp0KBJc4VoP3dyBONW8uydBgBHUThqQKCk3mEZ/LoUG+RBioJO7VarAwEAntjYPiUUW9Hh4b2R7k9j98hN37xWx8fGAt3eIAdVMLn+uUv+b2KReSCZjZJiB9bV9jIz2ofr1BKvvd7G9dRC80lae0HzOt+cWVnrSKDrMJykifwNBpCgE/UAllEXufmDu8Zlffvvm8XSQ90eAAQA0pF7c08o4PAAAAABJRU5ErkJggg==);background-repeat:no-repeat;background-size:contain}.ipfs-wmv {background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M9.1 91.1L4.7 72.5h3.9l2.8 12.8 3.4-12.8h4.5l3.3 13 2.9-13h3.8l-4.6 18.6h-4L17 77.2l-3.7 13.9H9.1zm22.1 0V72.5h5.7l3.4 12.7 3.4-12.7h5.7v18.6h-3.5V76.4l-3.7 14.7h-3.7l-3.7-14.7v14.7h-3.6zm26.7 0l-6.7-18.6h4.1l4.8 13.8 4.6-13.8h4L62 91.1h-4.1z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain}.ipfs-xls {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmxJREFUeNpsU0trFEEQ/mamZ3Y2+0zIC2MmITEkUYgERFQErx5E8KTi1b/h79A/4SW3nCNeYggBYZVEMU/y3N3Z7M7OTD/G6lk2ruw20zRdU/XV91VVG0mSQK/3n1a/jky6d6Xs3G8WXS+Pw5N6LXjLLGuna/78oZKerGsYKtrDE16uJGL1L9gEOOcYd2dL1fNwrbL//aXN7J1efPMmkUqEFAk0A0VZNbFEaQCBscIkXj975y3NLq9xye8PBkAniHOFph+j2eC4rsdoB4LsFubGl/Hq8RtvYWpxTQi52o1jvWiGYaRZL0/auDgOkC/Z8BYL2Pqxidp1FZkhoDxpeaXA/Ujuj/4HoOxKKjiOiek7RUShRNQWaNYFQuMafrYCxiw4ozZKfqbYJ0EvRdl1DQyyTs8XCNTA6UELMwvDyLpZWIZNNlNLlQOK2LMJRJ+5AkuZ1S7CFFzJzk56GnUjQWlYkqCoBWFbonEVYcLLA4dNnB624GQsDBWIgfZJEgxkoChzSFWvn4VpQemDm2VwXQsXJwF1h6c+gxlQ5jgSiEUEt0wdIe7tMES+nEG2aCLiJMOIIWIr9e0DEELAMUrwRuchVAyTKimUwO75Jm6VF3Bv7imOaj+xd7UFKVS/BPJF1b/E4tgTrE49J60O5kceoNqowiuuYKa8ghHXA48U9MT2AQgyRvTThE30bQiaSGa4yLMJNFo+Dq/2cHt4CYlwyFf2S6BHwwrMw/avDbR5C1k7h1YQ4KH3Amf+AcZyEbZPv9CItzQD1l9EbtYOjv74v/d3O9RMPTDrsEwGIWN8q2yk7XNYRs9JrRv3V4ABADSGR6eQ0/NQAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-xlsx {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8tqFEEUPVXdPY/ueWZIoiYZiSYKYhJc6EbduHOhgijo3t/wH1z6B0JAhOyMILhxo4kJGk1ASTAxwWF0Mpp5dHc9vFUzYwidaoqmq+8959xzbzGtNcx69PTS26ETmQtS9r4Hy/xv7MW7jV+th5yzVcaYPX/++It9u4NAv+CVR6tBUUTqMJsDcRzjZOZM8W9ZLKx+/XDb4e5/kH5In0lpIYWGUaC0YTZnBCAEKoVR3L36oDo7NbsglZwbqD6iQKOXFMcKUVfBkBAoQhlD5xxMDp/HrSv3q1JgYW3z0x0KXzkCYJaRZljru23aHWTzLiamAyytv0O9UYdf5PArqlppBfMUfu4oALErqZBKcUxMFRCHEp0DgW5Lo4N9NIN1dF0XXsVFOUyPJTzo+WBANDidjp8tgHGG3c0DnJ4uIRf4cOCBaW5KjY8xkZL72xpJ9QcFz5bVqHUJGHZL2YtNmKi06YCyiVFb4s/vEKMTAf1p4edOG6mMi1zR6wEpdUwX+vLDtkCzHoK7ptcM6ayLmGajvtex4PliyoIkFRjmUEASelB2rXQRSfjUCT9PlWpmW21iTGzCAyEkUixPRqXhe2V4zKczbdmybgkpJ0cGOuA6Y2MTCsKoi5HsNK7N3MN+uwYaWbxYfoLLkzdxcew6lrYWaZhm8PHHG3zffp1UwJSHz9vvkU8PodbcQYYYS5lxYkxTkGdVDQdV1Js1qPgYD6JIuIE7gsXVefIhIuM05k7dwMbeMmh87a18ufIMaVYyprrJLgje2Nr+1tzYXANnDnr3zRhHj37Vvy2wpXHtNAd5/wQYAD6WMuT2CwoVAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-xml {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAilJREFUeNqMks1PE0EYxh+g3W2t1G0sEqyISynUFJsSOShNwCamiYZED3LgIkcuxoN/iCZePZiYGD2aGD+i0F5KMChxlVaakAK2ykcAt+WzdLu7zkxo3WZL4pu8mXfmeeY3885ug67roPFh5nvc62m9hjoR+5LMp7MrkYf370qVtco+VtCUFpbj+jGR+JbWn76OyQ8ePwsZATQb8R/hanZgINgj9IqeuBFCw1Kt9OMBnNWCs24XwkG/QKYUEiGjVAPQof/rq0783pShET3ULQo8xz0iS5FaANmrHQH2DoqY+DSLSz6RzecWlnD9ymU47LYjd4O5BXqDTG4FM3NpTEkpdJ5rw0AowLRMbhUfp58gTOaD/UHmNQPI6YmvKWRX1zESHUJ/oBs2nmPa+Mgw0ZIM3tZyGoJwygzQNB2jNyJIZX7iB0lpPoM70UGmPX8zCU+rG8NDVxHwdiC5mKsPUFUN/gvtLLf39sFzVqaN3YrC6TjBauqhXhNA1TQoqloV7Da+pjZq1FsXUCamF29j6LvYhf3iISamZ3Fv9DZevouhRzzPfOG+3hpA9U9UyioOlTJ7pFeTCQS6RGzIebyf+oz5pSzWtmSW1EO9phvQ00slBRt/8qR3DoWdXbiczUiTzd52D+tdLmyTB14mx1rMAKVcRpEATjrsuElee/HXGmnFRyBOGD30C/nEDjNgs7CDpsYmnHG3YPegBCvHs9oYfm8nG9dJa5X4K8AAQzQX4KSN3wcAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain}.ipfs-yml {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdxJREFUeNqMUl1rE0EUPbM7m5Y0Zptu21AwWwhYpfSDFh+kvvRd8N0Hf4I/xWdf/Q158F0QoQ+CVsFKaLSQpt/dpmvztTOzzky6cetOpWcZZvbO3MO5514SxzEU3r57/3GpWllM/tP4sL3TarROXuSo/SWJvX71Uu80Cfhlr/T4UdWFAVfdnmsTUtvdP35OUyQKVnJgXDBTcj9icAsTeLax7j/052qM81UjwW1QJXEhMF0qYnN90fdnvdogYmvJPU0/VBApD4hcDrWRcyikfB17srzgW7b9Rh1vEvxDlI4tVytaBSEEtmWh0xsUMwpwnWjqAlcxogiHd1wiQyCu87iI/+sJtf6+NXsgpd7FWCMB50KvkYMGMbLdZgLlfj+K9K4+FnFQ2x7WntIs50AbmiGwLILt+k+EvzvSNIHzdigdJ/AmXQRhiHv5POSwYmG+cqPVo0HqDxj8uTK2vn1Hfa+JmdIkvtZ/4fOPXU3WPDpFeNWVyUKryCiIGMN4zsH98gym3CIcOTwT+XHdXrdQQHAZotE8kBPpSqPNHtBOr48HUmLOcXRJT9dWNMGYJFby91pHOAvaykSaITg+bwefdhrteDRTMSwyrFCgI88E056Hy+4Ah2cXQZL3R4ABALUe7fqXWFN6AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}.ipfs-zip {background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm9JREFUeNpsk0tv00AUhc+MY6dOmgeFJg1FoVVpUWlFC0s2IFF1jxBbhKj4BSxYdscPYcEmQmIDq0gsERIViy4TpD7VFzF1Ho5je2a4thOqNhlp5Mz4zudzzp0wpRTC8fPrk0/TC6+fDtYicLH97T1Kc2vQDcs+rH3eUAxVznn0fn1DRM8E+iOdv5ct3XmZG6yVlNj6solUbgVTt0q5FGtX6vXqC6VklTE+KAO/OODHSIQPRQpsXC+kkEz2ELA0ystv84tLzyucsbWByisAGf+QAS2CCDRRLMJMmxC+i8C4jdLCm/zM7OOKFGptcO6/BTpJ0yeQB0Y+mfKQuZZG0jQgeRbW8Xdomobs9LN8scc+UPHNy4Dwq8IljotIIQEm59/RoSyM1CKkXKZNBm7kIVgyM6wgAnSgRK9vqQfHPiMFDHqyFVsLR9Cm0o4YzoAASrSjCelQfRPb1Vc4qn0EY5L2W9GEaBLcxQgFHpGbkMIDJ69e+wjJ8VXqRgKid0r7ftQdxkRs9SqA2kgAm14SSIQh9uhuLGPMnKJs/5KquL1x0N0RCsizigoDaLqBdHoMiyvrlBsHVx1wphD4BCewoqxGKKDwAgtOy8JufYuk+5golGGaGZwc1sIGoDz3AOPZSVLaHgVwydoJDM1H4DbQODughB3YpOD44HfoHgnu4e7So0uAi0stHLJ3Aud8B9bpHu6vPoSu9TtDl6tUuoFiIYOgu0+158MKmOxomtyD3Qi/3MTR7i8K0EDG1GHO5DE3X4DvNahZlJOwEkOATvdPc2//hx3mXJ5lFJaF8K8bStd0YGfnOJbMGex21x6c+yfAAOlIPDJzr7cLAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:contain}body {color:#34373f;font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;font-size:14px;line-height:1.43;margin:0;word-break:break-all;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}a {color:#117eb3;text-decoration:none}a:hover {color:#00b0e9;text-decoration:underline}a:active,a:visited {color:#00b0e9}strong {font-weight:700}table {border-collapse:collapse;border-spacing:0;max-width:100%;width:100%}table:last-child {border-bottom-left-radius:3px;border-bottom-right-radius:3px}tr:first-child td {border-top:0}tr:nth-of-type(even) {background-color:#f7f8fa}td {border-top:1px solid #d9dbe2;padding:.65em;vertical-align:top}#page-header {align-items:center;background:#0b3a53;border-bottom:4px solid #69c4cd;color:#fff;display:flex;font-size:1.12em;font-weight:500;justify-content:space-between;padding:0 1em}#page-header a {color:#69c4cd}#page-header a:active {color:#9ad4db}#page-header a:hover {color:#fff}#page-header-logo {height:2.25em;margin:.7em .7em .7em 0;width:7.15em}#page-header-menu {align-items:center;display:flex;margin:.65em 0}#page-header-menu div {margin:0 .6em}#page-header-menu div:last-child {margin:0 0 0 .6em}#page-header-menu svg {fill:#69c4cd;height:1.8em;margin-top:.125em}#page-header-menu svg:hover {fill:#fff}.menu-item-narrow {display:none}#content {border:1px solid #d9dbe2;border-radius:4px;margin:1em}#content-header {background-color:#edf0f4;border-bottom:1px solid #d9dbe2;border-top-left-radius:3px;border-top-right-radius:3px;padding:.7em 1em}.type-icon,.type-icon>* {width:1.15em}.no-linebreak {white-space:nowrap}.ipfs-hash {color:#7f8491;font-family:monospace}@media only screen and (max-width:500px) {.menu-item-narrow {display:inline}.menu-item-wide {display:none}}@media print {#page-header {display:none}#content-header,.ipfs-hash,body {color:#000}#content-header {border-bottom:1px solid #000}#content {border:1px solid #000}a,a:visited {color:#000;text-decoration:underline}a[href]:after {content:" (" attr(href) ")"}tr {page-break-inside:avoid}tr:nth-of-type(even) {background-color:transparent}td {border-top:1px solid #000}}@-ms-viewport {width:device-width}.d-flex {display:flex}.flex-wrap {flex-flow:wrap}.flex-shrink-1 {flex-shrink:1}.ml-auto {margin-left:auto}.table-responsive {display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}
-</style>
-</head>
-<body>
-  <div id="page-header">
-    <div id="page-header-logo" class="ipfs-logo">&nbsp;</div>
-    <div id="page-header-menu">
-      <div class="menu-item-wide"><a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About IPFS</a></div>
-      <div class="menu-item-wide"><a href="https://ipfs.tech#install" target="_blank" rel="noopener noreferrer">Install IPFS</a></div>
-      <div class="menu-item-narrow"><a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About</a></div>
-      <div class="menu-item-narrow"><a href="https://ipfs.tech#install" target="_blank" rel="noopener noreferrer">Install</a></div>
-      <div>
-        <a href="https://github.com/ipfs/kubo/issues/new/choose" target="_blank" rel="noopener noreferrer" title="Report a bug">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.4 21"><circle cx="7.5" cy="4.8" r="1"/><circle cx="11.1" cy="4.8" r="1"/><path d="M12.7 8.4c-0.5-1.5-1.9-2.5-3.5-2.5 -1.6 0-3 1-3.5 2.5H12.7z"/><path d="M8.5 9.7H5c-0.5 0.8-0.7 1.7-0.7 2.7 0 2.6 1.8 4.8 4.2 5.2V9.7z"/><path d="M13.4 9.7H9.9v7.9c2.4-0.4 4.2-2.5 4.2-5.2C14.1 11.4 13.9 10.5 13.4 9.7z"/><circle cx="15.7" cy="12.9" r="1"/><circle cx="15.1" cy="15.4" r="1"/><circle cx="15.3" cy="10.4" r="1"/><circle cx="2.7" cy="12.9" r="1"/><circle cx="3.3" cy="15.4" r="1"/><circle cx="3.1" cy="10.4" r="1"/></svg>
-        </a>
-      </div>
-    </div>
-  </div>
-  <div id="content">
-    <div id="content-header" class="d-flex flex-wrap">
-      <div>
-        <strong>
-          Index of
-          {{ range .Breadcrumbs -}}
-          /{{ if .Path }}<a href="{{ $root.GatewayURL }}{{ .Path | urlEscape }}">{{ .Name }}</a>{{ else }}{{ .Name }}{{ end }}
-          {{- else }}
-          {{ .Path }}
-          {{ end }}
-        </strong>
-        {{ if .Hash }}
-        <div class="ipfs-hash" translate="no">
-          {{ .Hash }}
-        </div>
-        {{ end }}
-      </div>
-      {{ if .Size }}
-      <div class="no-linebreak flex-shrink-1 ml-auto">
-        <strong title="Cumulative size of IPFS DAG (data + metadata)">&nbsp;{{ .Size }}</strong>
-      </div>
-      {{ end }}
-    </div>
-    <div class="table-responsive">
-    <table>
-      {{ if .BackLink }}
-      <tr>
-        <td class="type-icon">
-          <div class="ipfs-_blank">&nbsp;</div>
-        </td>
-        <td>
-          <a href="{{.BackLink | urlEscape}}">..</a>
-        </td>
-        <td></td>
-        <td></td>
-      </tr>
-      {{ end }}
-      {{ range .Listing }}
-      <tr>
-        <td class="type-icon">
-          <div class="{{iconFromExt .Name}}">&nbsp;</div>
-        </td>
-        <td>
-          <a href="{{ .Path | urlEscape }}">{{ .Name }}</a>
-        </td>
-        <td class="no-linebreak">
-          {{ if .Hash }}
-          <a class="ipfs-hash" translate="no" href={{ if $root.DNSLink }}"https://cid.ipfs.tech/#{{ .Hash | urlEscape}}" target="_blank" rel="noreferrer noopener"{{ else }}"{{ $root.GatewayURL }}/ipfs/{{ .Hash | urlEscape}}?filename={{ .Name | urlEscape }}"{{ end }}>
-            {{ .ShortHash }}
-          </a>
-          {{ end }}
-        </td>
-        <td class="no-linebreak" title="Cumulative size of IPFS DAG (data + metadata)">{{ .Size }}</td>
-      </tr>
-      {{ end }}
-    </table>
-    </div>
-  </div>
-</body>
-</html>
diff --git a/assets/dir-index-html/index.go b/assets/dir-index-html/index.go
deleted file mode 100644
index 98933e3f612f96745a97ce3ef697aca7ca0a9878..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/index.go
+++ /dev/null
@@ -1 +0,0 @@
-package dirindexhtml
diff --git a/assets/dir-index-html/knownIcons.txt b/assets/dir-index-html/knownIcons.txt
deleted file mode 100644
index c110530ea599dfb42184c245b1d0b1c3fd34e91b..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/knownIcons.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-.aac
-.aiff
-.ai
-.avi
-.bmp
-.c
-.cpp
-.css
-.dat
-.dmg
-.doc
-.dotx
-.dwg
-.dxf
-.eps
-.exe
-.flv
-.gif
-.h
-.hpp
-.html
-.ics
-.iso
-.java
-.jpg
-.jpeg
-.js
-.key
-.less
-.mid
-.mkv
-.mov
-.mp3
-.mp4
-.mpg
-.odf
-.ods
-.odt
-.otp
-.ots
-.ott
-.pdf
-.php
-.png
-.ppt
-.psd
-.py
-.qt
-.rar
-.rb
-.rtf
-.sass
-.scss
-.sql
-.tga
-.tgz
-.tiff
-.txt
-.wav
-.wmv
-.xls
-.xlsx
-.xml
-.yml
-.zip
diff --git a/assets/dir-index-html/package.json b/assets/dir-index-html/package.json
deleted file mode 100644
index 4b24275740668da0179a2cebb8958b4a98143183..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/package.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "dir-index-html",
-  "description": "Directory listing HTML for go-ipfs gateways",
-  "version": "1.3.0",
-  "private": true,
-  "homepage": "https://github.com/ipfs/go-ipfs",
-  "license": "MIT",
-  "scripts": {
-    "start": "cd test && go run .",
-    "build": "npm run build:clean && npm run build:remove-style-links && npm run build:minify-wrap-css && npm run build:combine-html-css && npm run build:remove-unused",
-    "build:clean": "rm dir-index.html",
-    "build:remove-style-links": "sed '/<link rel=\"stylesheet\"/d' ./src/dir-index.html > ./base-html.html",
-    "build:minify-wrap-css": "(echo \"<style>\" && cat ./src/icons.css ./src/style.css | tr -d \"\t\n\r\" && echo && echo \"</style>\") > ./minified-wrapped-style.html",
-    "build:combine-html-css": "sed '/<\\/title>/ r ./minified-wrapped-style.html' ./base-html.html > ./dir-index.html",
-    "build:remove-unused": "rm ./base-html.html && rm ./minified-wrapped-style.html"
-  }
-}
diff --git a/assets/dir-index-html/src/dir-index.html b/assets/dir-index-html/src/dir-index.html
deleted file mode 100644
index 109c7afbf442dbd88dc30b8f3db53a3629d42b81..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/src/dir-index.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE html>
-{{ $root := . }}
-<html lang="en">
-<head>
-<meta charset="utf-8" />
-<meta name="description" content="A directory of content-addressed files hosted on IPFS">
-<meta property="og:title" content="Files on IPFS">
-<meta property="og:description" content="{{ .Path }}">
-<meta property="og:type" content="website">
-<meta property="og:image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-<meta name="twitter:title" content="{{ .Path }}">
-<meta name="twitter:description" content="A directory of files hosted on the distributed, decentralized web using IPFS">
-<meta name="twitter:card" content="summary_large_image">
-<meta name="twitter:image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-<meta name="twitter:creator" content="@ipfs">
-<meta name="twitter:site" content="@ipfs">
-<meta name="image" content="https://gateway.ipfs.io/ipfs/QmSDeYAe9mga6NdTozAZuyGL3Q1XjsLtvX28XFxJH8oPjq">
-<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="shortcut icon" href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlo89/56ZQ/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACUjDu1lo89/6mhTP+zrVP/nplD/5+aRK8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHNiIS6Wjz3/ubFY/761W/+vp1D/urRZ/8vDZf/GvmH/nplD/1BNIm8AAAAAAAAAAAAAAAAAAAAAAAAAAJaPPf+knEj/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf+tpk7/nplD/wAAAAAAAAAAAAAAAJaPPf+2rVX/vrVb/761W/++tVv/vrVb/6+nUP+6tFn/y8Nl/8vDZf/Lw2X/y8Nl/8G6Xv+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/761W/+vp1D/urRZ/8vDZf/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/vrVb/761W/++tVv/r6dQ/7q0Wf/Lw2X/y8Nl/8vDZf/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf++tVv/vrVb/761W/++tVv/vbRa/5aPPf+emUP/y8Nl/8vDZf/Lw2X/y8Nl/8vDZf+emUP/AAAAAAAAAACWjz3/vrVb/761W/++tVv/vrVb/5qTQP+inkb/op5G/6KdRv/Lw2X/y8Nl/8vDZf/Lw2X/nplD/wAAAAAAAAAAlo89/761W/++tVv/sqlS/56ZQ//LxWb/0Mlp/9DJaf/Kw2X/oJtE/7+3XP/Lw2X/y8Nl/56ZQ/8AAAAAAAAAAJaPPf+9tFr/mJE+/7GsUv/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+xrFL/nplD/8vDZf+emUP/AAAAAAAAAACWjz3/op5G/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+inkb/nplD/wAAAAAAAAAAAAAAAKKeRv+3slb/0cpq/9HKav/Rymr/0cpq/9HKav/Rymr/0cpq/9HKav+1sFX/op5G/wAAAAAAAAAAAAAAAAAAAAAAAAAAop5GUKKeRv/Nxmf/0cpq/9HKav/Rymr/0cpq/83GZ/+inkb/op5GSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G16KeRv/LxWb/y8Vm/6KeRv+inkaPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAop5G/6KeRtcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/n8AAPgfAADwDwAAwAMAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAwAMAAPAPAAD4HwAA/n8AAA==" />
-<link rel="stylesheet" href="style.css"/>
-<link rel="stylesheet" href="icons.css">
-<title>{{ .Path }}</title>
-</head>
-<body>
-  <div id="page-header">
-    <div id="page-header-logo" class="ipfs-logo">&nbsp;</div>
-    <div id="page-header-menu">
-      <div class="menu-item-wide"><a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About IPFS</a></div>
-      <div class="menu-item-wide"><a href="https://ipfs.tech#install" target="_blank" rel="noopener noreferrer">Install IPFS</a></div>
-      <div class="menu-item-narrow"><a href="https://ipfs.tech" target="_blank" rel="noopener noreferrer">About</a></div>
-      <div class="menu-item-narrow"><a href="https://ipfs.tech#install" target="_blank" rel="noopener noreferrer">Install</a></div>
-      <div>
-        <a href="https://github.com/ipfs/kubo/issues/new/choose" target="_blank" rel="noopener noreferrer" title="Report a bug">
-          <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.4 21"><circle cx="7.5" cy="4.8" r="1"/><circle cx="11.1" cy="4.8" r="1"/><path d="M12.7 8.4c-0.5-1.5-1.9-2.5-3.5-2.5 -1.6 0-3 1-3.5 2.5H12.7z"/><path d="M8.5 9.7H5c-0.5 0.8-0.7 1.7-0.7 2.7 0 2.6 1.8 4.8 4.2 5.2V9.7z"/><path d="M13.4 9.7H9.9v7.9c2.4-0.4 4.2-2.5 4.2-5.2C14.1 11.4 13.9 10.5 13.4 9.7z"/><circle cx="15.7" cy="12.9" r="1"/><circle cx="15.1" cy="15.4" r="1"/><circle cx="15.3" cy="10.4" r="1"/><circle cx="2.7" cy="12.9" r="1"/><circle cx="3.3" cy="15.4" r="1"/><circle cx="3.1" cy="10.4" r="1"/></svg>
-        </a>
-      </div>
-    </div>
-  </div>
-  <div id="content">
-    <div id="content-header" class="d-flex flex-wrap">
-      <div>
-        <strong>
-          Index of
-          {{ range .Breadcrumbs -}}
-          /{{ if .Path }}<a href="{{ $root.GatewayURL }}{{ .Path | urlEscape }}">{{ .Name }}</a>{{ else }}{{ .Name }}{{ end }}
-          {{- else }}
-          {{ .Path }}
-          {{ end }}
-        </strong>
-        {{ if .Hash }}
-        <div class="ipfs-hash" translate="no">
-          {{ .Hash }}
-        </div>
-        {{ end }}
-      </div>
-      {{ if .Size }}
-      <div class="no-linebreak flex-shrink-1 ml-auto">
-        <strong title="Cumulative size of IPFS DAG (data + metadata)">&nbsp;{{ .Size }}</strong>
-      </div>
-      {{ end }}
-    </div>
-    <div class="table-responsive">
-    <table>
-      {{ if .BackLink }}
-      <tr>
-        <td class="type-icon">
-          <div class="ipfs-_blank">&nbsp;</div>
-        </td>
-        <td>
-          <a href="{{.BackLink | urlEscape}}">..</a>
-        </td>
-        <td></td>
-        <td></td>
-      </tr>
-      {{ end }}
-      {{ range .Listing }}
-      <tr>
-        <td class="type-icon">
-          <div class="{{iconFromExt .Name}}">&nbsp;</div>
-        </td>
-        <td>
-          <a href="{{ .Path | urlEscape }}">{{ .Name }}</a>
-        </td>
-        <td class="no-linebreak">
-          {{ if .Hash }}
-          <a class="ipfs-hash" translate="no" href={{ if $root.DNSLink }}"https://cid.ipfs.tech/#{{ .Hash | urlEscape}}" target="_blank" rel="noreferrer noopener"{{ else }}"{{ $root.GatewayURL }}/ipfs/{{ .Hash | urlEscape}}?filename={{ .Name | urlEscape }}"{{ end }}>
-            {{ .ShortHash }}
-          </a>
-          {{ end }}
-        </td>
-        <td class="no-linebreak" title="Cumulative size of IPFS DAG (data + metadata)">{{ .Size }}</td>
-      </tr>
-      {{ end }}
-    </table>
-    </div>
-  </div>
-</body>
-</html>
diff --git a/assets/dir-index-html/src/icons.css b/assets/dir-index-html/src/icons.css
deleted file mode 100644
index dcdbd3cd9e2ed663ecf5982ee1152825ca12aa76..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/src/icons.css
+++ /dev/null
@@ -1,403 +0,0 @@
-/* Source - fileicons.org */
-
-.ipfs-_blank {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAWBJREFUeNqEUj1LxEAQnd1MVA4lyIEWx6UIKEGUExGsbC3tLfwJ/hT/g7VlCnubqxXBwg/Q4hQP/LhKL5nZuBsvuGfW5MGyuzM7jzdvVuR5DgYnZ+f99ai7Vt5t9K9unu4HLweI3qWYxI6PDosdy0fhcntxO44CcOBzPA7mfEyuHwf7ntQk4jcnywOxIlfxOCNYaLVgb6cXbkTdhJXq2SIlNMC0xIqhHczDbi8OVzpLSUa0WebRfmigLHqj1EcPZnwf7gbDIrYVRyEinurj6jTBHyI7pqVrFQqEbt6TEmZ9v1NRAJNC1xTYxIQh/MmRUlmFQE3qWOW1nqB2TWk1/3tgJV0waVvkFIEeZbHq4ElyKzAmEXOx6gnEVJuWBzmkRJBRPYGZBDsVaOlpSgVJE2yVaAe/0kx/3azBRO0VsbMFZE3CDSZKweZfYIVg+DZ6v7h9GDVOwZPw/PoxKu/fAgwALbDAXf7DdQkAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-_page {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNpsUztv01AYPfdhOy/XTZ80VV1VoCqlA2zQqUgwMEErWBALv4GJDfEDmOEHsFTqVCTExAiiSI2QEKJKESVFFBWo04TESRzfy2c7LY/kLtf2d8+555zvM9NaI1ora5svby9OnbUEBxgDlIKiWjXQeLy19/X17sEtcPY2rtHS96/Hu0RvXXLz+cUzM87zShsI29DpHCYt4E6Box4IZzTnbDx7V74GjhOSfwgE0H2638K9h08A3iHGVbjTw7g6YmAyw/BgecHNGGJjvfQhIfmfIFDAXJpjuugi7djIFVI4P0plctgJQ0xnFe5eOO02OwEp2VkhSCnC8WOCdqgwnzFx4/IyppwRVN+XYXsecqZA1pB48ekAnw9/4GZx3L04N/GoTwEjX4cNH5vlPfjtAIYp8cWrQutxrC5Mod3VsXVTMFSqtaE+gl9dhaUxE2tXZiF7nYiiatJ3v5s8R/1yOCNLOuwjkELiTbmC9dJHpIaGASsDkoFQGJQwHWMcHWJYOmUj1OjvQotuytt5nHMLEGkCyx6QU384jwkUAd2sxJbS/QShZtg/8rHzzQOzSaFhxQrA6YgQMQHojCUlgnCAAvKFBoXXaHfArSCZDE0gyWJgFIKmvUFKO4MUNIk2a4+hODtDUVuJ/J732AKS6ZtImdTyAQQB3bZN8l9t75IFh0JMUdVKsohsUPqRgnka0tYgggYpCHkKGTsHI5NOMojB4iTICCepvX53AIEfQta1iUCmoTiBmdEri2RgddKFhuJoqb/af/yw/d3zTNM6UkaOfis62aUgddAbnz+rXuPY+Vnzjt9/CzAAbmLjCrfBiRgAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-aac {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNp0Uk1PE0EYftruVlvAUkhVEPoBcsEoLRJBY01MPHjCs3cvogcT/4qJJN5NvHhoohcOnPw4YEGIkCh+oLGBKm3Z7nZ3dme2vjOhTcjiJJvZzPvOM8/HG2q325Dr3kLp7Y1ibpIxjs4KhQBZfvV6s7K5Vb0bjeof5ZlcGysP1a51mifODybvzE8mzCbrAoTDIThMoGXZiZ4YSiurf+Z1XeuCqJ7Oj+sK3jQcNAmg8xkGQ71mYejcAB49vpmeuzJccl0+dUj6KIAvfHCPg3N+uAv4vg9BOxcCmfEzuP/genpmeqhEMgude10Jwm+DuUIyUdTlqu2byoMfX/dRermBeExHsTiWNi3+lMpzRwDki8zxCIATmzbevfmClukiP5NFhJgwkjeRTeLShdOoVJqnAgwkgCAZ6+UdLC9twjQZ8pdzioFkZBHY3q6B3l4dJEEEPOCeD4cYVH7Xsf15F+FImC775INAJBJSkVoWo0QY9YqgiR4ZZzRaGBkdwK3bFxGLRZUfB3Rm2x4x9CGtsUxH9QYkKICDFuLxKAozGZwdTqBRs2FbLlXbiPdECMCHadj/AaDXZNFqedCIvnRcS4UpRo7+hC5zUmw8Ope9wUFinvpmZ7NKt2RTmB4hKZo6n8qP4Oq1HBkKlVYAQBrUlziB0XQSif4YmQhksgNIJk9iaLhPaV9b/Um+uJSCdzyDbGZQRSkvjo+n4JNxubGUSsCj+ZCpODYjkGMAND2k7exUsfhkCd+29yguB88Wl7FW/o6tT7/gcXqAgGv7hhx1LWBireHVn79YP6ChQ3njb/eFlfWqGqT3H3ZlGIhGI2i2UO/U/wkwAAmoalcxlNA1AAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-ai {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk5JREFUeNpsU01vElEUPTPzZqBAQaSFQiJYUmlKYhoTF41L3Tbu/Q/+AvsX3Bp/gPsuWLrqyqQ7TUxMtAvF1tYGoXwNw7wv7zwYgtKX3Lw379575p5z77O01ohW+/DVh8zj7aYKhflGdG9ZsGwLNydffgVfr19YHvsEa+Zu/nxndob5StQK+dyzvZzyw/gKlmMj7IygFM+xvNcanp4/t5dAomXHBy2UUBOO2MAl/B9/cPb6PULuoHx0WM0e3GvpUOxD3wZAJWutZqYUYmqpSg5OMgH3YQObL59W0/ullpryR3HegkKEqiWBSGV4R3vQ7sIhScTZFTpHx3A215B5sluVY/WWMg7+ATB/lcLsKpTonHzD+OMFEuTz8ikkt9Kwt9YJZB38cpBdoQAZJdLvCGByfoPB6Xdk90pYy6Xg3c/DaWwArg09DaG5lCsUFN0pckZAojdC8m4auBqaALuSgez7VB1RtDSUWOQvUaBLFUzJBMJ2DwmPgd1Jwm0WoSgJfjDvrTKxtwAIyEkAOQ5hU//Zdg5uowDlUNMnwZLW0sSuUuACYhwQRwFvJxupCjEYUUccOkoaKmdOlZnY1TkgAcXAhxhOwLsDsHoN3u4O5JTDfVCH6I9nfjId3gIgSUATFJk/hVevGtOMwS0XwQ3AzB/FrlKg8Q27I2javVoZrFgwD4qVipAEyMlnaFArzaj/D0DiMXlJAFQyK2r8fnMMRZp4lQ1MaSL5tU/1kqAkMCh2tYI+7+kh70cjPbr4bEZ51jZr8TJnB9PJXpz3V4ABAPOQVJn2Q60GAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-aiff {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAohJREFUeNpkU9tqE1EUXZmZpE3aTBLbJFPTtFURtSCthr7UCyKKFJ/9An3og6Ag/oXfoUj7og9asCBYKT6UIPHaWtpq7NU2aZK5z5wZ9xxMpMwZDuewz9prr32ZiO/7CNaDx3OLt6fOjBqGg/aKRCIInp8+KzfKH7fudnVF58nE16el+/yU2mBFSWZKpWJKVc0OgUBo02K4NDmU6o75Mx+Wdu9IUXFeiOA/pn1xHeYaugVDdzpbp91qGlAKGTx8dC19/Wpxhjnsxj/RRwk85hGJC9d1O6fneWAuoztDYSSLe9OT6SuXB2ccx73Z9uukwDwfls1g0xZIY/Ad/Gnyt/XVfbyYrSDRE8PExHB6/8B6QuaxIwRBFMt0iIAiMx+LCys8jfGJEUik2WpZOD2SQf9oDtVqQwopCAiY66FS/om3b75CVS2MlU7AJ2WiJBCZjZ2dJuRkDJZFwFAR7UCBja3fNfxY2YEoCtRCj9em3Tpds6FpJseGCBxS0GgYGBzqw62p84gnYnAI2CSbSbPhEpFAaE2zODaUAlWWwDoS5DheGqbWpVE/0CmqCY9qkEyINBceb2uADRNQ8bSWAVVzIFKomCQim+0luS4yKYlsHlRyZo7EsSEC23K5vAsXh/H92zZkuRvxeBS5nEx2yp2KqhxPoV5TYS/8CtdApylM9sZQKKSQzyeRTseRV2QoAzIYY8jme5DN9fI0dQoUIjANGydP9VM7PZw9p/AiBpNYrdbw/t0yTJqRtdU9UrfJCUMpSJIgbWzsYe51BcViHzLHeqCRqhZ1YX1tFwNfZBxS9O3NWkAcHqR606k/n/3coKAoV/Y7vQ/OYCZevlrmv3c0GsFh06u3/f4KMABvSWfDHmbK2gAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-avi {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm1JREFUeNpsU8tu00AUPXZcN0nzTpq2KQ3pAwkIAnWHqCoeexBb+AQ+ABZ8A2s+AIkdm266QUJIFWKBkHg1KpRHi5omJGkbJ3bGHj+4M1EQrTvSyGPPueeec++1EgQBxHp+/9mbyuriRZdxjJaiKBD3W+u1+p9a856max+gDO8ebT+WT20Ezi9NZi/crqadvn2MQBAGfpCOpqNru2937vxPIpY6Onjccx3Twck9MBiSU0ncfHirXFmZX3Md9wqCUwiEVN/zaQfHt0vfbBe5uQyuPVgpl5Zn11ybL4/i/lkICOw5niQRGQShoiqI6Bo43W2ub8n3hRtLZT7gTynk6gkCX9gAOxpAnxhHZDwC1/aI1EViJolu/QhKRMHZ1UX0Gr1USIEn5FPWHy+/wTokkrQOq2vBaHZBN4hmY9Jwfr4An/teiEB45ZZDwDiMhoExT0N+sYDCuUkkplLIlXP4/XEXdo+RUhdhBSSfUwtVTUG8MIHK9QVqI7D/uY6vr2pwmCPrkz+Tk9gwARWQ9WxppbXZhNnpw+ya4A5HZi6L4lIR8WyCcL6sTZiAWjWgAmpxkn5+kqTamK6WkCwmERmLDLvjB0ML9ikWXPLFuozYOap3L8HYN6DHdbS/d5CeTVBndBz87FCBLYkNTyIjBQemnIEsSY5lYrK1+UoWcToLMjEHAyIQ2BCBSx/NVh+ZUhrqmEqBebS3WyhdLg0zt/ugAaIklsSGLHCLa6zDMGhZ2HjyGsnpFPqNHnY2fmHv3R5SMymYbROszSQ2ROAY9qHiofvlxSc5xsKKqqnY3diRE9h4X5d/pzg7lnM4ivsrwADe9Wg/CQJgFAAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-bmp {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmZJREFUeNp0U+1rUlEY/13v9YV0vq2wttI5CdpL9aEGBZUDv0df668I6n+or0UQ/RuuD0EgVDAZrsKF4AR1a6COKW5qXvXec27PuVeda3bgcF6e8/ye5/d7niMZhgExnK9fbTrm5pbBGMZDkgCyq+VyhTUaT6Eo2ZHJePPWXJXRhez3B1yxmM/QdctXUSCgtV4Py4CvY3cky4e1x5DlLCaGbbzjXDcousG5OQe5HPRSCQPK4PpsEM/XH4WvhS4noeu3JwHGGRiULhsMoKZS4I0GtEIB9mgULJGA0+9DPBpBT7sffvf1W/Lg6OgJufw8C0CRGEXWazUwiiyFQjA8bsjVKjaJzovMD/Q5gxyJhG2cvyeXe2cAuADQNGBmBvLaGuTFRaDfh31lBTWi9pumjbK0B4JQul3vOQpM8JdskOLrdCvDcDjAsjtg5TIkoiKLaokMNR2cnZbqNAMycqG7XbHKR2fMzwO/dsxSwu0BiBJsNsv2LwAJAJCI5ux2gXYbqNetcz5PoORI1cDS0n8AxGW7A+zvEYBKZ2ZlcsEtJLbedMjePBaCTQMghx45ulyWkzxMVUQ2RMQhLfFO16YAqCrixPnm6iqKrRb2W23EfF4cUNSrHg90cr7hDyB33MTnSmUKALVs4uIlROjxg+AsPhGVl3fuIl2tIOB0Ya91gkOi9mxhAal0ekork1ic/kGLBORMxy2K1qS9V1ZQbNThIj2EGh+2tsyOnSai8r1UxMNIBB+LRTTULr4Uds0K1tU/uOLxIrmbNz8XXSrnASSpubG9fbKRyVh1n/zSw29t9oC1b47MfwUYAAUsLiWr4QUJAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-c {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcxJREFUeNqEUk1rE0EYfmZnkgoJCaGNCehuJTalhJZSUZB66a0HwXsP/Qn+FM+9+hty0LNYCr2I7UVLIW0Fc0hpQpSS7O7MrO9MspuvVV8YMnk/nn2e5x0WRRFMvP/w6WSz5jbi/9NxfP693Wp3DrJCnMW5d28P7a+IE15lufR8o1ZEStwPhkWHsWbrZ+eNEPxsuubEF6m0TBv2Q4liPofXuzveulttSqW2UwH+GjqC0horpSL2njU89+FyMwjlTlxOJMTa9ZQHzDQIjgwdom9zLzfXPc75kbnOAswBJTlC2XrqQRMLxhi442DgB4UFBhgPpm3B5pgBHNUUxQKAHs8pHf3TEuFMetM9IKr/i2mWMwC0SnuSFTG2YKyppwKYVdGO7TFhzBqGIenVeLCUtfURgErucx5ECKREKBU4d3B718PHz6cICGT/1Qs8qpQtGOdyhtGEARWDQFqQJSeDL98u4VbLaKw9IRAJPwjtoJGlVAoDQ800+fRFTTYXcjlcXN2g++s36p5Lzzlve1iEROa8BGH1EbrSAeqrjxEqicHQt8/YSDHMpaNs7wJAp9vvfb287idboAVkRAa5fBYXP9rxO4Mgf0xvPPdHgAEA8OoGd40i1j0AAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-cpp {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfJJREFUeNqEUs9PE0EU/mZ2WgqpXX+QIDFdalVslh8NlAOQaOKFAwfvHvwT/FM8e/U/MOnBmwcj8WD0ACEGghIkbU0baaEthe3OTJ0ZWV26q37JZt68ee/b9733yGAwgMbL12/fz+azbnAPY2Nrt7Zfqz9JMrYZ+J4/e2pOFjiciRvXlgp5GzHonXk2o6S8V6k/TjBrM/xGA4MLyeOSPZ8jkx7D+uqCU3Amy1yIYizB36AlCSkwfjWDR4uu40yMl/s+XwjeWThQQ4Z6QNSnSkYykcDXasP4lmfvOZTSF9q8TDBEFPbN5bOqCglCCCxK0TvvZyIV4CIxbgpC+4gm/PUmFCIE8iJPyME/e8Lon9j4HvyHYLjKSwRCSEUgf9+15mFbx8QS6CZJMzJ9SlBCwX3fJDLG4PX7ykcwkmQmJtpEhWa7g1dvNlSwjwelebz7tAXLolh0p/Fxe9fErK2WDFGEgKjxfNjegX0lDTc/heNuF99/HGEslcKXwyoazWNDdlCr6+DoJgrBzdI0T9rYO6yg2zszMlaKM3Dv5OBzbuyZuzm1B16U4Nzz2f3cFOx0Gq12F9cztpExncsqYoaHpSIKtx0zJdVIFpHQ6py29muNk1uTN829o/6SHEnh80HFaE6NjmLnWxUJy1LyTltB3k8BBgBeEeQTiWRskAAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-css {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAk1JREFUeNpsUktvUlEQ/u5DoCLl/RAKKKUvWmIxjYntQtcu3LvwJ/hTXLt16coFC2PsojEaMKZtCqFaTdGmjbS0CG3By+vei3OOBSGXSU7uzNyZ78z3zRF6vR6YvXzzPrMUCyf68bB9zO+VfpROn5hkOdfPPX/2lH/lfiLidztX5mN2jLGG0rKLENIE8liWpdzwP7HvqJqujmvudFU4bFY8Wk1FZsOBtKppd8YCDNu77CZevd3gflfTUFcUhP0ePLibiIR9rjSBpgwAfe4dVcV6dhtep4PH5msylGYLrzeybErcT85FYiH/CyPAf74gObC2vMhzsiRhPhpC6eQUM+EA1pJzILEnjRSuJsju7MJqsUCSRei6Dp3yXqcdGlHZ/rLPazQWGCn8+6YW4pAkEW0SjzUzanWlCa/LgcR0lNfovTEi6lcIkzesnM/R8RlN0INGp3h4DHoDsE5YRvQyiKiRSMzikRAOS2WoqoZWu41K7RwzlOOAVDMMMHhIGvFlRxJFrKYW0ep0IYgC3SDh4b1lTJjNfENsrazOAMAw680mPuW+8lFno1P4XDigRhOiwQAyJK7TbsNS/PaA7giAIAhYz2yRgBIfsVA8wIetPG6FAqhdNrC5u0f+TUyHgyMTDDToEt/ftQsEvW4EPG5OZcrvw0mlimarTXkPfpXPcNlQoGtjACgpryQXsPNtH/nvRXqBJpoKHMzGNkNB0Odls7LNyAYKpUq1dt1iuvB7fRDp9kr9D1xOFwkpoksXusmXaZWFn0coV89r/b6/AgwAkUENaQaRxswAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-dat {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfVJREFUeNqMU01PE1EUPe/Na0uptmlASg3MoiZgCA3hQ8PHAjbqwsS9C3+CP8W1W/+BSReyYUPwI4QAVkAgUEgIbVIg1FZb2pl5b3zv2cHBjsaTTOa+e989OffcGeK6LhTevFv+OJoZHPHOfrz/sl86KpWfhxnLe7lXL1/oN/MSZqonOXU/k0AA6lfNhEFIrlAsP2PMyPtr1AscLpyg5pbtIHErhqez4+awmc45nI8FEvwNaiQuBHqTcSxMjJhmX0/Osp1xr878FxWEzwMinxAzEA4xFIpnOjedHTKpYbxW4U2CP4j8uWxmUKsghMCgFI2mFe9QgHZj0Ba4yhFF+KvGJToIRLuPC/efnjD6+26wB1Lq/xgbSCBXKeWJG/OTdky8cWTdT3C9RmWSGk2XCLlWo4xTNbfN5qh7PpXM72GjZeHt0gpq9QbmH4whGb+NpU/reDQ7hcWVVXxvXOHxzCQopQEKXKEbL6o1ZIcy+LC5g62DY2zsHeC0fA4zndIrHOjvg2XbAQRSfsuy9XxC2qzi/H5B6/68W0AsGkW0KyJPBLbDO0fg3JX/CUM81i0bD6WKe6j9qOPJ3EMcF0tSNsFA6g6alqW+VtZBUL78Vtk+Oqne7U9rs5qOQCjSheJFBeFIFOfVujSUYu3rIc4uqxWv76cAAwCwbvRb3SgYxQAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-dmg {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNpsU01rE1EUPe9lkk47yWTStCmtNhFSWxos2EXVhSsRcasuxYV05V8Qf4DgD/AvCK5EV1oFI7iUBqmCNdDvppq2mWSSzEzy3vPOpFFq+uDNfR/3nnvueXeYUgrBWH1/9/NE7k5BKRnuRcfF2qdnmJq9DeF9tQ+2isuMsxXGWHh/a1mEVsPJSI5fSU3OPEj291IIlN49RXz0KqzEQjIeZS/L5Y/3wPGhDxIM/i/A7fZWgVG0t5EaG0ZUa0JGM8gvPrZmLt58QYwv91mfAqCIE0sAqgumBFITGQzpUYhuF0KfRa7waDyXXXolpVrsh/0tgSLDr5I+wUZo1UHCSkAficPzY6juFSmbRPrC/azjq+fkcO00gAqoU7B0ETKkfWbuCTjTYeq5oESAauexcTScX+ZACWFm0YQSLZKhHdr67+/wW0e0dgjYo3sCEXXybYtBDVSHLp2es3IpsILS24c42lkBg6DzRjgRzCDZ/xr0GNRJwwYiWgzt+hYMawleu0V3wbkT+kUirOc7IGJAz68R/Qak1BAlx3hqASPGBJRXpXOv58dkz3eAgQoOm4hyj57NgZm0MHvpBmK6QdUdg/DAg9cRkhicBSDaKJdeo1bdxmR2DtWDDUxl51HZ+QHTysD3XdQO95Gfv06aeGcAdBrY3Chi8lwO3768QWX7J5q1XWyVSxgajiOXLyBG2hzurRKV9lmt7ISNkkjo6HhNyjoK+2gXRsKE57ZIE2ot10Z1fz0Ue4ABVw3NMjnW14rInh8jTYywoTg3EOFpOM4mXNfH9PQUfGlrAwBOs3I8ljbtuMWhRWzIIPrkn+GcYcgIWEowbZ+0qB334/4IMADESjqbnHbH0gAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-doc {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAppJREFUeNpsU79PFEEU/mZ39vZu77g7DokcP04BBSUmiEKCSCxs7Ei00JAYO2NlTKyMrX+CJhaGwopSQ0dMtFEsbDRBgiZEQIF4IHcg+2t2Z8eZ5QDlnM1mZ9+8973vfe8NEUJArfSNhzPG0VIfeIiDRSDkw1cWVt3N8rhG6SdSO2Gvn8dfuueqZwuNZqk3Jxg7iNcIfBbgXD6ZC8u5qffzX8eoYeyDxC77uygKhcouovgVUQj1H4YB2ovNuD9+tTTU0zMVBmG/+C8AIYh8F361DL/yE5HnADKYlVdg6MDAmW7cuz5WGuw+PsWDYGAvbL8ECFUt4K7/AHd/I9c7BLaxinD2Ld5Zo7g78RLuRhlBS2cpWbGfStfhfwCEpK0nUjCbWuGsLciSOELPhkq/YgdY3l6HsLfRcLYf+pHNbH0JigEPkLAyMsiEJ7NrqQzM1i7wyhoMZqOhvQs6Z0ovXgdAJACRoulEg5HOwrOroKk0zOY2BDtVpTF0CU6kLkQJXa+BNEoG0lMSsBBKQXWNQktmoGcaYeSaQCIVWOvUYQAiWZFQtk5mSMoSzEILtBrTfEcviC5bwVwQmoh96wA0ic5dB57ngeoaTIPCdb34zDITYNLOOIeVSsW+dQC+7+NSWx6jJ4tY/rWNV7PfcGv0tBoPTM7M4eKJVgx2FTE9u4QPS6x+kHzfw/mOAjarW2hJG3hy8zIceweuY+PRtREMdzbjzcd5WBqPB6xeRGUMGRzHjWvMmxQ7tiOF1JBN6FiTd6Sy9RuFbHpX7MMMqOD088Ii+op5OUAO7jyeRGfBwrF8Cg8mXuDL4neMXzgFwhwZz+hf7a9d5yu3Z6DTPjVQIY9k7erO7Y63Lvc8ErEeyq6JaM6efjai4v4IMABI0DEPqPKkigAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-dotx {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAndJREFUeNpsU01rE1EUPTPzJk0y+WhMStW2qdVWxUVEQUF0I+4ELQiC7lz4N9z0T+hG9wrdZKUgLqulhrbSag1CKpT0g7RpYjqZmffle5NEKdMHlzfvvXvPPffcO4aUEno9f3Vt4dTp+BXOe+fB0u/NbVpv7h89NU1j1TCM8H7+xY9wJwPHZMbOjRadLAvE/2gToJTiTPx89k+OlVd/LT+0TPIPpO/SzyQk40xCMxBSZ9Z3CoAx5DOjeHT7SbE0XSpzwa8OWB9jINELolQg8AR0EgUKn1PIlIWpkUt4cPNxkTOU12trs8p95RiAXpqaztqou8q6SKQJJmZSqGwsodFsIJk1kcyLYv7IeafcLx4HUNkFF4jFTExMZ0B9DrfD4HUEusYhWs4GPEJg5wly/tBYRIOeDhpEwlS34xcyajdQr3UwOT2MlJOEBRuGNHWp9AQRVXDfQiFV/U5GBSiQ5p6ngBEa5z3fiIhC6g6IMDBwOdoHPkYnHPVyhN0tF7E4QSpr94CEOKELffq+y9Bq+DCJ7rWBoQQBVbPR2O6G4OlsLASJMtCZfQqm0NP5IVWnamdAkUxbyuIYtD7wWegb0YAzAVMkkI6NwPM9xEwHloyDGAmk7AKS9rAS0FKOdugbYeAHPu7OPEM+MY7q3hIKqTFQHmC3XcONc/fxdfMDrk/ew/edzyhvvTmBAddocVRqH3Frahau56qpZDho7+PnTgXffi/gbHYmLEvPSIQBp5JU62sYz13G609zKBXvoOMdYn2zgm7Xg2MVML/4Eu3uPgxhk2gXmNl8v/i2pcXTP8tKdTEcbWLZqDQXwu/l6pfwbEnSGsT9FWAA4mdHv2/9YJ4AAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-dwg {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAoFJREFUeNpsU0tPE2EUPfOg006hD4rQh8WgbCSwkKgbF2owujaCiQsXxpX+D6MmbtXEsHCLmIAbE6NLo8YlGIxREIshIqVl+mQ6j8/zFVCb4UtuZua795577rl3FCEE5Bl79vPd5LHYiOP7cH1AUWi85ytmvlas1bJ9E5ryBntH3BpuP/X9i7ovkluuiE8N9SDepaLpCcRCCqa/VDCaMuIjSWP25Upl6n+QDoCz6Yh7KKzh3sI2LuUimPtRRyaqodj0MDloYiITSTi+mH29Wu0AUf9CsZPJoW5czJl48LmCc5kIKo5Al67B9gUGYxrun+5NnMlFZ+GKiQADj2a7AquseLIvjMv5KMaSBu4sWVir+3i8VIVKYSby0UTdFU8Znu8AYBHQgVOJEN5uOXi4UsdawwU0FSf6TaSoyw6DRvukPkgGWpDKy4F8a3jImCrqFDFn6rhKPR4VGnhvOTAY3WLcjifcQAsqRfhUc/Gq1MKNbBh9nIAMDjEppocxs9HCMktfGTCwP/oOBkUKNk/qF3pDYC6Ktk8RfWzyaaoKrqdDaBDwya8W1m0/CPCR3kFy7CcnmWQRUJqcRJFUKtTnPCeR71LwoeYF92CYyVnCFZpCTrRtCv5to2St8SOrKxiPqEEA4fkYT+mI0rdoeUiH1XZVuQPpsIKqw2QmfifTsnOABiWySlH9uU0Hh2MqjsZV5LtpPSoGeN9rKnhBX7ehoOSLIIPfnGONXGMMWN7xUfVldYDbjM3mrh5HCDgS17DhHgDQcIU+XbBxnDTn1x1UuQcJ9iv7l5Q5e1zLGri92EDJFnoAgHtcfr6wbbVXUqq193+0z97n3UJt1+d51n7aHwEGAAHXJoAuZNlzAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-dxf {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo5JREFUeNpsU0trE1EYPfNMmtdoH2kDNmJbaVFcaBVFpAsREQpFwY0bu3HjQnTj1mVd+ANcuC3qQixmry6E0kWFVIQ+bKy2tbFJm3emyXTujGca+4DkwsedfLnn3POd77uS67rw1vC79ek7fZEzpu3AYUqS9tKQGZPLpa3VXP0uFCmJ/8t9OLC3q/uJbcs5bkIybvdHoMsSbLKENRmvU2WcNnTjRFD7ML1WGSPJHI6sA4KRWMAWVDPxLYex3iCmfpuIh1QsFSyMxQO4GvXHHwOJ6XWSyIck8v6HQsnjAxFc7vTj2VwBg4aG78VdBHQFCk+dbVcxMdwev9gTSEC455sIBOu2KLsoJFzqasP9vjCeDBlYqzn4VXXwarGKZN7Crd5QfLDT/7KpBM84c9fFUFjFp2wdk6smflRsKKqMa7EgfJJ3Ac2OKlit2pEmBTQfngdpnupoU7BUtRGiiTe7fXiRqmK+KuDn6TpvYogmBRJcrOwIJLIWxmM+dOsyLKryQAaJpjJ1/AxrGO3SqdZt7kKZJrzJWBg5piHENuY8vV6e0UOye1TyftvC5l+gZB8SHJTwpSx4q4JeTUKaxhXoR57h7Rn+3iFolJ3xvPhab6HgJG/pJ7jsNP4sUX+jZiCgEsWd/DjH5IrSYpBUAr0yHpzSoXKOP25a6OBhndh0zcX1qIYM2RIbu6i0KiHD5B/GTMHG03kTGpEL7H80wHFOWwhqDZ+SpkBOtCDYJDhZE4gRcKNbYynAqbCMbXpwpVPFbEng0aKJGbYzK1p4wIegLlcEPmdt+DjXbzcsxFlCynRwwVAwW6hjqeg0Zt521SYCWCJvbe0Un29UDx7Hgrs3IEitHXkw3jOv2fl92D8BBgAJeyqBh90ENQAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-eps {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNp0U01vElEUPfMFCEVArdoSqEA0KV246UJdUJM2Lo2JK/9FjXu3utJqTNz4D9worrsQExbFpAFT0TYp0CZ8pIAiyMfMvBnvm2Foa9uX3Lw7c98979x77hNM0wRf7ufPsq7Z2SQYw2QJAkDxQalUZa3WI8hy3gmZr15bu+z8kILBkCeRCJi6bufKMji0NhwiCQR6iitdatTvQ5LyOLLEiWcYukm3m4Zhmbq1BX13FyoxuH7xAlbvpqKRK1fT0PWbRwEmDEyiy1QVg/V1GO02tO1tKLEY2PIy3KEAlmJRDLXb0TeZL+n9g4MHlLJ5HIBuYnSzXq+DlcsQLk/D9Hoh1WrIUjlPcpsYGQzS3LWoaBhvKeXWMQCDA1D9pt8PaXERUjwOjEZQFhZQp9L2yERiqYRCkPt/z58ogTGqHQLE1BLgUmC6XGD5AlipBIFKkbhanKHGYLBDqQ4ZED0OAbfLlo8OIxwGvhVgyTHlA3xkomjH/gegBgDURMv6faDbBZpN+/tHkUApkdTA/PwZAPxntwdUyjYA/+ZMqJHjLgM9iv/6zRt2GgMaIE21aVIjnSm0DGPfmhzyde0UAE2Dj+p7urKCPvkZku9eJILOSMUnkvVhIo7GYIB3xSKYdhoA1erXGVKXpvFxZwdBonnD68PQ7YEwM4O4xwMPxc8RYE87g4FIcz+kvfmnA0YzIJIy77/m0OCqsTkkCTysKPjJG3viLei63Gm3kCO6UWqcMejjxecMPmxsoFKtYop6UNirYL9Wtc5OHqzznIXHq1na7OfMJROcK8a6O7MjW7nfzZdrd7jzT4ABACh3NGsh3GcdAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-exe {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAo1JREFUeNp0k8tPE1EUxr+ZzvRJO62lUAQaKIQ0FVJFjBBdoIkrDDHuXJi4NnHtX+HCjW408Q/QmHTRaCRRohIJifgiiBICTQu29mHfnc7MHc+MlECKdxZz595zf+c737nD6boOYzxJLC6Nhwej7e/24HkO779s7G6mMjcEwfKZ21+/d+em+RbagaFev28qEpZwzKg3ZckqCPH1nfS8hScIdyhBe6JqTG3PfyTTeLrwFhvbKdy9/xi5QglXL0yGJsKDccZY7LDIAwWHpSferWBh+RN8ni4UylVER8MY6PHj0uSpUK0hxzfTmWsUtnoEwO3rer64jEyxim6/Hy67DXaHExvJX3jw7CX8XjfORUdDlOohhU4fAVjILCPbm9V1yIqK2FgYt+ZmsZcv4lH8Nb5upXD7+hVMjIRQa8qeDg8UTYPU5cTcxSk4nS709XTD53ZhpD+IYMAPj+TBz93fZiz5oHV4AP1fGdlyHZIkIZkrI7GyhnK9CZXy+Aig6p1+HQAY003AcF8AVtGGfLWG9XTO4MLZ5cL0WAixoT4zVmPHADSiMo3hzHA/xgeDWFjbNg8H3A7kKnX0koEcPdTu/ylgRGZgOjNv38zoSXC8BZJDRKOlwGEV0VJVGM0y4joAPO1spXbx6sNHeD1uRIYGUCxVSRlDt1fC8rfvcDnsmJ+dOaLgoAs6AVLZPJJ7WdhEkUyT8GJpBflSBcVKDTvpDBw2GzQqQT1OgaZqUOhtFQUTUKnVTVWNpgy51YLVKph7sqKYkA4A1ScEfT66vm5kC3+ofh6Xz59FQ5bpkvE4QW3M5Apoyorhl9ABIKnFgNdTOh2NkJG6WSf9eRBJtmFwLDJmriUzeaOkYvvcXwEGAIVNH6cDA1DkAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-flv {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsUl1PE0EUPbssLYUCXdpaC9gWoSTgAyFigiRGY+KjvuuTr/4A44MP/gx/gMYfwIsan0RjIjGiJIZgSIGFIoXSD0t3Z3dnd70zpITazuZmJzP3nnvumaMEQQCx3jx69SV3a3KWMxetpSgKxP3m242Do43SQy2k/YRydvds67n8a63k+FRSn7l/bdg5tdsAuM3he/5weDC8vLdqPLgIIpba2niux52mg//DqlsYSg3iztO7mczN3DJ3+ByCLgCBH4hOFEF7cDpzPCRyOpaeLGXSc2PL3HbnW3XaRQCPEgWI2MsRVAVqrwbX9bHxbhOKpiJ/bzpDOr2k68V2BtRNzMtqDEqPejY/4zSGjb54BM0mQ8k4xsDoIMauXxnqYOD7PmwScP31d0SS/eAuh1lrolFpIBQNQw2pqJdqsAlIceB1AJCIkkE/FZskXDQVRXw6IYHiE0nBEcaPXSSvJnGwWkQXAE4acAhbxPMJpOdHweoMhc9b2F8zwKizbdlyPLVH7QLg+JKBYzoorxzjz3oRzUoToaEw9KyO8XQW5AE5jrFT6AbAYVVNxCZ0Ka3So+DSTAoDiej5ywTySbls1OEDobhFlMcXxrHw+AbINEjNXgb7y6BndLhk8cRkHHbD7g4gEhiJFxsdhrDqaamBaDKKerGGSKwPI9kR9EZCaNA5ubE7A5s8IFhsrxQkgJhZoa/06xC5xRz2v+3BOjFlbqcGlquxsondT9vY+2pAJdeZR6fI355CgQCN2A4O1w7gkQ7cdLUOAKdhV6uFSv3kd/n8mT68eC8dKWLnY4FsfeZQh7nVVt0/AQYAsf5g+SvepeQAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-gif {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmVJREFUeNp0U0tPE1EU/trplAqlL0laiw40xASByEJIZFGVnSvj1j+gWxNXJq7VrbrwF7h10cSNhMRHojEuACVBKmH6SJQyJeXRxzzv9dyZPiCtN5lMe8853znf953xcc4hztDzZ1+C6fQMHAfd4/MBFG+p6h/n4OAeAoGNToi/eOm+A50LKRaLh6amoty2vVpZdotNXccMEK3LwZxa2bsDSdrAqePv/mLM5tSdMwYBYqyvw9zdhUn/L59P4OGtG8qlZCoH254/DdCdQBCxqZu+ugqnWoW9swN5ehp2NotgIo6bGQWGtaS8+vQ5V9a0u5S+1gfABEilAqdUgm98HDwUQkDT8JXoPPq+BoM5kCYmFT9jryn1+hkAt7heBx8dhbSwACmTAUwTgdlZ/CVKJaLnI1GD8TikZiPSR8Gxib8chH95mZTxgwWHwH7+gFMswqcokIRbjMO2HDCnZ1VvArpjEmnKZc8+cZJJYGsLsMiZ8AgwEqaY6Mb6RQR33JFhGECzCRyfAFXNu9v+RVNRZWIMuDJNuYMAaDycUFGhCOgtuAtFVDA83G5A8TrFDw+F5QMAxAKJJxz2xnW3RPJGbm+rCyjotZetH4DGzaSSeDA3h4Zl4R0JOEZWTpIzF4n/m995bNdqZwB6m0gFft3Ak6vz+KYWwFsGlqIxXItEcDt1ARMEtKdVgZb+fwA0G2C2hXM0ZTZNRcSf0b1pmXi7uYnjI+Lfanm5fRQsK8BIxKcrK7i/uIgP+Tw+FlREqHN5fx/vyU4uHBE6UO4gDWqk/JFaLuMxcXeFk6TuJ90V0HOk1in7J8AAjmgkPfjU+isAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-h {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAbRJREFUeNqMUk1Lw0AQnf0woK0ttVqp0hwqVCl+UBERT94F7x78Cf4Uz179DT14F8WbYHtRkBYRLNqDtdaPZLObuLs1NGlXcWDJZGbey+x7QUEQgIqT07PL5WKhHL5H46J+22q22vsWpbWwdnR4oJ80LNiz2czGUjENhvj4ctIE4Wrj8XmPUlKL9nCYcOFzE9j1OKSTCdjdrtiLdr7KhVgzEvwW6krC92E6k4Kd9bJt57JV5vFK2KfRQRV+RAMkzxglYI1RaDy2dW1rpWRjQo5VGicYIorWVooFvQVCCAjG8Omw1MgG8AM0uSBUDSnCfk/IGCHwf3DCD/7UhOLBrFkDuep/hDUSSCv1iYo4rIfqGwmUSNJjfYbBcQKhZw0aBMA4B48LwBhBt/cON80HmM9NQ6fXg/Wlku4TwmNWDzaQqzHG+0PSKod5cH5Vh2RiAhYKc8DlV1UPSyuFMGygVlMg1/P6BC6DqXQK8jNZDXAYA1f21V34wMXYFaiyVw0rJyzLgs3VMkxOjGtix/V0XWChZ0cI2i/dzvXdfTd0Qf91BMPrhyNzgKfOmxaWypqaDXHfAgwAtCL8XOfF47gAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-hpp {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAehJREFUeNqEUk1v00AUHK/XKf1yZdESVRBXjRSRFqMQVBA5Ic5I3DnwE/gpnLnyG3LgXglx4UDDLZS0RWkDLiRxSusk9u6GXSembmLgWZbX7+2bnZl92mg0goo3b3ffO/ncdvyfjHef6q2Dlvs8Q2ktzr16+SL60jhhZ69bO8X8ClLC7w9XdKJVG8fuM0r1WrJG4gXjgqU1D0MGc2kBTytl+7a9XmWcl1IB/hZKEhccq5aJJ/e3bTu7Wg1CVo7rNLlRhUh4oMnXoDoyhoHGyWmUe+QUbELIa7W8CjAFlMzdzeckCwFN06ATAn8QmDMMMGlMuwWucpoCHNe4jBkAMenjYvRPTyi53JvuwX8AplleAeBcRFrH6rXIxLim9I/pi3QA1RhKaYxdjkN8IwalCMIwWs9ljMkh0wzk+9M7w179C3LZNXxve2h+c3Hu91HeKmD/6zHOLnw83ilB1/V0CeqU3Q81LC/O41b2Btx2N2JVP2riR8eTUxmi0TzBwrKZMsqMoz8MsDh/DWuWhUBKURLKxQIeOMWoptYPnS1c+INZBkwISomOSsmBZS7B+3WOzZvrKGzkMAiGqNy7g+LmRkRfekBnANy2163PZXrSbrQ6vch19Xz8fPDHyL39QzkHBKedXjfu+y3AAGU37INBJto1AAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-html {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmBJREFUeNqEUktPE1EU/mY605a+hhZTBNKRDApNrWIRA4nEBUZdmCgLNi4MK5f+FNdu3bFv1J1EXODCR1JJSMTwpqUP6NiCpe10Zjz3hj5Mm3iSybl37jnf+c53jmDbNpi9eb+6Ftcisea909bWNzNb6dwzSXKkhIt/r14+515qBqmDA8HpqKagh53XaopblpIbe+knDpFAhPab2Dw0TKvRK7lmNODzePBgZlK9oUWSpmVNdpIU8T+jaMsyMaD4MDcZVa+NhJMN00w0n6V2nN3yQgdHWZag+LzYPTomIAtT0THVtPGanmb/BbjwLFkvn2IttYGYplKyDzsHh7gdmyAWfh5zVq0Guhg4RAHFUhmfvq3j134aXo8bd+ITnMFOOovU5jbGRoZwNxFn1cxuAIcDW/sZDjA/c4u+BNxOJyxqaenpI3z88gMfPn9Hv98HQZS6RazW6kjExvFi8TGdDSy/W0Emf4LS6R8sv11BmfzSwkPcm74Jo9Ei0GZgmkw8QCOao8OXcaz/5vSZnPdnp3ApqBBLkWJE0Ci7ASzbIhCLLQ1E0iOkBDh9NpUgiUejo8oNuJwyn0YPABtn51UYFFivG3yBGCNZkuDtc/MW+ZQI3OrYpBaARCKufk3B5XIiWyhiL5ODp8+FfFHH+KiKSqWKUL8fC/NznGlPBmz+24dZjKnD0CJDcMoyW0SqXuMtHBFw7rhIAD1ErNUNafxKBNevapwu65NpEQ4FqXIA+RMd6VwBP3cPSERb6gLIFIq61+UqGWaFdcrVt/lmAuWjAi2aiMFwmOYuIJ/N6M28vwIMAMoNDyg4rcU9AAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-ics {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhRJREFUeNqEUkFPE0EU/mZ2dra7bLNpi2AxQFKalkJrohICiYkXPagXrx78Df4K48GDBzmQePLMhUODNxQ5ciEkJVqDtJGmMWrCATRbd2ecoS5u3aovmezsvu9973vfPiKlhI4XL7c2r5YL81LIELEghLA3u/udxmHnPmfGW/Wuv+LpwwdneRYBx7PeWK0wOYYhcXxyckGV1fdbnbuMsXcklqPRJQxFMKz4RxDCtVO4s3xlRjWoB0FYjlQPEEBieChwKCRGMx5uLtaKs1P5ei8IKlGa/YkXMXYtlTEDlsnw/mMXhBJcqxSK6vlcpa4PEpCooUyIqs5M6hG1o2CUwqA091cFcYLf/sjzcX75EiQIojI9779CTYR4jwTBf+r7GAwh0AxCiL6JMT/04vQ79u8aI2O/7Jzg69o6Go8ewycUahtBpADhHKLnK/eVbkMdtROWIv80NQ2sPhncA9Htwn+9hZG0rY6DzFwJl+7dhs0ZstUy8rduwPS/wd/ehmi3kwq4zTHiWUgXp+EuL8FvNvFl5Rn4xAS86iyI2kY3n0Mv48ByrOQmancdi8I0Kcj3U5iuA29xAelKCUHrEIayzltagG2E4IwkFaQgSC6lYI09iN0d8It5uNV5nG5sgJdKYC0G8WoTOZvBISFNEBxnsuzD3GX4vfDsszzqAu0jkJQDedCGbB6AWg54pYbPo+NGVPdTgAEAqQq70PytIL0AAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-iso {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjlJREFUeNp0kstrU0EUxr/k5qbJzdPYpGkpsUJoA2q1oLjTdiGiIC5cuXHlxv9BEOrStTvBnQvRrSAIsejCrlqpsURq2hCJNQ+TNLm5uc/x3MmzJh34mDNnvvnNzOE4GGOwx8+t9XQkfn0VE0Y5/7Z+kHm+dvOhtd3P9c/xwNZh7nWaMYtNUmX/Fct/vlN7/8J5aRRgyzm8xzpRDjGE2aVH4VTqdnoUYg/XkEhmy+Cx3DhA5tMzdFolvg5Mx3Fx9SmH0JIg79Zo3j4GADMIokJTKtjbfAKXU4Y/2NvSfyH75TFOxa9Cmr0XnlPFl5ReOQ6wNMDsoFX6AElqQlNV1KsOuNwS/AGFjEUIDhmn5+/DMM16/9igBowAzFKIswPJr6MjlxFP3sV04gaP7RzMPe6xvWM1gNUBM2UKYlBau3QghGphg29J3gDlLLilWNdD3gkvIIDRhD9yGe2mCV0V4HFXuCxT5Dlv8Dz3sIkAs03FalDxBMQSt9BRBMhNncuO7dyU28c9tnf8C/Q0ZtR4GImeQSj8APLRH772BWcgiFODffCv/t8H9tO0v3RjV7VqkeeXLlzDfvYjj88uXhl4JwIsrYxmLY/M1gYclIvGE9jZfNPrSCD3/QgLyeWTADV6wW9AryIcCkB0u1Aq/oCPumlufoF72vIheaLDr4wCLIOqrYnULA14PSoqpSJEAUilZrD77Sv3LK+cI0+Be8cAbbmAOrob0agtD491LYfkoqvnyZLsWRkA/gkwABL4S3L78XYyAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-java {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjxJREFUeNp8U01v00AUnNiOEyepQyhQobRBSlVIoRCBEPTAjQsSEneE+An8FM5cuXLNoQduIAE3qopKNJAIIppA2jrOR93aa6/N8yZuUxyxkrXr3ffmzczbTQRBgHC83nj3ca28dD36nx6fvnzrNNrdp4oibyUmey9fPBezEgWVFuYLdyvlPGaMY4fl1aRS+9pqP5ElAkmcnknRwuO+Nyt5u/ETYfyj9WrpZnmpxn2/Ok1Swn/GvtnH5k4TLue4kNfxoFoprRQv1TzOb8cAIu3+ZD7oD/Hm7XuxzqRUNDtdkuLiTmW5tFxceBXlnXgQTAORSMt2oGezUJJJrK9dFWdEH7Ik4dB29LiESeUEJXd7/dAT3L+1ivlCHr8NEzutXTBvbJPPSdO/AH5wysChwM/1HzCGlmAzOrKxu2eCud6Z2Jke2MwThpUXL6Nn2ZAVFTlNw70bK0iRnGAq9qwHtOmTRpsx1NsHyKRVnNPnoMoK9kc2BjbD4vk5JGV5NkBoEPM4FFnCteJFWOS4ntHEfphQyKaFTWFLw704AJ26ZFx/ZEEi3YyY0O1Dmr4EKTUHA8hUnS6siI0DEHLYog+b28RCRuNXR/iQUpPUEQ+NVht6Lodnjx+GXYgDSFRnq97Ed2pXSlXhUSeGhxYc5sKlNXM5DGLR2TMwfZVPAIi+otGNWy1fEZUKeo4qc4ysI+F8VksLIJfYcD9QYgB/DNPMptWBlsnBIS86xmDMTBo/PWd0LB6VZfdEbJT3V4ABAA5HIzlv9dtdAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-jpeg,
-.ipfs-jpg {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8luUlEY/s4dmMpkWxRopGJNNbiwhk1tItbGtXHr0hcwmvgOdWld6Bu4coXumtREE3ZKu8FgOlC1kIoXtC3jPfdc/8PUIpzkBM7wf+f/hsts24YczuerGUc0moBlYTAYA+i8sbdXtAzjITRtq39kr73s/Gr9DTUYPOeamwvYnHdrdR0SnDebuCbswJGqpX+Uf92Hqm7hzFAG/4TgNr1uCwEJ0trcBC8U0Kb1/PQkHt9JxSLnL6TB+Y2zAIMOJBGLXmtsbEAYBsx8HnqCGKVScAX8uHf5EpqmGXv18VO6VDEe0PXsKABN8+AAgiabmYFNNJTDQ2RUFc8+Z9G0OPR4PKYwvKari0MAgiY/OQGCAajhMNR4nDZMaInrKBGl70SPMScck1NQG3X/CAWLE3/dAWV5hRRVIJxOWNksrP19sFgMqqAebUGYHMI6teq0A9oTVAhqu2sfbYYjsL7lCZ3683gA70T3TK7/B4BNoO020GwB9TpwfAz8LgMtWn/NkV8EHgoB81c7nYwCyBZlEVkHcqMTKFnkmehJTOPvEfCnKi0fAyADJKfXC/h83TaZTJjaa5lANLpOFqAXtlEAorAwO9u5syT5UxLfU0e3o1FMu1x4u7ODYq02BKAMAVSrSNLrK1MhLPj8mNF0vFm+C1ZvwKBwXXE4AGn1WAASazESwUW3BzUSMeJ2o1Aq4sPurvQYSRLwlhRR6mSaYyi0WlpAJrFRx3ouh5/lMt5lv8BLwXp0M4lSpYL17e2uK5wP6lj/c2ZPn2RI+YT8fDvqoyegVLyfG5kBKaQQOfvF2pLc+ifAABiQH3PEc1i/AAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-js {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RUQ5ODY5Q0NGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RUQ5ODY5Q0RGMTE4MTFFMTlDRjlDN0VBQTY3QTk0MTEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpFRDk4NjlDQUYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpFRDk4NjlDQkYxMTgxMUUxOUNGOUM3RUFBNjdBOTQxMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoT8zQ8AAAJdSURBVHjadFNbTxNREP52t7S0bktbKFAvTUVaw60YqkExUTD6oD74qC/yD/wp/gh885XEEI0RAyYQUiMpIBGMkYR6o23abi+73e2uc04v1LROMtnZPTPffvPNHMGyLDB7sbJ2ciUSli3U35smkK9t7x9v7n2dD/g8KUkUwWqeP3vKz23NxJGzgwOx0RC6mSgIo+WKuvP56MeUzy2nJEk8PWsGJVVTuhWbpgmHw47FB7d98Wg4mVWK52o1sxOg3Va3PmFp+Q2PdUquaFUM9/vw+O6cP3bxwm46Xwh1ALR3/vL1e+hGjcc9koScUsTSq3coVDQsXJ3wzo5HEs3clgZNMTVdx1T0Ep7cn6//QRQwMhzA6uZHLD5cIFEFSKIU+G8LK+tb0KsGZKcTJoEyP08AbpcLy6sbPKdQrigdAGaDwWxsDH1uGbliCYIgcM8WFPg8Mq5Pjzdyu4jYbCE44EepXMHuwXe+A8x3KKYxYsjvbUzmlPGpBmYdgI1oYjSMbL4Ao1YXMkcM2Dd2xnbAamPQAqg1GORLZdycmYTdJqFKk2DPR3fmwI4zBDrg9RADqxPAbPBif2WTSB584/3/TGegEOit+DRcvQ4OZJi1LgwIQKVCg2i6nb1I7H3Br3QWqT9pBAP9uDY5xjdSM3RqxeoUkfVnEOW8UkLykERTNXjkM7h3Iw6NNvHw6JjuhAhVrba0+QeALozcI9nQR0VvNxJc/ZmxCNGvIBQcpDG6udA22kyW29HC72wu8yG579ZoiSYuR/ly2+y9CA4NceWLmo717T1i5ULqJNtapL8CDACskxPFZRxLwQAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-key {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlZJREFUeNpsU11PE0EUPbM7u/2AtJUWU6qiiSYYo5EmmPDCD9AH46sx8cEnja/+CB989z+Y+MKPgMiDsYQACcbaWBBogYD92t2Zud7ZlQZsbzKZ3bl3zj3n3IwgItjYeDO3MlWme0bjUth8e8/fO2tHzx3XqUEk50uft+Ndnhdmc3SlfNPkVZT8Cy600DoIISvVfKYtlvfX1p66XmoIYsMZdjJQWvEFbbsC/S5g2QhSkKUK7rx6OzvzqLpsovAhaAxA3DUBQn2TUFsl7KwTfm4Z9DoO5LW7uPXi9Wxpfn7ZKF09vyPxX2iWcNRkKGZz0mQWKoNs8AVB6x1yRY2pYnc2LLofuXTxMgAlmlXIfngCxNxEzM+DPv6NQa2BygLgZyX6JT83ngHTN5GAL0WSoUQkSQnXkyBh/k0GegTAaldM20sTKvet+yyhIZApECamL0jUSe3oFChx3TopM4TeEQP2gc6BgGIwb4KGNXRhCkMGxgg2kJeybRiZM45D8W61qEAknSmpHStBhywu0nFVupSCTAcM4ECwqapv+NQ6LS9JGALoMIIoPYDjZiEL1xHtbyO39AQUDaA7R1AH23DSeSA4hv5RG/VAhxomPYP8sw9A4TaC9iHkjUWmrtGvbyC18BLe3GP0m3WW4I5hEBEnPIStXzyuFIxb4EkMEJ79Qa/xHbKxCdM7xeCwzUZOjgEwnuzt7qLz6T3cySmQP43uzjeIiTJM6io6W19B/NLCKMVGCzkCoLR/0lrfOI2fNy/huKC1FTsK/rbGNeMRC8dHpHByfu+vAAMAL/0jvAVZQl0AAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-less {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjZERjZENTJGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjZERjZENTNGMTE4MTFFMUIwOEVERjQ5MTZEMkVBREUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGNkRGNkQ1MEYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNkRGNkQ1MUYxMTgxMUUxQjA4RURGNDkxNkQyRUFERSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pl1w97IAAAJhSURBVHjahJNLbxJRFMf/wPAIMIxMkUI7tS0VYqlGDLGhjdKkqyZ24cJFN925de+XcONHaHRj4k7TND6SGo1VWwmp2kSLhlqMDbQ87gzPYcY7k4GgoJ6bmdw598zvnvM/95pUVYVma+svcovx8yMnFZHAMJPJBJfDzq5vpX6+/vD5qo/z7DOMBdo/d26t6jFMJ3iY51jBz4M+LP6wxEw40Gy23qYzB3HO7fpmpZCOmfEfa7Xb4NxOrC4lvbPToe2yKE3K1PdPwNOtHdx79ESfq4qKkijB5/XgevIyHxEC24USmewDqD2ABxubaLRkfW6zMqjWGlh7/ByyAtxYnOPnL0Q2+gGGmKRaw8zUBJaTiS5QOO1FJnuIAM8hciaIWHgi8NcSNt+loVDY8JBXh2ojJAR1HbTSNFMUpV8Dxcjg0nSYBrtBxdLbqI1iheCUh9XXNGurAwCdEkb9QyBSFam9TDfoPZ1LUg1BH28IiwEARTVAQOzcFKRaHZpLoa9avY6L1Gfs0c32t4PU6W2lWsV8LAorw0Cs1nXftYWE3qZGqwWHzYp2zzlgetuolVFvtiDLbRRKFTAWCxx2G/KlMtXFhWPqOzsWHJwBx7rxKv2R7mwFz3lw9/5DLC/M4Us2RwV0g3U58XJnF7dvrsBOoX0Abbej/DFKRMKI30fTVGC32WA2m5H9cQQvhYi0vE/7Wdgczn6ARA9QPBrBszcp/XvpyqxebzQ0Tlsq6llxLhe9bD4cFMr9XdjLHpLv+SLGBYHAYiVu1kNOpAaRTWbCejgiw0zGhFGSK1aw+zXbvfK/BBgAPwADAs5GpGsAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-logo {
-	background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 553 235.3'%3E%3Cdefs%3E%3C/defs%3E%3Cpath fill='%23ffffff' d='M239 63h17.8v105H239V63zm35.6 0h36.3c7.9 0 14.5.9 19.6 2.6s9.2 4.1 12.1 7.1a24.45 24.45 0 0 1 6.2 10.2 40.75 40.75 0 0 1 1.8 12.1 45.69 45.69 0 0 1-1.8 12.9 26.58 26.58 0 0 1-6.2 10.8 30.59 30.59 0 0 1-12.1 7.3c-5.1 1.8-11.5 2.7-19.3 2.7h-19.1V168h-17.5V63zm36.2 51a38.37 38.37 0 0 0 11.1-1.3 16.3 16.3 0 0 0 6.8-3.7 13.34 13.34 0 0 0 3.5-5.8 29.75 29.75 0 0 0 1-7.6 25.68 25.68 0 0 0-1-7.7 12 12 0 0 0-3.6-5.5 17.15 17.15 0 0 0-6.9-3.4 41.58 41.58 0 0 0-10.9-1.2h-18.5V114h18.5zm119.9-51v15.3h-49.2V108h46.3v15.4h-46.3V168h-17.8V63h67zm26.2 72.9c.8 6.9 3.3 11.9 7.4 15s10.4 4.7 18.6 4.7a32.61 32.61 0 0 0 10.1-1.3 20.52 20.52 0 0 0 6.6-3.5 12 12 0 0 0 3.5-5.2 19.08 19.08 0 0 0 1-6.4 16.14 16.14 0 0 0-.7-4.9 12.87 12.87 0 0 0-2.6-4.5 16.59 16.59 0 0 0-5.1-3.6 35 35 0 0 0-8.2-2.4l-13.4-2.5a89.76 89.76 0 0 1-14.1-3.7 33.51 33.51 0 0 1-10.4-5.8 22.28 22.28 0 0 1-6.3-8.8 34.1 34.1 0 0 1-2.1-12.7 26 26 0 0 1 11.3-22.4 36.35 36.35 0 0 1 12.6-5.6 65.89 65.89 0 0 1 15.8-1.8c7.2 0 13.3.8 18.2 2.5a34.46 34.46 0 0 1 11.9 6.5 28.21 28.21 0 0 1 6.9 9.3 42.1 42.1 0 0 1 3.2 11l-16.8 2.6c-1.4-5.9-3.7-10.2-7.1-13.1s-8.7-4.3-16.1-4.3a43.9 43.9 0 0 0-10.5 1.1 19.47 19.47 0 0 0-6.8 3.1 11.63 11.63 0 0 0-3.7 4.6 14.08 14.08 0 0 0-1.1 5.4c0 4.6 1.2 8 3.7 10.3s6.9 4 13.2 5.3l14.5 2.8c11.1 2.1 19.2 5.6 24.4 10.5s7.8 12.1 7.8 21.4a31.37 31.37 0 0 1-2.4 12.3 25.27 25.27 0 0 1-7.4 9.8 36.58 36.58 0 0 1-12.4 6.6 56 56 0 0 1-17.3 2.4c-13.4 0-24-2.8-31.6-8.5s-11.9-14.4-12.6-26.2h18z'/%3E%3Cpath fill='%23469ea2' d='M30.3 164l84 48.5 84-48.5V67l-84-48.5-84 48.5v97z'/%3E%3Cpath fill='%236acad1' d='M105.7 30.1l-61 35.2a18.19 18.19 0 0 1 0 3.3l60.9 35.2a14.55 14.55 0 0 1 17.3 0l60.9-35.2a18.19 18.19 0 0 1 0-3.3L123 30.1a14.55 14.55 0 0 1-17.3 0zm84 48.2l-61 35.6a14.73 14.73 0 0 1-8.6 15l.1 70a15.57 15.57 0 0 1 2.8 1.6l60.9-35.2a14.73 14.73 0 0 1 8.6-15V79.9a20 20 0 0 1-2.8-1.6zm-150.8.4a15.57 15.57 0 0 1-2.8 1.6v70.4a14.38 14.38 0 0 1 8.6 15l60.9 35.2a15.57 15.57 0 0 1 2.8-1.6v-70.4a14.38 14.38 0 0 1-8.6-15L38.9 78.7z'/%3E%3Cpath fill='%23469ea2' d='M114.3 29l75.1 43.4v86.7l-75.1 43.4-75.1-43.4V72.3L114.3 29m0-10.3l-84 48.5v97l84 48.5 84-48.5v-97l-84-48.5z'/%3E%3Cpath fill='%23469ea2' d='M114.9 132h-1.2A15.66 15.66 0 0 1 98 116.3v-1.2a15.66 15.66 0 0 1 15.7-15.7h1.2a15.66 15.66 0 0 1 15.7 15.7v1.2a15.66 15.66 0 0 1-15.7 15.7zm0 64.5h-1.2a15.65 15.65 0 0 0-13.7 8l14.3 8.2 14.3-8.2a15.65 15.65 0 0 0-13.7-8zm83.5-48.5h-.6a15.66 15.66 0 0 0-15.7 15.7v1.2a15.13 15.13 0 0 0 2 7.6l14.3-8.3V148zm-14.3-89a15.4 15.4 0 0 0-2 7.6v1.2a15.66 15.66 0 0 0 15.7 15.7h.6V67.2L184.1 59zm-69.8-40.3L100 26.9a15.73 15.73 0 0 0 13.7 8.1h1.2a15.65 15.65 0 0 0 13.7-8l-14.3-8.3zM44.6 58.9l-14.3 8.3v16.3h.6a15.66 15.66 0 0 0 15.7-15.7v-1.2a16.63 16.63 0 0 0-2-7.7zM30.9 148h-.6v16.2l14.3 8.3a15.4 15.4 0 0 0 2-7.6v-1.2A15.66 15.66 0 0 0 30.9 148z'/%3E%3Cpath fill='%23083b54' fill-opacity='0.15' d='M114.3 213.2v-97.1l-84-48.5v97.1z'/%3E%3Cpath fill='%23083b54' fill-opacity='0.05' d='M198.4 163.8v-97l-84 48.5v97.1z'/%3E%3C/svg%3E%0A");
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-mid {
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-mkv {
-	background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M7.5 91.1V71.2h6.1l3.6 13.5 3.6-13.5h6.1V91h-3.8V75.4l-4 15.6h-3.9l-4-15.6V91H7.5zm23.5 0V71.2h4V80l8.2-8.8h5.4L41.1 79l8 12.1h-5.2l-5.5-9.3-3.4 3.3v6h-4zm25.2 0L49 71.3h4.4L58.5 86l4.9-14.7h4.3l-7.2 19.8h-4.3z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-mov {
-	background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M6.1 91.1V71.2h6.1l3.6 13.5 3.6-13.5h6.1V91h-3.8V75.4l-4 15.6h-3.9l-4-15.6V91H6.1zm22.6-9.8c0-2 .3-3.7.9-5.1.5-1 1.1-1.9 1.9-2.7.8-.8 1.7-1.4 2.6-1.8 1.2-.5 2.7-.8 4.3-.8 3 0 5.3.9 7.1 2.7 1.8 1.8 2.7 4.3 2.7 7.6 0 3.2-.9 5.7-2.6 7.5-1.8 1.8-4.1 2.7-7.1 2.7s-5.4-.9-7.1-2.7c-1.8-1.8-2.7-4.3-2.7-7.4zm4.1-.2c0 2.2.5 4 1.6 5.1 1 1.2 2.4 1.7 4 1.7s2.9-.6 4-1.7c1-1.2 1.6-2.9 1.6-5.2 0-2.3-.5-4-1.5-5.1-1-1.1-2.3-1.7-4-1.7s-3 .6-4 1.7c-1.1 1.2-1.7 3-1.7 5.2zm23.6 10l-7.2-19.8h4.4L58.7 86l4.9-14.7h4.3l-7.2 19.8h-4.3z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-mp3 {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra7XWxpSsFYIbVQf9REFBHkYBRIPJh4wrN3DsZ4MPGP8b/wUCIHEw5EY0w04o9ILcREGmwVgaXbbXdnd2bXNxPahGyczebtzrz3ve99740WRRHkWn5cebu4cH6SMY7e0jRAHr9c3WxsVvcemmbys9yT6+uHJ8oaPefypdPDD5Ymh5w26wMkEho8JtDtuEOZFCrvN/4uJZNGH0T59D58X/C27aFNAL3Xthmsww5GCyN4+uzu+OLtQsUPxPQx6ZMAoQjBAw7O+bEVCMMQgqygs+LFs1h+dGd8bna0QmXO9OL6JYgwAvOFZKKoy3V44CgNfv7Yx8oLH+lUEgvzF8Ydhz+n41snAGRG5gUEwClzhHdvttFxfNyYK0EnJozKK5eGcf1qHo1GOxtjwI+pfvm4g/W1qtJgerYE2SXJSIL9+W0jk0mCShAxDXgQKgbNXxZq35vQKCiKQkSUXdc1+gcch1FHGPmKuIgBCdc66qJQHMG9+1NIpUylxxHtuW6gEiTIu+N4yjdWgty0yTmdNjFzcwKjY0MU7MLt+IjoSad16FoIx3b/A0DZ7FYXnsdpAjUMDOjI5zPgfoBsRodhhGhZHfBBU/nGAGRtxWIOg5lT2NtrI5dL0SB5KJzLodloqXaOEatPGztKq5gG3S5DNjuAK5NjKJfPYKI0okBkSdemCiSgS/rkQNLSePtxBj4LSCwfFtE0krqqX7ZVMnu9XlMXy2l7ME0dzA3iANQyY6vWxC61UY41zTyNcYh6/QCNXQvzi5dR39nHVq1BUyuMGAARsF6tbbe4iKD1r7Om5iFBdmW1SsDflLiuB6sX90+AAQDHAW7dW0YnzgAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-mp4 {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnBJREFUeNpsk99r01AUx79psrTrujVtbceabnZs4DYRHSoMh6Dgq77rn+AfoA/+If4Bok+C0CfxVRDBh+I2NqZzrpS1DVvbtU3SJPcm8SSlsJlecsn9dT73nO85V/B9H0H78OLdt/LDlQ1uMYybIAgI9n99OWxoe83nkiz9hDDae330JvxL48O51Xxm/enNtKPbVwAh0Ec6kYpXat9Pnl2GBC02HrjM5Y7h4P8+7FtIFVJ49OrxUnl7ucIdfhv+BIDv+fBcj7p/tXMPrs2RXVTw4OX2UnFTrXCbbY7tpMsA13FDSDAOQ4gJEGUJLs0PPh9CkESsPrmxxEz2lra3rnpAt3G6adgdQhBpmeLkFodNmsjpOPoXBrQTDcmFFNS7i3MRDzzPCw/vva8ikU+COQxm14BBhvJcHLGpGPTOAJxxeLbrRgAkYujBdH4G5oWJWXUW19YL4XqunAMFhnq1BqWYgaY1MAHASQOiU96zKzkU76mwehaOvx6h9uMv7KFN3RopL4oTAI4HRh4wSl399xla+00YbR3yrIzM9SzSqgJJnoKcklGrH08CcJjnBtLLCsSEGGpSWJvHtDKNoFippsJ0ulIsDDUCCATMlBQkNuahEyiZTcLsmFBKaQxaOk53TlHeKkM70AjAooCghBOk9sKtIvqtPqS4FBaRnJSRX8tj2DOh3lFB5Qw2ZNFK5LRo6w4sKt2ggAzywidAMN/9uIPSZglBLDO5FF3mRD3wHE9qVRvoHrUpfn+UEQK0/7ShtwboHJ6jdH8RZxSC57hSVETb7e5/2u0FxqPHJow+8iZ4lYY2QGu3idhIxO7Y7p8AAwALCGZKEPBGCgAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-mpg {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNpsU0tPE1EU/ubRdlqmnUBboa0UeUQDiUGCC1+JmrhxoXt/gBvXJi74If4AV0Y3sNKF0YUaICqoIfjgVShEiGF4tDOdO/fOeOaSKtie5GZu7pzz3e/c7ztKGIaI4vn9p+/P3h4e4a6Pv6EoQBDiy7P5rc1P1Xt6XP8M5ejXo6UJ+dWbuemeTGdpvNdiNe9YvQLe4Bi4PmTpRmyq8m71rp74BxKF2twIHvAo+f/l1T2Yp0zceHizfOZa/xRnfBRhG4CQqAYioBWeXDyA8Di6ei1ceXC1XBwrTXHPH2vW6ccBBBMI6BsSUEQzakGL6xB0tvjyBxRNxdCtc2Xf8R9TyaWTDOg2TjfVdw6hqIoE9B2GxkEDWlLH7s4ette2kSp0oDRezrQwCIIA3oGHr0/mKMmE53qo23W4+w5S+Q5ohob9X3tgHgO8ULQACC7gMx9mKQP30EW6mEHpYi8xcJEdzMucjfkKcrTfmqmiFYBxCF/Id+gayKJwoQjHdrA5v4HK7Cq44KjZNWpagaqp7QACks0H9znW365ia24DzoEDozOJbH8eVtGShXHTwNracnsG7q6LzsEuaAlNPm9h7DSSVjLyCMkppDI+GS2StQWA1RlKo0X56n2X+6QHkmkDakxF9WMVqWyK+s/BrthYfvWz1Ug+zUDcjMPMm0h3pxEjFma3CbIuCud7oMc0LL1ZgmElpGJtW3B+15HIGNITrMYIlOH7i0U41NrInREylYbu4R5qQbQBaAh95fVKZCnpQCnb9DrWZyrRERS6NDeUw+yHaXh7rt4C4B8y+9vkwn7kwKNRpDoa9aiFKBYnF+RcREqQ2e1m3R8BBgAy9kz9ysCE6QAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-odf {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAi5JREFUeNp0UktrU0EU/mbu3FfE1KRRUpWYheALNBURUVy7cy9UkO6KW/+Lbt0IPsFui4gLBbUqFaUuXETUKCYa0jS5yZ2ZO557b5MmTXpgmDPnfOc7jznMGINYPi0de5UvmpORxpjE/kbNqW005DVu8TWw1H758ZfkFgNgJmtyxSPRjJIj0QTW/RDiYGXGb7Dl32/eXrVsd0gSCx9miqC0ooCdp69g5Q/h6OLN0ty5ynIkwzMwUwh2FwMdcbDiCZQXlkqFCpEoPT/wih1YjLInANcD+/Ua9bu3wJlGvrBZCmet2+S6ME5g4oGlZ9A/I70XCDhhDexPNTFmswJBwcnuXkF86VSNZxVu0ukLSGnBcqlnN4HoCQIaIuIv7LUooMOgQ7q75LAAb59B9gCBHSKgqemRr94mMKmD24CfM8nb7THYGQNLpAkUkcb66JyGBFFEWRVL57gFEH5qj8Lxwca2qS3EZaugmzAw24dR/XQgwtsCSBjPIdWbUoE2UJLBnV8Ac/ciWHsK9/glWLnD6K2vgPszsOdOQdfeQ1c/ThKoTgDn9A3KUED/52d45xchZsvorD6Bf/Z60riV3Q9Z/0bbGU1uopYGkfERSQ3VbsMwl0qlqoIARmSoPYXWy0dor79LfBMEEd8jGs/uQ3Yl7PJFNFbuEXiV2riCf88fovXhBbo/vqP3t02/ZYmJFqTkzY160Go9uEMbFK8hR/NrdXtFuUVmnmySVGgO4v4LMAAjRgmO+SJJiQAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-ods {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAetJREFUeNqMUj1IHEEU/i7u7Z23e8tGgneGQPw3hZDkkhQiSuwMQREba4uUgpVlCrvEQhurkCoWqcQQ0oTAaYKNqJygGEwgHCSB6Knn7eXcdX/GmdHVPWYFP3gw78173/vmvYkQQsAwNvckq96UnyIEh7/d4t7uUd/8y+85P+bXSX4grkhI6nJYPW7LrXpBK2YxiSoShhu4Buq1NPofDeqdrZ3Z4cl7D4J3UtA5VyVAlmJoru9Af2ZAp1lcCQ3nqgiuKmbY3l/BH+MnHM9GVLP0Ww3KNA33CQoQQnL834Fj74PUGkANEIkCSSsa8gQqgYTIcB0PVsXB318GInRiCVWCkpRFAs+j5gKlA4t29Ggh4d0t04FKt9PQqF4UFgumSEA8ApeaElilWbYRVy/lsns/N1QBkxtENF4jxPxcgcB1CZVOrvMteK5IQDtJJIGh++PcX9iYwWjXK37+vP0WdYk0Ht99jtX8JywWFkQChw4tc+cZcvlF7rMze+ubbxN40fMalRMDP/6twaiUeK7wlZ0TD0a5hLTWxo2d45KKprqHKJslTsy209s2wnMFBTYNZjc/oLt9gPvLOx+hxVJIKS2YW5pCbSyJTGMK775O8VyBwDJd2LTDl/X5i8v3S7NVw9vJb51tITDEUwEGANCx2/rXEEFFAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-odt {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAepJREFUeNqMkz1II1EQx/+7Ca6JkqyYiJ8cKEpAQbBQFDm0sVOsFBS9wt5KOTgEG5twxVlZ+XEnKNiIghYKxx5nwEpIIXaiSAgKGmMi0d23u8+3T7OaZJEMLG9mmPnN/w1vBUopLPNNhRWXHOyDg0nx82TiJtZPlPVoNpftc2cTotcHtxx06kdXpSQ/BvzKESZzIDmAz6y+NojOjpDMZiqRPIgNoFyWM8DrKUV7axO+gcp4g7AzmquAdVNqOgL2z2I4id1B0wgeygOyt/rLL5buLwAIDgA9dY+L+DkuDQOCrkMgBsRglcMOqAGwIstMg8AkGsuZMNUMRMkLqE+QGloglvlA7uIOAKvZajR0qJkUj/XHe0BTIclVKKlrfKsj9qA8gA6wqSJzPaXlr7ky//tdLEUfawsBjExUFGVWbT7AxSa42H2LMfODmvd3wKb7RAMLYwM8nts8xJ/pEe7/3PmP2eGv3D+9usb35W0bINoA7RmjXSHsH0f5Z/mUSZ0Ir2JmsBtD80s8/rGyzWsLFTD5yUQCbfUBHl9d38LvkdDTXIuHVBo0k+bbt06qO+yAPGXwe/cA4wO9PN44jKDG70GougIzi2tQ00ms7/3lpwnBBgjZ37Kkd1Shht5XzBIFl/ufFtniT/lFgAEAU//g6kvdGBMAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-otp {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAcJJREFUeNqMkssvA1EUxr+ZjkdbrfFKVD12ErYSRELY2fkH+BMsLcQaSwsrSzZi47EjJEQkEhYkFlhYSVtFpdqOqpk717l3jKZmiC+5mZlzv/s795wzCuccQncz3YeRBj4KHz0/RrOZe2NsZPP20o255zQ3EAxzEAC+6uzTw13G4TFQAakA/CWtIYbY0KBOrx7IvwDQqlHV1o3YxKTOvyAUvfQCfqmA3e4ikyS/zRAKvOot7eoSHEgZIHrCfQAfBqBaKQQDKScQAExd8emBANg+2U2CvNMkkgSqBmrCxFB8mujeoJBWwEqARcssKTAJEGrmaGrjqK1zvNknH4BtyxKl2VUpRxmj5W+x73q9AEaZrR/ND1EJluIpS3i9JQiA+a+hSq8HwJjTsLrRaWitPTCOlhEZn5N75sM1qigmlN+dB3u++Qao5W4TtbEXXIsiszGL4PA00itTsu6XnQWo0TjMTAJqfMDx/ryBJcaVzSNSH4fW0Q+rkIf5rsjRiid7yyN7uoXS3Zn0egE0NiORAN9bQ017D1Lri7CLlP2EDr3Rf7C/itzV2bfXA/igLDaRixfngFhSCooH2xVPCWBlwKcAAwBX1suA6te+hAAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-ots {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAfZJREFUeNqMUk1rE1EUPS8zmabJdDKB2glEwY9ExJYiBUEQpV25qgtBXfgbpEtXuujKf+AfEKRddOdOGHClbYVCvyKWaijT2mhjphk7Sd7Me76ZONp0EsiBYWbOvfe88+69hHOOAE9f3zTVnDKNHvhlsfqPw/rM0ovyWsRFdXJEpDIyRnSlVz0KSkmvabaJeXSJBEhgAJzTDNybmtUnS5Pmg/lrN07H5NM/f13FoMgpXDSuhiIiK3Qi6LUugX7FAbaPPsJqfIHHKCStqRsXVFPQuZgD9BBxjikSiRq41AAkgCQBzVf0+BWEBX7GBm0xgHHUqk1UbBuEcIydzyCZlOI9YEGuDxwduCCitS3Xh3viCZ4jrcq4PJ6DLHd67tjtuAAXib54dCPVEfQ5XIcik/0/2iDeOYz3ceCxrisMi904y0XiMQFfkB7lg6xFHwFxEqUMV0anUNBLWKm8xd3i4zBWOzmASx0UsiW831mA59Xjm+h7HCOygduXHqJatzA7Poey9QnXjTuoVD/j/sRcmDOWLgqnLC5A2wwST+Pn8T629lahSCo291bwu9XA7vcy3m2+gTaUR14thrk9BXasbdiOjSe3nmPpwys0xSi/HpbDd3bIQC6dx/q3ZbRb/j8BEi3Po5cTJpHI9CBNDEa++GyDBN9/BBgAwfDlCVUQaNAAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-ott {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdFJREFUeNqMU89r02AYfpJ0iVm7EqhVOxw7dDBEdpiCE1RoEZRddvUgbIex/Rs7eehppyF4LOzQu4MxwYp0HgShIuwwUVSCVtl0s13afl+SzzcpyZYmyF74eN583/s+PO+PSEIIeJZdrtQVI19Cgmk/Ph39bpllXq82g7sgLxVcyKNZpIx8Uj5u5zSjc9Gov8ZihCRC8D+7On4JczevGeTGSEIC4ctKJtB1DTPXi1iCCEkIm1EFlC2Em0iwtWfinXkIzjiO0jljtDC5TtflGIGUQMB+mfja/oPv2Rx9MMjpMdJxOXyXTwkcwIkewfqQ1QtQNB385zcI14FrtQexsSb6SRysZ4Fbf+F6eHwATc9gJGNAm5iCTL5n/LCVRGADNoeaGoHqyaXj5gqQlTODovcwNk5Aj6wXqV8eCo7EDhMonEHpW+dZC7gUG98D3geo7vkb01h9cAvPdt76OGy1xntUd3bjUxAk3+l2sHJ/FgtrT0MUJNfDSm0bjQ/72Hzxxo+NK+h3B7XRNO4UrwymQtMIkdTBU0m+sBOayLsn8Ka78mQDjx/e87HXPkb1+UsfP37+AmZ1fP/suknBb6nefVQXjl06TxMlJfWKNWr+Kv8TYAAkUueexJF47QAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-pdf {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmhJREFUeNp0U0trU0EYPTP35qYxaW6TlDapNKWGbgo2FkF8rARB6rboXusf0F/hyq2U4krFqugqSBeuAyL4SERBstHa0iR9JKZJ7mvu+M0tqZGkH3x8987jzDnnm2FSSqh4ns0VU1ybFzj674Wa3uWiWbfsFQb+jrGj8Xvbm0HlvYVRxhJprpmTlGmum+OMm5uNPZNbtjk3l82ey8++8oW4Jv/H/wdA456g2kvH99FyHNiuAz2dwflbN8YW8zMK5Go/CMfQkAhpGsyQgRCtlpE4jIULyC9fHzu7MPPEl/5ib6WOE0JJNRiHHg6j86mMjw/2gG4bkbY4PW4Yj2j64skA5FTHdaEMPiAJszt1sK0d4suJmY4k0+IDDGRfqmh0u5gejQc+fG8eYCIahRQCEfgQnIuhEkgtONE+dGxYxEDj1DhiEycZ+1YXdUpHCqTMJIYyEES5aXXQsi2kYlGEia5GtHVKn+amPBeCutPgfLALPuVu+xDVPw2EQyFEjHDghbpYNm1yKVVnYjTOerepn4E6XQmLGSPkPkOXWATMSDcjQEkAaqOu6+i/rccALtFL53LI3r0Nq1ZD4/MXZJaWYFer+PXiJc6s3IEgY3+uPYZHTAcAHM+DTE8gnM1CSyaCulv+GrRy8uYyElcu4XfhLVpkpNtn/DGA5Uu0abFH36WnzzCayWAkmYJvWeCkfb9SwY+NDbSoOx4bYqJF8rZqVRRXV/HhzWtUSmWwmWl0RmN4v76OUqGASrmMOkntSHF8MOs954dT08W248wzYsJDOujRBAaqqikTpRo/qqd0/dv97c3Lat9fAQYA4z8bX9nTsb8AAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-php {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAhNJREFUeNqMkltrE0EUx//ZbDaXNrvZzdIkbYOXGgxYQlCK2IIY6EufxGdB8Av44AdR8AP44JOPBR+Ego0PClUKTTXQSmkTYtOkmubSJrQ1e3H2yJSEJNIDs3PmP+f89pyZcdm2DcdWvn7LzkxFHmCIra7nm9ulg8yLZ09yXON55Dgjt1PM2iPs0+aW/frdh8bzV2/SvQBnCLiEqcFxLKSSodlrU9leiGPihWePBkgeEZO6ShC2dCAZNuf6ADb+ldQ5PUPx4BCFcgXfdwq4Ph1Dtd5CZi4Nw7SQiMdCXkl6yVIy/QBWgcU+yx/XsLK2cdHndqlK/lZxH/OpJO7fnsWY3z/YAq+g0TmHpoUH2vB5PXi8RD9Fo10aAmDJTgWyIuOupmK38rsPcOvqJO33XWEvwLJsmKxHRVEwf/MKWl/yUMf8mIloWN8rw+sP0D6PHQmYuzGNgCRiMZVA17IQV4OIaTI8buH/AJMFd02Tkp05PO4jnWvc57EDAINt7u1X8Pb9KgI+Lxbv3cFR8xjx6AQ+b+Txs/qL9KePlih2CMBCq92hg2qzt1AoV7H5YxdhdqhHzRbgcpFeqdUplpvQW4FhmAixZ/sws4BoWCM/qmsE5XqE3dDQCrqGAYWdejqZgK6GUD8+IV9VghBFN1RZJv3sT5diBwC15gncggCPJKF0WCPN8dun55jQdVpz3Ynl9leAAQAJhiGatD9AOgAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-png {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmtJREFUeNpsU9tOE1EUXXPp0CAUWmJbC04xBANNTF+kKhG8fID6aqL/gPEj9E0lIf6Dj30HL03wxQtVIC0QKrWxNG1Dk9Z2Oj1zxn1m0oIZTnIyZ8/ee+211z5Hsm0bYg29fLGpxWIJWBYGS5IA8ncKhT9Wvf4Yqprtu+w3q85X7f9QxseD/pmZMZsxN9fnc5JNw0ACGGv6tPSvyvEDKEoWZ5Y8OHHObKpucw4B0t3agnl4CJPs2YkQVu4s61ORaBqMJc8CDBiIRhhVM9bXYdVqYAcH8M3NgS0tQQsFcfdKHEbvlr6WyaR/V6uPKPy7B4DT7lUq4MUipMlJ2MPDUKtVfKZ2nn/5BoNbkONxXeb8LYXe/A9AJLNWCxgdhZJagDI9DZg9qIkEytRSkdqTSFQtGILSbgc8LViM+tc0yPfukzIyOJ359k9YR0eQdB2KmBbpwXoM3Dod1SkD+scpEapCI5DdpsJhIJcjajQZagcjI+5oLe4VkeQnyiZgdIH2X6BJ7dSqQLfrggjw0AQwP+/GegCIHppNoFAgEMO1RZKo7BQgRi3yN05cnwdA0BQMAgF3C6pnbuNg92M9AFT1diSCh6kb+FGvo2MxnBB9ocZxp4Mns1cde213B81e7xwAcl4jkaa0IUSjUdLJwkL0Ej6VSvArCt7l81iku6GrKnYEU89VJlSJRmR0Dax+fI9suYxSo4HlWIw6M3FBlnD9YhiXabyOsOeIqG7TzDeIYo6EDGp+ZPb2kKKqH8h+mkxiI5/D1/19J3bwYPvPWXq2skkiJVxesqt0XzghpKM8nRVV2Lv2q9eLIvSfAAMAaacnllcFBmYAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-ppt {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAkhJREFUeNpsU11rE0EUPTM7ySZpmzT9DNamWAtFfSiCigr+AxF9zKtv/hvf/Aki+FEi6ov4ItWHPGiwiBUKoUqqTUJImmR3M7Mz3t0kNe1m4LIwc+65595zlxljEJzdR5uf5nLmsvZx6gSvtd9W9bjhF7jg5dH9nRc/wq8YXaTSJptb0xklx7IZoKUEz1zJ2DUU69/37vFYrDxegJ9U0lC+AoIIVGg9CL+vIObP48KDQn7x0sWiVnJrnEDg7KGk+i/Ac4iUM/R7BsmrSSxtXMfa3X7el8+Kjf3KfUJ+iRJQw4w0Tc8BRyWGRAZY3rBR/VlC+XED2ayDhZyXl03+hNA3TxNQshlGLAnE44zCIL1goXZwiMNvB1i6zbC0KuAsxNITWwgNMYPeLVJiFEO9ArjHAivrAjNzBr4f4vwIgdGD4YUACsZCE8AtYGWT5jCsGQw5wEYJzP/pj5RwYTA1b07eQmfZ8P0sgdaM2FlYwWkMgMpl6NQAO33GKM0wsQWflkh1uqGVmVWblsiDkQyqxwfag35SqcktaEWTUTHYNx4iGU/C29+BvX4Lpu/C7zYgFjegSY63WySsHyXwpYHU00ieu0bAOuJbBTArBkiXKiaAmTzcvRJUV9E8rOgqBwqlY8ASs/AadbRLb8CzeTjVClqft6FdB17tL7yeCbFRBYoLr6vR/PiSEl5BZJaBD0/R2nkOZqfQ2fsKt+0SEQ+GLSIEUvJm+6jbah2+pS2aon+4g/afd4SYJVuA7vvXdC/IHQtSoTnK+yfAAIEaId1m+vudAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-psd {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAqxJREFUeNpsU01ME0EYfbtdKKWGtoItRWgJHApCBE2I0YuoiSaaeDJeOJh41YN3TfTixcRwMfEk8eDJGA+Eg0YTTRRMg02KKFooCBbTlkJLS7f7P+u3K9Xo8iWT3Zn55s173/uGM00TVlwZfzJztD92iKO5ouvQGQPHcQDN380vlDPr65fdLj4Oa41i9sFt+ytgN7o7woGOrqgvvpLBaF8vWj1NUAwGTVNRM3mf5vU/zaU+XySQuTqIFXz9hxmGLkoS7r+YxvVnrzGzlgXPDOzUZPT4m3Dt/KlIuH9oUjXYEHZZ/wOgGQZi4TZcGI5hLb+FO++TSOSKcLtcMA0dI0EPrp4+HtnfG5skiUecDGwQE2MjAwiGWlFVNDz+tIyCokJhPKYSX7Gdz2I01hOJdnY9rJ/7UwPGTEiqjtbmJtw4MYx78S/4Wa3h5UoOYwPdIOp2Xi/t18rlFgcDw6o+ydiWVRwOBnCpL0oOAMmNEhLZIgSeoxwGSWcERon/M9DoBknTIdNQNAMnO4PIVGpIFXcwndlA2OtGc4MAxml27p4AIulWSIa9QVadiYSoJxhqBJivKgh5ad3k9gaw6JdlDaqq7q5wINY4F22HaLHSDZQkBW72O9cBYFEviBIURQH7a7MN0uDisUW12ZZcaGlmdq4DwCqeTo1zNtZuW7hUqGIw7MNqSUS2ImNsKEpSdEwt5lGhfQdAkQBEoub3NNrDJfAIeBuRrcrY5xGQ2RFJAjl00I8PCckJUCB9q1URBnk38XEJEuk41tmGwZAf66s1VOh2keqwoUnYpFxHH4iKIixkN3HzVQKP3iQR/5GDKMuYmE3h+fx3MHqh1sMafztHLuiCg0FAk0uFdLqcpGY5QEXbTC/j7mIaVjc18DxufUtBJ/vcggs+3ijVz/0SYABsJHPUtu/OYwAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-py {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlVJREFUeNpsUktvEmEUPTPzTUFmgJK2UqXQFG3pA6OBLrQxamJcaYwuu3Dp0l9iXLvVtRuDpgt3JIYaTVSaxtRHsJq2xEJBHgXmifebMhECXzKZme+ee+65516h2+2Cn2cb2VwyHl12//vP2/zOQaF4uD7GWN69e/LogfNm7kUsPBFaXYwHMeK0OlpQEJApHJTuykzK98dE98O0bLM/UNgr4v32Dj1fwSQRt9dSsfmZcMa0rIv9ODaqYrPVxuPnL1Cu1aEbJu7fvIZUIo4bqeVYRzcyv/8c3SPYpwECt/dmu4ON3Ed4TymI+hQc1ZqoE+F+uQLDsnHlwkKMscJTgl4eJOi9fxZLePNhGx6ZQRRFqH4VjZaGSv0Y6cQcJLpra0ZguIWegqDiw7lYBBZV6xiGk9DQDLzK5bEyF4Hi9VLMsoYI7J6Es5PjeHjnOl5ubqHaaJGBEkzbxplQAKIgDmBHekDTgI+qKKqKLvNApgmEgyquLs1CoFn2Y4cIeLJpkjoCLkWnUSIF3JxISIUsCjAoxhWNJLBIJs3YeXj/08oYZkOKY65HllE/bkMmY504YUd40HUq2JSSyW6iVPmLiXE/ZMYQCU+hXK3h1toqdNN0sEObyKtqtDQ6kXDwcadDS2TBryp4nX2HxXjsJK6bDnZIAZem6Tp5YMMmicn5OC4lztNWtvB9cg+hQABtWjKL2jH/T3GgBcYDXEE6mcDM6SlaJAGMWkivLBC54ZgniZaDHSI4rNSqn7/t1vgkGJPwZXffSeCjk2iUWz9+nSTQN8e6ef8EGAClUi/qoiOc3wAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-qt {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNpsU8tu00AUPU5sp41NkzRxpfSZqi0VIIQqEEJUZYXECvbwCWxYsuBD+ABUFrDrCnWBQEJdIWigBSr6pqRJ1ebhxrE9M7aZmSrQ4o505fHMnXPPPWdGiaIIYrx89GKpNDdxmXkU3aEoCsT+z8W1Sm21+jCpJctQTvaerj+TX7WbnJ+0cpfuX8mQtn8GgJ4AZtIFY2Hz3foDVRcgyt+cRHcS0IARh+D/8G0PpmVi7smd0dLs+AIjwTVEiANEYYQwCHlEZyJgIQKfoX84g9uPZ0cHZ4YWmE9nuufU0wABCSSImMsWEgqSuoqA/39/swZFTWLy7vQo7dDnfPvWWQa8GuOV3IYLJXmyzDzG2/ChZ3pwbHdQ267BKJoYuj7SF2MQhiF8LuDK/Gf0DKTBKINz1IbTbEMzU1ANDW7LAfEIQKIgBsBFlAx6LYOz6MAcvoDCtAVGGPKlAiIu/F55F33FDA6W93EOAOMaMOl7biKPwRtD8Foetj5sYPfTDtxjl1f3Ubo5jkQieQ4ACSUD2iE4XDpAdbUiW9D7UsiN9WNkZgxajwbd0LGzt3keAJPUc1N5SVeENT0Ao2BKV6QzwlZeRBSKAYhe3aYHcZWn7l1EfjyPypcK9LQGa8qCvW9j9+MvaasQOHaRhGWdhsNLR8hwodYWf6B4tYjDjSOovRqq32rSYq/lytw4A77o1V2ERiAtzY5kkUrrsH+3QF2KY87ArTtQuQ6nAf4x6FCV1D001+vYersBM2vA4y1Rm2D7/Rac/TZIw4d/6MrcGAPf9htN0miJh7Lyuoyvr8rQeP9iVJcrSKgJ+TrFcyYebXTP/RFgAFQobmIOBxbsAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-rar {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNpsUktPE1EU/u68OgylZXi0hZACQU1LEKKCMcat7jTRnQsXxsQtv4E/4M74P1iriUaNCw1FgxpjCJQKKAU60+m8mJnrmSll4XCTc8+959zz3e88GOcc8aq9evChOHl/lvMoubvWX/z4+BwTlbvw7bXdg8b7h6LE1gGW+O88CRMt4XTlR6/rYxce5Xv3jlHH19fPkBu+gWy5mlcFb3Wn/umeKOEMJF5C7xCFbtA9dRXjFoYKGiTRAlPGUV1aKU9O3VwNQ74A8DQAIZxqAuAhBPIMFYpQVAVB4CPSZjEzv1weH5tbDQN+JQ2Abu488mnzIbAAA3o/VK2PwDJo7r5Fy7ZRuvi4PFS6+qIXdVYD8Jg6BUcuOD8BozSLlRWyicgVKkTMQWwUlFF0Ooe5FIPk57BD7G0SiywyjD8bCDyHsOkeeeR3SUxEkROmU6BfQYFJMHfhWXV8efkUrb13VPMTsrcTQSzxZ/+n0GVA6EGbSGdgG9vo15fg2nFgbO8k70SRdd+mahDT81vUxTZRlJBRMsjq89C0EXCvSf7TIBZ136YZUJEiE7LgJ2dN01BZuE0dkIhxE7KcQTK1QUj+cwAEyrPZ+IydzRoyah+mLy2isbWBweESJEnB9q+1RM9Ub9GQOWkABg8HjRr2d9Yh0hTlBlRsfn+D4vg0BvUC9rZqECUJuk7Tzr1zahCYlB6HJAREPwfbbMBzLBzsbUKVI0qBgQkc+SxgWUYaIAqOpKwKXJ6bgGlaaDV/YvHaFNrtDsKTfVSrJeqIg/bRNwjclFIALeP3saybhu8SC4VBHwnhBXXIKocYRXD9QzBi4Xgchmkd9+L+CTAAMqwy+ZzluBgAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-rb {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAixJREFUeNqEUktvElEU/mag5f2yJhXLwxIt0kiqsVEXujP+A925cu1Pce3WtXVtYuJCF7KtTY0NrVQIpRVKeXTkMcO9F8+9ZVooJJ5kcmbmfOe733fO1YbDIWS8+/g1dycVX7W/xyO3vdsuVKqvnE7HZ230783rlyo7bVBicSGyfjsVwozomVbIPe/c+FmsPHfoRKJd1HT7hXHBZjVbA4aA14NnD9bC2VR8gwuxPi5Sx39Cp+M0XUP0ahhP1jLhW7HFD4zze3b93ILtXYyyVKlR8/5hFbnvO9gtlrGSjOF+OpXkYviWyo8mCS4R6bqO4p86vm3v4fC4DrPfw4unj1XN6JvBaQtjChzUXK43sVU4wNFJA43Tv/B73edQwTmfIhAjCVL6UdPAj1IVFSKhCdAcAI9rnjBiAjtBYEu3GEeh1sKJ0YXR68sVIujzIhzwY8DEBHZqiLRKkicQDfvABxaiQTc4Y/C65pCOXwcjcmlvJgHtlwi4epYifiQWgmoLZwPW6HQG07LgcOgKO0UglAKOTt/E+09fwAiUWU7QAE9xUK3jbvomsispZVHMVEDSZdHo9rCZ/4VIMKAu0XGjpU7d2S8hk0pCELHEzrjKnCQOYJoD+Dxu1RyiwUm5LaMDo9NFt2cqDLvY4oQFp/QpfT/MrmI5FkWebt+NpWto0j2QmQkOjZ9hpwhqjXZzM/+7LU+cc7lRrjXh8/lVLRK5ovLWXglOsiOxdt8/AQYAzv8qbmu6vgEAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-rtf {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAe5JREFUeNqEU01PE0EYfnZmd5FSvgLYFuwWt9EgHyEaox68eDJevHvwJ/hTPHv1N/QgZ2NC4g3kUAQKFKGhjVKqRrvbnRlnht262FHfy+y8877PPM8z71pCCKh4/ebt+rJfXEz26Vjf2mnsN5rPKKWbVpx7+eK5Xu2kyMtNTd5d8MdhiJ9BOO7atFI9ajy1UyAqSPIRMR6ZmoNehNHMMB7fX/UWvEKFMbYKE8DfQnAhwRmmJkbx6M6S5+WmK2Evup2c9yUk2nnKA0XVcSiGXAe1k5beP1i+4RFCXqnPywB/AKVzK34RjHNYlgVKCH50w7EBBogbTa/AVM5SgBdn0gc2AMDjPsbFPz2xye9asweS6n+NTbG8BCCfUtLjff2WoVnVpAH6z6hMUtJE3EykYfpF4vUiL3QNS7FMeSAQRBHW3r1Hq91B+VoBQRji4+ExFsvz6Hz7jm7Yw5OH92AcJKW9G4SoHhzhy/lXbB98Qmm2oCXN5WawsV2TACEoJXqwTKOsb3BtR2ucmZxANpPB8JUhyPnHWDaDpfJ1eZFALzJJ4MKO5MEtv4TSXB7V/br8iQLMz+almRZWbvoo5q9qRlxwewCgeXbe3qrVO5ZkUD/9jJGRLPaOm6COi92TU1DbxYe9umRD0DrrtJO+XwIMABWp9nS+FgaoAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-sass {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDNDMTBBM0JGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDNDMTBBM0NGMTE5MTFFMTg3N0NFOTIyMTQ2QzhBNkQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowM0MxMEEzOUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowM0MxMEEzQUYxMTkxMUUxODc3Q0U5MjIxNDZDOEE2RCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Po72XUcAAAJcSURBVHjahFJdTxNBFD1bykc/ttvdtttWGgI0bYrUgDZoNYqRJ014kMRXHvwB/hQTH/wFhMREJfFBQxBjhMRIFEQSCAlQxKYGggiU3e3HbnfX2bFt1EU9k9m9mblz5p4zlzFNExYmpue/jmTSZw5PZAl1MAwDT0c7O72wvPdudeNakPNtOZ0tsM7cvzdOc5yN5LDAsTFRAJks/kC2PxFRVe39Si6f4byez62EpAEH/gNN18F53Ri/Ocxf7OtdLMpKT42s/ZPg1cISJp/P0tg0TBzLCoK8D7eHh4RkLLJ4cCz12AjMXwgez8yhqtVo3NbqRKlcxcSL16gZwJ2Ry8KVc8kZO0HdTKlURn+8G6PD2SZhLMQj96WAiMAh2RXFYKI78lcJcx9WYBCycICnpNbojUWpD5Y0C4Zh2D0w6hWc70uQZC+IWfQZrXF0IsHvY+meBd08haAhoVMMQFJKWF7PNZM+klhRyogGhbqxOIXAMOtEwGAqDqVcgbVkkE+5UsEAWavf0az2t0ZqvK2qabh6IU3joizDwTgwej1LdVfJXkdbK8mt2QkayO99A0/0trQ46I1lVcX+UREhnsP34yLp1AD1xibBMuntpzU8mJyi3Tc1O4+l9U06n7x8Q/8PHz1DrrALt8tlr0CrkbJMHTop9Sk5sLa1g8L+ARJdnShKClY3tunN69t5iGLYTlCtakjFY7gxNABdN3B37BaqqoYT8pyX0in4ORbRkIA46YlDRbUTbBZ2Jb/Pw4qiKFnapcpPo9pdbrg8DjAOBsFgELJmsGs7eWkkc5bu/xBgAHkWC6UPADTOAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-scss {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RkM4QjYyNDVGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RkM4QjYyNDZGMTE4MTFFMTlBREZCNDNEM0ExMTk0MUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpGQzhCNjI0M0YxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGQzhCNjI0NEYxMTgxMUUxOUFERkI0M0QzQTExOTQxQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pkf1yeMAAAJbSURBVHjahFNdTxNBFD0tLULpB91uodVWPmorUIxo0VSiNSExMYYHE33l0Ud/in+C+OSjYgjRGDBRCKJIUkIEWi0WKlja0ul22+5219lJ26gLeiezuXvn7rnnnrlrUFUVms3Mvd2bjIyezRVLBA0zGAzo6jhjm1te+7EU37rFO+w7JlMbtG+ePJ5mOaZmci/nsPl6ONBtw18WDQc9tZq0sp7YjTisXV/NFKRpRvzHpHodDqsF03djzuvDg6vHJWFAprF/Arxe/oins6+YryoqCiUBvNOO+7FrXMjnWc0WyIAOQP0N4Nn8IqqSzPx2swllsYqZl28gK8DDyRvcxKXQvB6gISYpiwgH+jEVi7YAfW4nEqk0PJwDofNejAX7Pae2sPhhHQoF63U5Gai2Bn1epoPWmmaKoug1UBoMrgwHabIVVCx2jdrKFwm67TZ2plldPQGg2cK5HheIUMbaZqKV9In6giDCy3MNYXECgKI2gICxoQAEsQItpNCHWKngMo01arTY/jFIzbutShJuXh1Fm9FImYiM7tTtKOtbO+toN9Nc+fQ5SGUOIVYl7HzPIH2YRZ0y2KZ+sVzBHn2v1mpMGx0DTaR3nzfwfGEJdybGkdo/wEigDyvxLzg4yiESvojZhfd49OAeLJ2degaSLIPOO6vwgiYaaRErTRREEdn8MeJbSVZ5M7nLdNExqFLaQwEfFfACQn1+HBWKSKb3MT4Sgstuh9vVDa+bQ4DORE6o6RlspzMk9TOPfr+fiLJCLFYr3TZSKNcI7+aJwWQmPM+TkqRg49tu65f/JcAAMwMas6WUKd8AAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-sql {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAh5JREFUeNp8kctrE1EUxr+ZyXMkoa1NBROaSkpTBE23PhZ25cql2y5duvAPUdGFS1FxIRRBXZlFQ9GVdDENIhGJxkDsw2mneZnM83ruNZlOmNoDhzlzz3d/9zv3Sowx8Ch/qlYK2XM3cEJsbH0+qjV/rd6/u6aN18b7RMFT+9aosP/Ex+0ae/puw7j36PlKEMAzctKJ3aGFamMHjV0d+wcGitkMrpWWp6hVIciEk2MAOwbUWjosx0UiFoWqJpGMx5DNzODq5aIPoa82AWBg/lyKLMH1PMp/a9XvLXLzG1cuFlBaWpiKxaIPSLY6CaC93ggQjyiQZRkeQSzLRovGaPciWLt5faSWEBoh6KBvOhiaNga0+Y9pwaFxvu7rfp8F5pWDt+qNMp2IijHGwddWCvN+33/CoAOP5nVdT9SdoQ1JkggiQ6Yvr7V60+9z7akA2gfH9cRF8hO5F5Ve4lQAF9uuK+qFsylkzsQxrcaQm04hdWkR83Mzfp9rQ3fAFzu9Ph6+WMfjl6/pGBdb2jbKmx8QlRjWy5vkyhUZBPgOeGNHN9AbDLGUz6He2hVj3Ll9C8/evsdgaMK0HV8bcmDTU0UUBYXcedR+NLGnH0I3jvDk1Rsy46FP4C/1BtrdntCGHNiOAzWZgEKQ5Qt5lIqLojbaXSQTcRy2OwT4SZqk0IYAOgkVWUE+lxX/zb0DpFNpkTzmZmfFtzewhHYcfwUYAMZmVaZQlLFHAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-tga {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnxJREFUeNp0U89PE0EU/ra725K22ILRGipb22pMG6JcSEQTbUIwnozxpBcvepeEP0KPogcT/wlNT17kIKbEmChFUYKGVtL0R2gLtNCl3Z1Z3+zSAlonmezOe/O+973vvZEsy4JYnqdPMu6RkSQYQ29JEkB+PZcrslrtPhQl23VZc8/tr9I1yMHg0EA8HrBM04lVFAhoY38fSSDQVN3pfKV8G7KcxZHl6v1xblqU3eLc3p2VFZjr6+gQgwsnhzGTuq6Nhs6kYZqXjwL0GFhEl3U60OfnwWs1GGtrUKNRsKkpeIIBpKIRtI1J7cX7hXRhc/MOhXw5DkCZGG2zXAajzFIoBMvng1ypIKOqmP30GW3OIEcimovzlxRy5RgAFwDEAIODkCcmIMdiQLsNdWwMZdJlg8pzEUt1aBhKq3XinxKYqF9yQbqRIqsMy+0Gyy47bKgUWXSLtDENE5wdtuqQATm50F1VnPbRGeEw8HXZbiV8fsDvI9ldju9vADAyihLEbrWAZhOoVp3z6iqBUiB1A4nEfwCEsbkL/M4TgE5n5jDx+oTEzp1d8m9tC8H6MaAB0imzx0NU/WKUYE+loEyawDBo2ui6TGfT6ANAxrvx87gYCGCxXEKVJvCWFsG3eh1vN/J4OD6Od4UC8o0G3TX7TGLHwI9iEQmvF9X6Fh7F4/iYy+GcLOMSlfEgGsP0qdNOmX0BiGKpVkV1bw/1nW2b/gCpf1PTcI+Y7eg6ps+G4bG4PR99SjAVo9HE4q+fKNE0vl5awuSohjeijbRefVjAtUgEQRK7Yhi9OKn7nKWZxxlSPWl3QwgnaIrW8QMhD542vUbx/W49m7sq4v4IMABOqi3Ej7bAEAAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-tgz {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnhJREFUeNpsU1trE0EYPbMzSTfdtInFtkkpiaXVWou2FRUEn/so6JugL/oH/Af+B1988if40jcFERQURNBSQdDWlLQN2lsue8neZsZvc7FoOrDszM75znfOmVmmtUYyvry++36yfOeS1qqzDtvH2P76ApPlW3Drb2sHex/uccHWAdbZX30kO2+B3siN3zhTnHuQ66+95i423jzFzOVljBdKOZNHazvVT7e5wF+SZBj9iZJ+3J11mbW2kR8T4LwFli5i4fqTUvnczTUp9RLtDhKgJx0q4dEwWAxrREKICHEsoYYXMXvlcWmquLgmY71yCkG/c0AkARgLMZpnMDMpGNzEYe0dGp6HwvmHpbHC1Wf9MnFCkHQOyYEPzSJwQ2B65Tm5NZG3Fshim6wbMNJn4bpHowMKtIqo2COgR2IcAptwjvcgo6i77igjEmVDqbY8xQJ1VwRULhiBI6+G9Zf3cbTziuzIDkmHSNqECTFgQScEcYuc2NA8TcdYwXD+GkK/TYVN+u72WrIudiAD8o6oAR2RRCmQMjis3CIy1iSpPySCXhFTXeyAgh4BR+JVw8pauLi0Cp4yCX9A90FQhnSBYtnF/k+Q+HYam9itfIZB3QvT8zj8XSW5EhNTs9ivbSLwPUzPLNPJBIMEKnaQYg6aB9+RGR5F5VsNgnNKXMI1NdJGG5WfHzFVLJ7k8c8xUngpVodlDSGbFYj8Y4yMpOG09lHf3yIFPzA3fwHZTAQVtU4JUTeFDrdgDdlI8wAz5Qy2KxswReI7QODZcOr0ZH3q2hIDBI7zq16tuk3FNPxAI4wN+pkoccYoE4YJU5EdUtM4Qst26v26PwIMAKj3P/2YUKgYAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-tiff {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmRJREFUeNp0UktPE1EU/qYzHWstlrYJNcWUElyUJsaNGh9B0g1Lo0v9Ey78EbrVxBhXuHShm25YGBJRQpAYBDEWpaEPEhksdVpbyjzveO4MfZDCTWbauefc736PIziOA77OPH2yJCcSGdg2uksQAKofFou/7VrtASRpvVNynj13f6XOhjg8HAlMTIQdy/LO+v3uYUPTkAHCTb+cK+0pdyGK6+hbvu4/xiyHbncYAwfR19ZgbG/DoO9LsSgeTd9JXoxfyMG2rvQDdBlwIZauQ5ufh12twioU4E+nYU1NIRCNIDs+Bt28mXzx8VNuZ796j9q/DgAwomwqClilAmF0FE4wCInAlkjO4y+r0JgNX2os6XPYS2q/cQyAcQatFjA0BPH6NYipccAwIGUy2CVJFZInkKlyJAqx3T4/IMGmJkeWIWSz5KgI5pdhb3yDXS5DSCYh8rTID8s0wexeVD0GtMd85KkkefFxUfE47M1NokbJkByEQl6tL+ouAI+MUwbFhnYbaJKc/Sqg0x4H4eDRGDA56fUOABA9/GsCpaIHwr8FOhQ823O5RfW66tUGADhNy3RNRDjcN41HLxdQ8J6jYTsOQLfOJBK4f+s2/uoathoNGKT1MtFeVHZxdWTEZfEq/wMKl3rCJOIzTV6ADs2R5ulYDDNkYjp0DhrF+zCVgkw31+v1UxjQZkNV0SADd2o1MIuc9gmY+/kLxb0/UFoHePd9A1qzeUoKpilx9xcLWzgg+u/zeVfuQqkM9bCN1ysrWKXxdtPgvScwUAm58XZ52W16QyPtifRUzi588GbEi1ztHPsvwAC4uC9qhnsZvwAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-txt {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAeJJREFUeNp8UrtOG1EQPfsyXiyzBguIJSyChZBBEFCKpKHLo6egpErNn8CHgH8gkZIiTSIXLhJAWCgkoMgRMSiRBSK29z4y9+I1d/HCrFb3MTPnnjkzlpQSynY+fP70fGF2gQuByCz6lfdd9Uurfvrrjes6762eb3tzQ69uFJwPsqOPC+MBEmxxphi4tlU5OGmsOzaBWLc+O9oIIVhScidkyGZ8vH62nHtSKlaI4cse6TjAfSaFBBcco0EWqyvzubmpyQrj/FXk75cQaSEMeMXU8xykPA/Hjd/6/LRcyjEpt2i7HAe4A2TeLZWKUOJaVLxj27j813EHGKCXaAJExu/4BOdiAED08riQD2riOrexyRoYc3CvsAbLGAAjZga7vgZG23WMCdBvoxKJc36TRBlMiaa2JByjNqqD8qkYc1pjDK7abey+/YhrWlfKswhpiCR96aEU9o5+QE3g2ovVWDm2Sc22bBQm8vrVpbkS9r+doPr1EOWZaQ0yFoxg2PcREosEAI4uvZhJpzFMP+cSXRbq+043RManez+tNWKMI6GN0g0Z04HFR+NoNC/0yx717efZOSbzY3AcR4Op2AGA5p/W31r9e0vNgSrh9OwCrpeCkqvZuqTybnpRqx/r2CjvvwADAJC/7lzAzQmwAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-wav {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApFJREFUeNpsU1tPE0EYPXtpKbX0wqUQKVQMFdIXQBNCQBs06KP+B8ODGh+Mf4b/4IsGE54kxhcMBrkp7YOQgBRvSKG73fvsrt8Otoask0xmd+b7zpxzvm8E3/cRjPkniyulW0NFy2JoDkEAguOlpXJ9p3L8MBqVl4O9YHxae8pXuRlcGO7KPLhfTDVUqwUgigJMy4Whm6lEXHjxYf3XnByRN0QB/2KaH7btMlUxoRJAcyqKhdOaht7+DJ49n+2cvTnwynXcsb+kLwJ4rgfmMDDGWqvneXCZS9ND7mov5h9ND85M9y86Dpto5rUkuJ4Py3YDJpy6QGJPayqB+Njf+43XL220t0cwOZkfrNXsBUqZugDA6CbLdAiAwaek1ZU9LmP8Rh6S78GsGxjOp9FdzKJaVZIhBgGASzK21w/wbrnCk8euX+EMAjaaZuPHdwUdHVFYluuGPGCORwwYjg5rqOwccRk+3Ux0IEvntmsNG4ZmUayL/wAwKHUNfZfTKN0ZRaw9Cof8qJ/pMAyHy5KkAMTksSEJtnMenM7EMVMawbejMzJRh67bXEYiIXEAVTW50SEAhzqwfqrBcXx4VOhYm4RsNgHbsJFOyZTsQ1MN+hcohoUlkFiMT+TQFpMwXOjGpXgE+XwGk1N5pFJtKNCequgYGupCRBbCDOp0KBJc4VoP3dyBONW8uydBgBHUThqQKCk3mEZ/LoUG+RBioJO7VarAwEAntjYPiUUW9Hh4b2R7k9j98hN37xWx8fGAt3eIAdVMLn+uUv+b2KReSCZjZJiB9bV9jIz2ofr1BKvvd7G9dRC80lae0HzOt+cWVnrSKDrMJykifwNBpCgE/UAllEXufmDu8Zlffvvm8XSQ90eAAQA0pF7c08o4PAAAAABJRU5ErkJggg==);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-wmv {
-	background-image:url("data:image/svg+xml;charset=utf8,%3Csvg id='Layer_2' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 100'%3E%3Cstyle/%3E%3ClinearGradient id='SVGID_1_' gradientUnits='userSpaceOnUse' x1='36.2' y1='101' x2='36.2' y2='3.005' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23e2cde4'/%3E%3Cstop offset='.17' stop-color='%23e0cae2'/%3E%3Cstop offset='.313' stop-color='%23dbc0dd'/%3E%3Cstop offset='.447' stop-color='%23d2b1d4'/%3E%3Cstop offset='.575' stop-color='%23c79dc7'/%3E%3Cstop offset='.698' stop-color='%23ba84b9'/%3E%3Cstop offset='.819' stop-color='%23ab68a9'/%3E%3Cstop offset='.934' stop-color='%239c4598'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill='url(%23SVGID_1_)'/%3E%3Cpath d='M45.2 1l27 26.7V99H.2V1h45z' fill-opacity='0' stroke='%23882383' stroke-width='2'/%3E%3Cpath d='M9.1 91.1L4.7 72.5h3.9l2.8 12.8 3.4-12.8h4.5l3.3 13 2.9-13h3.8l-4.6 18.6h-4L17 77.2l-3.7 13.9H9.1zm22.1 0V72.5h5.7l3.4 12.7 3.4-12.7h5.7v18.6h-3.5V76.4l-3.7 14.7h-3.7l-3.7-14.7v14.7h-3.6zm26.7 0l-6.7-18.6h4.1l4.8 13.8 4.6-13.8h4L62 91.1h-4.1z' fill='%23fff'/%3E%3ClinearGradient id='SVGID_2_' gradientUnits='userSpaceOnUse' x1='18.2' y1='50.023' x2='18.2' y2='50.023' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3ClinearGradient id='SVGID_3_' gradientUnits='userSpaceOnUse' x1='11.511' y1='51.716' x2='65.211' y2='51.716' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='.005' stop-color='%23963491'/%3E%3Cstop offset='1' stop-color='%2370136b'/%3E%3C/linearGradient%3E%3Cpath d='M64.3 55.5c-1.7-.2-3.4-.3-5.1-.3-7.3-.1-13.3 1.6-18.8 3.7S29.6 63.6 23.3 64c-3.4.2-7.3-.6-8.5-2.4-.8-1.3-.8-3.5-1-5.7-.6-5.7-1.6-11.7-2.4-17.3.8-.9 2.1-1.3 3.4-1.7.4 1.1.2 2.7.6 3.8 7.1.7 13.6-.4 20-1.5 6.3-1.1 12.4-2.2 19.4-2.6 3.4-.2 6.9-.2 10.3 0m-9.9 15.3c.5-.2 1.1-.3 1.9-.2.2-3.7.3-7.3.3-11.2-6.2.2-11.9.9-17 2.2.2 4 .4 7.8.3 12 4-1.1 7.7-2.5 12.6-2.7m2-12.1h1.1c.4-.4.2-1.2.2-1.9-1.5-.6-1.8 1-1.3 1.9zm3.9-.2h1.5V38h-1.3c0 .7-.4.9-.2 1.7zm4 0c.5-.1.8 0 1.1.2.4-.3.2-1.2.2-1.9h-1.3v1.7zm-11.5.3h.9c.4-.3.2-1.2.2-1.9-1.4-.4-1.6 1.2-1.1 1.9zm-4 .4c.7.2.8-.3 1.5-.2v-1.7c-1.5-.4-1.7.6-1.5 1.9zm-3.6-1.1c0 .6-.1 1.4.2 1.7.5.1.5-.4 1.1-.2-.2-.6.5-2-.4-1.9-.1.4-.8.1-.9.4zm-31.5.8c.4-.1 1.1.6 1.3 0-.5 0-.1-.8-.2-1.1-.7.2-1.3.3-1.1 1.1zm28.3-.4c-.3.3.2 1.1 0 1.9.6.2.6-.3 1.1-.2-.2-.6.5-2-.4-1.9-.1.3-.4.2-.7.2zm-3.5 2.8c.5-.1.9-.2 1.3-.4.2-.8-.4-.9-.2-1.7h-.9c-.3.3-.1 1.3-.2 2.1zm26.9-1.8c-2.1-.1-3.3-.2-5.5-.2-.5 3.4 0 7.8-.5 11.2 2.4 0 3.6.1 5.8.3M33.4 41.6c.5.2.1 1.2.2 1.7.5-.1 1.1-.2 1.5-.4.6-1.9-.9-2.4-1.7-1.3zm-4.7.6v1.9c.9.2 1.2-.2 1.9-.2-.1-.7.2-1.7-.2-2.1-.5.2-1.3.1-1.7.4zm-5.3.6c.3.5 0 1.6.4 2.1.7.1.8-.4 1.5-.2-.1-.7-.3-1.2-.2-2.1-.8-.2-.9.3-1.7.2zm-7.5 2H17c.2-.9-.4-1.2-.2-2.1-.4.1-1.2-.3-1.3.2.6.2-.1 1.7.4 1.9zm3.4 1c.1 4.1.9 9.3 1.4 13.7 8 .1 13.1-2.7 19.2-4.5-.5-3.9.1-8.7-.7-12.2-6.2 1.6-12.1 3.2-19.9 3zm.5-.8h1.1c.4-.5-.2-1.2 0-2.1h-1.5c.1.7.1 1.6.4 2.1zm-5.4 7.8c.2 0 .3.2.4.4-.4-.7-.7.5-.2.6.1-.2 0-.4.2-.4.3.5-.8.7-.2.8.7-.5 1.3-1.2 2.4-1.5-.1 1.5.4 2.4.4 3.8-.7.5-1.7.7-1.9 1.7 1.2.7 2.5 1.2 4.2 1.3-.7-4.9-1.1-8.8-1.6-13.7-2.2.3-4-.8-5.1-.9.9.8.6 2.5.8 3.6 0-.2 0-.4.2-.4-.1.7.1 1.7-.2 2.1.7.3.5-.2.4.9m44.6 3.2h1.1c.3-.3.2-1.1.2-1.7h-1.3v1.7zm-4-1.4v1.3c.4.4.7-.2 1.5 0v-1.5c-.6 0-1.2 0-1.5.2zm7.6 1.4h1.3v-1.5h-1.3c.1.5 0 1 0 1.5zm-11-1v1.3h1.1c.3-.3.4-1.7-.2-1.7-.1.4-.8.1-.9.4zm-3.6.4c.1.6-.3 1.7.4 1.7 0-.3.5-.2.9-.2-.2-.5.4-1.8-.4-1.7-.1.3-.6.2-.9.2zm-3.4 1v1.5c.7.2.6-.4 1.3-.2-.2-.5.4-1.8-.4-1.7-.1.3-.8.2-.9.4zM15 57c.7-.5 1.3-1.7.2-2.3-.7.4-.8 1.6-.2 2.3zm26.1-1.3c-.1.7.4.8.2 1.5.9 0 1.2-.6 1.1-1.7-.4-.5-.8.1-1.3.2zm-3 2.7c1 0 1.2-.8 1.1-1.9h-.9c-.3.4-.1 1.3-.2 1.9zm-3.6-.4v1.7c.6-.1 1.3-.2 1.5-.8-.6 0 .3-1.6-.6-1.3 0 .4-.7.1-.9.4zM16 60.8c-.4-.7-.2-2-1.3-1.9.2.7.2 2.7 1.3 1.9zm13.8-.9c.5 0 .1.9.2 1.3.8.1 1.2-.2 1.7-.4v-1.7c-.9-.1-1.6.1-1.9.8zm-4.7.6c0 .8-.1 1.7.4 1.9 0-.5.8-.1 1.1-.2.3-.3-.2-1.1 0-1.9-.7-.2-1 .1-1.5.2zM19 62.3v-1.7c-.5 0-.6-.4-1.3-.2-.1 1.1 0 2.1 1.3 1.9zm2.5.2h1.3c.2-.9-.3-1.1-.2-1.9h-1.3c-.1.9.2 1.2.2 1.9z' fill='url(%23SVGID_3_)'/%3E%3ClinearGradient id='SVGID_4_' gradientUnits='userSpaceOnUse' x1='45.269' y1='74.206' x2='58.769' y2='87.706' gradientTransform='matrix(1 0 0 -1 0 102)'%3E%3Cstop offset='0' stop-color='%23f9eff6'/%3E%3Cstop offset='.378' stop-color='%23f8edf5'/%3E%3Cstop offset='.515' stop-color='%23f3e6f1'/%3E%3Cstop offset='.612' stop-color='%23ecdbeb'/%3E%3Cstop offset='.69' stop-color='%23e3cce2'/%3E%3Cstop offset='.757' stop-color='%23d7b8d7'/%3E%3Cstop offset='.817' stop-color='%23caa1c9'/%3E%3Cstop offset='.871' stop-color='%23bc88bb'/%3E%3Cstop offset='.921' stop-color='%23ae6cab'/%3E%3Cstop offset='.965' stop-color='%239f4d9b'/%3E%3Cstop offset='1' stop-color='%23932a8e'/%3E%3C/linearGradient%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill='url(%23SVGID_4_)'/%3E%3Cpath d='M45.2 1l27 26.7h-27V1z' fill-opacity='0' stroke='%23882383' stroke-width='2' stroke-linejoin='bevel'/%3E%3C/svg%3E");
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-xls {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmxJREFUeNpsU0trFEEQ/mamZ3Y2+0zIC2MmITEkUYgERFQErx5E8KTi1b/h79A/4SW3nCNeYggBYZVEMU/y3N3Z7M7OTD/G6lk2ruw20zRdU/XV91VVG0mSQK/3n1a/jky6d6Xs3G8WXS+Pw5N6LXjLLGuna/78oZKerGsYKtrDE16uJGL1L9gEOOcYd2dL1fNwrbL//aXN7J1efPMmkUqEFAk0A0VZNbFEaQCBscIkXj975y3NLq9xye8PBkAniHOFph+j2eC4rsdoB4LsFubGl/Hq8RtvYWpxTQi52o1jvWiGYaRZL0/auDgOkC/Z8BYL2Pqxidp1FZkhoDxpeaXA/Ujuj/4HoOxKKjiOiek7RUShRNQWaNYFQuMafrYCxiw4ozZKfqbYJ0EvRdl1DQyyTs8XCNTA6UELMwvDyLpZWIZNNlNLlQOK2LMJRJ+5AkuZ1S7CFFzJzk56GnUjQWlYkqCoBWFbonEVYcLLA4dNnB624GQsDBWIgfZJEgxkoChzSFWvn4VpQemDm2VwXQsXJwF1h6c+gxlQ5jgSiEUEt0wdIe7tMES+nEG2aCLiJMOIIWIr9e0DEELAMUrwRuchVAyTKimUwO75Jm6VF3Bv7imOaj+xd7UFKVS/BPJF1b/E4tgTrE49J60O5kceoNqowiuuYKa8ghHXA48U9MT2AQgyRvTThE30bQiaSGa4yLMJNFo+Dq/2cHt4CYlwyFf2S6BHwwrMw/avDbR5C1k7h1YQ4KH3Amf+AcZyEbZPv9CItzQD1l9EbtYOjv74v/d3O9RMPTDrsEwGIWN8q2yk7XNYRs9JrRv3V4ABADSGR6eQ0/NQAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-xlsx {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU8tqFEEUPVXdPY/ueWZIoiYZiSYKYhJc6EbduHOhgijo3t/wH1z6B0JAhOyMILhxo4kJGk1ASTAxwWF0Mpp5dHc9vFUzYwidaoqmq+8959xzbzGtNcx69PTS26ETmQtS9r4Hy/xv7MW7jV+th5yzVcaYPX/++It9u4NAv+CVR6tBUUTqMJsDcRzjZOZM8W9ZLKx+/XDb4e5/kH5In0lpIYWGUaC0YTZnBCAEKoVR3L36oDo7NbsglZwbqD6iQKOXFMcKUVfBkBAoQhlD5xxMDp/HrSv3q1JgYW3z0x0KXzkCYJaRZljru23aHWTzLiamAyytv0O9UYdf5PArqlppBfMUfu4oALErqZBKcUxMFRCHEp0DgW5Lo4N9NIN1dF0XXsVFOUyPJTzo+WBANDidjp8tgHGG3c0DnJ4uIRf4cOCBaW5KjY8xkZL72xpJ9QcFz5bVqHUJGHZL2YtNmKi06YCyiVFb4s/vEKMTAf1p4edOG6mMi1zR6wEpdUwX+vLDtkCzHoK7ptcM6ayLmGajvtex4PliyoIkFRjmUEASelB2rXQRSfjUCT9PlWpmW21iTGzCAyEkUixPRqXhe2V4zKczbdmybgkpJ0cGOuA6Y2MTCsKoi5HsNK7N3MN+uwYaWbxYfoLLkzdxcew6lrYWaZhm8PHHG3zffp1UwJSHz9vvkU8PodbcQYYYS5lxYkxTkGdVDQdV1Js1qPgYD6JIuIE7gsXVefIhIuM05k7dwMbeMmh87a18ufIMaVYyprrJLgje2Nr+1tzYXANnDnr3zRhHj37Vvy2wpXHtNAd5/wQYAD6WMuT2CwoVAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-xml {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAilJREFUeNqMks1PE0EYxh+g3W2t1G0sEqyISynUFJsSOShNwCamiYZED3LgIkcuxoN/iCZePZiYGD2aGD+i0F5KMChxlVaakAK2ykcAt+WzdLu7zkxo3WZL4pu8mXfmeeY3885ug67roPFh5nvc62m9hjoR+5LMp7MrkYf370qVtco+VtCUFpbj+jGR+JbWn76OyQ8ePwsZATQb8R/hanZgINgj9IqeuBFCw1Kt9OMBnNWCs24XwkG/QKYUEiGjVAPQof/rq0783pShET3ULQo8xz0iS5FaANmrHQH2DoqY+DSLSz6RzecWlnD9ymU47LYjd4O5BXqDTG4FM3NpTEkpdJ5rw0AowLRMbhUfp58gTOaD/UHmNQPI6YmvKWRX1zESHUJ/oBs2nmPa+Mgw0ZIM3tZyGoJwygzQNB2jNyJIZX7iB0lpPoM70UGmPX8zCU+rG8NDVxHwdiC5mKsPUFUN/gvtLLf39sFzVqaN3YrC6TjBauqhXhNA1TQoqloV7Da+pjZq1FsXUCamF29j6LvYhf3iISamZ3Fv9DZevouhRzzPfOG+3hpA9U9UyioOlTJ7pFeTCQS6RGzIebyf+oz5pSzWtmSW1EO9phvQ00slBRt/8qR3DoWdXbiczUiTzd52D+tdLmyTB14mx1rMAKVcRpEATjrsuElee/HXGmnFRyBOGD30C/nEDjNgs7CDpsYmnHG3YPegBCvHs9oYfm8nG9dJa5X4K8AAQzQX4KSN3wcAAAAASUVORK5CYII=);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-yml {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdxJREFUeNqMUl1rE0EUPbM7m5Y0Zptu21AwWwhYpfSDFh+kvvRd8N0Hf4I/xWdf/Q158F0QoQ+CVsFKaLSQpt/dpmvztTOzzky6cetOpWcZZvbO3MO5514SxzEU3r57/3GpWllM/tP4sL3TarROXuSo/SWJvX71Uu80Cfhlr/T4UdWFAVfdnmsTUtvdP35OUyQKVnJgXDBTcj9icAsTeLax7j/052qM81UjwW1QJXEhMF0qYnN90fdnvdogYmvJPU0/VBApD4hcDrWRcyikfB17srzgW7b9Rh1vEvxDlI4tVytaBSEEtmWh0xsUMwpwnWjqAlcxogiHd1wiQyCu87iI/+sJtf6+NXsgpd7FWCMB50KvkYMGMbLdZgLlfj+K9K4+FnFQ2x7WntIs50AbmiGwLILt+k+EvzvSNIHzdigdJ/AmXQRhiHv5POSwYmG+cqPVo0HqDxj8uTK2vn1Hfa+JmdIkvtZ/4fOPXU3WPDpFeNWVyUKryCiIGMN4zsH98gym3CIcOTwT+XHdXrdQQHAZotE8kBPpSqPNHtBOr48HUmLOcXRJT9dWNMGYJFby91pHOAvaykSaITg+bwefdhrteDRTMSwyrFCgI88E056Hy+4Ah2cXQZL3R4ABALUe7fqXWFN6AAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
-
-.ipfs-zip {
-	background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAm9JREFUeNpsk0tv00AUhc+MY6dOmgeFJg1FoVVpUWlFC0s2IFF1jxBbhKj4BSxYdscPYcEmQmIDq0gsERIViy4TpD7VFzF1Ho5je2a4thOqNhlp5Mz4zudzzp0wpRTC8fPrk0/TC6+fDtYicLH97T1Kc2vQDcs+rH3eUAxVznn0fn1DRM8E+iOdv5ct3XmZG6yVlNj6solUbgVTt0q5FGtX6vXqC6VklTE+KAO/OODHSIQPRQpsXC+kkEz2ELA0ystv84tLzyucsbWByisAGf+QAS2CCDRRLMJMmxC+i8C4jdLCm/zM7OOKFGptcO6/BTpJ0yeQB0Y+mfKQuZZG0jQgeRbW8Xdomobs9LN8scc+UPHNy4Dwq8IljotIIQEm59/RoSyM1CKkXKZNBm7kIVgyM6wgAnSgRK9vqQfHPiMFDHqyFVsLR9Cm0o4YzoAASrSjCelQfRPb1Vc4qn0EY5L2W9GEaBLcxQgFHpGbkMIDJ69e+wjJ8VXqRgKid0r7ftQdxkRs9SqA2kgAm14SSIQh9uhuLGPMnKJs/5KquL1x0N0RCsizigoDaLqBdHoMiyvrlBsHVx1wphD4BCewoqxGKKDwAgtOy8JufYuk+5golGGaGZwc1sIGoDz3AOPZSVLaHgVwydoJDM1H4DbQODughB3YpOD44HfoHgnu4e7So0uAi0stHLJ3Aud8B9bpHu6vPoSu9TtDl6tUuoFiIYOgu0+158MKmOxomtyD3Qi/3MTR7i8K0EDG1GHO5DE3X4DvNahZlJOwEkOATvdPc2//hx3mXJ5lFJaF8K8bStd0YGfnOJbMGex21x6c+yfAAOlIPDJzr7cLAAAAAElFTkSuQmCC);
-	background-repeat:no-repeat;
-	background-size:contain
-}
diff --git a/assets/dir-index-html/src/style.css b/assets/dir-index-html/src/style.css
deleted file mode 100644
index 3e7b8a734bc2d38de2ffc896db8895d1fec50046..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/src/style.css
+++ /dev/null
@@ -1,212 +0,0 @@
-body {
-	color:#34373f;
-	font-family:"Helvetica Neue", Helvetica, Arial, sans-serif;
-	font-size:14px;
-	line-height:1.43;
-	margin:0;
-	word-break:break-all;
-	-webkit-text-size-adjust:100%;
-	-ms-text-size-adjust:100%;
-	-webkit-tap-highlight-color:transparent
-}
-
-a {
-	color:#117eb3;
-	text-decoration:none
-}
-
-a:hover {
-	color:#00b0e9;
-	text-decoration:underline
-}
-
-a:active,
-a:visited {
-	color:#00b0e9
-}
-
-strong {
-	font-weight:700
-}
-
-table {
-	border-collapse:collapse;
-	border-spacing:0;
-	max-width:100%;
-	width:100%
-}
-
-table:last-child {
-	border-bottom-left-radius:3px;
-	border-bottom-right-radius:3px
-}
-
-tr:first-child td {
-	border-top:0
-}
-
-tr:nth-of-type(even) {
-	background-color:#f7f8fa
-}
-
-td {
-	border-top:1px solid #d9dbe2;
-	padding:.65em;
-	vertical-align:top
-}
-
-#page-header {
-	align-items:center;
-	background:#0b3a53;
-	border-bottom:4px solid #69c4cd;
-	color:#fff;
-	display:flex;
-	font-size:1.12em;
-	font-weight:500;
-	justify-content:space-between;
-	padding:0 1em
-}
-
-#page-header a {
-	color:#69c4cd
-}
-
-#page-header a:active {
-	color:#9ad4db
-}
-
-#page-header a:hover {
-	color:#fff
-}
-
-#page-header-logo {
-	height:2.25em;
-	margin:.7em .7em .7em 0;
-	width:7.15em
-}
-
-#page-header-menu {
-	align-items:center;
-	display:flex;
-	margin:.65em 0
-}
-
-#page-header-menu div {
-	margin:0 .6em
-}
-
-#page-header-menu div:last-child {
-	margin:0 0 0 .6em
-}
-
-#page-header-menu svg {
-	fill:#69c4cd;
-	height:1.8em;
-	margin-top:.125em
-}
-
-#page-header-menu svg:hover {
-	fill:#fff
-}
-
-.menu-item-narrow {
-	display:none
-}
-
-#content {
-	border:1px solid #d9dbe2;
-	border-radius:4px;
-	margin:1em
-}
-
-#content-header {
-	background-color:#edf0f4;
-	border-bottom:1px solid #d9dbe2;
-	border-top-left-radius:3px;
-	border-top-right-radius:3px;
-	padding:.7em 1em
-}
-
-.type-icon,
-.type-icon>* {
-	width:1.15em
-}
-
-.no-linebreak {
-	white-space:nowrap
-}
-
-.ipfs-hash {
-	color:#7f8491;
-	font-family:monospace
-}
-
-@media only screen and (max-width:500px) {
-	.menu-item-narrow {
-		display:inline
-	}
-	.menu-item-wide {
-		display:none
-	}
-}
-
-@media print {
-	#page-header {
-		display:none
-	}
-	#content-header,
-	.ipfs-hash,
-	body {
-		color:#000
-	}
-	#content-header {
-		border-bottom:1px solid #000
-	}
-	#content {
-		border:1px solid #000
-	}
-	a,
-	a:visited {
-		color:#000;
-		text-decoration:underline
-	}
-	a[href]:after {
-		content:" (" attr(href) ")"
-	}
-	tr {
-		page-break-inside:avoid
-	}
-	tr:nth-of-type(even) {
-		background-color:transparent
-	}
-	td {
-		border-top:1px solid #000
-	}
-}
-
-@-ms-viewport {
-	width:device-width
-}
-
-.d-flex {
-	display:flex
-}
-
-.flex-wrap {
-	flex-flow:wrap
-}
-
-.flex-shrink-1 {
-	flex-shrink:1
-}
-
-.ml-auto {
-	margin-left:auto
-}
-
-.table-responsive {
-	display:block;
-	width:100%;
-	overflow-x:auto;
-	-webkit-overflow-scrolling:touch
-}
diff --git a/assets/dir-index-html/test/go.mod b/assets/dir-index-html/test/go.mod
deleted file mode 100644
index c1cff1b746fa745f2247ab5b8d8d8cfce09fed6d..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/test/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/ipfs/dir-index-html/test
-
-go 1.17
diff --git a/assets/dir-index-html/test/main.go b/assets/dir-index-html/test/main.go
deleted file mode 100644
index c02523a9f40ad8a7aaf54271f9e52ba19265e25b..0000000000000000000000000000000000000000
--- a/assets/dir-index-html/test/main.go
+++ /dev/null
@@ -1,116 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"net/http"
-	"net/url"
-	"os"
-	"text/template"
-)
-
-const templateFile = "../dir-index.html"
-
-// Copied from go-ipfs/core/corehttp/gateway_indexPage.go
-type listingTemplateData struct {
-	GatewayURL  string
-	DNSLink     bool
-	Listing     []directoryItem
-	Size        string
-	Path        string
-	Breadcrumbs []breadcrumb
-	BackLink    string
-	Hash        string
-}
-
-type directoryItem struct {
-	Size      string
-	Name      string
-	Path      string
-	Hash      string
-	ShortHash string
-}
-
-type breadcrumb struct {
-	Name string
-	Path string
-}
-
-var testPath = "/ipfs/QmFooBarQXB2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7/a/b/c"
-var testData = listingTemplateData{
-	GatewayURL: "//localhost:3000",
-	DNSLink:    true,
-	Listing: []directoryItem{{
-		Size:      "25 MiB",
-		Name:      "short-film.mov",
-		Path:      testPath + "/short-film.mov",
-		Hash:      "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR",
-		ShortHash: "QmbW\u2026sMnR",
-	}, {
-		Size:      "23 KiB",
-		Name:      "250pxيوسف_الوزاني_صورة_ملتقطة_بواسطة_مرصد_هابل_الفضائي_توضح_سديم_السرطان،_وهو_بقايا_مستعر_أعظم._.jpg",
-		Path:      testPath + "/250pxيوسف_الوزاني_صورة_ملتقطة_بواسطة_مرصد_هابل_الفضائي_توضح_سديم_السرطان،_وهو_بقايا_مستعر_أعظم._.jpg",
-		Hash:      "QmUwrKrMTrNv8QjWGKMMH5QV9FMPUtRCoQ6zxTdgxATQW6",
-		ShortHash: "QmUw\u2026TQW6",
-	}, {
-		Size:      "1 KiB",
-		Name:      "this-piece-of-papers-got-47-words-37-sentences-58-words-we-wanna-know.txt",
-		Path:      testPath + "/this-piece-of-papers-got-47-words-37-sentences-58-words-we-wanna-know.txt",
-		Hash:      "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
-		ShortHash: "bafy\u2026bzdi",
-	}},
-	Size: "25 MiB",
-	Path: testPath,
-	Breadcrumbs: []breadcrumb{{
-		Name: "ipfs",
-	}, {
-		Name: "QmFooBarQXB2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7",
-		Path: testPath + "/../../..",
-	}, {
-		Name: "a",
-		Path: testPath + "/../..",
-	}, {
-		Name: "b",
-		Path: testPath + "/..",
-	}, {
-		Name: "c",
-		Path: testPath,
-	}},
-	BackLink: testPath + "/..",
-	Hash:     "QmFooBazBar2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7",
-}
-
-func main() {
-	mux := http.NewServeMux()
-	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-		if r.URL.Path != "/" {
-			http.Error(w, "Ha-ha, tricked you! There are no files here!", http.StatusNotFound)
-			return
-		}
-		listingTemplate, err := template.New("dir-index.html").Funcs(template.FuncMap{
-			"iconFromExt": func(name string) string {
-				return "ipfs-_blank" // place-holder
-			},
-			"urlEscape": func(rawUrl string) string {
-				pathUrl := url.URL{Path: rawUrl}
-				return pathUrl.String()
-			},
-		}).ParseFiles(templateFile)
-		if err != nil {
-			http.Error(w, fmt.Sprintf("failed to parse template file: %s", err), http.StatusInternalServerError)
-			return
-		}
-		err = listingTemplate.Execute(w, &testData)
-		if err != nil {
-			http.Error(w, fmt.Sprintf("failed to execute template: %s", err), http.StatusInternalServerError)
-			return
-		}
-		w.WriteHeader(http.StatusOK)
-	})
-	if _, err := os.Stat(templateFile); err != nil {
-		wd, _ := os.Getwd()
-		fmt.Printf("could not open template file %q, relative to %q: %s\n", templateFile, wd, err)
-		os.Exit(1)
-	}
-	fmt.Printf("listening on localhost:3000\n")
-	http.ListenAndServe("localhost:3000", mux)
-}
diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go
index 12b3f4d9ccccc14f4740b4e70392c9d3c960242e..52addcc072cedd0a01b15f523cd423e82d96b89f 100644
--- a/cmd/ipfs/daemon.go
+++ b/cmd/ipfs/daemon.go
@@ -45,32 +45,33 @@ import (
 )
 
 const (
-	adjustFDLimitKwd          = "manage-fdlimit"
-	enableGCKwd               = "enable-gc"
-	initOptionKwd             = "init"
-	initConfigOptionKwd       = "init-config"
-	initProfileOptionKwd      = "init-profile"
-	ipfsMountKwd              = "mount-ipfs"
-	ipnsMountKwd              = "mount-ipns"
-	migrateKwd                = "migrate"
-	mountKwd                  = "mount"
-	offlineKwd                = "offline" // global option
-	routingOptionKwd          = "routing"
-	routingOptionSupernodeKwd = "supernode"
-	routingOptionDHTClientKwd = "dhtclient"
-	routingOptionDHTKwd       = "dht"
-	routingOptionDHTServerKwd = "dhtserver"
-	routingOptionNoneKwd      = "none"
-	routingOptionCustomKwd    = "custom"
-	routingOptionDefaultKwd   = "default"
-	routingOptionAutoKwd      = "auto"
-	unencryptTransportKwd     = "disable-transport-encryption"
-	unrestrictedAPIAccessKwd  = "unrestricted-api"
-	writableKwd               = "writable"
-	enablePubSubKwd           = "enable-pubsub-experiment"
-	enableIPNSPubSubKwd       = "enable-namesys-pubsub"
-	enableMultiplexKwd        = "enable-mplex-experiment"
-	agentVersionSuffix        = "agent-version-suffix"
+	adjustFDLimitKwd           = "manage-fdlimit"
+	enableGCKwd                = "enable-gc"
+	initOptionKwd              = "init"
+	initConfigOptionKwd        = "init-config"
+	initProfileOptionKwd       = "init-profile"
+	ipfsMountKwd               = "mount-ipfs"
+	ipnsMountKwd               = "mount-ipns"
+	migrateKwd                 = "migrate"
+	mountKwd                   = "mount"
+	offlineKwd                 = "offline" // global option
+	routingOptionKwd           = "routing"
+	routingOptionSupernodeKwd  = "supernode"
+	routingOptionDHTClientKwd  = "dhtclient"
+	routingOptionDHTKwd        = "dht"
+	routingOptionDHTServerKwd  = "dhtserver"
+	routingOptionNoneKwd       = "none"
+	routingOptionCustomKwd     = "custom"
+	routingOptionDefaultKwd    = "default"
+	routingOptionAutoKwd       = "auto"
+	routingOptionAutoClientKwd = "autoclient"
+	unencryptTransportKwd      = "disable-transport-encryption"
+	unrestrictedAPIAccessKwd   = "unrestricted-api"
+	writableKwd                = "writable"
+	enablePubSubKwd            = "enable-pubsub-experiment"
+	enableIPNSPubSubKwd        = "enable-namesys-pubsub"
+	enableMultiplexKwd         = "enable-mplex-experiment"
+	agentVersionSuffix         = "agent-version-suffix"
 	// apiAddrKwd    = "address-api"
 	// swarmAddrKwd  = "address-swarm"
 )
@@ -162,7 +163,7 @@ Headers.
 		cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"),
 		cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd),
 		cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem using FUSE (experimental)"),
-		cmds.BoolOption(writableKwd, "Enable writing objects (with POST, PUT and DELETE)"),
+		cmds.BoolOption(writableKwd, "Enable legacy Gateway.Writable (deprecated)"),
 		cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount). Defaults to config setting."),
 		cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount). Defaults to config setting."),
 		cmds.BoolOption(unrestrictedAPIAccessKwd, "Allow API access to unlisted hashes"),
@@ -170,7 +171,7 @@ Headers.
 		cmds.BoolOption(enableGCKwd, "Enable automatic periodic repo garbage collection"),
 		cmds.BoolOption(adjustFDLimitKwd, "Check and raise file descriptor limits if needed").WithDefault(true),
 		cmds.BoolOption(migrateKwd, "If true, assume yes at the migrate prompt. If false, assume no."),
-		cmds.BoolOption(enablePubSubKwd, "Enable experimental pubsub feature. Overrides Pubsub.Enabled config."),
+		cmds.BoolOption(enablePubSubKwd, "DEPRECATED"),
 		cmds.BoolOption(enableIPNSPubSubKwd, "Enable IPNS over pubsub. Implicitly enables pubsub, overrides Ipns.UsePubsub config."),
 		cmds.BoolOption(enableMultiplexKwd, "DEPRECATED"),
 		cmds.StringOption(agentVersionSuffix, "Optional suffix to the AgentVersion presented by `ipfs id` and also advertised through BitSwap."),
@@ -416,6 +417,14 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
 			cfg.Identity.PeerID,
 			cfg.Addresses.Swarm,
 			cfg.Identity.PrivKey,
+			libp2p.DHTOption,
+		)
+	case routingOptionAutoClientKwd:
+		ncfg.Routing = libp2p.ConstructDefaultRouting(
+			cfg.Identity.PeerID,
+			cfg.Addresses.Swarm,
+			cfg.Identity.PrivKey,
+			libp2p.DHTClientOption,
 		)
 	case routingOptionDHTClientKwd:
 		ncfg.Routing = libp2p.DHTClientOption
@@ -791,7 +800,11 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
 
 	writable, writableOptionFound := req.Options[writableKwd].(bool)
 	if !writableOptionFound {
-		writable = cfg.Gateway.Writable
+		writable = cfg.Gateway.Writable.WithDefault(false)
+	}
+
+	if writable {
+		log.Error("serveHTTPGateway: legacy Gateway.Writable is DEPRECATED and will be removed or changed in future versions. If you are still using this, provide feedback in https://github.com/ipfs/specs/issues/375")
 	}
 
 	listeners, err := sockets.TakeListeners("io.ipfs.gateway")
diff --git a/cmd/ipfs/dist/README.md b/cmd/ipfs/dist/README.md
index f541482cafac521ab473384cb3fe4cd51e3604f7..4517f655b7b0f5ca7eeaf3f56dd385f8eb416d5b 100644
--- a/cmd/ipfs/dist/README.md
+++ b/cmd/ipfs/dist/README.md
@@ -1,6 +1,6 @@
-# ipfs commandline tool
+# ipfs command line tool
 
-This is the [ipfs](http://ipfs.io) commandline tool. It contains a full ipfs node.
+This is the [ipfs](http://ipfs.io) command line tool. It contains a full ipfs node.
 
 ## Install
 
diff --git a/config/gateway.go b/config/gateway.go
index ad01b263b366a720510bf9dceacbf1f1d98bb17c..de43dd39e11b4fa9d28afba667ab2101c6b2aa6c 100644
--- a/config/gateway.go
+++ b/config/gateway.go
@@ -38,9 +38,9 @@ type Gateway struct {
 	// should be redirected.
 	RootRedirect string
 
-	// Writable enables PUT/POST request handling by this gateway. Usually,
-	// writing is done through the API, not the gateway.
-	Writable bool
+	// DEPRECATED: Enables legacy PUT/POST request handling.
+	// Modern replacement tracked in https://github.com/ipfs/specs/issues/375
+	Writable Flag `json:",omitempty"`
 
 	// PathPrefixes was removed: https://github.com/ipfs/go-ipfs/issues/7702
 	PathPrefixes []string
diff --git a/config/init.go b/config/init.go
index 621ff95f35316b5faf64e255ba93fedebdde0506..288f8a1d58c207eb6993b0cec6caff5056a0cec5 100644
--- a/config/init.go
+++ b/config/init.go
@@ -65,7 +65,6 @@ func InitWithIdentity(identity Identity) (*Config, error) {
 
 		Gateway: Gateway{
 			RootRedirect: "",
-			Writable:     false,
 			NoFetch:      false,
 			PathPrefixes: []string{},
 			HTTPHeaders: map[string][]string{
diff --git a/config/routing.go b/config/routing.go
index f19414ff3086b5e0106d2363fff4ad973c8b3de6..1210bb3cecc3a71f76181d7e0406ac03e30b45d7 100644
--- a/config/routing.go
+++ b/config/routing.go
@@ -10,7 +10,7 @@ import (
 type Routing struct {
 	// Type sets default daemon routing mode.
 	//
-	// Can be one of "auto", "dht", "dhtclient", "dhtserver", "none", or "custom".
+	// Can be one of "auto", "autoclient", "dht", "dhtclient", "dhtserver", "none", or "custom".
 	// When unset or set to "auto", DHT and implicit routers are used.
 	// When "custom" is set, user-provided Routing.Routers is used.
 	Type *OptionalString `json:",omitempty"`
diff --git a/config/swarm.go b/config/swarm.go
index d8fd17e946d85cb3288afd2ce201a259e3d37dba..d7e40e27cb6a939442fd59e7f3bd0bb97d8cf584 100644
--- a/config/swarm.go
+++ b/config/swarm.go
@@ -1,7 +1,5 @@
 package config
 
-import rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
-
 type SwarmConfig struct {
 	// AddrFilters specifies a set libp2p addresses that we should never
 	// dial or receive connections from.
@@ -141,8 +139,8 @@ type ConnMgr struct {
 // <https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#readme>
 type ResourceMgr struct {
 	// Enables the Network Resource Manager feature, default to on.
-	Enabled Flag               `json:",omitempty"`
-	Limits  *rcmgr.LimitConfig `json:",omitempty"`
+	Enabled Flag        `json:",omitempty"`
+	Limits  swarmLimits `json:",omitempty"`
 
 	MaxMemory          *OptionalString  `json:",omitempty"`
 	MaxFileDescriptors *OptionalInteger `json:",omitempty"`
diff --git a/config/types.go b/config/types.go
index 1af244f9ce41388bfd394189fb9b71b41183560c..3a0d4f4b3b2d02d9cc656beded145e2c1af8b1cd 100644
--- a/config/types.go
+++ b/config/types.go
@@ -1,8 +1,10 @@
 package config
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
+	"io"
 	"strings"
 	"time"
 )
@@ -306,6 +308,11 @@ type OptionalInteger struct {
 	value *int64
 }
 
+// NewOptionalInteger returns an OptionalInteger from a int64
+func NewOptionalInteger(v int64) *OptionalInteger {
+	return &OptionalInteger{value: &v}
+}
+
 // WithDefault resolves the integer with the given default.
 func (p *OptionalInteger) WithDefault(defaultValue int64) (value int64) {
 	if p == nil || p.value == nil {
@@ -345,7 +352,7 @@ func (p OptionalInteger) String() string {
 	if p.value == nil {
 		return "default"
 	}
-	return fmt.Sprintf("%d", p.value)
+	return fmt.Sprintf("%d", *p.value)
 }
 
 var _ json.Unmarshaler = (*OptionalInteger)(nil)
@@ -407,3 +414,27 @@ func (p OptionalString) String() string {
 
 var _ json.Unmarshaler = (*OptionalInteger)(nil)
 var _ json.Marshaler = (*OptionalInteger)(nil)
+
+type swarmLimits struct{}
+
+var _ json.Unmarshaler = swarmLimits{}
+
+func (swarmLimits) UnmarshalJSON(b []byte) error {
+	d := json.NewDecoder(bytes.NewReader(b))
+	for {
+		switch tok, err := d.Token(); err {
+		case io.EOF:
+			return nil
+		case nil:
+			switch tok {
+			case json.Delim('{'), json.Delim('}'):
+				// accept empty objects
+				continue
+			}
+			//nolint
+			return fmt.Errorf("The Swarm.ResourceMgr.Limits configuration has been removed in Kubo 0.19 and should be empty or not present. To set custom libp2p limits, read https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#user-supplied-override-limits")
+		default:
+			return err
+		}
+	}
+}
diff --git a/core/commands/bitswap.go b/core/commands/bitswap.go
index d524263be3c2fb93d1176531f8a7f1a586aad2a0..51c2f916dee7a7838e45bdc7eb7d0702482b1dd9 100644
--- a/core/commands/bitswap.go
+++ b/core/commands/bitswap.go
@@ -8,10 +8,10 @@ import (
 	e "github.com/ipfs/kubo/core/commands/e"
 
 	humanize "github.com/dustin/go-humanize"
-	bitswap "github.com/ipfs/go-bitswap"
-	decision "github.com/ipfs/go-bitswap/decision"
 	cidutil "github.com/ipfs/go-cidutil"
 	cmds "github.com/ipfs/go-ipfs-cmds"
+	bitswap "github.com/ipfs/go-libipfs/bitswap"
+	"github.com/ipfs/go-libipfs/bitswap/server"
 	peer "github.com/libp2p/go-libp2p/core/peer"
 )
 
@@ -179,7 +179,7 @@ prints the ledger associated with a given peer.
 	Arguments: []cmds.Argument{
 		cmds.StringArg("peer", true, false, "The PeerID (B58) of the ledger to inspect."),
 	},
-	Type: decision.Receipt{},
+	Type: server.Receipt{},
 	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
 		nd, err := cmdenv.GetNode(env)
 		if err != nil {
@@ -203,7 +203,7 @@ prints the ledger associated with a given peer.
 		return cmds.EmitOnce(res, bs.LedgerForPeer(partner))
 	},
 	Encoders: cmds.EncoderMap{
-		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *decision.Receipt) error {
+		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *server.Receipt) error {
 			fmt.Fprintf(w, "Ledger for %s\n"+
 				"Debt ratio:\t%f\n"+
 				"Exchanges:\t%d\n"+
diff --git a/core/commands/commands_test.go b/core/commands/commands_test.go
index ec4cc1bb6dc47244bf25a392dea70968da899d42..bf1b764508537fc88ae4f14e03394933f7074c9e 100644
--- a/core/commands/commands_test.go
+++ b/core/commands/commands_test.go
@@ -173,6 +173,7 @@ func TestCommands(t *testing.T) {
 		"/multibase/transcode",
 		"/multibase/list",
 		"/name",
+		"/name/inspect",
 		"/name/publish",
 		"/name/pubsub",
 		"/name/pubsub/cancel",
@@ -247,13 +248,12 @@ func TestCommands(t *testing.T) {
 		"/swarm/filters",
 		"/swarm/filters/add",
 		"/swarm/filters/rm",
-		"/swarm/limit",
 		"/swarm/peers",
 		"/swarm/peering",
 		"/swarm/peering/add",
 		"/swarm/peering/ls",
 		"/swarm/peering/rm",
-		"/swarm/stats",
+		"/swarm/resources",
 		"/tar",
 		"/tar/add",
 		"/tar/cat",
diff --git a/core/commands/dag/export.go b/core/commands/dag/export.go
index e9d120e8794f7d5642997d1036b603ca16aad812..b78523ce5ce99143c77bee54bc86533685cc1520 100644
--- a/core/commands/dag/export.go
+++ b/core/commands/dag/export.go
@@ -9,9 +9,9 @@ import (
 	"time"
 
 	"github.com/cheggaaa/pb"
-	blocks "github.com/ipfs/go-block-format"
 	cid "github.com/ipfs/go-cid"
 	ipld "github.com/ipfs/go-ipld-format"
+	blocks "github.com/ipfs/go-libipfs/blocks"
 	iface "github.com/ipfs/interface-go-ipfs-core"
 	"github.com/ipfs/kubo/core/commands/cmdenv"
 
diff --git a/core/commands/dag/put.go b/core/commands/dag/put.go
index ed00c5bee71f3049de45af1c2da7ef3fa2f49c61..351b9cacd67fc2d4e8a73cac785c7a2bc3cbdf68 100644
--- a/core/commands/dag/put.go
+++ b/core/commands/dag/put.go
@@ -4,9 +4,9 @@ import (
 	"bytes"
 	"fmt"
 
-	blocks "github.com/ipfs/go-block-format"
 	"github.com/ipfs/go-cid"
 	ipldlegacy "github.com/ipfs/go-ipld-legacy"
+	blocks "github.com/ipfs/go-libipfs/blocks"
 	"github.com/ipfs/kubo/core/commands/cmdenv"
 	"github.com/ipfs/kubo/core/commands/cmdutils"
 	"github.com/ipld/go-ipld-prime/multicodec"
diff --git a/core/commands/id.go b/core/commands/id.go
index 887f93efe311de247b07a4cd733cd623f44170db..2c4223bb49295459cca11988af9ccac2bcb2d050 100644
--- a/core/commands/id.go
+++ b/core/commands/id.go
@@ -10,28 +10,29 @@ import (
 	"strings"
 
 	version "github.com/ipfs/kubo"
-	core "github.com/ipfs/kubo/core"
-	cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
+	"github.com/ipfs/kubo/core"
+	"github.com/ipfs/kubo/core/commands/cmdenv"
 
 	cmds "github.com/ipfs/go-ipfs-cmds"
 	ke "github.com/ipfs/kubo/core/commands/keyencode"
 	kb "github.com/libp2p/go-libp2p-kbucket"
 	ic "github.com/libp2p/go-libp2p/core/crypto"
 	"github.com/libp2p/go-libp2p/core/host"
-	peer "github.com/libp2p/go-libp2p/core/peer"
+	"github.com/libp2p/go-libp2p/core/peer"
 	pstore "github.com/libp2p/go-libp2p/core/peerstore"
-	identify "github.com/libp2p/go-libp2p/p2p/protocol/identify"
+	"github.com/libp2p/go-libp2p/core/protocol"
+	"github.com/libp2p/go-libp2p/p2p/protocol/identify"
 )
 
 const offlineIDErrorMessage = "'ipfs id' cannot query information on remote peers without a running daemon; if you only want to convert --peerid-base, pass --offline option"
 
-type IdOutput struct { //nolint
+type IdOutput struct { // nolint
 	ID              string
 	PublicKey       string
 	Addresses       []string
 	AgentVersion    string
 	ProtocolVersion string
-	Protocols       []string
+	Protocols       []protocol.ID
 }
 
 const (
@@ -129,7 +130,7 @@ EXAMPLE:
 				output = strings.Replace(output, "<pver>", out.ProtocolVersion, -1)
 				output = strings.Replace(output, "<pubkey>", out.PublicKey, -1)
 				output = strings.Replace(output, "<addrs>", strings.Join(out.Addresses, "\n"), -1)
-				output = strings.Replace(output, "<protocols>", strings.Join(out.Protocols, "\n"), -1)
+				output = strings.Replace(output, "<protocols>", strings.Join(protocol.ConvertToStrings(out.Protocols), "\n"), -1)
 				output = strings.Replace(output, "\\n", "\n", -1)
 				output = strings.Replace(output, "\\t", "\t", -1)
 				fmt.Fprint(w, output)
@@ -175,10 +176,8 @@ func printPeer(keyEnc ke.KeyEncoder, ps pstore.Peerstore, p peer.ID) (interface{
 	sort.Strings(info.Addresses)
 
 	protocols, _ := ps.GetProtocols(p) // don't care about errors here.
-	for _, p := range protocols {
-		info.Protocols = append(info.Protocols, string(p))
-	}
-	sort.Strings(info.Protocols)
+	info.Protocols = append(info.Protocols, protocols...)
+	sort.Slice(info.Protocols, func(i, j int) bool { return info.Protocols[i] < info.Protocols[j] })
 
 	if v, err := ps.Get(p, "ProtocolVersion"); err == nil {
 		if vs, ok := v.(string); ok {
@@ -216,7 +215,7 @@ func printSelf(keyEnc ke.KeyEncoder, node *core.IpfsNode) (interface{}, error) {
 		}
 		sort.Strings(info.Addresses)
 		info.Protocols = node.PeerHost.Mux().Protocols()
-		sort.Strings(info.Protocols)
+		sort.Slice(info.Protocols, func(i, j int) bool { return info.Protocols[i] < info.Protocols[j] })
 	}
 	info.ProtocolVersion = identify.DefaultProtocolVersion
 	info.AgentVersion = version.GetUserAgentVersion()
diff --git a/core/commands/name/name.go b/core/commands/name/name.go
index d9e3de57fab78a0d80a02f2ebf4161990872fa76..0e4fa6cb5481a6628e989713a25244f9245b19a6 100644
--- a/core/commands/name/name.go
+++ b/core/commands/name/name.go
@@ -1,7 +1,25 @@
 package name
 
 import (
-	"github.com/ipfs/go-ipfs-cmds"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"strings"
+	"text/tabwriter"
+	"time"
+
+	"github.com/gogo/protobuf/proto"
+	cmds "github.com/ipfs/go-ipfs-cmds"
+	"github.com/ipfs/go-ipns"
+	ipns_pb "github.com/ipfs/go-ipns/pb"
+	cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
+	"github.com/ipld/go-ipld-prime"
+	"github.com/ipld/go-ipld-prime/codec/dagcbor"
+	"github.com/ipld/go-ipld-prime/codec/dagjson"
+	ic "github.com/libp2p/go-libp2p/core/crypto"
+	"github.com/libp2p/go-libp2p/core/peer"
+	mbase "github.com/multiformats/go-multibase"
 )
 
 type IpnsEntry struct {
@@ -62,5 +80,218 @@ Resolve the value of a dnslink:
 		"publish": PublishCmd,
 		"resolve": IpnsCmd,
 		"pubsub":  IpnsPubsubCmd,
+		"inspect": IpnsInspectCmd,
+	},
+}
+
+type IpnsInspectValidation struct {
+	Valid     bool
+	Reason    string
+	PublicKey peer.ID
+}
+
+// IpnsInspectEntry contains the deserialized values from an IPNS Entry:
+// https://github.com/ipfs/specs/blob/main/ipns/IPNS.md#record-serialization-format
+type IpnsInspectEntry struct {
+	Value        string
+	ValidityType *ipns_pb.IpnsEntry_ValidityType
+	Validity     *time.Time
+	Sequence     uint64
+	TTL          *uint64
+	PublicKey    string
+	SignatureV1  string
+	SignatureV2  string
+	Data         interface{}
+}
+
+type IpnsInspectResult struct {
+	Entry      IpnsInspectEntry
+	Validation *IpnsInspectValidation
+}
+
+var IpnsInspectCmd = &cmds.Command{
+	Status: cmds.Experimental,
+	Helptext: cmds.HelpText{
+		Tagline: "Inspects an IPNS Record",
+		ShortDescription: `
+Prints values inside of IPNS Record protobuf and its DAG-CBOR Data field.
+Passing --verify will verify signature against provided public key.
+`,
+		LongDescription: `
+Prints values inside of IPNS Record protobuf and its DAG-CBOR Data field.
+
+The input can be a file or STDIN, the output can be JSON:
+
+  $ ipfs routing get "/ipns/$PEERID" > ipns_record
+  $ ipfs name inspect --enc=json < ipns_record
+
+Values in PublicKey, SignatureV1 and SignatureV2 fields are raw bytes encoded
+in Multibase. The Data field is DAG-CBOR represented as DAG-JSON.
+
+Passing --verify will verify signature against provided public key.
+
+`,
+	},
+	Arguments: []cmds.Argument{
+		cmds.FileArg("record", true, false, "The IPNS record payload to be verified.").EnableStdin(),
+	},
+	Options: []cmds.Option{
+		cmds.StringOption("verify", "CID of the public IPNS key to validate against."),
+	},
+	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
+		file, err := cmdenv.GetFileArg(req.Files.Entries())
+		if err != nil {
+			return err
+		}
+		defer file.Close()
+
+		var b bytes.Buffer
+
+		_, err = io.Copy(&b, file)
+		if err != nil {
+			return err
+		}
+
+		var entry ipns_pb.IpnsEntry
+		err = proto.Unmarshal(b.Bytes(), &entry)
+		if err != nil {
+			return err
+		}
+
+		encoder, err := mbase.EncoderByName("base64")
+		if err != nil {
+			return err
+		}
+
+		result := &IpnsInspectResult{
+			Entry: IpnsInspectEntry{
+				Value:        string(entry.Value),
+				ValidityType: entry.ValidityType,
+				Sequence:     *entry.Sequence,
+				TTL:          entry.Ttl,
+				PublicKey:    encoder.Encode(entry.PubKey),
+				SignatureV1:  encoder.Encode(entry.SignatureV1),
+				SignatureV2:  encoder.Encode(entry.SignatureV2),
+				Data:         nil,
+			},
+		}
+
+		if len(entry.Data) != 0 {
+			// This is hacky. The variable node (datamodel.Node) doesn't directly marshal
+			// to JSON. Therefore, we need to first decode from DAG-CBOR, then encode in
+			// DAG-JSON and finally unmarshal it from JSON. Since DAG-JSON is a subset
+			// of JSON, that should work. Then, we can store the final value in the
+			// result.Entry.Data for further inspection.
+			node, err := ipld.Decode(entry.Data, dagcbor.Decode)
+			if err != nil {
+				return err
+			}
+
+			var buf bytes.Buffer
+			err = dagjson.Encode(node, &buf)
+			if err != nil {
+				return err
+			}
+
+			err = json.Unmarshal(buf.Bytes(), &result.Entry.Data)
+			if err != nil {
+				return err
+			}
+		}
+
+		validity, err := ipns.GetEOL(&entry)
+		if err == nil {
+			result.Entry.Validity = &validity
+		}
+
+		verify, ok := req.Options["verify"].(string)
+		if ok {
+			key := strings.TrimPrefix(verify, "/ipns/")
+			id, err := peer.Decode(key)
+			if err != nil {
+				return err
+			}
+
+			result.Validation = &IpnsInspectValidation{
+				PublicKey: id,
+			}
+
+			pub, err := id.ExtractPublicKey()
+			if err != nil {
+				// Make sure it works with all those RSA that cannot be embedded into the
+				// Peer ID.
+				if len(entry.PubKey) > 0 {
+					pub, err = ic.UnmarshalPublicKey(entry.PubKey)
+					if err != nil {
+						return err
+					}
+
+					// Verify the public key matches the name we are verifying.
+					entryID, err := peer.IDFromPublicKey(pub)
+
+					if err != nil {
+						return err
+					}
+
+					if id != entryID {
+						return fmt.Errorf("record public key does not match the verified name")
+					}
+				}
+			}
+			if err != nil {
+				return err
+			}
+
+			err = ipns.Validate(pub, &entry)
+			if err == nil {
+				result.Validation.Valid = true
+			} else {
+				result.Validation.Reason = err.Error()
+			}
+		}
+
+		return cmds.EmitOnce(res, result)
+	},
+	Type: IpnsInspectResult{},
+	Encoders: cmds.EncoderMap{
+		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *IpnsInspectResult) error {
+			tw := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
+			defer tw.Flush()
+
+			fmt.Fprintf(tw, "Value:\t%q\n", string(out.Entry.Value))
+			fmt.Fprintf(tw, "Validity Type:\t%q\n", out.Entry.ValidityType)
+			if out.Entry.Validity != nil {
+				fmt.Fprintf(tw, "Validity:\t%s\n", out.Entry.Validity.Format(time.RFC3339Nano))
+			}
+			fmt.Fprintf(tw, "Sequence:\t%d\n", out.Entry.Sequence)
+			if out.Entry.TTL != nil {
+				fmt.Fprintf(tw, "TTL:\t%d\n", *out.Entry.TTL)
+			}
+			fmt.Fprintf(tw, "PublicKey:\t%q\n", out.Entry.PublicKey)
+			fmt.Fprintf(tw, "Signature V1:\t%q\n", out.Entry.SignatureV1)
+			fmt.Fprintf(tw, "Signature V2:\t%q\n", out.Entry.SignatureV2)
+
+			data, err := json.Marshal(out.Entry.Data)
+			if err != nil {
+				return err
+			}
+			fmt.Fprintf(tw, "Data:\t%s\n", string(data))
+
+			if out.Validation == nil {
+				tw.Flush()
+				fmt.Fprintf(w, "\nThis record was not validated.\n")
+			} else {
+				tw.Flush()
+				fmt.Fprintf(w, "\nValidation results:\n")
+
+				fmt.Fprintf(tw, "\tValid:\t%v\n", out.Validation.Valid)
+				if out.Validation.Reason != "" {
+					fmt.Fprintf(tw, "\tReason:\t%s\n", out.Validation.Reason)
+				}
+				fmt.Fprintf(tw, "\tPublicKey:\t%s\n", out.Validation.PublicKey)
+			}
+
+			return nil
+		}),
 	},
 }
diff --git a/core/commands/profile.go b/core/commands/profile.go
index 3875cfdcba2cba6382ca4ea3f835a882c9f1f2a2..d25711dac228db3d0031251ef591a1e23995c474 100644
--- a/core/commands/profile.go
+++ b/core/commands/profile.go
@@ -49,7 +49,8 @@ The output file includes:
 
 - A list of running goroutines.
 - A CPU profile.
-- A heap profile.
+- A heap inuse profile.
+- A heap allocation profile.
 - A mutex profile.
 - A block profile.
 - Your copy of go-ipfs.
@@ -79,6 +80,7 @@ However, it could reveal:
 				profile.CollectorGoroutinesPprof,
 				profile.CollectorVersion,
 				profile.CollectorHeap,
+				profile.CollectorAllocs,
 				profile.CollectorBin,
 				profile.CollectorCPU,
 				profile.CollectorMutex,
diff --git a/core/commands/pubsub.go b/core/commands/pubsub.go
index ef8afcb4458c22cd9967e37eadfb529a3bcd056a..ee795e07829b5ec13e5274e91a33f287ab168b58 100644
--- a/core/commands/pubsub.go
+++ b/core/commands/pubsub.go
@@ -16,14 +16,14 @@ import (
 )
 
 var PubsubCmd = &cmds.Command{
-	Status: cmds.Experimental,
+	Status: cmds.Deprecated,
 	Helptext: cmds.HelpText{
 		Tagline: "An experimental publish-subscribe system on ipfs.",
 		ShortDescription: `
 ipfs pubsub allows you to publish messages to a given topic, and also to
 subscribe to new messages on a given topic.
 
-EXPERIMENTAL FEATURE
+DEPRECATED FEATURE (see https://github.com/ipfs/kubo/issues/9717)
 
   It is not intended in its current state to be used in a production
   environment.  To use, the daemon must be run with
@@ -46,13 +46,13 @@ type pubsubMessage struct {
 }
 
 var PubsubSubCmd = &cmds.Command{
-	Status: cmds.Experimental,
+	Status: cmds.Deprecated,
 	Helptext: cmds.HelpText{
 		Tagline: "Subscribe to messages on a given topic.",
 		ShortDescription: `
 ipfs pubsub sub subscribes to messages on a given topic.
 
-EXPERIMENTAL FEATURE
+DEPRECATED FEATURE (see https://github.com/ipfs/kubo/issues/9717)
 
   It is not intended in its current state to be used in a production
   environment.  To use, the daemon must be run with
@@ -145,14 +145,14 @@ TOPIC AND DATA ENCODING
 }
 
 var PubsubPubCmd = &cmds.Command{
-	Status: cmds.Experimental,
+	Status: cmds.Deprecated,
 	Helptext: cmds.HelpText{
 		Tagline: "Publish data to a given pubsub topic.",
 		ShortDescription: `
 ipfs pubsub pub publishes a message to a specified topic.
 It reads binary data from stdin or a file.
 
-EXPERIMENTAL FEATURE
+DEPRECATED FEATURE (see https://github.com/ipfs/kubo/issues/9717)
 
   It is not intended in its current state to be used in a production
   environment.  To use, the daemon must be run with
@@ -201,13 +201,13 @@ HTTP RPC ENCODING
 }
 
 var PubsubLsCmd = &cmds.Command{
-	Status: cmds.Experimental,
+	Status: cmds.Deprecated,
 	Helptext: cmds.HelpText{
 		Tagline: "List subscribed topics by name.",
 		ShortDescription: `
 ipfs pubsub ls lists out the names of topics you are currently subscribed to.
 
-EXPERIMENTAL FEATURE
+DEPRECATED FEATURE (see https://github.com/ipfs/kubo/issues/9717)
 
   It is not intended in its current state to be used in a production
   environment.  To use, the daemon must be run with
@@ -273,7 +273,7 @@ func safeTextListEncoder(req *cmds.Request, w io.Writer, list *stringList) error
 }
 
 var PubsubPeersCmd = &cmds.Command{
-	Status: cmds.Experimental,
+	Status: cmds.Deprecated,
 	Helptext: cmds.HelpText{
 		Tagline: "List peers we are currently pubsubbing with.",
 		ShortDescription: `
@@ -281,7 +281,7 @@ ipfs pubsub peers with no arguments lists out the pubsub peers you are
 currently connected to. If given a topic, it will list connected peers who are
 subscribed to the named topic.
 
-EXPERIMENTAL FEATURE
+DEPRECATED FEATURE (see https://github.com/ipfs/kubo/issues/9717)
 
   It is not intended in its current state to be used in a production
   environment.  To use, the daemon must be run with
diff --git a/core/commands/routing.go b/core/commands/routing.go
index bf7d2a6995b8e8b3a676165dd639ea0b4af8c856..460abb97ae4fe97156d5c3e390ae21ebb81575e7 100644
--- a/core/commands/routing.go
+++ b/core/commands/routing.go
@@ -135,6 +135,7 @@ const (
 )
 
 var provideRefRoutingCmd = &cmds.Command{
+	Status: cmds.Experimental,
 	Helptext: cmds.HelpText{
 		Tagline: "Announce to the network that you are providing given values.",
 	},
@@ -346,6 +347,7 @@ var findPeerRoutingCmd = &cmds.Command{
 }
 
 var getValueRoutingCmd = &cmds.Command{
+	Status: cmds.Experimental,
 	Helptext: cmds.HelpText{
 		Tagline: "Given a key, query the routing system for its best value.",
 		ShortDescription: `
@@ -362,78 +364,37 @@ Different key types can specify other 'best' rules.
 	Arguments: []cmds.Argument{
 		cmds.StringArg("key", true, true, "The key to find a value for."),
 	},
-	Options: []cmds.Option{
-		cmds.BoolOption(dhtVerboseOptionName, "v", "Print extra information."),
-	},
 	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
-		nd, err := cmdenv.GetNode(env)
+		api, err := cmdenv.GetApi(env, req)
 		if err != nil {
 			return err
 		}
 
-		if !nd.IsOnline {
-			return ErrNotOnline
-		}
-
-		dhtkey, err := escapeDhtKey(req.Arguments[0])
+		r, err := api.Routing().Get(req.Context, req.Arguments[0])
 		if err != nil {
 			return err
 		}
 
-		ctx, cancel := context.WithCancel(req.Context)
-		ctx, events := routing.RegisterForQueryEvents(ctx)
-
-		var getErr error
-		go func() {
-			defer cancel()
-			var val []byte
-			val, getErr = nd.Routing.GetValue(ctx, dhtkey)
-			if getErr != nil {
-				routing.PublishQueryEvent(ctx, &routing.QueryEvent{
-					Type:  routing.QueryError,
-					Extra: getErr.Error(),
-				})
-			} else {
-				routing.PublishQueryEvent(ctx, &routing.QueryEvent{
-					Type:  routing.Value,
-					Extra: base64.StdEncoding.EncodeToString(val),
-				})
-			}
-		}()
-
-		for e := range events {
-			if err := res.Emit(e); err != nil {
-				return err
-			}
-		}
-
-		return getErr
+		return res.Emit(routing.QueryEvent{
+			Extra: base64.StdEncoding.EncodeToString(r),
+			Type:  routing.Value,
+		})
 	},
 	Encoders: cmds.EncoderMap{
-		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
-			pfm := pfuncMap{
-				routing.Value: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
-					if verbose {
-						_, err := fmt.Fprintf(out, "got value: '%s'\n", obj.Extra)
-						return err
-					}
-					res, err := base64.StdEncoding.DecodeString(obj.Extra)
-					if err != nil {
-						return err
-					}
-					_, err = out.Write(res)
-					return err
-				},
+		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, obj *routing.QueryEvent) error {
+			res, err := base64.StdEncoding.DecodeString(obj.Extra)
+			if err != nil {
+				return err
 			}
-
-			verbose, _ := req.Options[dhtVerboseOptionName].(bool)
-			return printEvent(out, w, verbose, pfm)
+			_, err = w.Write(res)
+			return err
 		}),
 	},
 	Type: routing.QueryEvent{},
 }
 
 var putValueRoutingCmd = &cmds.Command{
+	Status: cmds.Experimental,
 	Helptext: cmds.HelpText{
 		Tagline: "Write a key/value pair to the routing system.",
 		ShortDescription: `
@@ -459,20 +420,8 @@ identified by QmFoo.
 		cmds.StringArg("key", true, false, "The key to store the value at."),
 		cmds.FileArg("value-file", true, false, "A path to a file containing the value to store.").EnableStdin(),
 	},
-	Options: []cmds.Option{
-		cmds.BoolOption(dhtVerboseOptionName, "v", "Print extra information."),
-	},
 	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
-		nd, err := cmdenv.GetNode(env)
-		if err != nil {
-			return err
-		}
-
-		if !nd.IsOnline {
-			return ErrNotOnline
-		}
-
-		key, err := escapeDhtKey(req.Arguments[0])
+		api, err := cmdenv.GetApi(env, req)
 		if err != nil {
 			return err
 		}
@@ -488,28 +437,20 @@ identified by QmFoo.
 			return err
 		}
 
-		ctx, cancel := context.WithCancel(req.Context)
-		ctx, events := routing.RegisterForQueryEvents(ctx)
-
-		var putErr error
-		go func() {
-			defer cancel()
-			putErr = nd.Routing.PutValue(ctx, key, []byte(data))
-			if putErr != nil {
-				routing.PublishQueryEvent(ctx, &routing.QueryEvent{
-					Type:  routing.QueryError,
-					Extra: putErr.Error(),
-				})
-			}
-		}()
+		err = api.Routing().Put(req.Context, req.Arguments[0], data)
+		if err != nil {
+			return err
+		}
 
-		for e := range events {
-			if err := res.Emit(e); err != nil {
-				return err
-			}
+		id, err := api.Key().Self(req.Context)
+		if err != nil {
+			return err
 		}
 
-		return putErr
+		return res.Emit(routing.QueryEvent{
+			Type: routing.Value,
+			ID:   id.ID(),
+		})
 	},
 	Encoders: cmds.EncoderMap{
 		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
diff --git a/core/commands/swarm.go b/core/commands/swarm.go
index d00291f78f5f4c7d3662c7140b80a773859e5395..7d5ae96afc0342ba9b367a2b33c7556fc6dc5fb6 100644
--- a/core/commands/swarm.go
+++ b/core/commands/swarm.go
@@ -1,7 +1,6 @@
 package commands
 
 import (
-	"bytes"
 	"context"
 	"encoding/json"
 	"errors"
@@ -9,10 +8,11 @@ import (
 	"io"
 	"path"
 	"sort"
+	"strconv"
 	"sync"
+	"text/tabwriter"
 	"time"
 
-	"github.com/ipfs/go-libipfs/files"
 	"github.com/ipfs/kubo/commands"
 	"github.com/ipfs/kubo/config"
 	"github.com/ipfs/kubo/core/commands/cmdenv"
@@ -57,8 +57,8 @@ ipfs peers in the internet.
 		"filters":    swarmFiltersCmd,
 		"peers":      swarmPeersCmd,
 		"peering":    swarmPeeringCmd,
-		"stats":      swarmStatsCmd, // libp2p Network Resource Manager
-		"limit":      swarmLimitCmd, // libp2p Network Resource Manager
+		"resources":  swarmResourcesCmd, // libp2p Network Resource Manager
+
 	},
 }
 
@@ -80,8 +80,8 @@ var swarmPeeringCmd = &cmds.Command{
 	Helptext: cmds.HelpText{
 		Tagline: "Modify the peering subsystem.",
 		ShortDescription: `
-'ipfs swarm peering' manages the peering subsystem. 
-Peers in the peering subsystem are maintained to be connected, reconnected 
+'ipfs swarm peering' manages the peering subsystem.
+Peers in the peering subsystem are maintained to be connected, reconnected
 on disconnect with a back-off.
 The changes are not saved to the config.
 `,
@@ -323,30 +323,15 @@ var swarmPeersCmd = &cmds.Command{
 	Type: connInfos{},
 }
 
-var swarmStatsCmd = &cmds.Command{
+var swarmResourcesCmd = &cmds.Command{
 	Status: cmds.Experimental,
 	Helptext: cmds.HelpText{
-		Tagline: "Report resource usage for a scope.",
-		LongDescription: `Report resource usage for a scope.
-The scope can be one of the following:
-- system        -- reports the system aggregate resource usage.
-- transient     -- reports the transient resource usage.
-- svc:<service> -- reports the resource usage of a specific service.
-- proto:<proto> -- reports the resource usage of a specific protocol.
-- peer:<peer>   -- reports the resource usage of a specific peer.
-- all           -- reports the resource usage for all currently active scopes.
-
-The output of this command is JSON.
-
-To see all resources that are close to hitting their respective limit, one can do something like:
-  ipfs swarm stats --min-used-limit-perc=90 all
+		Tagline: "Get a summary of all resources accounted for by the libp2p Resource Manager.",
+		LongDescription: `
+Get a summary of all resources accounted for by the libp2p Resource Manager.
+This includes the limits and the usage against those limits.
+This can output a human readable table and JSON encoding.
 `},
-	Arguments: []cmds.Argument{
-		cmds.StringArg("scope", true, false, "scope of the stat report"),
-	},
-	Options: []cmds.Option{
-		cmds.IntOption(swarmUsedResourcesPercentageName, "Only display resources that are using above the specified percentage of their respective limit"),
-	},
 	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
 		node, err := cmdenv.GetNode(env)
 		if err != nil {
@@ -357,125 +342,68 @@ To see all resources that are close to hitting their respective limit, one can d
 			return libp2p.ErrNoResourceMgr
 		}
 
-		if len(req.Arguments) != 1 {
-			return fmt.Errorf("must specify exactly one scope")
-		}
-
-		percentage, _ := req.Options[swarmUsedResourcesPercentageName].(int)
-		scope := req.Arguments[0]
-
-		if percentage != 0 && scope != "all" {
-			return fmt.Errorf("%q can only be used when scope is %q", swarmUsedResourcesPercentageName, "all")
-		}
-
-		result, err := libp2p.NetStat(node.ResourceManager, scope, percentage)
+		cfg, err := node.Repo.Config()
 		if err != nil {
 			return err
 		}
 
-		b := new(bytes.Buffer)
-		enc := json.NewEncoder(b)
-		err = enc.Encode(result)
+		userResourceOverrides, err := node.Repo.UserResourceOverrides()
 		if err != nil {
 			return err
 		}
-		return cmds.EmitOnce(res, b)
-	},
-	Encoders: cmds.EncoderMap{
-		cmds.Text: HumanJSONEncoder,
-	},
-}
-
-var swarmLimitCmd = &cmds.Command{
-	Status: cmds.Experimental,
-	Helptext: cmds.HelpText{
-		Tagline: "Get or set resource limits for a scope.",
-		LongDescription: `Get or set resource limits for a scope.
-The scope can be one of the following:
-- all           -- all limits actually being applied.
-- system        -- limits for the system aggregate resource usage.
-- transient     -- limits for the transient resource usage.
-- svc:<service> -- limits for the resource usage of a specific service.
-- proto:<proto> -- limits for the resource usage of a specific protocol.
-- peer:<peer>   -- limits for the resource usage of a specific peer.
-
-The output of this command is JSON.
-
-It is possible to use this command to inspect and tweak limits at runtime:
-
-	$ ipfs swarm limit system > limit.json
-	$ vi limit.json
-	$ ipfs swarm limit system limit.json
 
-Changes made via command line are persisted in the Swarm.ResourceMgr.Limits field of the $IPFS_PATH/config file.
-`},
-	Arguments: []cmds.Argument{
-		cmds.StringArg("scope", true, false, "scope of the limit"),
-		cmds.FileArg("limit.json", false, false, "limits to be set").EnableStdin(),
-	},
-	Options: []cmds.Option{
-		cmds.BoolOption(swarmResetLimitsOptionName, "reset limit to default"),
-	},
-	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
-		node, err := cmdenv.GetNode(env)
+		// FIXME: we shouldn't recompute limits, either save them or load them from libp2p (https://github.com/libp2p/go-libp2p/issues/2166)
+		limitConfig, _, err := libp2p.LimitConfig(cfg.Swarm, userResourceOverrides)
 		if err != nil {
 			return err
 		}
 
-		if node.ResourceManager == nil {
+		rapi, ok := node.ResourceManager.(rcmgr.ResourceManagerState)
+		if !ok { // NullResourceManager
 			return libp2p.ErrNoResourceMgr
 		}
 
-		scope := req.Arguments[0]
-
-		//  set scope limit to new values (when limit.json is passed as a second arg)
-		if req.Files != nil {
-			var newLimit rcmgr.BaseLimit
-			it := req.Files.Entries()
-			if it.Next() {
-				file := files.FileFromEntry(it)
-				if file == nil {
-					return errors.New("expected a JSON file")
-				}
-
-				r := io.LimitReader(file, 32*1024*1024) // 32MiB
-
-				if err := json.NewDecoder(r).Decode(&newLimit); err != nil {
-					return fmt.Errorf("decoding JSON as ResourceMgrScopeConfig: %w", err)
+		return cmds.EmitOnce(res, libp2p.MergeLimitsAndStatsIntoLimitsConfigAndUsage(limitConfig, rapi.Stat()))
+	},
+	Encoders: cmds.EncoderMap{
+		cmds.JSON: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, limitsAndUsage libp2p.LimitsConfigAndUsage) error {
+			return json.NewEncoder(w).Encode(limitsAndUsage)
+		}),
+		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, limitsAndUsage libp2p.LimitsConfigAndUsage) error {
+			tw := tabwriter.NewWriter(w, 20, 8, 0, '\t', 0)
+			defer tw.Flush()
+
+			fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t\n", "Scope", "Limit Name", "Limit Value", "Limit Usage Amount", "Limit Usage Percent")
+			for _, ri := range libp2p.LimitConfigsToInfo(limitsAndUsage) {
+				var limit, percentage string
+				switch ri.LimitValue {
+				case rcmgr.Unlimited64:
+					limit = "unlimited"
+					percentage = "n/a"
+				case rcmgr.BlockAllLimit64:
+					limit = "blockAll"
+					percentage = "n/a"
+				default:
+					limit = strconv.FormatInt(int64(ri.LimitValue), 10)
+					if ri.CurrentUsage == 0 {
+						percentage = "0%"
+					} else {
+						percentage = strconv.FormatFloat(float64(ri.CurrentUsage)/float64(ri.LimitValue)*100, 'f', 1, 64) + "%"
+					}
 				}
-				return libp2p.NetSetLimit(node.ResourceManager, node.Repo, scope, newLimit)
+				fmt.Fprintf(tw, "%s\t%s\t%s\t%d\t%s\t\n",
+					ri.ScopeName,
+					ri.LimitName,
+					limit,
+					ri.CurrentUsage,
+					percentage,
+				)
 			}
-			if err := it.Err(); err != nil {
-				return fmt.Errorf("error opening limit JSON file: %w", err)
-			}
-		}
 
-		var result interface{}
-		_, reset := req.Options[swarmResetLimitsOptionName]
-		if reset {
-			result, err = libp2p.NetResetLimit(node.ResourceManager, node.Repo, scope)
-		} else if scope == "all" {
-			result, err = libp2p.NetLimitAll(node.ResourceManager)
-		} else {
-			// get scope limit
-			result, err = libp2p.NetLimit(node.ResourceManager, scope)
-		}
-
-		if err != nil {
-			return err
-		}
-
-		b := new(bytes.Buffer)
-		enc := json.NewEncoder(b)
-		err = enc.Encode(result)
-		if err != nil {
-			return err
-		}
-		return cmds.EmitOnce(res, b)
-	},
-	Encoders: cmds.EncoderMap{
-		cmds.Text: HumanJSONEncoder,
+			return nil
+		}),
 	},
+	Type: libp2p.LimitsConfigAndUsage{},
 }
 
 type streamInfo struct {
diff --git a/core/coreapi/block.go b/core/coreapi/block.go
index 886a21bf4e2ac1526992ae4ab3053e3b9970cb9b..450f06f3bdc24e9f3ac8149c8a39e38dc8a3c587 100644
--- a/core/coreapi/block.go
+++ b/core/coreapi/block.go
@@ -6,9 +6,9 @@ import (
 	"errors"
 	"io"
 
-	blocks "github.com/ipfs/go-block-format"
 	cid "github.com/ipfs/go-cid"
 	pin "github.com/ipfs/go-ipfs-pinner"
+	blocks "github.com/ipfs/go-libipfs/blocks"
 	coreiface "github.com/ipfs/interface-go-ipfs-core"
 	caopts "github.com/ipfs/interface-go-ipfs-core/options"
 	path "github.com/ipfs/interface-go-ipfs-core/path"
@@ -60,7 +60,9 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
 	}
 
 	if settings.Pin {
-		api.pinning.PinWithMode(b.Cid(), pin.Recursive)
+		if err = api.pinning.PinWithMode(ctx, b.Cid(), pin.Recursive); err != nil {
+			return nil, err
+		}
 		if err := api.pinning.Flush(ctx); err != nil {
 			return nil, err
 		}
diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go
index fb549171a6cee0be26aebee21d7fb8f2f6c40ed3..85bd60c12403a4c8dc1b1b5da84890e413ffd437 100644
--- a/core/coreapi/coreapi.go
+++ b/core/coreapi/coreapi.go
@@ -144,6 +144,11 @@ func (api *CoreAPI) PubSub() coreiface.PubSubAPI {
 	return (*PubSubAPI)(api)
 }
 
+// Routing returns the RoutingAPI interface implementation backed by the kubo node
+func (api *CoreAPI) Routing() coreiface.RoutingAPI {
+	return (*RoutingAPI)(api)
+}
+
 // WithOptions returns api with global options applied
 func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, error) {
 	settings := api.parentOpts // make sure to copy
diff --git a/core/coreapi/dag.go b/core/coreapi/dag.go
index 0f38fc4d56aa5b34f93353107d13df4da4ceca25..b352a2d3f46476ab7b4972d742ecf51a90ba319f 100644
--- a/core/coreapi/dag.go
+++ b/core/coreapi/dag.go
@@ -7,9 +7,10 @@ import (
 	pin "github.com/ipfs/go-ipfs-pinner"
 	ipld "github.com/ipfs/go-ipld-format"
 	dag "github.com/ipfs/go-merkledag"
-	"github.com/ipfs/kubo/tracing"
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/trace"
+
+	"github.com/ipfs/kubo/tracing"
 )
 
 type dagAPI struct {
@@ -29,7 +30,9 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
 		return err
 	}
 
-	adder.pinning.PinWithMode(nd.Cid(), pin.Recursive)
+	if err := adder.pinning.PinWithMode(ctx, nd.Cid(), pin.Recursive); err != nil {
+		return err
+	}
 
 	return adder.pinning.Flush(ctx)
 }
@@ -48,7 +51,9 @@ func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
 	for _, nd := range nds {
 		c := nd.Cid()
 		if cids.Visit(c) {
-			adder.pinning.PinWithMode(c, pin.Recursive)
+			if err := adder.pinning.PinWithMode(ctx, c, pin.Recursive); err != nil {
+				return err
+			}
 		}
 	}
 
diff --git a/core/coreapi/name.go b/core/coreapi/name.go
index 69dc1137bf0e06e90789eec11b7769bd22221b07..87af34af476615eebac224d24012b1c61fd77f82 100644
--- a/core/coreapi/name.go
+++ b/core/coreapi/name.go
@@ -15,6 +15,7 @@ import (
 	ipath "github.com/ipfs/go-path"
 	coreiface "github.com/ipfs/interface-go-ipfs-core"
 	caopts "github.com/ipfs/interface-go-ipfs-core/options"
+	nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
 	path "github.com/ipfs/interface-go-ipfs-core/path"
 	ci "github.com/libp2p/go-libp2p/core/crypto"
 	peer "github.com/libp2p/go-libp2p/core/peer"
@@ -37,8 +38,6 @@ func (e *ipnsEntry) Value() path.Path {
 	return e.value
 }
 
-type requestContextKey string
-
 // Publish announces new IPNS name and returns the new IPNS entry.
 func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.NamePublishOption) (coreiface.IpnsEntry, error) {
 	ctx, span := tracing.Span(ctx, "CoreAPI.NameAPI", "Publish", trace.WithAttributes(attribute.String("path", p.String())))
@@ -76,13 +75,17 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam
 		return nil, err
 	}
 
+	eol := time.Now().Add(options.ValidTime)
+
+	publishOptions := []nsopts.PublishOption{
+		nsopts.PublishWithEOL(eol),
+	}
+
 	if options.TTL != nil {
-		// nolint: staticcheck // non-backward compatible change
-		ctx = context.WithValue(ctx, requestContextKey("ipns-publish-ttl"), *options.TTL)
+		publishOptions = append(publishOptions, nsopts.PublishWithTTL(*options.TTL))
 	}
 
-	eol := time.Now().Add(options.ValidTime)
-	err = api.namesys.PublishWithEOL(ctx, k, pth, eol)
+	err = api.namesys.Publish(ctx, k, pth, publishOptions...)
 	if err != nil {
 		return nil, err
 	}
diff --git a/core/coreapi/object.go b/core/coreapi/object.go
index 28dd0df08f63feedf67928d04a43b663b5df2cb9..4b509c78210c13618c99690cf139aafd0ff72893 100644
--- a/core/coreapi/object.go
+++ b/core/coreapi/object.go
@@ -19,9 +19,10 @@ import (
 	coreiface "github.com/ipfs/interface-go-ipfs-core"
 	caopts "github.com/ipfs/interface-go-ipfs-core/options"
 	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/tracing"
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/trace"
+
+	"github.com/ipfs/kubo/tracing"
 )
 
 const inputLimit = 2 << 20
@@ -132,7 +133,10 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj
 	}
 
 	if options.Pin {
-		api.pinning.PinWithMode(dagnode.Cid(), pin.Recursive)
+		if err := api.pinning.PinWithMode(ctx, dagnode.Cid(), pin.Recursive); err != nil {
+			return nil, err
+		}
+
 		err = api.pinning.Flush(ctx)
 		if err != nil {
 			return nil, err
diff --git a/core/coreapi/routing.go b/core/coreapi/routing.go
new file mode 100644
index 0000000000000000000000000000000000000000..78f21c42997f7bc934db8490d4f234c7844b9189
--- /dev/null
+++ b/core/coreapi/routing.go
@@ -0,0 +1,53 @@
+package coreapi
+
+import (
+	"context"
+	"errors"
+
+	"github.com/ipfs/go-path"
+	coreiface "github.com/ipfs/interface-go-ipfs-core"
+	peer "github.com/libp2p/go-libp2p/core/peer"
+)
+
+type RoutingAPI CoreAPI
+
+func (r *RoutingAPI) Get(ctx context.Context, key string) ([]byte, error) {
+	if !r.nd.IsOnline {
+		return nil, coreiface.ErrOffline
+	}
+
+	dhtKey, err := normalizeKey(key)
+	if err != nil {
+		return nil, err
+	}
+
+	return r.routing.GetValue(ctx, dhtKey)
+}
+
+func (r *RoutingAPI) Put(ctx context.Context, key string, value []byte) error {
+	if !r.nd.IsOnline {
+		return coreiface.ErrOffline
+	}
+
+	dhtKey, err := normalizeKey(key)
+	if err != nil {
+		return err
+	}
+
+	return r.routing.PutValue(ctx, dhtKey, value)
+}
+
+func normalizeKey(s string) (string, error) {
+	parts := path.SplitList(s)
+	if len(parts) != 3 ||
+		parts[0] != "" ||
+		!(parts[1] == "ipns" || parts[1] == "pk") {
+		return "", errors.New("invalid key")
+	}
+
+	k, err := peer.Decode(parts[2])
+	if err != nil {
+		return "", err
+	}
+	return path.Join(append(parts[:2], string(k))), nil
+}
diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go
index 334000b5ab31e846c74f50585c71c0192b867407..c20ab6e4a4f518a5b18e797f34bc90d324fe09c9 100644
--- a/core/corehttp/gateway.go
+++ b/core/corehttp/gateway.go
@@ -3,60 +3,27 @@ package corehttp
 import (
 	"context"
 	"fmt"
+	"io"
 	"net"
 	"net/http"
-	"sort"
 
-	coreiface "github.com/ipfs/interface-go-ipfs-core"
+	cid "github.com/ipfs/go-cid"
+	"github.com/ipfs/go-libipfs/blocks"
+	"github.com/ipfs/go-libipfs/files"
+	"github.com/ipfs/go-libipfs/gateway"
+	"github.com/ipfs/go-namesys"
+	iface "github.com/ipfs/interface-go-ipfs-core"
 	options "github.com/ipfs/interface-go-ipfs-core/options"
-	path "github.com/ipfs/interface-go-ipfs-core/path"
+	nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
+	"github.com/ipfs/interface-go-ipfs-core/path"
 	version "github.com/ipfs/kubo"
+	config "github.com/ipfs/kubo/config"
 	core "github.com/ipfs/kubo/core"
 	coreapi "github.com/ipfs/kubo/core/coreapi"
 	id "github.com/libp2p/go-libp2p/p2p/protocol/identify"
 	"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
 )
 
-type GatewayConfig struct {
-	Headers  map[string][]string
-	Writable bool
-}
-
-// NodeAPI defines the minimal set of API services required by a gateway handler
-type NodeAPI interface {
-	// Unixfs returns an implementation of Unixfs API
-	Unixfs() coreiface.UnixfsAPI
-
-	// Block returns an implementation of Block API
-	Block() coreiface.BlockAPI
-
-	// Dag returns an implementation of Dag API
-	Dag() coreiface.APIDagService
-
-	// ResolvePath resolves the path using Unixfs resolver
-	ResolvePath(context.Context, path.Path) (path.Resolved, error)
-}
-
-// A helper function to clean up a set of headers:
-// 1. Canonicalizes.
-// 2. Deduplicates.
-// 3. Sorts.
-func cleanHeaderSet(headers []string) []string {
-	// Deduplicate and canonicalize.
-	m := make(map[string]struct{}, len(headers))
-	for _, h := range headers {
-		m[http.CanonicalHeaderKey(h)] = struct{}{}
-	}
-	result := make([]string, 0, len(m))
-	for k := range m {
-		result = append(result, k)
-	}
-
-	// Sort
-	sort.Strings(result)
-	return result
-}
-
 func GatewayOption(writable bool, paths ...string) ServeOption {
 	return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
 		cfg, err := n.Repo.Config()
@@ -74,69 +41,70 @@ func GatewayOption(writable bool, paths ...string) ServeOption {
 			headers[http.CanonicalHeaderKey(h)] = v
 		}
 
-		AddAccessControlHeaders(headers)
+		gateway.AddAccessControlHeaders(headers)
+
+		gwConfig := gateway.Config{
+			Headers: headers,
+		}
 
-		offlineAPI, err := api.WithOptions(options.Api.Offline(true))
+		gwAPI, err := newGatewayAPI(n)
 		if err != nil {
 			return nil, err
 		}
 
-		gateway := NewGatewayHandler(GatewayConfig{
-			Headers:  headers,
-			Writable: writable,
-		}, api, offlineAPI)
-
-		gateway = otelhttp.NewHandler(gateway, "Gateway.Request")
+		gw := gateway.NewHandler(gwConfig, gwAPI)
+		gw = otelhttp.NewHandler(gw, "Gateway.Request")
+
+		// By default, our HTTP handler is the gateway handler.
+		handler := gw.ServeHTTP
+
+		// If we have the writable gateway enabled, we have to replace our
+		// http handler by a handler that takes care of the different methods.
+		if writable {
+			writableGw := &writableGatewayHandler{
+				config: &gwConfig,
+				api:    api,
+			}
+
+			handler = func(w http.ResponseWriter, r *http.Request) {
+				switch r.Method {
+				case http.MethodPost:
+					writableGw.postHandler(w, r)
+				case http.MethodDelete:
+					writableGw.deleteHandler(w, r)
+				case http.MethodPut:
+					writableGw.putHandler(w, r)
+				default:
+					gw.ServeHTTP(w, r)
+				}
+			}
+		}
 
 		for _, p := range paths {
-			mux.Handle(p+"/", gateway)
+			mux.HandleFunc(p+"/", handler)
 		}
+
 		return mux, nil
 	}
 }
 
-// AddAccessControlHeaders adds default headers used for controlling
-// cross-origin requests. This function adds several values to the
-// Access-Control-Allow-Headers and Access-Control-Expose-Headers entries.
-// If the Access-Control-Allow-Origin entry is missing a value of '*' is
-// added, indicating that browsers should allow requesting code from any
-// origin to access the resource.
-// If the Access-Control-Allow-Methods entry is missing a value of 'GET' is
-// added, indicating that browsers may use the GET method when issuing cross
-// origin requests.
-func AddAccessControlHeaders(headers map[string][]string) {
-	// Hard-coded headers.
-	const ACAHeadersName = "Access-Control-Allow-Headers"
-	const ACEHeadersName = "Access-Control-Expose-Headers"
-	const ACAOriginName = "Access-Control-Allow-Origin"
-	const ACAMethodsName = "Access-Control-Allow-Methods"
-
-	if _, ok := headers[ACAOriginName]; !ok {
-		// Default to *all*
-		headers[ACAOriginName] = []string{"*"}
-	}
-	if _, ok := headers[ACAMethodsName]; !ok {
-		// Default to GET
-		headers[ACAMethodsName] = []string{http.MethodGet}
-	}
+func HostnameOption() ServeOption {
+	return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
+		cfg, err := n.Repo.Config()
+		if err != nil {
+			return nil, err
+		}
+
+		gwAPI, err := newGatewayAPI(n)
+		if err != nil {
+			return nil, err
+		}
 
-	headers[ACAHeadersName] = cleanHeaderSet(
-		append([]string{
-			"Content-Type",
-			"User-Agent",
-			"Range",
-			"X-Requested-With",
-		}, headers[ACAHeadersName]...))
-
-	headers[ACEHeadersName] = cleanHeaderSet(
-		append([]string{
-			"Content-Length",
-			"Content-Range",
-			"X-Chunked-Output",
-			"X-Stream-Output",
-			"X-Ipfs-Path",
-			"X-Ipfs-Roots",
-		}, headers[ACEHeadersName]...))
+		publicGateways := convertPublicGateways(cfg.Gateway.PublicGateways)
+		childMux := http.NewServeMux()
+		mux.HandleFunc("/", gateway.WithHostname(childMux, gwAPI, publicGateways, cfg.Gateway.NoDNSLink).ServeHTTP)
+		return childMux, nil
+	}
 }
 
 func VersionOption() ServeOption {
@@ -149,3 +117,119 @@ func VersionOption() ServeOption {
 		return mux, nil
 	}
 }
+
+type gatewayAPI struct {
+	ns         namesys.NameSystem
+	api        iface.CoreAPI
+	offlineAPI iface.CoreAPI
+}
+
+func newGatewayAPI(n *core.IpfsNode) (*gatewayAPI, error) {
+	cfg, err := n.Repo.Config()
+	if err != nil {
+		return nil, err
+	}
+
+	api, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch))
+	if err != nil {
+		return nil, err
+	}
+	offlineAPI, err := api.WithOptions(options.Api.Offline(true))
+	if err != nil {
+		return nil, err
+	}
+
+	return &gatewayAPI{
+		ns:         n.Namesys,
+		api:        api,
+		offlineAPI: offlineAPI,
+	}, nil
+}
+
+func (gw *gatewayAPI) GetUnixFsNode(ctx context.Context, pth path.Resolved) (files.Node, error) {
+	return gw.api.Unixfs().Get(ctx, pth)
+}
+
+func (gw *gatewayAPI) LsUnixFsDir(ctx context.Context, pth path.Resolved) (<-chan iface.DirEntry, error) {
+	// Optimization: use Unixfs.Ls without resolving children, but using the
+	// cumulative DAG size as the file size. This allows for a fast listing
+	// while keeping a good enough Size field.
+	return gw.api.Unixfs().Ls(ctx, pth,
+		options.Unixfs.ResolveChildren(false),
+		options.Unixfs.UseCumulativeSize(true),
+	)
+}
+
+func (gw *gatewayAPI) GetBlock(ctx context.Context, cid cid.Cid) (blocks.Block, error) {
+	r, err := gw.api.Block().Get(ctx, path.IpfsPath(cid))
+	if err != nil {
+		return nil, err
+	}
+
+	data, err := io.ReadAll(r)
+	if err != nil {
+		return nil, err
+	}
+
+	return blocks.NewBlockWithCid(data, cid)
+}
+
+func (gw *gatewayAPI) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte, error) {
+	return gw.api.Routing().Get(ctx, "/ipns/"+c.String())
+}
+
+func (gw *gatewayAPI) GetDNSLinkRecord(ctx context.Context, hostname string) (path.Path, error) {
+	p, err := gw.ns.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
+	if err == namesys.ErrResolveRecursion {
+		err = nil
+	}
+	return path.New(p.String()), err
+}
+
+func (gw *gatewayAPI) IsCached(ctx context.Context, pth path.Path) bool {
+	_, err := gw.offlineAPI.Block().Stat(ctx, pth)
+	return err == nil
+}
+
+func (gw *gatewayAPI) ResolvePath(ctx context.Context, pth path.Path) (path.Resolved, error) {
+	return gw.api.ResolvePath(ctx, pth)
+}
+
+var defaultPaths = []string{"/ipfs/", "/ipns/", "/api/", "/p2p/"}
+
+var subdomainGatewaySpec = &gateway.Specification{
+	Paths:         defaultPaths,
+	UseSubdomains: true,
+}
+
+var defaultKnownGateways = map[string]*gateway.Specification{
+	"localhost": subdomainGatewaySpec,
+}
+
+func convertPublicGateways(publicGateways map[string]*config.GatewaySpec) map[string]*gateway.Specification {
+	gws := map[string]*gateway.Specification{}
+
+	// First, implicit defaults such as subdomain gateway on localhost
+	for hostname, gw := range defaultKnownGateways {
+		gws[hostname] = gw
+	}
+
+	// Then apply values from Gateway.PublicGateways, if present in the config
+	for hostname, gw := range publicGateways {
+		if gw == nil {
+			// Remove any implicit defaults, if present. This is useful when one
+			// wants to disable subdomain gateway on localhost etc.
+			delete(gws, hostname)
+			continue
+		}
+
+		gws[hostname] = &gateway.Specification{
+			Paths:         gw.Paths,
+			NoDNSLink:     gw.NoDNSLink,
+			UseSubdomains: gw.UseSubdomains,
+			InlineDNSLink: gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink),
+		}
+	}
+
+	return gws
+}
diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go
deleted file mode 100644
index 1c6797e685d011d17d3b4e90b960edcfe3a04537..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler.go
+++ /dev/null
@@ -1,1111 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"fmt"
-	"html/template"
-	"io"
-	"mime"
-	"net/http"
-	"net/textproto"
-	"net/url"
-	"os"
-	gopath "path"
-	"regexp"
-	"runtime/debug"
-	"strings"
-	"time"
-
-	cid "github.com/ipfs/go-cid"
-	ipld "github.com/ipfs/go-ipld-format"
-	"github.com/ipfs/go-libipfs/files"
-	dag "github.com/ipfs/go-merkledag"
-	mfs "github.com/ipfs/go-mfs"
-	path "github.com/ipfs/go-path"
-	"github.com/ipfs/go-path/resolver"
-	coreiface "github.com/ipfs/interface-go-ipfs-core"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	routing "github.com/libp2p/go-libp2p/core/routing"
-	mc "github.com/multiformats/go-multicodec"
-	prometheus "github.com/prometheus/client_golang/prometheus"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-	"go.uber.org/zap"
-)
-
-const (
-	ipfsPathPrefix        = "/ipfs/"
-	ipnsPathPrefix        = "/ipns/"
-	immutableCacheControl = "public, max-age=29030400, immutable"
-)
-
-var (
-	onlyASCII = regexp.MustCompile("[[:^ascii:]]")
-	noModtime = time.Unix(0, 0) // disables Last-Modified header if passed as modtime
-)
-
-// HTML-based redirect for errors which can be recovered from, but we want
-// to provide hint to people that they should fix things on their end.
-var redirectTemplate = template.Must(template.New("redirect").Parse(`<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="utf-8">
-		<meta http-equiv="refresh" content="10;url={{.RedirectURL}}" />
-		<link rel="canonical" href="{{.RedirectURL}}" />
-	</head>
-	<body>
-		<pre>{{.ErrorMsg}}</pre><pre>(if a redirect does not happen in 10 seconds, use "{{.SuggestedPath}}" instead)</pre>
-	</body>
-</html>`))
-
-type redirectTemplateData struct {
-	RedirectURL   string
-	SuggestedPath string
-	ErrorMsg      string
-}
-
-// gatewayHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
-// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
-type gatewayHandler struct {
-	config     GatewayConfig
-	api        NodeAPI
-	offlineAPI NodeAPI
-
-	// generic metrics
-	firstContentBlockGetMetric *prometheus.HistogramVec
-	unixfsGetMetric            *prometheus.SummaryVec // deprecated, use firstContentBlockGetMetric
-
-	// response type metrics
-	unixfsFileGetMetric   *prometheus.HistogramVec
-	unixfsGenDirGetMetric *prometheus.HistogramVec
-	carStreamGetMetric    *prometheus.HistogramVec
-	rawBlockGetMetric     *prometheus.HistogramVec
-}
-
-// StatusResponseWriter enables us to override HTTP Status Code passed to
-// WriteHeader function inside of http.ServeContent.  Decision is based on
-// presence of HTTP Headers such as Location.
-type statusResponseWriter struct {
-	http.ResponseWriter
-}
-
-// Custom type for collecting error details to be handled by `webRequestError`
-type requestError struct {
-	Message    string
-	StatusCode int
-	Err        error
-}
-
-func (r *requestError) Error() string {
-	return r.Err.Error()
-}
-
-func newRequestError(message string, err error, statusCode int) *requestError {
-	return &requestError{
-		Message:    message,
-		Err:        err,
-		StatusCode: statusCode,
-	}
-}
-
-func (sw *statusResponseWriter) WriteHeader(code int) {
-	// Check if we need to adjust Status Code to account for scheduled redirect
-	// This enables us to return payload along with HTTP 301
-	// for subdomain redirect in web browsers while also returning body for cli
-	// tools which do not follow redirects by default (curl, wget).
-	redirect := sw.ResponseWriter.Header().Get("Location")
-	if redirect != "" && code == http.StatusOK {
-		code = http.StatusMovedPermanently
-		log.Debugw("subdomain redirect", "location", redirect, "status", code)
-	}
-	sw.ResponseWriter.WriteHeader(code)
-}
-
-// ServeContent replies to the request using the content in the provided ReadSeeker
-// and returns the status code written and any error encountered during a write.
-// It wraps http.ServeContent which takes care of If-None-Match+Etag,
-// Content-Length and range requests.
-func ServeContent(w http.ResponseWriter, req *http.Request, name string, modtime time.Time, content io.ReadSeeker) (int, bool, error) {
-	ew := &errRecordingResponseWriter{ResponseWriter: w}
-	http.ServeContent(ew, req, name, modtime, content)
-
-	// When we calculate some metrics we want a flag that lets us to ignore
-	// errors and 304 Not Modified, and only care when requested data
-	// was sent in full.
-	dataSent := ew.code/100 == 2 && ew.err == nil
-
-	return ew.code, dataSent, ew.err
-}
-
-// errRecordingResponseWriter wraps a ResponseWriter to record the status code and any write error.
-type errRecordingResponseWriter struct {
-	http.ResponseWriter
-	code int
-	err  error
-}
-
-func (w *errRecordingResponseWriter) WriteHeader(code int) {
-	if w.code == 0 {
-		w.code = code
-	}
-	w.ResponseWriter.WriteHeader(code)
-}
-
-func (w *errRecordingResponseWriter) Write(p []byte) (int, error) {
-	n, err := w.ResponseWriter.Write(p)
-	if err != nil && w.err == nil {
-		w.err = err
-	}
-	return n, err
-}
-
-// ReadFrom exposes errRecordingResponseWriter's underlying ResponseWriter to io.Copy
-// to allow optimized methods to be taken advantage of.
-func (w *errRecordingResponseWriter) ReadFrom(r io.Reader) (n int64, err error) {
-	n, err = io.Copy(w.ResponseWriter, r)
-	if err != nil && w.err == nil {
-		w.err = err
-	}
-	return n, err
-}
-
-func newGatewaySummaryMetric(name string, help string) *prometheus.SummaryVec {
-	summaryMetric := prometheus.NewSummaryVec(
-		prometheus.SummaryOpts{
-			Namespace: "ipfs",
-			Subsystem: "http",
-			Name:      name,
-			Help:      help,
-		},
-		[]string{"gateway"},
-	)
-	if err := prometheus.Register(summaryMetric); err != nil {
-		if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
-			summaryMetric = are.ExistingCollector.(*prometheus.SummaryVec)
-		} else {
-			log.Errorf("failed to register ipfs_http_%s: %v", name, err)
-		}
-	}
-	return summaryMetric
-}
-
-func newGatewayHistogramMetric(name string, help string) *prometheus.HistogramVec {
-	// We can add buckets as a parameter in the future, but for now using static defaults
-	// suggested in https://github.com/ipfs/kubo/issues/8441
-	defaultBuckets := []float64{0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 30, 60}
-	histogramMetric := prometheus.NewHistogramVec(
-		prometheus.HistogramOpts{
-			Namespace: "ipfs",
-			Subsystem: "http",
-			Name:      name,
-			Help:      help,
-			Buckets:   defaultBuckets,
-		},
-		[]string{"gateway"},
-	)
-	if err := prometheus.Register(histogramMetric); err != nil {
-		if are, ok := err.(prometheus.AlreadyRegisteredError); ok {
-			histogramMetric = are.ExistingCollector.(*prometheus.HistogramVec)
-		} else {
-			log.Errorf("failed to register ipfs_http_%s: %v", name, err)
-		}
-	}
-	return histogramMetric
-}
-
-// NewGatewayHandler returns an http.Handler that can act as a gateway to IPFS content
-// offlineApi is a version of the API that should not make network requests for missing data
-func NewGatewayHandler(c GatewayConfig, api NodeAPI, offlineAPI NodeAPI) http.Handler {
-	return newGatewayHandler(c, api, offlineAPI)
-}
-
-func newGatewayHandler(c GatewayConfig, api NodeAPI, offlineAPI NodeAPI) *gatewayHandler {
-	i := &gatewayHandler{
-		config:     c,
-		api:        api,
-		offlineAPI: offlineAPI,
-		// Improved Metrics
-		// ----------------------------
-		// Time till the first content block (bar in /ipfs/cid/foo/bar)
-		// (format-agnostic, across all response types)
-		firstContentBlockGetMetric: newGatewayHistogramMetric(
-			"gw_first_content_block_get_latency_seconds",
-			"The time till the first content block is received on GET from the gateway.",
-		),
-
-		// Response-type specific metrics
-		// ----------------------------
-		// UnixFS: time it takes to return a file
-		unixfsFileGetMetric: newGatewayHistogramMetric(
-			"gw_unixfs_file_get_duration_seconds",
-			"The time to serve an entire UnixFS file from the gateway.",
-		),
-		// UnixFS: time it takes to generate static HTML with directory listing
-		unixfsGenDirGetMetric: newGatewayHistogramMetric(
-			"gw_unixfs_gen_dir_listing_get_duration_seconds",
-			"The time to serve a generated UnixFS HTML directory listing from the gateway.",
-		),
-		// CAR: time it takes to return requested CAR stream
-		carStreamGetMetric: newGatewayHistogramMetric(
-			"gw_car_stream_get_duration_seconds",
-			"The time to GET an entire CAR stream from the gateway.",
-		),
-		// Block: time it takes to return requested Block
-		rawBlockGetMetric: newGatewayHistogramMetric(
-			"gw_raw_block_get_duration_seconds",
-			"The time to GET an entire raw Block from the gateway.",
-		),
-
-		// Legacy Metrics
-		// ----------------------------
-		unixfsGetMetric: newGatewaySummaryMetric( // TODO: remove?
-			// (deprecated, use firstContentBlockGetMetric instead)
-			"unixfs_get_latency_seconds",
-			"The time to receive the first UnixFS node on a GET from the gateway.",
-		),
-	}
-	return i
-}
-
-func parseIpfsPath(p string) (cid.Cid, string, error) {
-	rootPath, err := path.ParsePath(p)
-	if err != nil {
-		return cid.Cid{}, "", err
-	}
-
-	// Check the path.
-	rsegs := rootPath.Segments()
-	if rsegs[0] != "ipfs" {
-		return cid.Cid{}, "", fmt.Errorf("WritableGateway: only ipfs paths supported")
-	}
-
-	rootCid, err := cid.Decode(rsegs[1])
-	if err != nil {
-		return cid.Cid{}, "", err
-	}
-
-	return rootCid, path.Join(rsegs[2:]), nil
-}
-
-func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	// the hour is a hard fallback, we don't expect it to happen, but just in case
-	ctx, cancel := context.WithTimeout(r.Context(), time.Hour)
-	defer cancel()
-	r = r.WithContext(ctx)
-
-	defer func() {
-		if r := recover(); r != nil {
-			log.Error("A panic occurred in the gateway handler!")
-			log.Error(r)
-			debug.PrintStack()
-		}
-	}()
-
-	if i.config.Writable {
-		switch r.Method {
-		case http.MethodPost:
-			i.postHandler(w, r)
-			return
-		case http.MethodPut:
-			i.putHandler(w, r)
-			return
-		case http.MethodDelete:
-			i.deleteHandler(w, r)
-			return
-		}
-	}
-
-	switch r.Method {
-	case http.MethodGet, http.MethodHead:
-		i.getOrHeadHandler(w, r)
-		return
-	case http.MethodOptions:
-		i.optionsHandler(w, r)
-		return
-	}
-
-	errmsg := "Method " + r.Method + " not allowed: "
-	var status int
-	if !i.config.Writable {
-		status = http.StatusMethodNotAllowed
-		errmsg = errmsg + "read only access"
-		w.Header().Add("Allow", http.MethodGet)
-		w.Header().Add("Allow", http.MethodHead)
-		w.Header().Add("Allow", http.MethodOptions)
-	} else {
-		status = http.StatusBadRequest
-		errmsg = errmsg + "bad request for " + r.URL.Path
-	}
-	http.Error(w, errmsg, status)
-}
-
-func (i *gatewayHandler) optionsHandler(w http.ResponseWriter, r *http.Request) {
-	/*
-		OPTIONS is a noop request that is used by the browsers to check
-		if server accepts cross-site XMLHttpRequest (indicated by the presence of CORS headers)
-		https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
-	*/
-	i.addUserHeaders(w) // return all custom headers (including CORS ones, if set)
-}
-
-func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request) {
-	begin := time.Now()
-
-	logger := log.With("from", r.RequestURI)
-	logger.Debug("http request received")
-
-	if err := handleUnsupportedHeaders(r); err != nil {
-		webRequestError(w, err)
-		return
-	}
-
-	if requestHandled := handleProtocolHandlerRedirect(w, r, logger); requestHandled {
-		return
-	}
-
-	if err := handleServiceWorkerRegistration(r); err != nil {
-		webRequestError(w, err)
-		return
-	}
-
-	contentPath := ipath.New(r.URL.Path)
-
-	if requestHandled := i.handleOnlyIfCached(w, r, contentPath, logger); requestHandled {
-		return
-	}
-
-	if requestHandled := handleSuperfluousNamespace(w, r, contentPath); requestHandled {
-		return
-	}
-
-	// Detect when explicit Accept header or ?format parameter are present
-	responseFormat, formatParams, err := customResponseFormat(r)
-	if err != nil {
-		webError(w, "error while processing the Accept header", err, http.StatusBadRequest)
-		return
-	}
-	trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResponseFormat", responseFormat))
-
-	resolvedPath, contentPath, ok := i.handlePathResolution(w, r, responseFormat, contentPath, logger)
-	if !ok {
-		return
-	}
-	trace.SpanFromContext(r.Context()).SetAttributes(attribute.String("ResolvedPath", resolvedPath.String()))
-
-	// Detect when If-None-Match HTTP header allows returning HTTP 304 Not Modified
-	if inm := r.Header.Get("If-None-Match"); inm != "" {
-		pathCid := resolvedPath.Cid()
-		// need to check against both File and Dir Etag variants
-		// because this inexpensive check happens before we do any I/O
-		cidEtag := getEtag(r, pathCid)
-		dirEtag := getDirListingEtag(pathCid)
-		if etagMatch(inm, cidEtag, dirEtag) {
-			// Finish early if client already has a matching Etag
-			w.WriteHeader(http.StatusNotModified)
-			return
-		}
-	}
-
-	if err := i.handleGettingFirstBlock(r, begin, contentPath, resolvedPath); err != nil {
-		webRequestError(w, err)
-		return
-	}
-
-	if err := i.setCommonHeaders(w, r, contentPath); err != nil {
-		webRequestError(w, err)
-		return
-	}
-
-	// Support custom response formats passed via ?format or Accept HTTP header
-	switch responseFormat {
-	case "", "application/json", "application/cbor":
-		switch mc.Code(resolvedPath.Cid().Prefix().Codec) {
-		case mc.Json, mc.DagJson, mc.Cbor, mc.DagCbor:
-			logger.Debugw("serving codec", "path", contentPath)
-			i.serveCodec(r.Context(), w, r, resolvedPath, contentPath, begin, responseFormat)
-		default:
-			logger.Debugw("serving unixfs", "path", contentPath)
-			i.serveUnixFS(r.Context(), w, r, resolvedPath, contentPath, begin, logger)
-		}
-		return
-	case "application/vnd.ipld.raw":
-		logger.Debugw("serving raw block", "path", contentPath)
-		i.serveRawBlock(r.Context(), w, r, resolvedPath, contentPath, begin)
-		return
-	case "application/vnd.ipld.car":
-		logger.Debugw("serving car stream", "path", contentPath)
-		carVersion := formatParams["version"]
-		i.serveCAR(r.Context(), w, r, resolvedPath, contentPath, carVersion, begin)
-		return
-	case "application/x-tar":
-		logger.Debugw("serving tar file", "path", contentPath)
-		i.serveTAR(r.Context(), w, r, resolvedPath, contentPath, begin, logger)
-		return
-	case "application/vnd.ipld.dag-json", "application/vnd.ipld.dag-cbor":
-		logger.Debugw("serving codec", "path", contentPath)
-		i.serveCodec(r.Context(), w, r, resolvedPath, contentPath, begin, responseFormat)
-		return
-	default: // catch-all for unsuported application/vnd.*
-		err := fmt.Errorf("unsupported format %q", responseFormat)
-		webError(w, "failed to respond with requested content type", err, http.StatusBadRequest)
-		return
-	}
-}
-
-func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) {
-	p, err := i.api.Unixfs().Add(r.Context(), files.NewReaderFile(r.Body))
-	if err != nil {
-		internalWebError(w, err)
-		return
-	}
-
-	i.addUserHeaders(w) // ok, _now_ write user's headers.
-	w.Header().Set("IPFS-Hash", p.Cid().String())
-	log.Debugw("CID created, http redirect", "from", r.URL, "to", p, "status", http.StatusCreated)
-	http.Redirect(w, r, p.String(), http.StatusCreated)
-}
-
-func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) {
-	ctx := r.Context()
-	ds := i.api.Dag()
-
-	// Parse the path
-	rootCid, newPath, err := parseIpfsPath(r.URL.Path)
-	if err != nil {
-		webError(w, "WritableGateway: failed to parse the path", err, http.StatusBadRequest)
-		return
-	}
-	if newPath == "" || newPath == "/" {
-		http.Error(w, "WritableGateway: empty path", http.StatusBadRequest)
-		return
-	}
-	newDirectory, newFileName := gopath.Split(newPath)
-
-	// Resolve the old root.
-
-	rnode, err := ds.Get(ctx, rootCid)
-	if err != nil {
-		webError(w, "WritableGateway: Could not create DAG from request", err, http.StatusInternalServerError)
-		return
-	}
-
-	pbnd, ok := rnode.(*dag.ProtoNode)
-	if !ok {
-		webError(w, "Cannot read non protobuf nodes through gateway", dag.ErrNotProtobuf, http.StatusBadRequest)
-		return
-	}
-
-	// Create the new file.
-	newFilePath, err := i.api.Unixfs().Add(ctx, files.NewReaderFile(r.Body))
-	if err != nil {
-		webError(w, "WritableGateway: could not create DAG from request", err, http.StatusInternalServerError)
-		return
-	}
-
-	newFile, err := ds.Get(ctx, newFilePath.Cid())
-	if err != nil {
-		webError(w, "WritableGateway: failed to resolve new file", err, http.StatusInternalServerError)
-		return
-	}
-
-	// Patch the new file into the old root.
-
-	root, err := mfs.NewRoot(ctx, ds, pbnd, nil)
-	if err != nil {
-		webError(w, "WritableGateway: failed to create MFS root", err, http.StatusBadRequest)
-		return
-	}
-
-	if newDirectory != "" {
-		err := mfs.Mkdir(root, newDirectory, mfs.MkdirOpts{Mkparents: true, Flush: false})
-		if err != nil {
-			webError(w, "WritableGateway: failed to create MFS directory", err, http.StatusInternalServerError)
-			return
-		}
-	}
-	dirNode, err := mfs.Lookup(root, newDirectory)
-	if err != nil {
-		webError(w, "WritableGateway: failed to lookup directory", err, http.StatusInternalServerError)
-		return
-	}
-	dir, ok := dirNode.(*mfs.Directory)
-	if !ok {
-		http.Error(w, "WritableGateway: target directory is not a directory", http.StatusBadRequest)
-		return
-	}
-	err = dir.Unlink(newFileName)
-	switch err {
-	case os.ErrNotExist, nil:
-	default:
-		webError(w, "WritableGateway: failed to replace existing file", err, http.StatusBadRequest)
-		return
-	}
-	err = dir.AddChild(newFileName, newFile)
-	if err != nil {
-		webError(w, "WritableGateway: failed to link file into directory", err, http.StatusInternalServerError)
-		return
-	}
-	nnode, err := root.GetDirectory().GetNode()
-	if err != nil {
-		webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError)
-		return
-	}
-	newcid := nnode.Cid()
-
-	i.addUserHeaders(w) // ok, _now_ write user's headers.
-	w.Header().Set("IPFS-Hash", newcid.String())
-
-	redirectURL := gopath.Join(ipfsPathPrefix, newcid.String(), newPath)
-	log.Debugw("CID replaced, redirect", "from", r.URL, "to", redirectURL, "status", http.StatusCreated)
-	http.Redirect(w, r, redirectURL, http.StatusCreated)
-}
-
-func (i *gatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
-	ctx := r.Context()
-
-	// parse the path
-
-	rootCid, newPath, err := parseIpfsPath(r.URL.Path)
-	if err != nil {
-		webError(w, "WritableGateway: failed to parse the path", err, http.StatusBadRequest)
-		return
-	}
-	if newPath == "" || newPath == "/" {
-		http.Error(w, "WritableGateway: empty path", http.StatusBadRequest)
-		return
-	}
-	directory, filename := gopath.Split(newPath)
-
-	// lookup the root
-
-	rootNodeIPLD, err := i.api.Dag().Get(ctx, rootCid)
-	if err != nil {
-		webError(w, "WritableGateway: failed to resolve root CID", err, http.StatusInternalServerError)
-		return
-	}
-	rootNode, ok := rootNodeIPLD.(*dag.ProtoNode)
-	if !ok {
-		http.Error(w, "WritableGateway: empty path", http.StatusInternalServerError)
-		return
-	}
-
-	// construct the mfs root
-
-	root, err := mfs.NewRoot(ctx, i.api.Dag(), rootNode, nil)
-	if err != nil {
-		webError(w, "WritableGateway: failed to construct the MFS root", err, http.StatusBadRequest)
-		return
-	}
-
-	// lookup the parent directory
-
-	parentNode, err := mfs.Lookup(root, directory)
-	if err != nil {
-		webError(w, "WritableGateway: failed to look up parent", err, http.StatusInternalServerError)
-		return
-	}
-
-	parent, ok := parentNode.(*mfs.Directory)
-	if !ok {
-		http.Error(w, "WritableGateway: parent is not a directory", http.StatusInternalServerError)
-		return
-	}
-
-	// delete the file
-
-	switch parent.Unlink(filename) {
-	case nil, os.ErrNotExist:
-	default:
-		webError(w, "WritableGateway: failed to remove file", err, http.StatusInternalServerError)
-		return
-	}
-
-	nnode, err := root.GetDirectory().GetNode()
-	if err != nil {
-		webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError)
-		return
-	}
-	ncid := nnode.Cid()
-
-	i.addUserHeaders(w) // ok, _now_ write user's headers.
-	w.Header().Set("IPFS-Hash", ncid.String())
-
-	redirectURL := gopath.Join(ipfsPathPrefix+ncid.String(), directory)
-	// note: StatusCreated is technically correct here as we created a new resource.
-	log.Debugw("CID deleted, redirect", "from", r.RequestURI, "to", redirectURL, "status", http.StatusCreated)
-	http.Redirect(w, r, redirectURL, http.StatusCreated)
-}
-
-func (i *gatewayHandler) addUserHeaders(w http.ResponseWriter) {
-	for k, v := range i.config.Headers {
-		w.Header()[k] = v
-	}
-}
-
-func addCacheControlHeaders(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, fileCid cid.Cid) (modtime time.Time) {
-	// Set Etag to based on CID (override whatever was set before)
-	w.Header().Set("Etag", getEtag(r, fileCid))
-
-	// Set Cache-Control and Last-Modified based on contentPath properties
-	if contentPath.Mutable() {
-		// mutable namespaces such as /ipns/ can't be cached forever
-
-		/* For now we set Last-Modified to Now() to leverage caching heuristics built into modern browsers:
-		 * https://github.com/ipfs/kubo/pull/8074#pullrequestreview-645196768
-		 * but we should not set it to fake values and use Cache-Control based on TTL instead */
-		modtime = time.Now()
-
-		// TODO: set Cache-Control based on TTL of IPNS/DNSLink: https://github.com/ipfs/kubo/issues/1818#issuecomment-1015849462
-		// TODO: set Last-Modified based on /ipns/ publishing timestamp?
-	} else {
-		// immutable! CACHE ALL THE THINGS, FOREVER! wolololol
-		w.Header().Set("Cache-Control", immutableCacheControl)
-
-		// Set modtime to 'zero time' to disable Last-Modified header (superseded by Cache-Control)
-		modtime = noModtime
-
-		// TODO: set Last-Modified? - TBD - /ipfs/ modification metadata is present in unixfs 1.5 https://github.com/ipfs/kubo/issues/6920?
-	}
-
-	return modtime
-}
-
-// Set Content-Disposition if filename URL query param is present, return preferred filename
-func addContentDispositionHeader(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) string {
-	/* This logic enables:
-	 * - creation of HTML links that trigger "Save As.." dialog instead of being rendered by the browser
-	 * - overriding the filename used when saving subresource assets on HTML page
-	 * - providing a default filename for HTTP clients when downloading direct /ipfs/CID without any subpath
-	 */
-
-	// URL param ?filename=cat.jpg triggers Content-Disposition: [..] filename
-	// which impacts default name used in "Save As.." dialog
-	name := getFilename(contentPath)
-	urlFilename := r.URL.Query().Get("filename")
-	if urlFilename != "" {
-		disposition := "inline"
-		// URL param ?download=true triggers Content-Disposition: [..] attachment
-		// which skips rendering and forces "Save As.." dialog in browsers
-		if r.URL.Query().Get("download") == "true" {
-			disposition = "attachment"
-		}
-		setContentDispositionHeader(w, urlFilename, disposition)
-		name = urlFilename
-	}
-	return name
-}
-
-// Set Content-Disposition to arbitrary filename and disposition
-func setContentDispositionHeader(w http.ResponseWriter, filename string, disposition string) {
-	utf8Name := url.PathEscape(filename)
-	asciiName := url.PathEscape(onlyASCII.ReplaceAllLiteralString(filename, "_"))
-	w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"; filename*=UTF-8''%s", disposition, asciiName, utf8Name))
-}
-
-// Set X-Ipfs-Roots with logical CID array for efficient HTTP cache invalidation.
-func (i *gatewayHandler) buildIpfsRootsHeader(contentPath string, r *http.Request) (string, error) {
-	/*
-		These are logical roots where each CID represent one path segment
-		and resolves to either a directory or the root block of a file.
-		The main purpose of this header is allow HTTP caches to do smarter decisions
-		around cache invalidation (eg. keep specific subdirectory/file if it did not change)
-
-		A good example is Wikipedia, which is HAMT-sharded, but we only care about
-		logical roots that represent each segment of the human-readable content
-		path:
-
-		Given contentPath = /ipns/en.wikipedia-on-ipfs.org/wiki/Block_of_Wikipedia_in_Turkey
-		rootCidList is a generated by doing `ipfs resolve -r` on each sub path:
-			/ipns/en.wikipedia-on-ipfs.org → bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze
-			/ipns/en.wikipedia-on-ipfs.org/wiki/ → bafybeihn2f7lhumh4grizksi2fl233cyszqadkn424ptjajfenykpsaiw4
-			/ipns/en.wikipedia-on-ipfs.org/wiki/Block_of_Wikipedia_in_Turkey → bafkreibn6euazfvoghepcm4efzqx5l3hieof2frhp254hio5y7n3hv5rma
-
-		The result is an ordered array of values:
-			X-Ipfs-Roots: bafybeiaysi4s6lnjev27ln5icwm6tueaw2vdykrtjkwiphwekaywqhcjze,bafybeihn2f7lhumh4grizksi2fl233cyszqadkn424ptjajfenykpsaiw4,bafkreibn6euazfvoghepcm4efzqx5l3hieof2frhp254hio5y7n3hv5rma
-
-		Note that while the top one will change every time any article is changed,
-		the last root (responsible for specific article) may not change at all.
-	*/
-	var sp strings.Builder
-	var pathRoots []string
-	pathSegments := strings.Split(contentPath[6:], "/")
-	sp.WriteString(contentPath[:5]) // /ipfs or /ipns
-	for _, root := range pathSegments {
-		if root == "" {
-			continue
-		}
-		sp.WriteString("/")
-		sp.WriteString(root)
-		resolvedSubPath, err := i.api.ResolvePath(r.Context(), ipath.New(sp.String()))
-		if err != nil {
-			return "", err
-		}
-		pathRoots = append(pathRoots, resolvedSubPath.Cid().String())
-	}
-	rootCidList := strings.Join(pathRoots, ",") // convention from rfc2616#sec4.2
-	return rootCidList, nil
-}
-
-func webRequestError(w http.ResponseWriter, err *requestError) {
-	webError(w, err.Message, err.Err, err.StatusCode)
-}
-
-func webError(w http.ResponseWriter, message string, err error, defaultCode int) {
-	if _, ok := err.(resolver.ErrNoLink); ok {
-		webErrorWithCode(w, message, err, http.StatusNotFound)
-	} else if err == routing.ErrNotFound {
-		webErrorWithCode(w, message, err, http.StatusNotFound)
-	} else if ipld.IsNotFound(err) {
-		webErrorWithCode(w, message, err, http.StatusNotFound)
-	} else if err == context.DeadlineExceeded {
-		webErrorWithCode(w, message, err, http.StatusRequestTimeout)
-	} else {
-		webErrorWithCode(w, message, err, defaultCode)
-	}
-}
-
-func webErrorWithCode(w http.ResponseWriter, message string, err error, code int) {
-	http.Error(w, fmt.Sprintf("%s: %s", message, err), code)
-	if code >= 500 {
-		log.Warnf("server error: %s: %s", message, err)
-	}
-}
-
-// return a 500 error and log
-func internalWebError(w http.ResponseWriter, err error) {
-	webErrorWithCode(w, "internalWebError", err, http.StatusInternalServerError)
-}
-
-func getFilename(contentPath ipath.Path) string {
-	s := contentPath.String()
-	if (strings.HasPrefix(s, ipfsPathPrefix) || strings.HasPrefix(s, ipnsPathPrefix)) && strings.Count(gopath.Clean(s), "/") <= 2 {
-		// Don't want to treat ipfs.io in /ipns/ipfs.io as a filename.
-		return ""
-	}
-	return gopath.Base(s)
-}
-
-// etagMatch evaluates if we can respond with HTTP 304 Not Modified
-// It supports multiple weak and strong etags passed in If-None-Matc stringh
-// including the wildcard one.
-func etagMatch(ifNoneMatchHeader string, cidEtag string, dirEtag string) bool {
-	buf := ifNoneMatchHeader
-	for {
-		buf = textproto.TrimString(buf)
-		if len(buf) == 0 {
-			break
-		}
-		if buf[0] == ',' {
-			buf = buf[1:]
-			continue
-		}
-		// If-None-Match: * should match against any etag
-		if buf[0] == '*' {
-			return true
-		}
-		etag, remain := scanETag(buf)
-		if etag == "" {
-			break
-		}
-		// Check for match both strong and weak etags
-		if etagWeakMatch(etag, cidEtag) || etagWeakMatch(etag, dirEtag) {
-			return true
-		}
-		buf = remain
-	}
-	return false
-}
-
-// scanETag determines if a syntactically valid ETag is present at s. If so,
-// the ETag and remaining text after consuming ETag is returned. Otherwise,
-// it returns "", "".
-// (This is the same logic as one executed inside of http.ServeContent)
-func scanETag(s string) (etag string, remain string) {
-	s = textproto.TrimString(s)
-	start := 0
-	if strings.HasPrefix(s, "W/") {
-		start = 2
-	}
-	if len(s[start:]) < 2 || s[start] != '"' {
-		return "", ""
-	}
-	// ETag is either W/"text" or "text".
-	// See RFC 7232 2.3.
-	for i := start + 1; i < len(s); i++ {
-		c := s[i]
-		switch {
-		// Character values allowed in ETags.
-		case c == 0x21 || c >= 0x23 && c <= 0x7E || c >= 0x80:
-		case c == '"':
-			return s[:i+1], s[i+1:]
-		default:
-			return "", ""
-		}
-	}
-	return "", ""
-}
-
-// etagWeakMatch reports whether a and b match using weak ETag comparison.
-func etagWeakMatch(a, b string) bool {
-	return strings.TrimPrefix(a, "W/") == strings.TrimPrefix(b, "W/")
-}
-
-// generate Etag value based on HTTP request and CID
-func getEtag(r *http.Request, cid cid.Cid) string {
-	prefix := `"`
-	suffix := `"`
-	responseFormat, _, err := customResponseFormat(r)
-	if err == nil && responseFormat != "" {
-		// application/vnd.ipld.foo → foo
-		// application/x-bar → x-bar
-		shortFormat := responseFormat[strings.LastIndexAny(responseFormat, "/.")+1:]
-		// Etag: "cid.shortFmt" (gives us nice compression together with Content-Disposition in block (raw) and car responses)
-		suffix = `.` + shortFormat + suffix
-	}
-	// TODO: include selector suffix when https://github.com/ipfs/kubo/issues/8769 lands
-	return prefix + cid.String() + suffix
-}
-
-// return explicit response format if specified in request as query parameter or via Accept HTTP header
-func customResponseFormat(r *http.Request) (mediaType string, params map[string]string, err error) {
-	if formatParam := r.URL.Query().Get("format"); formatParam != "" {
-		// translate query param to a content type
-		switch formatParam {
-		case "raw":
-			return "application/vnd.ipld.raw", nil, nil
-		case "car":
-			return "application/vnd.ipld.car", nil, nil
-		case "tar":
-			return "application/x-tar", nil, nil
-		case "json":
-			return "application/json", nil, nil
-		case "cbor":
-			return "application/cbor", nil, nil
-		case "dag-json":
-			return "application/vnd.ipld.dag-json", nil, nil
-		case "dag-cbor":
-			return "application/vnd.ipld.dag-cbor", nil, nil
-		}
-	}
-	// Browsers and other user agents will send Accept header with generic types like:
-	// Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
-	// We only care about explicit, vendor-specific content-types and respond to the first match (in order).
-	// TODO: make this RFC compliant and respect weights (eg. return CAR for Accept:application/vnd.ipld.dag-json;q=0.1,application/vnd.ipld.car;q=0.2)
-	for _, header := range r.Header.Values("Accept") {
-		for _, value := range strings.Split(header, ",") {
-			accept := strings.TrimSpace(value)
-			// respond to the very first matching content type
-			if strings.HasPrefix(accept, "application/vnd.ipld") ||
-				strings.HasPrefix(accept, "application/x-tar") ||
-				strings.HasPrefix(accept, "application/json") ||
-				strings.HasPrefix(accept, "application/cbor") {
-				mediatype, params, err := mime.ParseMediaType(accept)
-				if err != nil {
-					return "", nil, err
-				}
-				return mediatype, params, nil
-			}
-		}
-	}
-	// If none of special-cased content types is found, return empty string
-	// to indicate default, implicit UnixFS response should be prepared
-	return "", nil, nil
-}
-
-// returns unquoted path with all special characters revealed as \u codes
-func debugStr(path string) string {
-	q := fmt.Sprintf("%+q", path)
-	if len(q) >= 3 {
-		q = q[1 : len(q)-1]
-	}
-	return q
-}
-
-// Resolve the provided contentPath including any special handling related to
-// the requested responseFormat. Returned ok flag indicates if gateway handler
-// should continue processing the request.
-func (i *gatewayHandler) handlePathResolution(w http.ResponseWriter, r *http.Request, responseFormat string, contentPath ipath.Path, logger *zap.SugaredLogger) (resolvedPath ipath.Resolved, newContentPath ipath.Path, ok bool) {
-	// Attempt to resolve the provided path.
-	resolvedPath, err := i.api.ResolvePath(r.Context(), contentPath)
-
-	switch err {
-	case nil:
-		return resolvedPath, contentPath, true
-	case coreiface.ErrOffline:
-		webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusServiceUnavailable)
-		return nil, nil, false
-	default:
-		// The path can't be resolved.
-		if isUnixfsResponseFormat(responseFormat) {
-			// If we have origin isolation (subdomain gw, DNSLink website),
-			// and response type is UnixFS (default for website hosting)
-			// check for presence of _redirects file and apply rules defined there.
-			// See: https://github.com/ipfs/specs/pull/290
-			if hasOriginIsolation(r) {
-				resolvedPath, newContentPath, ok, hadMatchingRule := i.serveRedirectsIfPresent(w, r, resolvedPath, contentPath, logger)
-				if hadMatchingRule {
-					logger.Debugw("applied a rule from _redirects file")
-					return resolvedPath, newContentPath, ok
-				}
-			}
-
-			// if Accept is text/html, see if ipfs-404.html is present
-			// This logic isn't documented and will likely be removed at some point.
-			// Any 404 logic in _redirects above will have already run by this time, so it's really an extra fall back
-			if i.serveLegacy404IfPresent(w, r, contentPath) {
-				logger.Debugw("served legacy 404")
-				return nil, nil, false
-			}
-		}
-
-		// Note: webError will replace http.StatusBadRequest  with StatusNotFound if necessary
-		webError(w, "ipfs resolve -r "+debugStr(contentPath.String()), err, http.StatusBadRequest)
-		return nil, nil, false
-	}
-}
-
-// Detect 'Cache-Control: only-if-cached' in request and return data if it is already in the local datastore.
-// https://github.com/ipfs/specs/blob/main/http-gateways/PATH_GATEWAY.md#cache-control-request-header
-func (i *gatewayHandler) handleOnlyIfCached(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) (requestHandled bool) {
-	if r.Header.Get("Cache-Control") == "only-if-cached" {
-		_, err := i.offlineAPI.Block().Stat(r.Context(), contentPath)
-		if err != nil {
-			if r.Method == http.MethodHead {
-				w.WriteHeader(http.StatusPreconditionFailed)
-				return true
-			}
-			errMsg := fmt.Sprintf("%q not in local datastore", contentPath.String())
-			http.Error(w, errMsg, http.StatusPreconditionFailed)
-			return true
-		}
-		if r.Method == http.MethodHead {
-			w.WriteHeader(http.StatusOK)
-			return true
-		}
-	}
-	return false
-}
-
-func handleUnsupportedHeaders(r *http.Request) (err *requestError) {
-	// X-Ipfs-Gateway-Prefix was removed (https://github.com/ipfs/kubo/issues/7702)
-	// TODO: remove this after  go-ipfs 0.13 ships
-	if prfx := r.Header.Get("X-Ipfs-Gateway-Prefix"); prfx != "" {
-		err := fmt.Errorf("X-Ipfs-Gateway-Prefix support was removed: https://github.com/ipfs/kubo/issues/7702")
-		return newRequestError("unsupported HTTP header", err, http.StatusBadRequest)
-	}
-	return nil
-}
-
-// ?uri query param support for requests produced by web browsers
-// via navigator.registerProtocolHandler Web API
-// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/registerProtocolHandler
-// TLDR: redirect /ipfs/?uri=ipfs%3A%2F%2Fcid%3Fquery%3Dval to /ipfs/cid?query=val
-func handleProtocolHandlerRedirect(w http.ResponseWriter, r *http.Request, logger *zap.SugaredLogger) (requestHandled bool) {
-	if uriParam := r.URL.Query().Get("uri"); uriParam != "" {
-		u, err := url.Parse(uriParam)
-		if err != nil {
-			webError(w, "failed to parse uri query parameter", err, http.StatusBadRequest)
-			return true
-		}
-		if u.Scheme != "ipfs" && u.Scheme != "ipns" {
-			webError(w, "uri query parameter scheme must be ipfs or ipns", err, http.StatusBadRequest)
-			return true
-		}
-		path := u.Path
-		if u.RawQuery != "" { // preserve query if present
-			path = path + "?" + u.RawQuery
-		}
-
-		redirectURL := gopath.Join("/", u.Scheme, u.Host, path)
-		logger.Debugw("uri param, redirect", "to", redirectURL, "status", http.StatusMovedPermanently)
-		http.Redirect(w, r, redirectURL, http.StatusMovedPermanently)
-		return true
-	}
-
-	return false
-}
-
-// Disallow Service Worker registration on namespace roots
-// https://github.com/ipfs/kubo/issues/4025
-func handleServiceWorkerRegistration(r *http.Request) (err *requestError) {
-	if r.Header.Get("Service-Worker") == "script" {
-		matched, _ := regexp.MatchString(`^/ip[fn]s/[^/]+$`, r.URL.Path)
-		if matched {
-			err := fmt.Errorf("registration is not allowed for this scope")
-			return newRequestError("navigator.serviceWorker", err, http.StatusBadRequest)
-		}
-	}
-
-	return nil
-}
-
-// Attempt to fix redundant /ipfs/ namespace as long as resulting
-// 'intended' path is valid.  This is in case gremlins were tickled
-// wrong way and user ended up at /ipfs/ipfs/{cid} or /ipfs/ipns/{id}
-// like in bafybeien3m7mdn6imm425vc2s22erzyhbvk5n3ofzgikkhmdkh5cuqbpbq :^))
-func handleSuperfluousNamespace(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) (requestHandled bool) {
-	// If the path is valid, there's nothing to do
-	if pathErr := contentPath.IsValid(); pathErr == nil {
-		return false
-	}
-
-	// If there's no superflous namespace, there's nothing to do
-	if !(strings.HasPrefix(r.URL.Path, "/ipfs/ipfs/") || strings.HasPrefix(r.URL.Path, "/ipfs/ipns/")) {
-		return false
-	}
-
-	// Attempt to fix the superflous namespace
-	intendedPath := ipath.New(strings.TrimPrefix(r.URL.Path, "/ipfs"))
-	if err := intendedPath.IsValid(); err != nil {
-		webError(w, "invalid ipfs path", err, http.StatusBadRequest)
-		return true
-	}
-	intendedURL := intendedPath.String()
-	if r.URL.RawQuery != "" {
-		// we render HTML, so ensure query entries are properly escaped
-		q, _ := url.ParseQuery(r.URL.RawQuery)
-		intendedURL = intendedURL + "?" + q.Encode()
-	}
-	// return HTTP 400 (Bad Request) with HTML error page that:
-	// - points at correct canonical path via <link> header
-	// - displays human-readable error
-	// - redirects to intendedURL after a short delay
-
-	w.WriteHeader(http.StatusBadRequest)
-	if err := redirectTemplate.Execute(w, redirectTemplateData{
-		RedirectURL:   intendedURL,
-		SuggestedPath: intendedPath.String(),
-		ErrorMsg:      fmt.Sprintf("invalid path: %q should be %q", r.URL.Path, intendedPath.String()),
-	}); err != nil {
-		webError(w, "failed to redirect when fixing superfluous namespace", err, http.StatusBadRequest)
-	}
-
-	return true
-}
-
-func (i *gatewayHandler) handleGettingFirstBlock(r *http.Request, begin time.Time, contentPath ipath.Path, resolvedPath ipath.Resolved) *requestError {
-	// Update the global metric of the time it takes to read the final root block of the requested resource
-	// NOTE: for legacy reasons this happens before we go into content-type specific code paths
-	_, err := i.api.Block().Get(r.Context(), resolvedPath)
-	if err != nil {
-		return newRequestError("ipfs block get "+resolvedPath.Cid().String(), err, http.StatusInternalServerError)
-	}
-	ns := contentPath.Namespace()
-	timeToGetFirstContentBlock := time.Since(begin).Seconds()
-	i.unixfsGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock) // deprecated, use firstContentBlockGetMetric instead
-	i.firstContentBlockGetMetric.WithLabelValues(ns).Observe(timeToGetFirstContentBlock)
-	return nil
-}
-
-func (i *gatewayHandler) setCommonHeaders(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) *requestError {
-	i.addUserHeaders(w) // ok, _now_ write user's headers.
-	w.Header().Set("X-Ipfs-Path", contentPath.String())
-
-	if rootCids, err := i.buildIpfsRootsHeader(contentPath.String(), r); err == nil {
-		w.Header().Set("X-Ipfs-Roots", rootCids)
-	} else { // this should never happen, as we resolved the contentPath already
-		return newRequestError("error while resolving X-Ipfs-Roots", err, http.StatusInternalServerError)
-	}
-
-	return nil
-}
diff --git a/core/corehttp/gateway_handler_block.go b/core/corehttp/gateway_handler_block.go
deleted file mode 100644
index 3bf7c76be2d6f929492dc4fd2bf7f6a6f3c59f1b..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_block.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package corehttp
-
-import (
-	"bytes"
-	"context"
-	"io"
-	"net/http"
-	"time"
-
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/tracing"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-)
-
-// serveRawBlock returns bytes behind a raw block
-func (i *gatewayHandler) serveRawBlock(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time) {
-	ctx, span := tracing.Span(ctx, "Gateway", "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
-	defer span.End()
-	blockCid := resolvedPath.Cid()
-	blockReader, err := i.api.Block().Get(ctx, resolvedPath)
-	if err != nil {
-		webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
-		return
-	}
-	block, err := io.ReadAll(blockReader)
-	if err != nil {
-		webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
-		return
-	}
-	content := bytes.NewReader(block)
-
-	// Set Content-Disposition
-	var name string
-	if urlFilename := r.URL.Query().Get("filename"); urlFilename != "" {
-		name = urlFilename
-	} else {
-		name = blockCid.String() + ".bin"
-	}
-	setContentDispositionHeader(w, name, "attachment")
-
-	// Set remaining headers
-	modtime := addCacheControlHeaders(w, r, contentPath, blockCid)
-	w.Header().Set("Content-Type", "application/vnd.ipld.raw")
-	w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^)
-
-	// ServeContent will take care of
-	// If-None-Match+Etag, Content-Length and range requests
-	_, dataSent, _ := ServeContent(w, r, name, modtime, content)
-
-	if dataSent {
-		// Update metrics
-		i.rawBlockGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds())
-	}
-}
diff --git a/core/corehttp/gateway_handler_car.go b/core/corehttp/gateway_handler_car.go
deleted file mode 100644
index 3363c5199e2cf222e78953a0d45102419ab1d2ce..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_car.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"time"
-
-	blocks "github.com/ipfs/go-block-format"
-	cid "github.com/ipfs/go-cid"
-	coreiface "github.com/ipfs/interface-go-ipfs-core"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/tracing"
-	gocar "github.com/ipld/go-car"
-	selectorparse "github.com/ipld/go-ipld-prime/traversal/selector/parse"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-)
-
-// serveCAR returns a CAR stream for specific DAG+selector
-func (i *gatewayHandler) serveCAR(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, carVersion string, begin time.Time) {
-	ctx, span := tracing.Span(ctx, "Gateway", "ServeCAR", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
-	defer span.End()
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-
-	switch carVersion {
-	case "": // noop, client does not care about version
-	case "1": // noop, we support this
-	default:
-		err := fmt.Errorf("only version=1 is supported")
-		webError(w, "unsupported CAR version", err, http.StatusBadRequest)
-		return
-	}
-	rootCid := resolvedPath.Cid()
-
-	// Set Content-Disposition
-	var name string
-	if urlFilename := r.URL.Query().Get("filename"); urlFilename != "" {
-		name = urlFilename
-	} else {
-		name = rootCid.String() + ".car"
-	}
-	setContentDispositionHeader(w, name, "attachment")
-
-	// Set Cache-Control (same logic as for a regular files)
-	addCacheControlHeaders(w, r, contentPath, rootCid)
-
-	// Weak Etag W/ because we can't guarantee byte-for-byte identical
-	// responses, but still want to benefit from HTTP Caching. Two CAR
-	// responses for the same CID and selector will be logically equivalent,
-	// but when CAR is streamed, then in theory, blocks may arrive from
-	// datastore in non-deterministic order.
-	etag := `W/` + getEtag(r, rootCid)
-	w.Header().Set("Etag", etag)
-
-	// Finish early if Etag match
-	if r.Header.Get("If-None-Match") == etag {
-		w.WriteHeader(http.StatusNotModified)
-		return
-	}
-
-	// Make it clear we don't support range-requests over a car stream
-	// Partial downloads and resumes should be handled using requests for
-	// sub-DAGs and IPLD selectors: https://github.com/ipfs/go-ipfs/issues/8769
-	w.Header().Set("Accept-Ranges", "none")
-
-	w.Header().Set("Content-Type", "application/vnd.ipld.car; version=1")
-	w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^)
-
-	// Same go-car settings as dag.export command
-	store := dagStore{dag: i.api.Dag(), ctx: ctx}
-
-	// TODO: support selectors passed as request param: https://github.com/ipfs/kubo/issues/8769
-	dag := gocar.Dag{Root: rootCid, Selector: selectorparse.CommonSelector_ExploreAllRecursively}
-	car := gocar.NewSelectiveCar(ctx, store, []gocar.Dag{dag}, gocar.TraverseLinksOnlyOnce())
-
-	if err := car.Write(w); err != nil {
-		// We return error as a trailer, however it is not something browsers can access
-		// (https://github.com/mdn/browser-compat-data/issues/14703)
-		// Due to this, we suggest client always verify that
-		// the received CAR stream response is matching requested DAG selector
-		w.Header().Set("X-Stream-Error", err.Error())
-		return
-	}
-
-	// Update metrics
-	i.carStreamGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds())
-}
-
-// FIXME(@Jorropo): https://github.com/ipld/go-car/issues/315
-type dagStore struct {
-	dag coreiface.APIDagService
-	ctx context.Context
-}
-
-func (ds dagStore) Get(_ context.Context, c cid.Cid) (blocks.Block, error) {
-	return ds.dag.Get(ds.ctx, c)
-}
diff --git a/core/corehttp/gateway_handler_codec.go b/core/corehttp/gateway_handler_codec.go
deleted file mode 100644
index 93e9593b7b3fbf098011e0bdb16b5802631b17ee..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_codec.go
+++ /dev/null
@@ -1,257 +0,0 @@
-package corehttp
-
-import (
-	"bytes"
-	"context"
-	"fmt"
-	"html"
-	"io"
-	"net/http"
-	"strings"
-	"time"
-
-	cid "github.com/ipfs/go-cid"
-	ipldlegacy "github.com/ipfs/go-ipld-legacy"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/assets"
-	dih "github.com/ipfs/kubo/assets/dag-index-html"
-	"github.com/ipfs/kubo/tracing"
-	"github.com/ipld/go-ipld-prime"
-	"github.com/ipld/go-ipld-prime/multicodec"
-	mc "github.com/multiformats/go-multicodec"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-)
-
-// codecToContentType maps the supported IPLD codecs to the HTTP Content
-// Type they should have.
-var codecToContentType = map[mc.Code]string{
-	mc.Json:    "application/json",
-	mc.Cbor:    "application/cbor",
-	mc.DagJson: "application/vnd.ipld.dag-json",
-	mc.DagCbor: "application/vnd.ipld.dag-cbor",
-}
-
-// contentTypeToRaw maps the HTTP Content Type to the respective codec that
-// allows raw response without any conversion.
-var contentTypeToRaw = map[string][]mc.Code{
-	"application/json": {mc.Json, mc.DagJson},
-	"application/cbor": {mc.Cbor, mc.DagCbor},
-}
-
-// contentTypeToCodec maps the HTTP Content Type to the respective codec. We
-// only add here the codecs that we want to convert-to-from.
-var contentTypeToCodec = map[string]mc.Code{
-	"application/vnd.ipld.dag-json": mc.DagJson,
-	"application/vnd.ipld.dag-cbor": mc.DagCbor,
-}
-
-// contentTypeToExtension maps the HTTP Content Type to the respective file
-// extension, used in Content-Disposition header when downloading the file.
-var contentTypeToExtension = map[string]string{
-	"application/json":              ".json",
-	"application/vnd.ipld.dag-json": ".json",
-	"application/cbor":              ".cbor",
-	"application/vnd.ipld.dag-cbor": ".cbor",
-}
-
-func (i *gatewayHandler) serveCodec(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, requestedContentType string) {
-	ctx, span := tracing.Span(ctx, "Gateway", "ServeCodec", trace.WithAttributes(attribute.String("path", resolvedPath.String()), attribute.String("requestedContentType", requestedContentType)))
-	defer span.End()
-
-	cidCodec := mc.Code(resolvedPath.Cid().Prefix().Codec)
-	responseContentType := requestedContentType
-
-	// If the resolved path still has some remainder, return error for now.
-	// TODO: handle this when we have IPLD Patch (https://ipld.io/specs/patch/) via HTTP PUT
-	// TODO: (depends on https://github.com/ipfs/kubo/issues/4801 and https://github.com/ipfs/kubo/issues/4782)
-	if resolvedPath.Remainder() != "" {
-		path := strings.TrimSuffix(resolvedPath.String(), resolvedPath.Remainder())
-		err := fmt.Errorf("%q of %q could not be returned: reading IPLD Kinds other than Links (CBOR Tag 42) is not implemented: try reading %q instead", resolvedPath.Remainder(), resolvedPath.String(), path)
-		webError(w, "unsupported pathing", err, http.StatusNotImplemented)
-		return
-	}
-
-	// If no explicit content type was requested, the response will have one based on the codec from the CID
-	if requestedContentType == "" {
-		cidContentType, ok := codecToContentType[cidCodec]
-		if !ok {
-			// Should not happen unless function is called with wrong parameters.
-			err := fmt.Errorf("content type not found for codec: %v", cidCodec)
-			webError(w, "internal error", err, http.StatusInternalServerError)
-			return
-		}
-		responseContentType = cidContentType
-	}
-
-	// Set HTTP headers (for caching etc)
-	modtime := addCacheControlHeaders(w, r, contentPath, resolvedPath.Cid())
-	name := setCodecContentDisposition(w, r, resolvedPath, responseContentType)
-	w.Header().Set("Content-Type", responseContentType)
-	w.Header().Set("X-Content-Type-Options", "nosniff")
-
-	// No content type is specified by the user (via Accept, or format=). However,
-	// we support this format. Let's handle it.
-	if requestedContentType == "" {
-		isDAG := cidCodec == mc.DagJson || cidCodec == mc.DagCbor
-		acceptsHTML := strings.Contains(r.Header.Get("Accept"), "text/html")
-		download := r.URL.Query().Get("download") == "true"
-
-		if isDAG && acceptsHTML && !download {
-			i.serveCodecHTML(ctx, w, r, resolvedPath, contentPath)
-		} else {
-			// This covers CIDs with codec 'json' and 'cbor' as those do not have
-			// an explicit requested content type.
-			i.serveCodecRaw(ctx, w, r, resolvedPath, contentPath, name, modtime)
-		}
-
-		return
-	}
-
-	// If DAG-JSON or DAG-CBOR was requested using corresponding plain content type
-	// return raw block as-is, without conversion
-	skipCodecs, ok := contentTypeToRaw[requestedContentType]
-	if ok {
-		for _, skipCodec := range skipCodecs {
-			if skipCodec == cidCodec {
-				i.serveCodecRaw(ctx, w, r, resolvedPath, contentPath, name, modtime)
-				return
-			}
-		}
-	}
-
-	// Otherwise, the user has requested a specific content type (a DAG-* variant).
-	// Let's first get the codecs that can be used with this content type.
-	toCodec, ok := contentTypeToCodec[requestedContentType]
-	if !ok {
-		// This is never supposed to happen unless function is called with wrong parameters.
-		err := fmt.Errorf("unsupported content type: %s", requestedContentType)
-		webError(w, err.Error(), err, http.StatusInternalServerError)
-		return
-	}
-
-	// This handles DAG-* conversions and validations.
-	i.serveCodecConverted(ctx, w, r, resolvedPath, contentPath, toCodec, modtime)
-}
-
-func (i *gatewayHandler) serveCodecHTML(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path) {
-	// A HTML directory index will be presented, be sure to set the correct
-	// type instead of relying on autodetection (which may fail).
-	w.Header().Set("Content-Type", "text/html")
-
-	// Clear Content-Disposition -- we want HTML to be rendered inline
-	w.Header().Del("Content-Disposition")
-
-	// Generated index requires custom Etag (output may change between Kubo versions)
-	dagEtag := getDagIndexEtag(resolvedPath.Cid())
-	w.Header().Set("Etag", dagEtag)
-
-	// Remove Cache-Control for now to match UnixFS dir-index-html responses
-	// (we don't want browser to cache HTML forever)
-	// TODO: if we ever change behavior for UnixFS dir listings, same changes should be applied here
-	w.Header().Del("Cache-Control")
-
-	cidCodec := mc.Code(resolvedPath.Cid().Prefix().Codec)
-	if err := dih.DagIndexTemplate.Execute(w, dih.DagIndexTemplateData{
-		Path:      contentPath.String(),
-		CID:       resolvedPath.Cid().String(),
-		CodecName: cidCodec.String(),
-		CodecHex:  fmt.Sprintf("0x%x", uint64(cidCodec)),
-	}); err != nil {
-		webError(w, "failed to generate HTML listing for this DAG: try fetching raw block with ?format=raw", err, http.StatusInternalServerError)
-	}
-}
-
-// serveCodecRaw returns the raw block without any conversion
-func (i *gatewayHandler) serveCodecRaw(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, name string, modtime time.Time) {
-	blockCid := resolvedPath.Cid()
-	blockReader, err := i.api.Block().Get(ctx, resolvedPath)
-	if err != nil {
-		webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
-		return
-	}
-	block, err := io.ReadAll(blockReader)
-	if err != nil {
-		webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
-		return
-	}
-	content := bytes.NewReader(block)
-
-	// ServeContent will take care of
-	// If-None-Match+Etag, Content-Length and range requests
-	_, _, _ = ServeContent(w, r, name, modtime, content)
-}
-
-// serveCodecConverted returns payload converted to codec specified in toCodec
-func (i *gatewayHandler) serveCodecConverted(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, toCodec mc.Code, modtime time.Time) {
-	obj, err := i.api.Dag().Get(ctx, resolvedPath.Cid())
-	if err != nil {
-		webError(w, "ipfs dag get "+html.EscapeString(resolvedPath.String()), err, http.StatusInternalServerError)
-		return
-	}
-
-	universal, ok := obj.(ipldlegacy.UniversalNode)
-	if !ok {
-		err = fmt.Errorf("%T is not a valid IPLD node", obj)
-		webError(w, err.Error(), err, http.StatusInternalServerError)
-		return
-	}
-	finalNode := universal.(ipld.Node)
-
-	encoder, err := multicodec.LookupEncoder(uint64(toCodec))
-	if err != nil {
-		webError(w, err.Error(), err, http.StatusInternalServerError)
-		return
-	}
-
-	// Ensure IPLD node conforms to the codec specification.
-	var buf bytes.Buffer
-	err = encoder(finalNode, &buf)
-	if err != nil {
-		webError(w, err.Error(), err, http.StatusInternalServerError)
-		return
-	}
-
-	// Sets correct Last-Modified header. This code is borrowed from the standard
-	// library (net/http/server.go) as we cannot use serveFile.
-	if !(modtime.IsZero() || modtime.Equal(unixEpochTime)) {
-		w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat))
-	}
-
-	_, _ = w.Write(buf.Bytes())
-}
-
-func setCodecContentDisposition(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentType string) string {
-	var dispType, name string
-
-	ext, ok := contentTypeToExtension[contentType]
-	if !ok {
-		// Should never happen.
-		ext = ".bin"
-	}
-
-	if urlFilename := r.URL.Query().Get("filename"); urlFilename != "" {
-		name = urlFilename
-	} else {
-		name = resolvedPath.Cid().String() + ext
-	}
-
-	// JSON should be inlined, but ?download=true should still override
-	if r.URL.Query().Get("download") == "true" {
-		dispType = "attachment"
-	} else {
-		switch ext {
-		case ".json": // codecs that serialize to JSON can be rendered by browsers
-			dispType = "inline"
-		default: // everything else is assumed binary / opaque bytes
-			dispType = "attachment"
-		}
-	}
-
-	setContentDispositionHeader(w, name, dispType)
-	return name
-}
-
-func getDagIndexEtag(dagCid cid.Cid) string {
-	return `"DagIndex-` + assets.AssetHash + `_CID-` + dagCid.String() + `"`
-}
diff --git a/core/corehttp/gateway_handler_tar.go b/core/corehttp/gateway_handler_tar.go
deleted file mode 100644
index 14edf4fbf5ff97f38e619636f379227a1b4d921d..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_tar.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"html"
-	"net/http"
-	"time"
-
-	"github.com/ipfs/go-libipfs/files"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/tracing"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-	"go.uber.org/zap"
-)
-
-var unixEpochTime = time.Unix(0, 0)
-
-func (i *gatewayHandler) serveTAR(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) {
-	ctx, span := tracing.Span(ctx, "Gateway", "ServeTAR", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
-	defer span.End()
-
-	ctx, cancel := context.WithCancel(ctx)
-	defer cancel()
-
-	// Get Unixfs file
-	file, err := i.api.Unixfs().Get(ctx, resolvedPath)
-	if err != nil {
-		webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusBadRequest)
-		return
-	}
-	defer file.Close()
-
-	rootCid := resolvedPath.Cid()
-
-	// Set Cache-Control and read optional Last-Modified time
-	modtime := addCacheControlHeaders(w, r, contentPath, rootCid)
-
-	// Weak Etag W/ because we can't guarantee byte-for-byte identical
-	// responses, but still want to benefit from HTTP Caching. Two TAR
-	// responses for the same CID will be logically equivalent,
-	// but when TAR is streamed, then in theory, files and directories
-	// may arrive in different order (depends on TAR lib and filesystem/inodes).
-	etag := `W/` + getEtag(r, rootCid)
-	w.Header().Set("Etag", etag)
-
-	// Finish early if Etag match
-	if r.Header.Get("If-None-Match") == etag {
-		w.WriteHeader(http.StatusNotModified)
-		return
-	}
-
-	// Set Content-Disposition
-	var name string
-	if urlFilename := r.URL.Query().Get("filename"); urlFilename != "" {
-		name = urlFilename
-	} else {
-		name = rootCid.String() + ".tar"
-	}
-	setContentDispositionHeader(w, name, "attachment")
-
-	// Construct the TAR writer
-	tarw, err := files.NewTarWriter(w)
-	if err != nil {
-		webError(w, "could not build tar writer", err, http.StatusInternalServerError)
-		return
-	}
-	defer tarw.Close()
-
-	// Sets correct Last-Modified header. This code is borrowed from the standard
-	// library (net/http/server.go) as we cannot use serveFile without throwing the entire
-	// TAR into the memory first.
-	if !(modtime.IsZero() || modtime.Equal(unixEpochTime)) {
-		w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat))
-	}
-
-	w.Header().Set("Content-Type", "application/x-tar")
-	w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^)
-
-	// The TAR has a top-level directory (or file) named by the CID.
-	if err := tarw.WriteFile(file, rootCid.String()); err != nil {
-		w.Header().Set("X-Stream-Error", err.Error())
-		// Trailer headers do not work in web browsers
-		// (see https://github.com/mdn/browser-compat-data/issues/14703)
-		// and we have limited options around error handling in browser contexts.
-		// To improve UX/DX, we finish response stream with error message, allowing client to
-		// (1) detect error by having corrupted TAR
-		// (2) be able to reason what went wrong by instecting the tail of TAR stream
-		_, _ = w.Write([]byte(err.Error()))
-		return
-	}
-}
diff --git a/core/corehttp/gateway_handler_unixfs.go b/core/corehttp/gateway_handler_unixfs.go
deleted file mode 100644
index 045c0f81d227e51bb84eec7292c22bc3490843f1..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_unixfs.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"fmt"
-	"html"
-	"net/http"
-	"time"
-
-	"github.com/ipfs/go-libipfs/files"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/tracing"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-	"go.uber.org/zap"
-)
-
-func (i *gatewayHandler) serveUnixFS(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, begin time.Time, logger *zap.SugaredLogger) {
-	ctx, span := tracing.Span(ctx, "Gateway", "ServeUnixFS", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
-	defer span.End()
-
-	// Handling UnixFS
-	dr, err := i.api.Unixfs().Get(ctx, resolvedPath)
-	if err != nil {
-		webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusBadRequest)
-		return
-	}
-	defer dr.Close()
-
-	// Handling Unixfs file
-	if f, ok := dr.(files.File); ok {
-		logger.Debugw("serving unixfs file", "path", contentPath)
-		i.serveFile(ctx, w, r, resolvedPath, contentPath, f, begin)
-		return
-	}
-
-	// Handling Unixfs directory
-	dir, ok := dr.(files.Directory)
-	if !ok {
-		internalWebError(w, fmt.Errorf("unsupported UnixFS type"))
-		return
-	}
-
-	logger.Debugw("serving unixfs directory", "path", contentPath)
-	i.serveDirectory(ctx, w, r, resolvedPath, contentPath, dir, begin, logger)
-}
diff --git a/core/corehttp/gateway_handler_unixfs__redirects.go b/core/corehttp/gateway_handler_unixfs__redirects.go
deleted file mode 100644
index 6906683a6390ef2b90a838e2062fbbf3cfad3c09..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_unixfs__redirects.go
+++ /dev/null
@@ -1,287 +0,0 @@
-package corehttp
-
-import (
-	"fmt"
-	"io"
-	"net/http"
-	gopath "path"
-	"strconv"
-	"strings"
-
-	redirects "github.com/ipfs/go-ipfs-redirects-file"
-	"github.com/ipfs/go-libipfs/files"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"go.uber.org/zap"
-)
-
-// Resolving a UnixFS path involves determining if the provided `path.Path` exists and returning the `path.Resolved`
-// corresponding to that path. For UnixFS, path resolution is more involved.
-//
-// When a path under requested CID does not exist, Gateway will check if a `_redirects` file exists
-// underneath the root CID of the path, and apply rules defined there.
-// See sepcification introduced in: https://github.com/ipfs/specs/pull/290
-//
-// Scenario 1:
-// If a path exists, we always return the `path.Resolved` corresponding to that path, regardless of the existence of a `_redirects` file.
-//
-// Scenario 2:
-// If a path does not exist, usually we should return a `nil` resolution path and an error indicating that the path
-// doesn't exist.  However, a `_redirects` file may exist and contain a redirect rule that redirects that path to a different path.
-// We need to evaluate the rule and perform the redirect if present.
-//
-// Scenario 3:
-// Another possibility is that the path corresponds to a rewrite rule (i.e. a rule with a status of 200).
-// In this case, we don't perform a redirect, but do need to return a `path.Resolved` and `path.Path` corresponding to
-// the rewrite destination path.
-//
-// Note that for security reasons, redirect rules are only processed when the request has origin isolation.
-// See https://github.com/ipfs/specs/pull/290 for more information.
-func (i *gatewayHandler) serveRedirectsIfPresent(w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, logger *zap.SugaredLogger) (newResolvedPath ipath.Resolved, newContentPath ipath.Path, continueProcessing bool, hadMatchingRule bool) {
-	redirectsFile := i.getRedirectsFile(r, contentPath, logger)
-	if redirectsFile != nil {
-		redirectRules, err := i.getRedirectRules(r, redirectsFile)
-		if err != nil {
-			internalWebError(w, err)
-			return nil, nil, false, true
-		}
-
-		redirected, newPath, err := i.handleRedirectsFileRules(w, r, contentPath, redirectRules)
-		if err != nil {
-			err = fmt.Errorf("trouble processing _redirects file at %q: %w", redirectsFile.String(), err)
-			internalWebError(w, err)
-			return nil, nil, false, true
-		}
-
-		if redirected {
-			return nil, nil, false, true
-		}
-
-		// 200 is treated as a rewrite, so update the path and continue
-		if newPath != "" {
-			// Reassign contentPath and resolvedPath since the URL was rewritten
-			contentPath = ipath.New(newPath)
-			resolvedPath, err = i.api.ResolvePath(r.Context(), contentPath)
-			if err != nil {
-				internalWebError(w, err)
-				return nil, nil, false, true
-			}
-
-			return resolvedPath, contentPath, true, true
-		}
-	}
-	// No matching rule, paths remain the same, continue regular processing
-	return resolvedPath, contentPath, true, false
-}
-
-func (i *gatewayHandler) handleRedirectsFileRules(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, redirectRules []redirects.Rule) (redirected bool, newContentPath string, err error) {
-	// Attempt to match a rule to the URL path, and perform the corresponding redirect or rewrite
-	pathParts := strings.Split(contentPath.String(), "/")
-	if len(pathParts) > 3 {
-		// All paths should start with /ipfs/cid/, so get the path after that
-		urlPath := "/" + strings.Join(pathParts[3:], "/")
-		rootPath := strings.Join(pathParts[:3], "/")
-		// Trim off the trailing /
-		urlPath = strings.TrimSuffix(urlPath, "/")
-
-		for _, rule := range redirectRules {
-			// Error right away if the rule is invalid
-			if !rule.MatchAndExpandPlaceholders(urlPath) {
-				continue
-			}
-
-			// We have a match!
-
-			// Rewrite
-			if rule.Status == 200 {
-				// Prepend the rootPath
-				toPath := rootPath + rule.To
-				return false, toPath, nil
-			}
-
-			// Or 4xx
-			if rule.Status == 404 || rule.Status == 410 || rule.Status == 451 {
-				toPath := rootPath + rule.To
-				content4xxPath := ipath.New(toPath)
-				err := i.serve4xx(w, r, content4xxPath, rule.Status)
-				return true, toPath, err
-			}
-
-			// Or redirect
-			if rule.Status >= 301 && rule.Status <= 308 {
-				http.Redirect(w, r, rule.To, rule.Status)
-				return true, "", nil
-			}
-		}
-	}
-
-	// No redirects matched
-	return false, "", nil
-}
-
-func (i *gatewayHandler) getRedirectRules(r *http.Request, redirectsFilePath ipath.Resolved) ([]redirects.Rule, error) {
-	// Convert the path into a file node
-	node, err := i.api.Unixfs().Get(r.Context(), redirectsFilePath)
-	if err != nil {
-		return nil, fmt.Errorf("could not get _redirects: %w", err)
-	}
-	defer node.Close()
-
-	// Convert the node into a file
-	f, ok := node.(files.File)
-	if !ok {
-		return nil, fmt.Errorf("could not parse _redirects: %w", err)
-	}
-
-	// Parse redirect rules from file
-	redirectRules, err := redirects.Parse(f)
-	if err != nil {
-		return nil, fmt.Errorf("could not parse _redirects: %w", err)
-	}
-
-	return redirectRules, nil
-}
-
-// Returns a resolved path to the _redirects file located in the root CID path of the requested path
-func (i *gatewayHandler) getRedirectsFile(r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) ipath.Resolved {
-	// contentPath is the full ipfs path to the requested resource,
-	// regardless of whether path or subdomain resolution is used.
-	rootPath := getRootPath(contentPath)
-
-	// Check for _redirects file.
-	// Any path resolution failures are ignored and we just assume there's no _redirects file.
-	// Note that ignoring these errors also ensures that the use of the empty CID (bafkqaaa) in tests doesn't fail.
-	path := ipath.Join(rootPath, "_redirects")
-	resolvedPath, err := i.api.ResolvePath(r.Context(), path)
-	if err != nil {
-		return nil
-	}
-	return resolvedPath
-}
-
-// Returns the root CID Path for the given path
-func getRootPath(path ipath.Path) ipath.Path {
-	parts := strings.Split(path.String(), "/")
-	return ipath.New(gopath.Join("/", path.Namespace(), parts[2]))
-}
-
-func (i *gatewayHandler) serve4xx(w http.ResponseWriter, r *http.Request, content4xxPath ipath.Path, status int) error {
-	resolved4xxPath, err := i.api.ResolvePath(r.Context(), content4xxPath)
-	if err != nil {
-		return err
-	}
-
-	node, err := i.api.Unixfs().Get(r.Context(), resolved4xxPath)
-	if err != nil {
-		return err
-	}
-	defer node.Close()
-
-	f, ok := node.(files.File)
-	if !ok {
-		return fmt.Errorf("could not convert node for %d page to file", status)
-	}
-
-	size, err := f.Size()
-	if err != nil {
-		return fmt.Errorf("could not get size of %d page", status)
-	}
-
-	log.Debugf("using _redirects: custom %d file at %q", status, content4xxPath)
-	w.Header().Set("Content-Type", "text/html")
-	w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
-	addCacheControlHeaders(w, r, content4xxPath, resolved4xxPath.Cid())
-	w.WriteHeader(status)
-	_, err = io.CopyN(w, f, size)
-	return err
-}
-
-func hasOriginIsolation(r *http.Request) bool {
-	_, gw := r.Context().Value(requestContextKey("gw-hostname")).(string)
-	_, dnslink := r.Context().Value("dnslink-hostname").(string)
-
-	if gw || dnslink {
-		return true
-	}
-
-	return false
-}
-
-func isUnixfsResponseFormat(responseFormat string) bool {
-	// The implicit response format is UnixFS
-	return responseFormat == ""
-}
-
-// Deprecated: legacy ipfs-404.html files are superseded by _redirects file
-// This is provided only for backward-compatibility, until websites migrate
-// to 404s managed via _redirects file (https://github.com/ipfs/specs/pull/290)
-func (i *gatewayHandler) serveLegacy404IfPresent(w http.ResponseWriter, r *http.Request, contentPath ipath.Path) bool {
-	resolved404Path, ctype, err := i.searchUpTreeFor404(r, contentPath)
-	if err != nil {
-		return false
-	}
-
-	dr, err := i.api.Unixfs().Get(r.Context(), resolved404Path)
-	if err != nil {
-		return false
-	}
-	defer dr.Close()
-
-	f, ok := dr.(files.File)
-	if !ok {
-		return false
-	}
-
-	size, err := f.Size()
-	if err != nil {
-		return false
-	}
-
-	log.Debugw("using pretty 404 file", "path", contentPath)
-	w.Header().Set("Content-Type", ctype)
-	w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
-	w.WriteHeader(http.StatusNotFound)
-	_, err = io.CopyN(w, f, size)
-	return err == nil
-}
-
-func (i *gatewayHandler) searchUpTreeFor404(r *http.Request, contentPath ipath.Path) (ipath.Resolved, string, error) {
-	filename404, ctype, err := preferred404Filename(r.Header.Values("Accept"))
-	if err != nil {
-		return nil, "", err
-	}
-
-	pathComponents := strings.Split(contentPath.String(), "/")
-
-	for idx := len(pathComponents); idx >= 3; idx-- {
-		pretty404 := gopath.Join(append(pathComponents[0:idx], filename404)...)
-		parsed404Path := ipath.New("/" + pretty404)
-		if parsed404Path.IsValid() != nil {
-			break
-		}
-		resolvedPath, err := i.api.ResolvePath(r.Context(), parsed404Path)
-		if err != nil {
-			continue
-		}
-		return resolvedPath, ctype, nil
-	}
-
-	return nil, "", fmt.Errorf("no pretty 404 in any parent folder")
-}
-
-func preferred404Filename(acceptHeaders []string) (string, string, error) {
-	// If we ever want to offer a 404 file for a different content type
-	// then this function will need to parse q weightings, but for now
-	// the presence of anything matching HTML is enough.
-	for _, acceptHeader := range acceptHeaders {
-		accepted := strings.Split(acceptHeader, ",")
-		for _, spec := range accepted {
-			contentType := strings.SplitN(spec, ";", 1)[0]
-			switch contentType {
-			case "*/*", "text/*", "text/html":
-				return "ipfs-404.html", "text/html", nil
-			}
-		}
-	}
-
-	return "", "", fmt.Errorf("there is no 404 file for the requested content types")
-}
diff --git a/core/corehttp/gateway_handler_unixfs_dir.go b/core/corehttp/gateway_handler_unixfs_dir.go
deleted file mode 100644
index 03d67e1c04049aa06696d5d7f7b6208e974627b0..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_unixfs_dir.go
+++ /dev/null
@@ -1,210 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"net/http"
-	"net/url"
-	gopath "path"
-	"strings"
-	"time"
-
-	"github.com/dustin/go-humanize"
-	cid "github.com/ipfs/go-cid"
-	"github.com/ipfs/go-libipfs/files"
-	path "github.com/ipfs/go-path"
-	"github.com/ipfs/go-path/resolver"
-	options "github.com/ipfs/interface-go-ipfs-core/options"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/assets"
-	"github.com/ipfs/kubo/tracing"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-	"go.uber.org/zap"
-)
-
-// serveDirectory returns the best representation of UnixFS directory
-//
-// It will return index.html if present, or generate directory listing otherwise.
-func (i *gatewayHandler) serveDirectory(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, dir files.Directory, begin time.Time, logger *zap.SugaredLogger) {
-	ctx, span := tracing.Span(ctx, "Gateway", "ServeDirectory", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
-	defer span.End()
-
-	// HostnameOption might have constructed an IPNS/IPFS path using the Host header.
-	// In this case, we need the original path for constructing redirects
-	// and links that match the requested URL.
-	// For example, http://example.net would become /ipns/example.net, and
-	// the redirects and links would end up as http://example.net/ipns/example.net
-	requestURI, err := url.ParseRequestURI(r.RequestURI)
-	if err != nil {
-		webError(w, "failed to parse request path", err, http.StatusInternalServerError)
-		return
-	}
-	originalURLPath := requestURI.Path
-
-	// Ensure directory paths end with '/'
-	if originalURLPath[len(originalURLPath)-1] != '/' {
-		// don't redirect to trailing slash if it's go get
-		// https://github.com/ipfs/kubo/pull/3963
-		goget := r.URL.Query().Get("go-get") == "1"
-		if !goget {
-			suffix := "/"
-			// preserve query parameters
-			if r.URL.RawQuery != "" {
-				suffix = suffix + "?" + r.URL.RawQuery
-			}
-			// /ipfs/cid/foo?bar must be redirected to /ipfs/cid/foo/?bar
-			redirectURL := originalURLPath + suffix
-			logger.Debugw("directory location moved permanently", "status", http.StatusMovedPermanently)
-			http.Redirect(w, r, redirectURL, http.StatusMovedPermanently)
-			return
-		}
-	}
-
-	// Check if directory has index.html, if so, serveFile
-	idxPath := ipath.Join(contentPath, "index.html")
-	idx, err := i.api.Unixfs().Get(ctx, idxPath)
-	switch err.(type) {
-	case nil:
-		f, ok := idx.(files.File)
-		if !ok {
-			internalWebError(w, files.ErrNotReader)
-			return
-		}
-
-		logger.Debugw("serving index.html file", "path", idxPath)
-		// write to request
-		i.serveFile(ctx, w, r, resolvedPath, idxPath, f, begin)
-		return
-	case resolver.ErrNoLink:
-		logger.Debugw("no index.html; noop", "path", idxPath)
-	default:
-		internalWebError(w, err)
-		return
-	}
-
-	// See statusResponseWriter.WriteHeader
-	// and https://github.com/ipfs/kubo/issues/7164
-	// Note: this needs to occur before listingTemplate.Execute otherwise we get
-	// superfluous response.WriteHeader call from prometheus/client_golang
-	if w.Header().Get("Location") != "" {
-		logger.Debugw("location moved permanently", "status", http.StatusMovedPermanently)
-		w.WriteHeader(http.StatusMovedPermanently)
-		return
-	}
-
-	// A HTML directory index will be presented, be sure to set the correct
-	// type instead of relying on autodetection (which may fail).
-	w.Header().Set("Content-Type", "text/html")
-
-	// Generated dir index requires custom Etag (output may change between go-ipfs versions)
-	dirEtag := getDirListingEtag(resolvedPath.Cid())
-	w.Header().Set("Etag", dirEtag)
-
-	if r.Method == http.MethodHead {
-		logger.Debug("return as request's HTTP method is HEAD")
-		return
-	}
-
-	// Optimization: use Unixfs.Ls without resolving children, but using the
-	// cumulative DAG size as the file size. This allows for a fast listing
-	// while keeping a good enough Size field.
-	results, err := i.api.Unixfs().Ls(ctx,
-		resolvedPath,
-		options.Unixfs.ResolveChildren(false),
-		options.Unixfs.UseCumulativeSize(true),
-	)
-	if err != nil {
-		internalWebError(w, err)
-		return
-	}
-
-	dirListing := make([]directoryItem, 0, len(results))
-	for link := range results {
-		if link.Err != nil {
-			internalWebError(w, err)
-			return
-		}
-
-		hash := link.Cid.String()
-		di := directoryItem{
-			Size:      humanize.Bytes(uint64(link.Size)),
-			Name:      link.Name,
-			Path:      gopath.Join(originalURLPath, link.Name),
-			Hash:      hash,
-			ShortHash: shortHash(hash),
-		}
-		dirListing = append(dirListing, di)
-	}
-
-	// construct the correct back link
-	// https://github.com/ipfs/kubo/issues/1365
-	backLink := originalURLPath
-
-	// don't go further up than /ipfs/$hash/
-	pathSplit := path.SplitList(contentPath.String())
-	switch {
-	// skip backlink when listing a content root
-	case len(pathSplit) == 3: // url: /ipfs/$hash
-		backLink = ""
-
-	// skip backlink when listing a content root
-	case len(pathSplit) == 4 && pathSplit[3] == "": // url: /ipfs/$hash/
-		backLink = ""
-
-	// add the correct link depending on whether the path ends with a slash
-	default:
-		if strings.HasSuffix(backLink, "/") {
-			backLink += ".."
-		} else {
-			backLink += "/.."
-		}
-	}
-
-	size := "?"
-	if s, err := dir.Size(); err == nil {
-		// Size may not be defined/supported. Continue anyways.
-		size = humanize.Bytes(uint64(s))
-	}
-
-	hash := resolvedPath.Cid().String()
-
-	// Gateway root URL to be used when linking to other rootIDs.
-	// This will be blank unless subdomain or DNSLink resolution is being used
-	// for this request.
-	var gwURL string
-
-	// Get gateway hostname and build gateway URL.
-	if h, ok := r.Context().Value(requestContextKey("gw-hostname")).(string); ok {
-		gwURL = "//" + h
-	} else {
-		gwURL = ""
-	}
-
-	dnslink := hasDNSLinkOrigin(gwURL, contentPath.String())
-
-	// See comment above where originalUrlPath is declared.
-	tplData := listingTemplateData{
-		GatewayURL:  gwURL,
-		DNSLink:     dnslink,
-		Listing:     dirListing,
-		Size:        size,
-		Path:        contentPath.String(),
-		Breadcrumbs: breadcrumbs(contentPath.String(), dnslink),
-		BackLink:    backLink,
-		Hash:        hash,
-	}
-
-	logger.Debugw("request processed", "tplDataDNSLink", dnslink, "tplDataSize", size, "tplDataBackLink", backLink, "tplDataHash", hash)
-
-	if err := listingTemplate.Execute(w, tplData); err != nil {
-		internalWebError(w, err)
-		return
-	}
-
-	// Update metrics
-	i.unixfsGenDirGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds())
-}
-
-func getDirListingEtag(dirCid cid.Cid) string {
-	return `"DirIndex-` + assets.AssetHash + `_CID-` + dirCid.String() + `"`
-}
diff --git a/core/corehttp/gateway_handler_unixfs_file.go b/core/corehttp/gateway_handler_unixfs_file.go
deleted file mode 100644
index 1abdc823e73cee469ec779f30929df3fb7a4f268..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_handler_unixfs_file.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"fmt"
-	"io"
-	"mime"
-	"net/http"
-	gopath "path"
-	"strings"
-	"time"
-
-	"github.com/gabriel-vasile/mimetype"
-	"github.com/ipfs/go-libipfs/files"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
-	"github.com/ipfs/kubo/tracing"
-	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/trace"
-)
-
-// serveFile returns data behind a file along with HTTP headers based on
-// the file itself, its CID and the contentPath used for accessing it.
-func (i *gatewayHandler) serveFile(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, file files.File, begin time.Time) {
-	_, span := tracing.Span(ctx, "Gateway", "ServeFile", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
-	defer span.End()
-
-	// Set Cache-Control and read optional Last-Modified time
-	modtime := addCacheControlHeaders(w, r, contentPath, resolvedPath.Cid())
-
-	// Set Content-Disposition
-	name := addContentDispositionHeader(w, r, contentPath)
-
-	// Prepare size value for Content-Length HTTP header (set inside of http.ServeContent)
-	size, err := file.Size()
-	if err != nil {
-		http.Error(w, "cannot serve files with unknown sizes", http.StatusBadGateway)
-		return
-	}
-
-	if size == 0 {
-		// We override null files to 200 to avoid issues with fragment caching reverse proxies.
-		// Also whatever you are asking for, it's cheaper to just give you the complete file (nothing).
-		// TODO: remove this if clause once https://github.com/golang/go/issues/54794 is fixed in two latest releases of go
-		w.Header().Set("Content-Type", "text/plain")
-		w.WriteHeader(http.StatusOK)
-		return
-	}
-
-	// Lazy seeker enables efficient range-requests and HTTP HEAD responses
-	content := &lazySeeker{
-		size:   size,
-		reader: file,
-	}
-
-	// Calculate deterministic value for Content-Type HTTP header
-	// (we prefer to do it here, rather than using implicit sniffing in http.ServeContent)
-	var ctype string
-	if _, isSymlink := file.(*files.Symlink); isSymlink {
-		// We should be smarter about resolving symlinks but this is the
-		// "most correct" we can be without doing that.
-		ctype = "inode/symlink"
-	} else {
-		ctype = mime.TypeByExtension(gopath.Ext(name))
-		if ctype == "" {
-			// uses https://github.com/gabriel-vasile/mimetype library to determine the content type.
-			// Fixes https://github.com/ipfs/kubo/issues/7252
-			mimeType, err := mimetype.DetectReader(content)
-			if err != nil {
-				http.Error(w, fmt.Sprintf("cannot detect content-type: %s", err.Error()), http.StatusInternalServerError)
-				return
-			}
-
-			ctype = mimeType.String()
-			_, err = content.Seek(0, io.SeekStart)
-			if err != nil {
-				http.Error(w, "seeker can't seek", http.StatusInternalServerError)
-				return
-			}
-		}
-		// Strip the encoding from the HTML Content-Type header and let the
-		// browser figure it out.
-		//
-		// Fixes https://github.com/ipfs/kubo/issues/2203
-		if strings.HasPrefix(ctype, "text/html;") {
-			ctype = "text/html"
-		}
-	}
-	// Setting explicit Content-Type to avoid mime-type sniffing on the client
-	// (unifies behavior across gateways and web browsers)
-	w.Header().Set("Content-Type", ctype)
-
-	// special fixup around redirects
-	w = &statusResponseWriter{w}
-
-	// ServeContent will take care of
-	// If-None-Match+Etag, Content-Length and range requests
-	_, dataSent, _ := ServeContent(w, r, name, modtime, content)
-
-	// Was response successful?
-	if dataSent {
-		// Update metrics
-		i.unixfsFileGetMetric.WithLabelValues(contentPath.Namespace()).Observe(time.Since(begin).Seconds())
-	}
-}
diff --git a/core/corehttp/gateway_indexPage.go b/core/corehttp/gateway_indexPage.go
deleted file mode 100644
index b0db8ac1a18377e2919274418a91d151f3396582..0000000000000000000000000000000000000000
--- a/core/corehttp/gateway_indexPage.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package corehttp
-
-import (
-	"html/template"
-	"net/url"
-	"path"
-	"strings"
-
-	ipfspath "github.com/ipfs/go-path"
-	"github.com/ipfs/kubo/assets"
-)
-
-// structs for directory listing
-type listingTemplateData struct {
-	GatewayURL  string
-	DNSLink     bool
-	Listing     []directoryItem
-	Size        string
-	Path        string
-	Breadcrumbs []breadcrumb
-	BackLink    string
-	Hash        string
-}
-
-type directoryItem struct {
-	Size      string
-	Name      string
-	Path      string
-	Hash      string
-	ShortHash string
-}
-
-type breadcrumb struct {
-	Name string
-	Path string
-}
-
-func breadcrumbs(urlPath string, dnslinkOrigin bool) []breadcrumb {
-	var ret []breadcrumb
-
-	p, err := ipfspath.ParsePath(urlPath)
-	if err != nil {
-		// No breadcrumbs, fallback to bare Path in template
-		return ret
-	}
-	segs := p.Segments()
-	contentRoot := segs[1]
-	for i, seg := range segs {
-		if i == 0 {
-			ret = append(ret, breadcrumb{Name: seg})
-		} else {
-			ret = append(ret, breadcrumb{
-				Name: seg,
-				Path: "/" + strings.Join(segs[0:i+1], "/"),
-			})
-		}
-	}
-
-	// Drop the /ipns/<fqdn> prefix from breadcrumb Paths when directory
-	// listing on a DNSLink website (loaded due to Host header in HTTP
-	// request).  Necessary because the hostname most likely won't have a
-	// public gateway mounted.
-	if dnslinkOrigin {
-		prefix := "/ipns/" + contentRoot
-		for i, crumb := range ret {
-			if strings.HasPrefix(crumb.Path, prefix) {
-				ret[i].Path = strings.Replace(crumb.Path, prefix, "", 1)
-			}
-		}
-		// Make contentRoot breadcrumb link to the website root
-		ret[1].Path = "/"
-	}
-
-	return ret
-}
-
-func shortHash(hash string) string {
-	if len(hash) <= 8 {
-		return hash
-	}
-	return (hash[0:4] + "\u2026" + hash[len(hash)-4:])
-}
-
-// helper to detect DNSLink website context
-// (when hostname from gwURL is matching /ipns/<fqdn> in path)
-func hasDNSLinkOrigin(gwURL string, path string) bool {
-	if gwURL != "" {
-		fqdn := stripPort(strings.TrimPrefix(gwURL, "//"))
-		return strings.HasPrefix(path, "/ipns/"+fqdn)
-	}
-	return false
-}
-
-var listingTemplate *template.Template
-
-func init() {
-	knownIconsBytes, err := assets.Asset.ReadFile("dir-index-html/knownIcons.txt")
-	if err != nil {
-		panic(err)
-	}
-	knownIcons := make(map[string]struct{})
-	for _, ext := range strings.Split(strings.TrimSuffix(string(knownIconsBytes), "\n"), "\n") {
-		knownIcons[ext] = struct{}{}
-	}
-
-	// helper to guess the type/icon for it by the extension name
-	iconFromExt := func(name string) string {
-		ext := path.Ext(name)
-		_, ok := knownIcons[ext]
-		if !ok {
-			// default blank icon
-			return "ipfs-_blank"
-		}
-		return "ipfs-" + ext[1:] // slice of the first dot
-	}
-
-	// custom template-escaping function to escape a full path, including '#' and '?'
-	urlEscape := func(rawUrl string) string {
-		pathURL := url.URL{Path: rawUrl}
-		return pathURL.String()
-	}
-
-	// Directory listing template
-	dirIndexBytes, err := assets.Asset.ReadFile("dir-index-html/dir-index.html")
-	if err != nil {
-		panic(err)
-	}
-
-	listingTemplate = template.Must(template.New("dir").Funcs(template.FuncMap{
-		"iconFromExt": iconFromExt,
-		"urlEscape":   urlEscape,
-	}).Parse(string(dirIndexBytes)))
-}
diff --git a/core/corehttp/gateway_test.go b/core/corehttp/gateway_test.go
index 74723579d6adbb24c041cf8996a17d274d9f42b9..d4e357740bd867f78401dbd7b063b14f7ed72b8b 100644
--- a/core/corehttp/gateway_test.go
+++ b/core/corehttp/gateway_test.go
@@ -6,10 +6,8 @@ import (
 	"io"
 	"net/http"
 	"net/http/httptest"
-	"regexp"
 	"strings"
 	"testing"
-	"time"
 
 	namesys "github.com/ipfs/go-namesys"
 	version "github.com/ipfs/kubo"
@@ -19,19 +17,14 @@ import (
 
 	datastore "github.com/ipfs/go-datastore"
 	syncds "github.com/ipfs/go-datastore/sync"
-	"github.com/ipfs/go-libipfs/files"
 	path "github.com/ipfs/go-path"
 	iface "github.com/ipfs/interface-go-ipfs-core"
 	nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
-	ipath "github.com/ipfs/interface-go-ipfs-core/path"
 	config "github.com/ipfs/kubo/config"
 	ci "github.com/libp2p/go-libp2p/core/crypto"
 	id "github.com/libp2p/go-libp2p/p2p/protocol/identify"
 )
 
-// `ipfs object new unixfs-dir`
-var emptyDir = "/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn"
-
 type mockNamesys map[string]path.Path
 
 func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) {
@@ -68,11 +61,7 @@ func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsop
 	return out
 }
 
-func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
-	return errors.New("not implemented for mockNamesys")
-}
-
-func (m mockNamesys) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, _ time.Time) error {
+func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path, opts ...nsopts.PublishOption) error {
 	return errors.New("not implemented for mockNamesys")
 }
 
@@ -150,478 +139,6 @@ func newTestServerAndNode(t *testing.T, ns mockNamesys) (*httptest.Server, iface
 	return ts, api, n.Context()
 }
 
-func matchPathOrBreadcrumbs(s string, expected string) bool {
-	matched, _ := regexp.MatchString("Index of\n[\t ]*"+regexp.QuoteMeta(expected), s)
-	return matched
-}
-
-func TestUriQueryRedirect(t *testing.T) {
-	ts, _, _ := newTestServerAndNode(t, mockNamesys{})
-
-	cid := "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"
-	for i, test := range []struct {
-		path     string
-		status   int
-		location string
-	}{
-		// - Browsers will send original URI in URL-escaped form
-		// - We expect query parameters to be persisted
-		// - We drop fragments, as those should not be sent by a browser
-		{"/ipfs/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html%23header-%C4%85", http.StatusMovedPermanently, "/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
-		{"/ipfs/?uri=ipns%3A%2F%2Fexample.com%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html", http.StatusMovedPermanently, "/ipns/example.com/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
-		{"/ipfs/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
-		{"/ipfs?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/?uri=ipfs://" + cid},
-		{"/ipfs/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
-		{"/ipns/?uri=ipfs%3A%2F%2FQmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html%23header-%C4%85", http.StatusMovedPermanently, "/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
-		{"/ipns/?uri=ipns%3A%2F%2Fexample.com%2Fwiki%2FFoo_%C4%85%C4%99.html%3Ffilename%3Dtest-%C4%99.html", http.StatusMovedPermanently, "/ipns/example.com/wiki/Foo_%c4%85%c4%99.html?filename=test-%c4%99.html"},
-		{"/ipns?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/?uri=ipns://" + cid},
-		{"/ipns/?uri=ipns://" + cid, http.StatusMovedPermanently, "/ipns/" + cid},
-		{"/ipns/?uri=ipfs://" + cid, http.StatusMovedPermanently, "/ipfs/" + cid},
-		{"/ipfs/?uri=unsupported://" + cid, http.StatusBadRequest, ""},
-		{"/ipfs/?uri=invaliduri", http.StatusBadRequest, ""},
-		{"/ipfs/?uri=" + cid, http.StatusBadRequest, ""},
-	} {
-
-		r, err := http.NewRequest(http.MethodGet, ts.URL+test.path, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		resp, err := doWithoutRedirect(r)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer resp.Body.Close()
-
-		if resp.StatusCode != test.status {
-			t.Errorf("(%d) got %d, expected %d from %s", i, resp.StatusCode, test.status, ts.URL+test.path)
-		}
-
-		locHdr := resp.Header.Get("Location")
-		if locHdr != test.location {
-			t.Errorf("(%d) location header got %s, expected %s from %s", i, locHdr, test.location, ts.URL+test.path)
-		}
-	}
-}
-
-func TestGatewayGet(t *testing.T) {
-	ns := mockNamesys{}
-	ts, api, ctx := newTestServerAndNode(t, ns)
-
-	k, err := api.Unixfs().Add(ctx, files.NewBytesFile([]byte("fnord")))
-	if err != nil {
-		t.Fatal(err)
-	}
-	ns["/ipns/example.com"] = path.FromString(k.String())
-	ns["/ipns/working.example.com"] = path.FromString(k.String())
-	ns["/ipns/double.example.com"] = path.FromString("/ipns/working.example.com")
-	ns["/ipns/triple.example.com"] = path.FromString("/ipns/double.example.com")
-	ns["/ipns/broken.example.com"] = path.FromString("/ipns/" + k.Cid().String())
-	// We picked .man because:
-	// 1. It's a valid TLD.
-	// 2. Go treats it as the file extension for "man" files (even though
-	//    nobody actually *uses* this extension, AFAIK).
-	//
-	// Unfortunately, this may not work on all platforms as file type
-	// detection is platform dependent.
-	ns["/ipns/example.man"] = path.FromString(k.String())
-
-	t.Log(ts.URL)
-	for i, test := range []struct {
-		host   string
-		path   string
-		status int
-		text   string
-	}{
-		{"127.0.0.1:8080", "/", http.StatusNotFound, "404 page not found\n"},
-		{"127.0.0.1:8080", "/" + k.Cid().String(), http.StatusNotFound, "404 page not found\n"},
-		{"127.0.0.1:8080", k.String(), http.StatusOK, "fnord"},
-		{"127.0.0.1:8080", "/ipns/nxdomain.example.com", http.StatusBadRequest, "ipfs resolve -r /ipns/nxdomain.example.com: " + namesys.ErrResolveFailed.Error() + "\n"},
-		{"127.0.0.1:8080", "/ipns/%0D%0A%0D%0Ahello", http.StatusBadRequest, "ipfs resolve -r /ipns/\\r\\n\\r\\nhello: " + namesys.ErrResolveFailed.Error() + "\n"},
-		{"127.0.0.1:8080", "/ipns/example.com", http.StatusOK, "fnord"},
-		{"example.com", "/", http.StatusOK, "fnord"},
-
-		{"working.example.com", "/", http.StatusOK, "fnord"},
-		{"double.example.com", "/", http.StatusOK, "fnord"},
-		{"triple.example.com", "/", http.StatusOK, "fnord"},
-		{"working.example.com", k.String(), http.StatusNotFound, "ipfs resolve -r /ipns/working.example.com" + k.String() + ": no link named \"ipfs\" under " + k.Cid().String() + "\n"},
-		{"broken.example.com", "/", http.StatusBadRequest, "ipfs resolve -r /ipns/broken.example.com/: " + namesys.ErrResolveFailed.Error() + "\n"},
-		{"broken.example.com", k.String(), http.StatusBadRequest, "ipfs resolve -r /ipns/broken.example.com" + k.String() + ": " + namesys.ErrResolveFailed.Error() + "\n"},
-		// This test case ensures we don't treat the TLD as a file extension.
-		{"example.man", "/", http.StatusOK, "fnord"},
-	} {
-		var c http.Client
-		r, err := http.NewRequest(http.MethodGet, ts.URL+test.path, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		r.Host = test.host
-		resp, err := c.Do(r)
-
-		urlstr := "http://" + test.host + test.path
-		if err != nil {
-			t.Errorf("error requesting %s: %s", urlstr, err)
-			continue
-		}
-		defer resp.Body.Close()
-		contentType := resp.Header.Get("Content-Type")
-		if contentType != "text/plain; charset=utf-8" {
-			t.Errorf("expected content type to be text/plain, got %s", contentType)
-		}
-		body, err := io.ReadAll(resp.Body)
-		if resp.StatusCode != test.status {
-			t.Errorf("(%d) got %d, expected %d from %s", i, resp.StatusCode, test.status, urlstr)
-			t.Errorf("Body: %s", body)
-			continue
-		}
-		if err != nil {
-			t.Fatalf("error reading response from %s: %s", urlstr, err)
-		}
-		if string(body) != test.text {
-			t.Errorf("unexpected response body from %s: expected %q; got %q", urlstr, test.text, body)
-			continue
-		}
-	}
-}
-
-func TestPretty404(t *testing.T) {
-	ns := mockNamesys{}
-	ts, api, ctx := newTestServerAndNode(t, ns)
-
-	f1 := files.NewMapDirectory(map[string]files.Node{
-		"ipfs-404.html": files.NewBytesFile([]byte("Custom 404")),
-		"deeper": files.NewMapDirectory(map[string]files.Node{
-			"ipfs-404.html": files.NewBytesFile([]byte("Deep custom 404")),
-		}),
-	})
-
-	k, err := api.Unixfs().Add(ctx, f1)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	host := "example.net"
-	ns["/ipns/"+host] = path.FromString(k.String())
-
-	for _, test := range []struct {
-		path   string
-		accept string
-		status int
-		text   string
-	}{
-		{"/ipfs-404.html", "text/html", http.StatusOK, "Custom 404"},
-		{"/nope", "text/html", http.StatusNotFound, "Custom 404"},
-		{"/nope", "text/*", http.StatusNotFound, "Custom 404"},
-		{"/nope", "*/*", http.StatusNotFound, "Custom 404"},
-		{"/nope", "application/json", http.StatusNotFound, "ipfs resolve -r /ipns/example.net/nope: no link named \"nope\" under QmcmnF7XG5G34RdqYErYDwCKNFQ6jb8oKVR21WAJgubiaj\n"},
-		{"/deeper/nope", "text/html", http.StatusNotFound, "Deep custom 404"},
-		{"/deeper/", "text/html", http.StatusOK, ""},
-		{"/deeper", "text/html", http.StatusOK, ""},
-		{"/nope/nope", "text/html", http.StatusNotFound, "Custom 404"},
-	} {
-		var c http.Client
-		req, err := http.NewRequest("GET", ts.URL+test.path, nil)
-		if err != nil {
-			t.Fatal(err)
-		}
-		req.Header.Add("Accept", test.accept)
-		req.Host = host
-		resp, err := c.Do(req)
-
-		if err != nil {
-			t.Fatalf("error requesting %s: %s", test.path, err)
-		}
-
-		defer resp.Body.Close()
-		if resp.StatusCode != test.status {
-			t.Fatalf("got %d, expected %d, from %s", resp.StatusCode, test.status, test.path)
-		}
-		body, err := io.ReadAll(resp.Body)
-		if err != nil {
-			t.Fatalf("error reading response from %s: %s", test.path, err)
-		}
-
-		if test.text != "" && string(body) != test.text {
-			t.Fatalf("unexpected response body from %s: got %q, expected %q", test.path, body, test.text)
-		}
-	}
-}
-
-func TestIPNSHostnameRedirect(t *testing.T) {
-	ns := mockNamesys{}
-	ts, api, ctx := newTestServerAndNode(t, ns)
-	t.Logf("test server url: %s", ts.URL)
-
-	// create /ipns/example.net/foo/index.html
-
-	f1 := files.NewMapDirectory(map[string]files.Node{
-		"_": files.NewBytesFile([]byte("_")),
-		"foo": files.NewMapDirectory(map[string]files.Node{
-			"index.html": files.NewBytesFile([]byte("_")),
-		}),
-	})
-
-	k, err := api.Unixfs().Add(ctx, f1)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	t.Logf("k: %s\n", k)
-	ns["/ipns/example.net"] = path.FromString(k.String())
-
-	// make request to directory containing index.html
-	req, err := http.NewRequest(http.MethodGet, ts.URL+"/foo", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Host = "example.net"
-
-	res, err := doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// expect 301 redirect to same path, but with trailing slash
-	if res.StatusCode != 301 {
-		t.Errorf("status is %d, expected 301", res.StatusCode)
-	}
-	hdr := res.Header["Location"]
-	if len(hdr) < 1 {
-		t.Errorf("location header not present")
-	} else if hdr[0] != "/foo/" {
-		t.Errorf("location header is %v, expected /foo/", hdr[0])
-	}
-
-	// make request with prefix to directory containing index.html
-	req, err = http.NewRequest(http.MethodGet, ts.URL+"/foo", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Host = "example.net"
-
-	res, err = doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// expect 301 redirect to same path, but with prefix and trailing slash
-	if res.StatusCode != 301 {
-		t.Errorf("status is %d, expected 301", res.StatusCode)
-	}
-	hdr = res.Header["Location"]
-	if len(hdr) < 1 {
-		t.Errorf("location header not present")
-	} else if hdr[0] != "/foo/" {
-		t.Errorf("location header is %v, expected /foo/", hdr[0])
-	}
-
-	// make sure /version isn't exposed
-	req, err = http.NewRequest(http.MethodGet, ts.URL+"/version", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Host = "example.net"
-
-	res, err = doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if res.StatusCode != 404 {
-		t.Fatalf("expected a 404 error, got: %s", res.Status)
-	}
-}
-
-// Test directory listing on DNSLink website
-// (scenario when Host header is the same as URL hostname)
-// This is basic regression test: additional end-to-end tests
-// can be found in test/sharness/t0115-gateway-dir-listing.sh
-func TestIPNSHostnameBacklinks(t *testing.T) {
-	ns := mockNamesys{}
-	ts, api, ctx := newTestServerAndNode(t, ns)
-	t.Logf("test server url: %s", ts.URL)
-
-	f1 := files.NewMapDirectory(map[string]files.Node{
-		"file.txt": files.NewBytesFile([]byte("1")),
-		"foo? #<'": files.NewMapDirectory(map[string]files.Node{
-			"file.txt": files.NewBytesFile([]byte("2")),
-			"bar": files.NewMapDirectory(map[string]files.Node{
-				"file.txt": files.NewBytesFile([]byte("3")),
-			}),
-		}),
-	})
-
-	// create /ipns/example.net/foo/
-	k, err := api.Unixfs().Add(ctx, f1)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	k2, err := api.ResolvePath(ctx, ipath.Join(k, "foo? #<'"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	k3, err := api.ResolvePath(ctx, ipath.Join(k, "foo? #<'/bar"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	t.Logf("k: %s\n", k)
-	ns["/ipns/example.net"] = path.FromString(k.String())
-
-	// make request to directory listing
-	req, err := http.NewRequest(http.MethodGet, ts.URL+"/foo%3F%20%23%3C%27/", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Host = "example.net"
-
-	res, err := doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// expect correct links
-	body, err := io.ReadAll(res.Body)
-	if err != nil {
-		t.Fatalf("error reading response: %s", err)
-	}
-	s := string(body)
-	t.Logf("body: %s\n", string(body))
-
-	if !matchPathOrBreadcrumbs(s, "/ipns/<a href=\"//example.net/\">example.net</a>/<a href=\"//example.net/foo%3F%20%23%3C%27\">foo? #&lt;&#39;</a>") {
-		t.Fatalf("expected a path in directory listing")
-	}
-	if !strings.Contains(s, "<a href=\"/foo%3F%20%23%3C%27/..\">") {
-		t.Fatalf("expected backlink in directory listing")
-	}
-	if !strings.Contains(s, "<a href=\"/foo%3F%20%23%3C%27/file.txt\">") {
-		t.Fatalf("expected file in directory listing")
-	}
-	if !strings.Contains(s, "<a class=\"ipfs-hash\" translate=\"no\" href=\"https://cid.ipfs.tech/#") {
-		// https://github.com/ipfs/dir-index-html/issues/42
-		t.Fatalf("expected links to cid.ipfs.tech in CID column when on DNSLink website")
-	}
-	if !strings.Contains(s, k2.Cid().String()) {
-		t.Fatalf("expected hash in directory listing")
-	}
-
-	// make request to directory listing at root
-	req, err = http.NewRequest(http.MethodGet, ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Host = "example.net"
-
-	res, err = doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// expect correct backlinks at root
-	body, err = io.ReadAll(res.Body)
-	if err != nil {
-		t.Fatalf("error reading response: %s", err)
-	}
-	s = string(body)
-	t.Logf("body: %s\n", string(body))
-
-	if !matchPathOrBreadcrumbs(s, "/") {
-		t.Fatalf("expected a path in directory listing")
-	}
-	if strings.Contains(s, "<a href=\"/\">") {
-		t.Fatalf("expected no backlink in directory listing of the root CID")
-	}
-	if !strings.Contains(s, "<a href=\"/file.txt\">") {
-		t.Fatalf("expected file in directory listing")
-	}
-	if !strings.Contains(s, "<a class=\"ipfs-hash\" translate=\"no\" href=\"https://cid.ipfs.tech/#") {
-		// https://github.com/ipfs/dir-index-html/issues/42
-		t.Fatalf("expected links to cid.ipfs.tech in CID column when on DNSLink website")
-	}
-	if !strings.Contains(s, k.Cid().String()) {
-		t.Fatalf("expected hash in directory listing")
-	}
-
-	// make request to directory listing
-	req, err = http.NewRequest(http.MethodGet, ts.URL+"/foo%3F%20%23%3C%27/bar/", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Host = "example.net"
-
-	res, err = doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// expect correct backlinks
-	body, err = io.ReadAll(res.Body)
-	if err != nil {
-		t.Fatalf("error reading response: %s", err)
-	}
-	s = string(body)
-	t.Logf("body: %s\n", string(body))
-
-	if !matchPathOrBreadcrumbs(s, "/ipns/<a href=\"//example.net/\">example.net</a>/<a href=\"//example.net/foo%3F%20%23%3C%27\">foo? #&lt;&#39;</a>/<a href=\"//example.net/foo%3F%20%23%3C%27/bar\">bar</a>") {
-		t.Fatalf("expected a path in directory listing")
-	}
-	if !strings.Contains(s, "<a href=\"/foo%3F%20%23%3C%27/bar/..\">") {
-		t.Fatalf("expected backlink in directory listing")
-	}
-	if !strings.Contains(s, "<a href=\"/foo%3F%20%23%3C%27/bar/file.txt\">") {
-		t.Fatalf("expected file in directory listing")
-	}
-	if !strings.Contains(s, k3.Cid().String()) {
-		t.Fatalf("expected hash in directory listing")
-	}
-}
-
-func TestCacheControlImmutable(t *testing.T) {
-	ts, _, _ := newTestServerAndNode(t, nil)
-	t.Logf("test server url: %s", ts.URL)
-
-	req, err := http.NewRequest(http.MethodGet, ts.URL+emptyDir+"/", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	res, err := doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// check the immutable tag isn't set
-	hdrs, ok := res.Header["Cache-Control"]
-	if ok {
-		for _, hdr := range hdrs {
-			if strings.Contains(hdr, "immutable") {
-				t.Fatalf("unexpected Cache-Control: immutable on directory listing: %s", hdr)
-			}
-		}
-	}
-}
-
-func TestGoGetSupport(t *testing.T) {
-	ts, _, _ := newTestServerAndNode(t, nil)
-	t.Logf("test server url: %s", ts.URL)
-
-	// mimic go-get
-	req, err := http.NewRequest(http.MethodGet, ts.URL+emptyDir+"?go-get=1", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	res, err := doWithoutRedirect(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if res.StatusCode != 200 {
-		t.Errorf("status is %d, expected 200", res.StatusCode)
-	}
-}
-
 func TestVersion(t *testing.T) {
 	version.CurrentCommit = "theshortcommithash"
 
@@ -656,28 +173,3 @@ func TestVersion(t *testing.T) {
 		t.Fatalf("response doesn't contain protocol version:\n%s", s)
 	}
 }
-
-func TestEtagMatch(t *testing.T) {
-	for _, test := range []struct {
-		header   string // value in If-None-Match HTTP header
-		cidEtag  string
-		dirEtag  string
-		expected bool // expected result of etagMatch(header, cidEtag, dirEtag)
-	}{
-		{"", `"etag"`, "", false},                        // no If-None-Match
-		{"", "", `"etag"`, false},                        // no If-None-Match
-		{`"etag"`, `"etag"`, "", true},                   // file etag match
-		{`W/"etag"`, `"etag"`, "", true},                 // file etag match
-		{`"foo", W/"bar", W/"etag"`, `"etag"`, "", true}, // file etag match (array)
-		{`"foo",W/"bar",W/"etag"`, `"etag"`, "", true},   // file etag match (compact array)
-		{`"etag"`, "", `W/"etag"`, true},                 // dir etag match
-		{`"etag"`, "", `W/"etag"`, true},                 // dir etag match
-		{`W/"etag"`, "", `W/"etag"`, true},               // dir etag match
-		{`*`, `"etag"`, "", true},                        // wildcard etag match
-	} {
-		result := etagMatch(test.header, test.cidEtag, test.dirEtag)
-		if result != test.expected {
-			t.Fatalf("unexpected result of etagMatch(%q, %q, %q), got %t, expected %t", test.header, test.cidEtag, test.dirEtag, result, test.expected)
-		}
-	}
-}
diff --git a/core/corehttp/gateway_writable.go b/core/corehttp/gateway_writable.go
new file mode 100644
index 0000000000000000000000000000000000000000..34cd8438ea7661dba2d3b072af1db7d331363196
--- /dev/null
+++ b/core/corehttp/gateway_writable.go
@@ -0,0 +1,265 @@
+package corehttp
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"os"
+	gopath "path"
+
+	cid "github.com/ipfs/go-cid"
+	ipld "github.com/ipfs/go-ipld-format"
+	"github.com/ipfs/go-libipfs/files"
+	"github.com/ipfs/go-libipfs/gateway"
+	dag "github.com/ipfs/go-merkledag"
+	"github.com/ipfs/go-mfs"
+	path "github.com/ipfs/go-path"
+	"github.com/ipfs/go-path/resolver"
+	iface "github.com/ipfs/interface-go-ipfs-core"
+	routing "github.com/libp2p/go-libp2p/core/routing"
+)
+
+const (
+	ipfsPathPrefix = "/ipfs/"
+)
+
+type writableGatewayHandler struct {
+	api    iface.CoreAPI
+	config *gateway.Config
+}
+
+func (i *writableGatewayHandler) addUserHeaders(w http.ResponseWriter) {
+	for k, v := range i.config.Headers {
+		w.Header()[http.CanonicalHeaderKey(k)] = v
+	}
+}
+
+func (i *writableGatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) {
+	p, err := i.api.Unixfs().Add(r.Context(), files.NewReaderFile(r.Body))
+	if err != nil {
+		internalWebError(w, err)
+		return
+	}
+
+	i.addUserHeaders(w) // ok, _now_ write user's headers.
+	w.Header().Set("IPFS-Hash", p.Cid().String())
+	log.Debugw("CID created, http redirect", "from", r.URL, "to", p, "status", http.StatusCreated)
+	http.Redirect(w, r, p.String(), http.StatusCreated)
+}
+
+func (i *writableGatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) {
+	ctx := r.Context()
+	ds := i.api.Dag()
+
+	// Parse the path
+	rootCid, newPath, err := parseIpfsPath(r.URL.Path)
+	if err != nil {
+		webError(w, "WritableGateway: failed to parse the path", err, http.StatusBadRequest)
+		return
+	}
+	if newPath == "" || newPath == "/" {
+		http.Error(w, "WritableGateway: empty path", http.StatusBadRequest)
+		return
+	}
+	newDirectory, newFileName := gopath.Split(newPath)
+
+	// Resolve the old root.
+
+	rnode, err := ds.Get(ctx, rootCid)
+	if err != nil {
+		webError(w, "WritableGateway: Could not create DAG from request", err, http.StatusInternalServerError)
+		return
+	}
+
+	pbnd, ok := rnode.(*dag.ProtoNode)
+	if !ok {
+		webError(w, "Cannot read non protobuf nodes through gateway", dag.ErrNotProtobuf, http.StatusBadRequest)
+		return
+	}
+
+	// Create the new file.
+	newFilePath, err := i.api.Unixfs().Add(ctx, files.NewReaderFile(r.Body))
+	if err != nil {
+		webError(w, "WritableGateway: could not create DAG from request", err, http.StatusInternalServerError)
+		return
+	}
+
+	newFile, err := ds.Get(ctx, newFilePath.Cid())
+	if err != nil {
+		webError(w, "WritableGateway: failed to resolve new file", err, http.StatusInternalServerError)
+		return
+	}
+
+	// Patch the new file into the old root.
+
+	root, err := mfs.NewRoot(ctx, ds, pbnd, nil)
+	if err != nil {
+		webError(w, "WritableGateway: failed to create MFS root", err, http.StatusBadRequest)
+		return
+	}
+
+	if newDirectory != "" {
+		err := mfs.Mkdir(root, newDirectory, mfs.MkdirOpts{Mkparents: true, Flush: false})
+		if err != nil {
+			webError(w, "WritableGateway: failed to create MFS directory", err, http.StatusInternalServerError)
+			return
+		}
+	}
+	dirNode, err := mfs.Lookup(root, newDirectory)
+	if err != nil {
+		webError(w, "WritableGateway: failed to lookup directory", err, http.StatusInternalServerError)
+		return
+	}
+	dir, ok := dirNode.(*mfs.Directory)
+	if !ok {
+		http.Error(w, "WritableGateway: target directory is not a directory", http.StatusBadRequest)
+		return
+	}
+	err = dir.Unlink(newFileName)
+	switch err {
+	case os.ErrNotExist, nil:
+	default:
+		webError(w, "WritableGateway: failed to replace existing file", err, http.StatusBadRequest)
+		return
+	}
+	err = dir.AddChild(newFileName, newFile)
+	if err != nil {
+		webError(w, "WritableGateway: failed to link file into directory", err, http.StatusInternalServerError)
+		return
+	}
+	nnode, err := root.GetDirectory().GetNode()
+	if err != nil {
+		webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError)
+		return
+	}
+	newcid := nnode.Cid()
+
+	i.addUserHeaders(w) // ok, _now_ write user's headers.
+	w.Header().Set("IPFS-Hash", newcid.String())
+
+	redirectURL := gopath.Join(ipfsPathPrefix, newcid.String(), newPath)
+	log.Debugw("CID replaced, redirect", "from", r.URL, "to", redirectURL, "status", http.StatusCreated)
+	http.Redirect(w, r, redirectURL, http.StatusCreated)
+}
+
+func (i *writableGatewayHandler) deleteHandler(w http.ResponseWriter, r *http.Request) {
+	ctx := r.Context()
+
+	// parse the path
+
+	rootCid, newPath, err := parseIpfsPath(r.URL.Path)
+	if err != nil {
+		webError(w, "WritableGateway: failed to parse the path", err, http.StatusBadRequest)
+		return
+	}
+	if newPath == "" || newPath == "/" {
+		http.Error(w, "WritableGateway: empty path", http.StatusBadRequest)
+		return
+	}
+	directory, filename := gopath.Split(newPath)
+
+	// lookup the root
+
+	rootNodeIPLD, err := i.api.Dag().Get(ctx, rootCid)
+	if err != nil {
+		webError(w, "WritableGateway: failed to resolve root CID", err, http.StatusInternalServerError)
+		return
+	}
+	rootNode, ok := rootNodeIPLD.(*dag.ProtoNode)
+	if !ok {
+		http.Error(w, "WritableGateway: empty path", http.StatusInternalServerError)
+		return
+	}
+
+	// construct the mfs root
+
+	root, err := mfs.NewRoot(ctx, i.api.Dag(), rootNode, nil)
+	if err != nil {
+		webError(w, "WritableGateway: failed to construct the MFS root", err, http.StatusBadRequest)
+		return
+	}
+
+	// lookup the parent directory
+
+	parentNode, err := mfs.Lookup(root, directory)
+	if err != nil {
+		webError(w, "WritableGateway: failed to look up parent", err, http.StatusInternalServerError)
+		return
+	}
+
+	parent, ok := parentNode.(*mfs.Directory)
+	if !ok {
+		http.Error(w, "WritableGateway: parent is not a directory", http.StatusInternalServerError)
+		return
+	}
+
+	// delete the file
+
+	switch parent.Unlink(filename) {
+	case nil, os.ErrNotExist:
+	default:
+		webError(w, "WritableGateway: failed to remove file", err, http.StatusInternalServerError)
+		return
+	}
+
+	nnode, err := root.GetDirectory().GetNode()
+	if err != nil {
+		webError(w, "WritableGateway: failed to finalize", err, http.StatusInternalServerError)
+		return
+	}
+	ncid := nnode.Cid()
+
+	i.addUserHeaders(w) // ok, _now_ write user's headers.
+	w.Header().Set("IPFS-Hash", ncid.String())
+
+	redirectURL := gopath.Join(ipfsPathPrefix+ncid.String(), directory)
+	// note: StatusCreated is technically correct here as we created a new resource.
+	log.Debugw("CID deleted, redirect", "from", r.RequestURI, "to", redirectURL, "status", http.StatusCreated)
+	http.Redirect(w, r, redirectURL, http.StatusCreated)
+}
+
+func parseIpfsPath(p string) (cid.Cid, string, error) {
+	rootPath, err := path.ParsePath(p)
+	if err != nil {
+		return cid.Cid{}, "", err
+	}
+
+	// Check the path.
+	rsegs := rootPath.Segments()
+	if rsegs[0] != "ipfs" {
+		return cid.Cid{}, "", fmt.Errorf("WritableGateway: only ipfs paths supported")
+	}
+
+	rootCid, err := cid.Decode(rsegs[1])
+	if err != nil {
+		return cid.Cid{}, "", err
+	}
+
+	return rootCid, path.Join(rsegs[2:]), nil
+}
+
+func webError(w http.ResponseWriter, message string, err error, defaultCode int) {
+	if _, ok := err.(resolver.ErrNoLink); ok {
+		webErrorWithCode(w, message, err, http.StatusNotFound)
+	} else if err == routing.ErrNotFound {
+		webErrorWithCode(w, message, err, http.StatusNotFound)
+	} else if ipld.IsNotFound(err) {
+		webErrorWithCode(w, message, err, http.StatusNotFound)
+	} else if err == context.DeadlineExceeded {
+		webErrorWithCode(w, message, err, http.StatusRequestTimeout)
+	} else {
+		webErrorWithCode(w, message, err, defaultCode)
+	}
+}
+
+func webErrorWithCode(w http.ResponseWriter, message string, err error, code int) {
+	http.Error(w, fmt.Sprintf("%s: %s", message, err), code)
+	if code >= 500 {
+		log.Warnf("server error: %s: %s", message, err)
+	}
+}
+
+// return a 500 error and log
+func internalWebError(w http.ResponseWriter, err error) {
+	webErrorWithCode(w, "internalWebError", err, http.StatusInternalServerError)
+}
diff --git a/core/corehttp/hostname.go b/core/corehttp/hostname.go
deleted file mode 100644
index 39e857aadfb53cb908abaff3c7f08a4ef4619d0f..0000000000000000000000000000000000000000
--- a/core/corehttp/hostname.go
+++ /dev/null
@@ -1,603 +0,0 @@
-package corehttp
-
-import (
-	"context"
-	"fmt"
-	"net"
-	"net/http"
-	"net/url"
-	"regexp"
-	"strings"
-
-	cid "github.com/ipfs/go-cid"
-	namesys "github.com/ipfs/go-namesys"
-	core "github.com/ipfs/kubo/core"
-	coreapi "github.com/ipfs/kubo/core/coreapi"
-	"github.com/libp2p/go-libp2p/core/peer"
-	dns "github.com/miekg/dns"
-
-	mbase "github.com/multiformats/go-multibase"
-
-	iface "github.com/ipfs/interface-go-ipfs-core"
-	options "github.com/ipfs/interface-go-ipfs-core/options"
-	nsopts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
-	config "github.com/ipfs/kubo/config"
-)
-
-var defaultPaths = []string{"/ipfs/", "/ipns/", "/api/", "/p2p/"}
-
-var subdomainGatewaySpec = &config.GatewaySpec{
-	Paths:         defaultPaths,
-	UseSubdomains: true,
-}
-
-var defaultKnownGateways = map[string]*config.GatewaySpec{
-	"localhost": subdomainGatewaySpec,
-}
-
-// Label's max length in DNS (https://tools.ietf.org/html/rfc1034#page-7)
-const dnsLabelMaxLength int = 63
-
-// HostnameOption rewrites an incoming request based on the Host header.
-func HostnameOption() ServeOption {
-	return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
-		childMux := http.NewServeMux()
-
-		coreAPI, err := coreapi.NewCoreAPI(n)
-		if err != nil {
-			return nil, err
-		}
-
-		cfg, err := n.Repo.Config()
-		if err != nil {
-			return nil, err
-		}
-
-		knownGateways := prepareKnownGateways(cfg.Gateway.PublicGateways)
-
-		mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
-			// Unfortunately, many (well, ipfs.io) gateways use
-			// DNSLink so if we blindly rewrite with DNSLink, we'll
-			// break /ipfs links.
-			//
-			// We fix this by maintaining a list of known gateways
-			// and the paths that they serve "gateway" content on.
-			// That way, we can use DNSLink for everything else.
-
-			// Support X-Forwarded-Host if added by a reverse proxy
-			// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
-			host := r.Host
-			if xHost := r.Header.Get("X-Forwarded-Host"); xHost != "" {
-				host = xHost
-			}
-
-			// HTTP Host & Path check: is this one of our  "known gateways"?
-			if gw, ok := isKnownHostname(host, knownGateways); ok {
-				// This is a known gateway but request is not using
-				// the subdomain feature.
-
-				// Does this gateway _handle_ this path?
-				if hasPrefix(r.URL.Path, gw.Paths...) {
-					// It does.
-
-					// Should this gateway use subdomains instead of paths?
-					if gw.UseSubdomains {
-						// Yes, redirect if applicable
-						// Example: dweb.link/ipfs/{cid} → {cid}.ipfs.dweb.link
-						useInlinedDNSLink := gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink)
-						newURL, err := toSubdomainURL(host, r.URL.Path, r, useInlinedDNSLink, coreAPI)
-						if err != nil {
-							http.Error(w, err.Error(), http.StatusBadRequest)
-							return
-						}
-						if newURL != "" {
-							// Set "Location" header with redirect destination.
-							// It is ignored by curl in default mode, but will
-							// be respected by user agents that follow
-							// redirects by default, namely web browsers
-							w.Header().Set("Location", newURL)
-
-							// Note: we continue regular gateway processing:
-							// HTTP Status Code http.StatusMovedPermanently
-							// will be set later, in statusResponseWriter
-						}
-					}
-
-					// Not a subdomain resource, continue with path processing
-					// Example: 127.0.0.1:8080/ipfs/{CID}, ipfs.io/ipfs/{CID} etc
-					childMux.ServeHTTP(w, r)
-					return
-				}
-				// Not a whitelisted path
-
-				// Try DNSLink, if it was not explicitly disabled for the hostname
-				if !gw.NoDNSLink && isDNSLinkName(r.Context(), coreAPI, host) {
-					// rewrite path and handle as DNSLink
-					r.URL.Path = "/ipns/" + stripPort(host) + r.URL.Path
-					childMux.ServeHTTP(w, withHostnameContext(r, host))
-					return
-				}
-
-				// If not, resource does not exist on the hostname, return 404
-				http.NotFound(w, r)
-				return
-			}
-
-			// HTTP Host check: is this one of our subdomain-based "known gateways"?
-			// IPFS details extracted from the host: {rootID}.{ns}.{gwHostname}
-			// /ipfs/ example: {cid}.ipfs.localhost:8080, {cid}.ipfs.dweb.link
-			// /ipns/ example: {libp2p-key}.ipns.localhost:8080, {inlined-dnslink-fqdn}.ipns.dweb.link
-			if gw, gwHostname, ns, rootID, ok := knownSubdomainDetails(host, knownGateways); ok {
-				// Looks like we're using a known gateway in subdomain mode.
-
-				// Assemble original path prefix.
-				pathPrefix := "/" + ns + "/" + rootID
-
-				// Retrieve whether or not we should inline DNSLink.
-				useInlinedDNSLink := gw.InlineDNSLink.WithDefault(config.DefaultInlineDNSLink)
-
-				// Does this gateway _handle_ subdomains AND this path?
-				if !(gw.UseSubdomains && hasPrefix(pathPrefix, gw.Paths...)) {
-					// If not, resource does not exist, return 404
-					http.NotFound(w, r)
-					return
-				}
-
-				// Check if rootID is a valid CID
-				if rootCID, err := cid.Decode(rootID); err == nil {
-					// Do we need to redirect root CID to a canonical DNS representation?
-					dnsCID, err := toDNSLabel(rootID, rootCID)
-					if err != nil {
-						http.Error(w, err.Error(), http.StatusBadRequest)
-						return
-					}
-					if !strings.HasPrefix(r.Host, dnsCID) {
-						dnsPrefix := "/" + ns + "/" + dnsCID
-						newURL, err := toSubdomainURL(gwHostname, dnsPrefix+r.URL.Path, r, useInlinedDNSLink, coreAPI)
-						if err != nil {
-							http.Error(w, err.Error(), http.StatusBadRequest)
-							return
-						}
-						if newURL != "" {
-							// Redirect to deterministic CID to ensure CID
-							// always gets the same Origin on the web
-							http.Redirect(w, r, newURL, http.StatusMovedPermanently)
-							return
-						}
-					}
-
-					// Do we need to fix multicodec in PeerID represented as CIDv1?
-					if isPeerIDNamespace(ns) {
-						if rootCID.Type() != cid.Libp2pKey {
-							newURL, err := toSubdomainURL(gwHostname, pathPrefix+r.URL.Path, r, useInlinedDNSLink, coreAPI)
-							if err != nil {
-								http.Error(w, err.Error(), http.StatusBadRequest)
-								return
-							}
-							if newURL != "" {
-								// Redirect to CID fixed inside of toSubdomainURL()
-								http.Redirect(w, r, newURL, http.StatusMovedPermanently)
-								return
-							}
-						}
-					}
-				} else { // rootID is not a CID..
-
-					// Check if rootID is a single DNS label with an inlined
-					// DNSLink FQDN a single DNS label. We support this so
-					// loading DNSLink names over TLS "just works" on public
-					// HTTP gateways.
-					//
-					// Rationale for doing this can be found under "Option C"
-					// at: https://github.com/ipfs/in-web-browsers/issues/169
-					//
-					// TLDR is:
-					// https://dweb.link/ipns/my.v-long.example.com
-					// can be loaded from a subdomain gateway with a wildcard
-					// TLS cert if represented as a single DNS label:
-					// https://my-v--long-example-com.ipns.dweb.link
-					if ns == "ipns" && !strings.Contains(rootID, ".") {
-						// if there is no TXT recordfor rootID
-						if !isDNSLinkName(r.Context(), coreAPI, rootID) {
-							// my-v--long-example-com → my.v-long.example.com
-							dnslinkFQDN := toDNSLinkFQDN(rootID)
-							if isDNSLinkName(r.Context(), coreAPI, dnslinkFQDN) {
-								// update path prefix to use real FQDN with DNSLink
-								pathPrefix = "/ipns/" + dnslinkFQDN
-							}
-						}
-					}
-				}
-
-				// Rewrite the path to not use subdomains
-				r.URL.Path = pathPrefix + r.URL.Path
-
-				// Serve path request
-				childMux.ServeHTTP(w, withHostnameContext(r, gwHostname))
-				return
-			}
-			// We don't have a known gateway. Fallback on DNSLink lookup
-
-			// Wildcard HTTP Host check:
-			// 1. is wildcard DNSLink enabled (Gateway.NoDNSLink=false)?
-			// 2. does Host header include a fully qualified domain name (FQDN)?
-			// 3. does DNSLink record exist in DNS?
-			if !cfg.Gateway.NoDNSLink && isDNSLinkName(r.Context(), coreAPI, host) {
-				// rewrite path and handle as DNSLink
-				r.URL.Path = "/ipns/" + stripPort(host) + r.URL.Path
-				ctx := context.WithValue(r.Context(), requestContextKey("dnslink-hostname"), host)
-				childMux.ServeHTTP(w, withHostnameContext(r.WithContext(ctx), host))
-				return
-			}
-
-			// else, treat it as an old school gateway, I guess.
-			childMux.ServeHTTP(w, r)
-		})
-		return childMux, nil
-	}
-}
-
-type gatewayHosts struct {
-	exact    map[string]*config.GatewaySpec
-	wildcard []wildcardHost
-}
-
-type wildcardHost struct {
-	re   *regexp.Regexp
-	spec *config.GatewaySpec
-}
-
-type requestContextKey string
-
-// Extends request context to include hostname of a canonical gateway root
-// (subdomain root or dnslink fqdn)
-func withHostnameContext(r *http.Request, hostname string) *http.Request {
-	// This is required for links on directory listing pages to work correctly
-	// on subdomain and dnslink gateways. While DNSlink could read value from
-	// Host header, subdomain gateways have more comples rules (knownSubdomainDetails)
-	// More: https://github.com/ipfs/dir-index-html/issues/42
-	// nolint: staticcheck // non-backward compatible change
-	ctx := context.WithValue(r.Context(), requestContextKey("gw-hostname"), hostname)
-	return r.WithContext(ctx)
-}
-
-func prepareKnownGateways(publicGateways map[string]*config.GatewaySpec) gatewayHosts {
-	var hosts gatewayHosts
-
-	hosts.exact = make(map[string]*config.GatewaySpec, len(publicGateways)+len(defaultKnownGateways))
-
-	// First, implicit defaults such as subdomain gateway on localhost
-	for hostname, gw := range defaultKnownGateways {
-		hosts.exact[hostname] = gw
-	}
-
-	// Then apply values from Gateway.PublicGateways, if present in the config
-	for hostname, gw := range publicGateways {
-		if gw == nil {
-			// Remove any implicit defaults, if present. This is useful when one
-			// wants to disable subdomain gateway on localhost etc.
-			delete(hosts.exact, hostname)
-			continue
-		}
-		if strings.Contains(hostname, "*") {
-			// from *.domain.tld, construct a regexp that match any direct subdomain
-			// of .domain.tld.
-			//
-			// Regexp will be in the form of ^[^.]+\.domain.tld(?::\d+)?$
-
-			escaped := strings.ReplaceAll(hostname, ".", `\.`)
-			regexed := strings.ReplaceAll(escaped, "*", "[^.]+")
-
-			re, err := regexp.Compile(fmt.Sprintf(`^%s(?::\d+)?$`, regexed))
-			if err != nil {
-				log.Warn("invalid wildcard gateway hostname \"%s\"", hostname)
-			}
-
-			hosts.wildcard = append(hosts.wildcard, wildcardHost{re: re, spec: gw})
-		} else {
-			hosts.exact[hostname] = gw
-		}
-	}
-
-	return hosts
-}
-
-// isKnownHostname checks Gateway.PublicGateways and returns matching
-// GatewaySpec with graceful fallback to version without port
-func isKnownHostname(hostname string, knownGateways gatewayHosts) (gw *config.GatewaySpec, ok bool) {
-	// Try hostname (host+optional port - value from Host header as-is)
-	if gw, ok := knownGateways.exact[hostname]; ok {
-		return gw, ok
-	}
-	// Also test without port
-	if gw, ok = knownGateways.exact[stripPort(hostname)]; ok {
-		return gw, ok
-	}
-
-	// Wildcard support. Test both with and without port.
-	for _, host := range knownGateways.wildcard {
-		if host.re.MatchString(hostname) {
-			return host.spec, true
-		}
-	}
-
-	return nil, false
-}
-
-// Parses Host header and looks for a known gateway matching subdomain host.
-// If found, returns GatewaySpec and subdomain components extracted from Host
-// header: {rootID}.{ns}.{gwHostname}
-// Note: hostname is host + optional port
-func knownSubdomainDetails(hostname string, knownGateways gatewayHosts) (gw *config.GatewaySpec, gwHostname, ns, rootID string, ok bool) {
-	labels := strings.Split(hostname, ".")
-	// Look for FQDN of a known gateway hostname.
-	// Example: given "dist.ipfs.tech.ipns.dweb.link":
-	// 1. Lookup "link" TLD in knownGateways: negative
-	// 2. Lookup "dweb.link" in knownGateways: positive
-	//
-	// Stops when we have 2 or fewer labels left as we need at least a
-	// rootId and a namespace.
-	for i := len(labels) - 1; i >= 2; i-- {
-		fqdn := strings.Join(labels[i:], ".")
-		gw, ok := isKnownHostname(fqdn, knownGateways)
-		if !ok {
-			continue
-		}
-
-		ns := labels[i-1]
-		if !isSubdomainNamespace(ns) {
-			continue
-		}
-
-		// Merge remaining labels (could be a FQDN with DNSLink)
-		rootID := strings.Join(labels[:i-1], ".")
-		return gw, fqdn, ns, rootID, true
-	}
-	// no match
-	return nil, "", "", "", false
-}
-
-// isDomainNameAndNotPeerID returns bool if string looks like a valid DNS name AND is not a PeerID
-func isDomainNameAndNotPeerID(hostname string) bool {
-	if len(hostname) == 0 {
-		return false
-	}
-	if _, err := peer.Decode(hostname); err == nil {
-		return false
-	}
-	_, ok := dns.IsDomainName(hostname)
-	return ok
-}
-
-// isDNSLinkName returns bool if a valid DNS TXT record exist for provided host
-func isDNSLinkName(ctx context.Context, ipfs iface.CoreAPI, host string) bool {
-	dnslinkName := stripPort(host)
-
-	if !isDomainNameAndNotPeerID(dnslinkName) {
-		return false
-	}
-
-	name := "/ipns/" + dnslinkName
-	// check if DNSLink exists
-	depth := options.Name.ResolveOption(nsopts.Depth(1))
-	_, err := ipfs.Name().Resolve(ctx, name, depth)
-	return err == nil || err == namesys.ErrResolveRecursion
-}
-
-func isSubdomainNamespace(ns string) bool {
-	switch ns {
-	case "ipfs", "ipns", "p2p", "ipld":
-		return true
-	default:
-		return false
-	}
-}
-
-func isPeerIDNamespace(ns string) bool {
-	switch ns {
-	case "ipns", "p2p":
-		return true
-	default:
-		return false
-	}
-}
-
-// Converts a CID to DNS-safe representation that fits in 63 characters
-func toDNSLabel(rootID string, rootCID cid.Cid) (dnsCID string, err error) {
-	// Return as-is if things fit
-	if len(rootID) <= dnsLabelMaxLength {
-		return rootID, nil
-	}
-
-	// Convert to Base36 and see if that helped
-	rootID, err = cid.NewCidV1(rootCID.Type(), rootCID.Hash()).StringOfBase(mbase.Base36)
-	if err != nil {
-		return "", err
-	}
-	if len(rootID) <= dnsLabelMaxLength {
-		return rootID, nil
-	}
-
-	// Can't win with DNS at this point, return error
-	return "", fmt.Errorf("CID incompatible with DNS label length limit of 63: %s", rootID)
-}
-
-// Returns true if HTTP request involves TLS certificate.
-// See https://github.com/ipfs/in-web-browsers/issues/169 to understand how it
-// impacts DNSLink websites on public gateways.
-func isHTTPSRequest(r *http.Request) bool {
-	// X-Forwarded-Proto if added by a reverse proxy
-	// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
-	xproto := r.Header.Get("X-Forwarded-Proto")
-	// Is request a native TLS (not used atm, but future-proofing)
-	// or a proxied HTTPS (eg. go-ipfs behind nginx at a public gw)?
-	return r.URL.Scheme == "https" || xproto == "https"
-}
-
-// Converts a FQDN to DNS-safe representation that fits in 63 characters:
-// my.v-long.example.com → my-v--long-example-com
-func toDNSLinkDNSLabel(fqdn string) (dnsLabel string, err error) {
-	dnsLabel = strings.ReplaceAll(fqdn, "-", "--")
-	dnsLabel = strings.ReplaceAll(dnsLabel, ".", "-")
-	if len(dnsLabel) > dnsLabelMaxLength {
-		return "", fmt.Errorf("DNSLink representation incompatible with DNS label length limit of 63: %s", dnsLabel)
-	}
-	return dnsLabel, nil
-}
-
-// Converts a DNS-safe representation of DNSLink FQDN to real FQDN:
-// my-v--long-example-com → my.v-long.example.com
-func toDNSLinkFQDN(dnsLabel string) (fqdn string) {
-	fqdn = strings.ReplaceAll(dnsLabel, "--", "@") // @ placeholder is unused in DNS labels
-	fqdn = strings.ReplaceAll(fqdn, "-", ".")
-	fqdn = strings.ReplaceAll(fqdn, "@", "-")
-	return fqdn
-}
-
-// Converts a hostname/path to a subdomain-based URL, if applicable.
-func toSubdomainURL(hostname, path string, r *http.Request, inlineDNSLink bool, ipfs iface.CoreAPI) (redirURL string, err error) {
-	var scheme, ns, rootID, rest string
-
-	query := r.URL.RawQuery
-	parts := strings.SplitN(path, "/", 4)
-	isHTTPS := isHTTPSRequest(r)
-	safeRedirectURL := func(in string) (out string, err error) {
-		safeURI, err := url.ParseRequestURI(in)
-		if err != nil {
-			return "", err
-		}
-		return safeURI.String(), nil
-	}
-
-	if isHTTPS {
-		scheme = "https:"
-	} else {
-		scheme = "http:"
-	}
-
-	switch len(parts) {
-	case 4:
-		rest = parts[3]
-		fallthrough
-	case 3:
-		ns = parts[1]
-		rootID = parts[2]
-	default:
-		return "", nil
-	}
-
-	if !isSubdomainNamespace(ns) {
-		return "", nil
-	}
-
-	// add prefix if query is present
-	if query != "" {
-		query = "?" + query
-	}
-
-	// Normalize problematic PeerIDs (eg. ed25519+identity) to CID representation
-	if isPeerIDNamespace(ns) && !isDomainNameAndNotPeerID(rootID) {
-		peerID, err := peer.Decode(rootID)
-		// Note: PeerID CIDv1 with protobuf multicodec will fail, but we fix it
-		// in the next block
-		if err == nil {
-			rootID = peer.ToCid(peerID).String()
-		}
-	}
-
-	// If rootID is a CID, ensure it uses DNS-friendly text representation
-	if rootCID, err := cid.Decode(rootID); err == nil {
-		multicodec := rootCID.Type()
-		var base mbase.Encoding = mbase.Base32
-
-		// Normalizations specific to /ipns/{libp2p-key}
-		if isPeerIDNamespace(ns) {
-			// Using Base36 for /ipns/ for consistency
-			// Context: https://github.com/ipfs/kubo/pull/7441#discussion_r452372828
-			base = mbase.Base36
-
-			// PeerIDs represented as CIDv1 are expected to have libp2p-key
-			// multicodec (https://github.com/libp2p/specs/pull/209).
-			// We ease the transition by fixing multicodec on the fly:
-			// https://github.com/ipfs/kubo/issues/5287#issuecomment-492163929
-			if multicodec != cid.Libp2pKey {
-				multicodec = cid.Libp2pKey
-			}
-		}
-
-		// Ensure CID text representation used in subdomain is compatible
-		// with the way DNS and URIs are implemented in user agents.
-		//
-		// 1. Switch to CIDv1 and enable case-insensitive Base encoding
-		//    to avoid issues when user agent force-lowercases the hostname
-		//    before making the request
-		//    (https://github.com/ipfs/in-web-browsers/issues/89)
-		rootCID = cid.NewCidV1(multicodec, rootCID.Hash())
-		rootID, err = rootCID.StringOfBase(base)
-		if err != nil {
-			return "", err
-		}
-		// 2. Make sure CID fits in a DNS label, adjust encoding if needed
-		//    (https://github.com/ipfs/kubo/issues/7318)
-		rootID, err = toDNSLabel(rootID, rootCID)
-		if err != nil {
-			return "", err
-		}
-	} else { // rootID is not a CID
-
-		// Check if rootID is a FQDN with DNSLink and convert it to TLS-safe
-		// representation that fits in a single DNS label.  We support this so
-		// loading DNSLink names over TLS "just works" on public HTTP gateways
-		// that pass 'https' in X-Forwarded-Proto to go-ipfs.
-		//
-		// Rationale can be found under "Option C"
-		// at: https://github.com/ipfs/in-web-browsers/issues/169
-		//
-		// TLDR is:
-		// /ipns/my.v-long.example.com
-		// can be loaded from a subdomain gateway with a wildcard TLS cert if
-		// represented as a single DNS label:
-		// https://my-v--long-example-com.ipns.dweb.link
-		if (inlineDNSLink || isHTTPS) && ns == "ipns" && strings.Contains(rootID, ".") {
-			if isDNSLinkName(r.Context(), ipfs, rootID) {
-				// my.v-long.example.com → my-v--long-example-com
-				dnsLabel, err := toDNSLinkDNSLabel(rootID)
-				if err != nil {
-					return "", err
-				}
-				// update path prefix to use real FQDN with DNSLink
-				rootID = dnsLabel
-			}
-		}
-	}
-
-	return safeRedirectURL(fmt.Sprintf(
-		"%s//%s.%s.%s/%s%s",
-		scheme,
-		rootID,
-		ns,
-		hostname,
-		rest,
-		query,
-	))
-}
-
-func hasPrefix(path string, prefixes ...string) bool {
-	for _, prefix := range prefixes {
-		// Assume people are creative with trailing slashes in Gateway config
-		p := strings.TrimSuffix(prefix, "/")
-		// Support for both /version and /ipfs/$cid
-		if p == path || strings.HasPrefix(path, p+"/") {
-			return true
-		}
-	}
-	return false
-}
-
-func stripPort(hostname string) string {
-	host, _, err := net.SplitHostPort(hostname)
-	if err == nil {
-		return host
-	}
-	return hostname
-}
diff --git a/core/corehttp/hostname_test.go b/core/corehttp/hostname_test.go
deleted file mode 100644
index b4a8b8d1643bf2ba99aef2f9960337619e602cd7..0000000000000000000000000000000000000000
--- a/core/corehttp/hostname_test.go
+++ /dev/null
@@ -1,307 +0,0 @@
-package corehttp
-
-import (
-	"errors"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-
-	cid "github.com/ipfs/go-cid"
-	"github.com/ipfs/go-libipfs/files"
-	path "github.com/ipfs/go-path"
-	config "github.com/ipfs/kubo/config"
-	coreapi "github.com/ipfs/kubo/core/coreapi"
-)
-
-func TestToSubdomainURL(t *testing.T) {
-	ns := mockNamesys{}
-	n, err := newNodeWithMockNamesys(ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	coreAPI, err := coreapi.NewCoreAPI(n)
-	if err != nil {
-		t.Fatal(err)
-	}
-	testCID, err := coreAPI.Unixfs().Add(n.Context(), files.NewBytesFile([]byte("fnord")))
-	if err != nil {
-		t.Fatal(err)
-	}
-	ns["/ipns/dnslink.long-name.example.com"] = path.FromString(testCID.String())
-	ns["/ipns/dnslink.too-long.f1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5o.example.com"] = path.FromString(testCID.String())
-	httpRequest := httptest.NewRequest("GET", "http://127.0.0.1:8080", nil)
-	httpsRequest := httptest.NewRequest("GET", "https://https-request-stub.example.com", nil)
-	httpsProxiedRequest := httptest.NewRequest("GET", "http://proxied-https-request-stub.example.com", nil)
-	httpsProxiedRequest.Header.Set("X-Forwarded-Proto", "https")
-
-	for _, test := range []struct {
-		// in:
-		request       *http.Request
-		gwHostname    string
-		inlineDNSLink bool
-		path          string
-		// out:
-		url string
-		err error
-	}{
-		// DNSLink
-		{httpRequest, "localhost", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost/", nil},
-		// Hostname with port
-		{httpRequest, "localhost:8080", false, "/ipns/dnslink.io", "http://dnslink.io.ipns.localhost:8080/", nil},
-		// CIDv0 → CIDv1base32
-		{httpRequest, "localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.localhost/", nil},
-		// CIDv1 with long sha512
-		{httpRequest, "localhost", false, "/ipfs/bafkrgqe3ohjcjplc6n4f3fwunlj6upltggn7xqujbsvnvyw764srszz4u4rshq6ztos4chl4plgg4ffyyxnayrtdi5oc4xb2332g645433aeg", "", errors.New("CID incompatible with DNS label length limit of 63: kf1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5oj")},
-		// PeerID as CIDv1 needs to have libp2p-key multicodec
-		{httpRequest, "localhost", false, "/ipns/QmY3hE8xgFCjGcz6PHgnvJz5HZi1BaKRfPkn1ghZUcYMjD", "http://k2k4r8n0flx3ra0y5dr8fmyvwbzy3eiztmtq6th694k5a3rznayp3e4o.ipns.localhost/", nil},
-		{httpRequest, "localhost", false, "/ipns/bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "http://k2k4r8l9ja7hkzynavdqup76ou46tnvuaqegbd04a4o1mpbsey0meucb.ipns.localhost/", nil},
-		// PeerID: ed25519+identity multihash → CIDv1Base36
-		{httpRequest, "localhost", false, "/ipns/12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", "http://k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna.ipns.localhost/", nil},
-		{httpRequest, "sub.localhost", false, "/ipfs/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "http://bafybeif7a7gdklt6hodwdrmwmxnhksctcuav6lfxlcyfz4khzl3qfmvcgu.ipfs.sub.localhost/", nil},
-		// HTTPS requires DNSLink name to fit in a single DNS label – see "Option C" from https://github.com/ipfs/in-web-browsers/issues/169
-		{httpRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "http://dnslink.long-name.example.com.ipns.dweb.link/", nil},
-		{httpsRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil},
-		{httpsProxiedRequest, "dweb.link", false, "/ipns/dnslink.long-name.example.com", "https://dnslink-long--name-example-com.ipns.dweb.link/", nil},
-		// HTTP requests can also be converted to fit into a single DNS label - https://github.com/ipfs/kubo/issues/9243
-		{httpRequest, "localhost", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.localhost/", nil},
-		{httpRequest, "dweb.link", true, "/ipns/dnslink.long-name.example.com", "http://dnslink-long--name-example-com.ipns.dweb.link/", nil},
-	} {
-		url, err := toSubdomainURL(test.gwHostname, test.path, test.request, test.inlineDNSLink, coreAPI)
-		if url != test.url || !equalError(err, test.err) {
-			t.Errorf("(%s, %v, %s) returned (%s, %v), expected (%s, %v)", test.gwHostname, test.inlineDNSLink, test.path, url, err, test.url, test.err)
-		}
-	}
-}
-
-func TestToDNSLinkDNSLabel(t *testing.T) {
-	for _, test := range []struct {
-		in  string
-		out string
-		err error
-	}{
-		{"dnslink.long-name.example.com", "dnslink-long--name-example-com", nil},
-		{"dnslink.too-long.f1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5o.example.com", "", errors.New("DNSLink representation incompatible with DNS label length limit of 63: dnslink-too--long-f1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5o-example-com")},
-	} {
-		out, err := toDNSLinkDNSLabel(test.in)
-		if out != test.out || !equalError(err, test.err) {
-			t.Errorf("(%s) returned (%s, %v), expected (%s, %v)", test.in, out, err, test.out, test.err)
-		}
-	}
-}
-
-func TestToDNSLinkFQDN(t *testing.T) {
-	for _, test := range []struct {
-		in  string
-		out string
-	}{
-		{"singlelabel", "singlelabel"},
-		{"docs-ipfs-tech", "docs.ipfs.tech"},
-		{"dnslink-long--name-example-com", "dnslink.long-name.example.com"},
-	} {
-		out := toDNSLinkFQDN(test.in)
-		if out != test.out {
-			t.Errorf("(%s) returned (%s), expected (%s)", test.in, out, test.out)
-		}
-	}
-}
-
-func TestIsHTTPSRequest(t *testing.T) {
-	httpRequest := httptest.NewRequest("GET", "http://127.0.0.1:8080", nil)
-	httpsRequest := httptest.NewRequest("GET", "https://https-request-stub.example.com", nil)
-	httpsProxiedRequest := httptest.NewRequest("GET", "http://proxied-https-request-stub.example.com", nil)
-	httpsProxiedRequest.Header.Set("X-Forwarded-Proto", "https")
-	httpProxiedRequest := httptest.NewRequest("GET", "http://proxied-http-request-stub.example.com", nil)
-	httpProxiedRequest.Header.Set("X-Forwarded-Proto", "http")
-	oddballRequest := httptest.NewRequest("GET", "foo://127.0.0.1:8080", nil)
-	for _, test := range []struct {
-		in  *http.Request
-		out bool
-	}{
-		{httpRequest, false},
-		{httpsRequest, true},
-		{httpsProxiedRequest, true},
-		{httpProxiedRequest, false},
-		{oddballRequest, false},
-	} {
-		out := isHTTPSRequest(test.in)
-		if out != test.out {
-			t.Errorf("(%+v): returned %t, expected %t", test.in, out, test.out)
-		}
-	}
-}
-
-func TestHasPrefix(t *testing.T) {
-	for _, test := range []struct {
-		prefixes []string
-		path     string
-		out      bool
-	}{
-		{[]string{"/ipfs"}, "/ipfs/cid", true},
-		{[]string{"/ipfs/"}, "/ipfs/cid", true},
-		{[]string{"/version/"}, "/version", true},
-		{[]string{"/version"}, "/version", true},
-	} {
-		out := hasPrefix(test.path, test.prefixes...)
-		if out != test.out {
-			t.Errorf("(%+v, %s) returned '%t', expected '%t'", test.prefixes, test.path, out, test.out)
-		}
-	}
-}
-
-func TestIsDomainNameAndNotPeerID(t *testing.T) {
-	for _, test := range []struct {
-		hostname string
-		out      bool
-	}{
-		{"", false},
-		{"example.com", true},
-		{"non-icann.something", true},
-		{"..", false},
-		{"12D3KooWFB51PRY9BxcXSH6khFXw1BZeszeLDy7C8GciskqCTZn5", false},           // valid peerid
-		{"k51qzi5uqu5di608geewp3nqkg0bpujoasmka7ftkyxgcm3fh1aroup0gsdrna", false}, // valid peerid
-	} {
-		out := isDomainNameAndNotPeerID(test.hostname)
-		if out != test.out {
-			t.Errorf("(%s) returned '%t', expected '%t'", test.hostname, out, test.out)
-		}
-	}
-}
-
-func TestPortStripping(t *testing.T) {
-	for _, test := range []struct {
-		in  string
-		out string
-	}{
-		{"localhost:8080", "localhost"},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.localhost:8080", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.localhost"},
-		{"example.com:443", "example.com"},
-		{"example.com", "example.com"},
-		{"foo-dweb.ipfs.pvt.k12.ma.us:8080", "foo-dweb.ipfs.pvt.k12.ma.us"},
-		{"localhost", "localhost"},
-		{"[::1]:8080", "::1"},
-	} {
-		out := stripPort(test.in)
-		if out != test.out {
-			t.Errorf("(%s): returned '%s', expected '%s'", test.in, out, test.out)
-		}
-	}
-}
-
-func TestToDNSLabel(t *testing.T) {
-	for _, test := range []struct {
-		in  string
-		out string
-		err error
-	}{
-		// <= 63
-		{"QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", "QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n", nil},
-		{"bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", "bafybeickencdqw37dpz3ha36ewrh4undfjt2do52chtcky4rxkj447qhdm", nil},
-		// > 63
-		// PeerID: ed25519+identity multihash → CIDv1Base36
-		{"bafzaajaiaejca4syrpdu6gdx4wsdnokxkprgzxf4wrstuc34gxw5k5jrag2so5gk", "k51qzi5uqu5dj16qyiq0tajolkojyl9qdkr254920wxv7ghtuwcz593tp69z9m", nil},
-		// CIDv1 with long sha512 → error
-		{"bafkrgqe3ohjcjplc6n4f3fwunlj6upltggn7xqujbsvnvyw764srszz4u4rshq6ztos4chl4plgg4ffyyxnayrtdi5oc4xb2332g645433aeg", "", errors.New("CID incompatible with DNS label length limit of 63: kf1siqrebi3vir8sab33hu5vcy008djegvay6atmz91ojesyjs8lx350b7y7i1nvyw2haytfukfyu2f2x4tocdrfa0zgij6p4zpl4u5oj")},
-	} {
-		inCID, _ := cid.Decode(test.in)
-		out, err := toDNSLabel(test.in, inCID)
-		if out != test.out || !equalError(err, test.err) {
-			t.Errorf("(%s): returned (%s, %v) expected (%s, %v)", test.in, out, err, test.out, test.err)
-		}
-	}
-
-}
-
-func TestKnownSubdomainDetails(t *testing.T) {
-	gwLocalhost := &config.GatewaySpec{Paths: []string{"/ipfs", "/ipns", "/api"}, UseSubdomains: true}
-	gwDweb := &config.GatewaySpec{Paths: []string{"/ipfs", "/ipns", "/api"}, UseSubdomains: true}
-	gwLong := &config.GatewaySpec{Paths: []string{"/ipfs", "/ipns", "/api"}, UseSubdomains: true}
-	gwWildcard1 := &config.GatewaySpec{Paths: []string{"/ipfs", "/ipns", "/api"}, UseSubdomains: true}
-	gwWildcard2 := &config.GatewaySpec{Paths: []string{"/ipfs", "/ipns", "/api"}, UseSubdomains: true}
-
-	knownGateways := prepareKnownGateways(map[string]*config.GatewaySpec{
-		"localhost":               gwLocalhost,
-		"dweb.link":               gwDweb,
-		"devgateway.dweb.link":    gwDweb,
-		"dweb.ipfs.pvt.k12.ma.us": gwLong, // note the sneaky ".ipfs." ;-)
-		"*.wildcard1.tld":         gwWildcard1,
-		"*.*.wildcard2.tld":       gwWildcard2,
-	})
-
-	for _, test := range []struct {
-		// in:
-		hostHeader string
-		// out:
-		gw       *config.GatewaySpec
-		hostname string
-		ns       string
-		rootID   string
-		ok       bool
-	}{
-		// no subdomain
-		{"127.0.0.1:8080", nil, "", "", "", false},
-		{"[::1]:8080", nil, "", "", "", false},
-		{"hey.look.example.com", nil, "", "", "", false},
-		{"dweb.link", nil, "", "", "", false},
-		// malformed Host header
-		{".....dweb.link", nil, "", "", "", false},
-		{"link", nil, "", "", "", false},
-		{"8080:dweb.link", nil, "", "", "", false},
-		{" ", nil, "", "", "", false},
-		{"", nil, "", "", "", false},
-		// unknown gateway host
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.unknown.example.com", nil, "", "", "", false},
-		// cid in subdomain, known gateway
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.localhost:8080", gwLocalhost, "localhost:8080", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.dweb.link", gwDweb, "dweb.link", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.devgateway.dweb.link", gwDweb, "devgateway.dweb.link", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-		// capture everything before .ipfs.
-		{"foo.bar.boo-buzz.ipfs.dweb.link", gwDweb, "dweb.link", "ipfs", "foo.bar.boo-buzz", true},
-		// ipns
-		{"bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju.ipns.localhost:8080", gwLocalhost, "localhost:8080", "ipns", "bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju", true},
-		{"bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju.ipns.dweb.link", gwDweb, "dweb.link", "ipns", "bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju", true},
-		// edge case check: public gateway under long TLD (see: https://publicsuffix.org)
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.dweb.ipfs.pvt.k12.ma.us", gwLong, "dweb.ipfs.pvt.k12.ma.us", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-		{"bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju.ipns.dweb.ipfs.pvt.k12.ma.us", gwLong, "dweb.ipfs.pvt.k12.ma.us", "ipns", "bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju", true},
-		// dnslink in subdomain
-		{"en.wikipedia-on-ipfs.org.ipns.localhost:8080", gwLocalhost, "localhost:8080", "ipns", "en.wikipedia-on-ipfs.org", true},
-		{"en.wikipedia-on-ipfs.org.ipns.localhost", gwLocalhost, "localhost", "ipns", "en.wikipedia-on-ipfs.org", true},
-		{"dist.ipfs.tech.ipns.localhost:8080", gwLocalhost, "localhost:8080", "ipns", "dist.ipfs.tech", true},
-		{"en.wikipedia-on-ipfs.org.ipns.dweb.link", gwDweb, "dweb.link", "ipns", "en.wikipedia-on-ipfs.org", true},
-		// edge case check: public gateway under long TLD (see: https://publicsuffix.org)
-		{"foo.dweb.ipfs.pvt.k12.ma.us", nil, "", "", "", false},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.dweb.ipfs.pvt.k12.ma.us", gwLong, "dweb.ipfs.pvt.k12.ma.us", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-		{"bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju.ipns.dweb.ipfs.pvt.k12.ma.us", gwLong, "dweb.ipfs.pvt.k12.ma.us", "ipns", "bafzbeihe35nmjqar22thmxsnlsgxppd66pseq6tscs4mo25y55juhh6bju", true},
-		// other namespaces
-		{"api.localhost", nil, "", "", "", false},
-		{"peerid.p2p.localhost", gwLocalhost, "localhost", "p2p", "peerid", true},
-		// wildcards
-		{"wildcard1.tld", nil, "", "", "", false},
-		{".wildcard1.tld", nil, "", "", "", false},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.wildcard1.tld", nil, "", "", "", false},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.sub.wildcard1.tld", gwWildcard1, "sub.wildcard1.tld", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.sub1.sub2.wildcard1.tld", nil, "", "", "", false},
-		{"bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am.ipfs.sub1.sub2.wildcard2.tld", gwWildcard2, "sub1.sub2.wildcard2.tld", "ipfs", "bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am", true},
-	} {
-		gw, hostname, ns, rootID, ok := knownSubdomainDetails(test.hostHeader, knownGateways)
-		if ok != test.ok {
-			t.Errorf("knownSubdomainDetails(%s): ok is %t, expected %t", test.hostHeader, ok, test.ok)
-		}
-		if rootID != test.rootID {
-			t.Errorf("knownSubdomainDetails(%s): rootID is '%s', expected '%s'", test.hostHeader, rootID, test.rootID)
-		}
-		if ns != test.ns {
-			t.Errorf("knownSubdomainDetails(%s): ns is '%s', expected '%s'", test.hostHeader, ns, test.ns)
-		}
-		if hostname != test.hostname {
-			t.Errorf("knownSubdomainDetails(%s): hostname is '%s', expected '%s'", test.hostHeader, hostname, test.hostname)
-		}
-		if gw != test.gw {
-			t.Errorf("knownSubdomainDetails(%s): gw is  %+v, expected %+v", test.hostHeader, gw, test.gw)
-		}
-	}
-
-}
-
-func equalError(a, b error) bool {
-	return (a == nil && b == nil) || (a != nil && b != nil && a.Error() == b.Error())
-}
diff --git a/core/corehttp/lazyseek.go b/core/corehttp/lazyseek.go
deleted file mode 100644
index 2a379dc918a13d6c10eb1f55a1f2c5ddbcd53abd..0000000000000000000000000000000000000000
--- a/core/corehttp/lazyseek.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package corehttp
-
-import (
-	"fmt"
-	"io"
-)
-
-// The HTTP server uses seek to determine the file size. Actually _seeking_ can
-// be slow so we wrap the seeker in a _lazy_ seeker.
-type lazySeeker struct {
-	reader io.ReadSeeker
-
-	size       int64
-	offset     int64
-	realOffset int64
-}
-
-func (s *lazySeeker) Seek(offset int64, whence int) (int64, error) {
-	switch whence {
-	case io.SeekEnd:
-		return s.Seek(s.size+offset, io.SeekStart)
-	case io.SeekCurrent:
-		return s.Seek(s.offset+offset, io.SeekStart)
-	case io.SeekStart:
-		if offset < 0 {
-			return s.offset, fmt.Errorf("invalid seek offset")
-		}
-		s.offset = offset
-		return s.offset, nil
-	default:
-		return s.offset, fmt.Errorf("invalid whence: %d", whence)
-	}
-}
-
-func (s *lazySeeker) Read(b []byte) (int, error) {
-	// If we're past the end, EOF.
-	if s.offset >= s.size {
-		return 0, io.EOF
-	}
-
-	// actually seek
-	for s.offset != s.realOffset {
-		off, err := s.reader.Seek(s.offset, io.SeekStart)
-		if err != nil {
-			return 0, err
-		}
-		s.realOffset = off
-	}
-	off, err := s.reader.Read(b)
-	s.realOffset += int64(off)
-	s.offset += int64(off)
-	return off, err
-}
-
-func (s *lazySeeker) Close() error {
-	if closer, ok := s.reader.(io.Closer); ok {
-		return closer.Close()
-	}
-	return nil
-}
diff --git a/core/corehttp/lazyseek_test.go b/core/corehttp/lazyseek_test.go
deleted file mode 100644
index 49aca0a0e2a1c8ee606a0e1d720239d143ab821a..0000000000000000000000000000000000000000
--- a/core/corehttp/lazyseek_test.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package corehttp
-
-import (
-	"fmt"
-	"io"
-	"strings"
-	"testing"
-)
-
-type badSeeker struct {
-	io.ReadSeeker
-}
-
-var errBadSeek = fmt.Errorf("bad seeker")
-
-func (bs badSeeker) Seek(offset int64, whence int) (int64, error) {
-	off, err := bs.ReadSeeker.Seek(0, io.SeekCurrent)
-	if err != nil {
-		panic(err)
-	}
-	return off, errBadSeek
-}
-
-func TestLazySeekerError(t *testing.T) {
-	underlyingBuffer := strings.NewReader("fubar")
-	s := &lazySeeker{
-		reader: badSeeker{underlyingBuffer},
-		size:   underlyingBuffer.Size(),
-	}
-	off, err := s.Seek(0, io.SeekEnd)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if off != s.size {
-		t.Fatal("expected to seek to the end")
-	}
-
-	// shouldn't have actually seeked.
-	b, err := io.ReadAll(s)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(b) != 0 {
-		t.Fatal("expected to read nothing")
-	}
-
-	// shouldn't need to actually seek.
-	off, err = s.Seek(0, io.SeekStart)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if off != 0 {
-		t.Fatal("expected to seek to the start")
-	}
-	b, err = io.ReadAll(s)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if string(b) != "fubar" {
-		t.Fatal("expected to read string")
-	}
-
-	// should fail the second time.
-	off, err = s.Seek(0, io.SeekStart)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if off != 0 {
-		t.Fatal("expected to seek to the start")
-	}
-	// right here...
-	b, err = io.ReadAll(s)
-	if err == nil {
-		t.Fatalf("expected an error, got output %s", string(b))
-	}
-	if err != errBadSeek {
-		t.Fatalf("expected a bad seek error, got %s", err)
-	}
-	if len(b) != 0 {
-		t.Fatalf("expected to read nothing")
-	}
-}
-
-func TestLazySeeker(t *testing.T) {
-	underlyingBuffer := strings.NewReader("fubar")
-	s := &lazySeeker{
-		reader: underlyingBuffer,
-		size:   underlyingBuffer.Size(),
-	}
-	expectByte := func(b byte) {
-		t.Helper()
-		var buf [1]byte
-		n, err := io.ReadFull(s, buf[:])
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n != 1 {
-			t.Fatalf("expected to read one byte, read %d", n)
-		}
-		if buf[0] != b {
-			t.Fatalf("expected %b, got %b", b, buf[0])
-		}
-	}
-	expectSeek := func(whence int, off, expOff int64, expErr string) {
-		t.Helper()
-		n, err := s.Seek(off, whence)
-		if expErr == "" {
-			if err != nil {
-				t.Fatal("unexpected seek error: ", err)
-			}
-		} else {
-			if err == nil || err.Error() != expErr {
-				t.Fatalf("expected %s, got %s", err, expErr)
-			}
-		}
-		if n != expOff {
-			t.Fatalf("expected offset %d, got, %d", expOff, n)
-		}
-	}
-
-	expectSeek(io.SeekEnd, 0, s.size, "")
-	b, err := io.ReadAll(s)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(b) != 0 {
-		t.Fatal("expected to read nothing")
-	}
-	expectSeek(io.SeekEnd, -1, s.size-1, "")
-	expectByte('r')
-	expectSeek(io.SeekStart, 0, 0, "")
-	expectByte('f')
-	expectSeek(io.SeekCurrent, 1, 2, "")
-	expectByte('b')
-	expectSeek(io.SeekCurrent, -100, 3, "invalid seek offset")
-}
diff --git a/core/corehttp/redirect.go b/core/corehttp/redirect.go
index bcd536d235ba9dd273be727cba8a8b01297e13ed..106355d247d583c75360e86934b2f8c6ca2139bc 100644
--- a/core/corehttp/redirect.go
+++ b/core/corehttp/redirect.go
@@ -8,8 +8,14 @@ import (
 )
 
 func RedirectOption(path string, redirect string) ServeOption {
-	handler := &redirectHandler{redirect}
 	return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
+		cfg, err := n.Repo.Config()
+		if err != nil {
+			return nil, err
+		}
+
+		handler := &redirectHandler{redirect, cfg.API.HTTPHeaders}
+
 		if len(path) > 0 {
 			mux.Handle("/"+path+"/", handler)
 		} else {
@@ -20,9 +26,14 @@ func RedirectOption(path string, redirect string) ServeOption {
 }
 
 type redirectHandler struct {
-	path string
+	path    string
+	headers map[string][]string
 }
 
 func (i *redirectHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	for k, v := range i.headers {
+		w.Header()[http.CanonicalHeaderKey(k)] = v
+	}
+
 	http.Redirect(w, r, i.path, http.StatusFound)
 }
diff --git a/core/corehttp/webui.go b/core/corehttp/webui.go
index e8531459d17fd54ee15651d398845712f2735d94..f7b27c93914f39885c74ef475430ca41071b6ad2 100644
--- a/core/corehttp/webui.go
+++ b/core/corehttp/webui.go
@@ -1,11 +1,12 @@
 package corehttp
 
 // TODO: move to IPNS
-const WebUIPath = "/ipfs/bafybeiequgo72mrvuml56j4gk7crewig5bavumrrzhkqbim6b3s2yqi7ty" // v2.21.0
+const WebUIPath = "/ipfs/bafybeifeqt7mvxaniphyu2i3qhovjaf3sayooxbh5enfdqtiehxjv2ldte" // v2.22.0
 
 // WebUIPaths is a list of all past webUI paths.
 var WebUIPaths = []string{
 	WebUIPath,
+	"/ipfs/bafybeiequgo72mrvuml56j4gk7crewig5bavumrrzhkqbim6b3s2yqi7ty",
 	"/ipfs/bafybeibjbq3tmmy7wuihhhwvbladjsd3gx3kfjepxzkq6wylik6wc3whzy",
 	"/ipfs/bafybeiavrvt53fks6u32n5p2morgblcmck4bh4ymf4rrwu7ah5zsykmqqa",
 	"/ipfs/bafybeiageaoxg6d7npaof6eyzqbwvbubyler7bq44hayik2hvqcggg7d2y",
diff --git a/core/coreunix/add.go b/core/coreunix/add.go
index f895baf738ed3a13c127193de4f435330f0cbf58..d2c4c3dff430379a7252cd3ddd6364000d294af3 100644
--- a/core/coreunix/add.go
+++ b/core/coreunix/add.go
@@ -24,6 +24,7 @@ import (
 	"github.com/ipfs/go-unixfs/importer/trickle"
 	coreiface "github.com/ipfs/interface-go-ipfs-core"
 	"github.com/ipfs/interface-go-ipfs-core/path"
+
 	"github.com/ipfs/kubo/tracing"
 )
 
@@ -185,7 +186,11 @@ func (adder *Adder) PinRoot(ctx context.Context, root ipld.Node) error {
 		adder.tempRoot = rnk
 	}
 
-	adder.pinning.PinWithMode(rnk, pin.Recursive)
+	err = adder.pinning.PinWithMode(ctx, rnk, pin.Recursive)
+	if err != nil {
+		return err
+	}
+
 	return adder.pinning.Flush(ctx)
 }
 
diff --git a/core/coreunix/add_test.go b/core/coreunix/add_test.go
index 1ba1b2f0edfd938a9a78da4429e4502141cc7ce4..e64d41001a74dc427abcd5ad8311b3dddd2dcdd7 100644
--- a/core/coreunix/add_test.go
+++ b/core/coreunix/add_test.go
@@ -14,13 +14,13 @@ import (
 	"github.com/ipfs/kubo/gc"
 	"github.com/ipfs/kubo/repo"
 
-	blocks "github.com/ipfs/go-block-format"
 	"github.com/ipfs/go-blockservice"
 	"github.com/ipfs/go-cid"
 	"github.com/ipfs/go-datastore"
 	syncds "github.com/ipfs/go-datastore/sync"
 	blockstore "github.com/ipfs/go-ipfs-blockstore"
 	pi "github.com/ipfs/go-ipfs-posinfo"
+	blocks "github.com/ipfs/go-libipfs/blocks"
 	"github.com/ipfs/go-libipfs/files"
 	dag "github.com/ipfs/go-merkledag"
 	coreiface "github.com/ipfs/interface-go-ipfs-core"
diff --git a/core/node/bitswap.go b/core/node/bitswap.go
index 42b948f7520a47bd648abcad784035f0d3458328..f78703039eda1c280cb4c5ece00125a62088922d 100644
--- a/core/node/bitswap.go
+++ b/core/node/bitswap.go
@@ -4,10 +4,10 @@ import (
 	"context"
 	"time"
 
-	"github.com/ipfs/go-bitswap"
-	"github.com/ipfs/go-bitswap/network"
 	blockstore "github.com/ipfs/go-ipfs-blockstore"
 	exchange "github.com/ipfs/go-ipfs-exchange-interface"
+	"github.com/ipfs/go-libipfs/bitswap"
+	"github.com/ipfs/go-libipfs/bitswap/network"
 	"github.com/ipfs/kubo/config"
 	irouting "github.com/ipfs/kubo/routing"
 	"github.com/libp2p/go-libp2p/core/host"
diff --git a/core/node/groups.go b/core/node/groups.go
index e640feff1ab4282c9a57ae51ed4fe9132541c233..866204ce36b27d7667b4352f8b46833b8d5f9820 100644
--- a/core/node/groups.go
+++ b/core/node/groups.go
@@ -6,21 +6,19 @@ import (
 	"fmt"
 	"time"
 
+	"github.com/dustin/go-humanize"
 	blockstore "github.com/ipfs/go-ipfs-blockstore"
+	offline "github.com/ipfs/go-ipfs-exchange-offline"
 	util "github.com/ipfs/go-ipfs-util"
 	"github.com/ipfs/go-log"
+	uio "github.com/ipfs/go-unixfs/io"
 	"github.com/ipfs/kubo/config"
+	"github.com/ipfs/kubo/core/node/libp2p"
+	"github.com/ipfs/kubo/p2p"
 	pubsub "github.com/libp2p/go-libp2p-pubsub"
 	"github.com/libp2p/go-libp2p-pubsub/timecache"
 	"github.com/libp2p/go-libp2p/core/peer"
-
-	"github.com/ipfs/kubo/core/node/libp2p"
-	"github.com/ipfs/kubo/p2p"
-
-	offline "github.com/ipfs/go-ipfs-exchange-offline"
-	uio "github.com/ipfs/go-unixfs/io"
-
-	"github.com/dustin/go-humanize"
+	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 	"go.uber.org/fx"
 )
 
@@ -37,7 +35,7 @@ var BaseLibP2P = fx.Options(
 	fx.Invoke(libp2p.PNetChecker),
 )
 
-func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
+func LibP2P(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.PartialLimitConfig) fx.Option {
 	var connmgr fx.Option
 
 	// set connmgr based on Swarm.ConnMgr.Type
@@ -150,7 +148,7 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
 		fx.Provide(libp2p.UserAgent()),
 
 		// Services (resource management)
-		fx.Provide(libp2p.ResourceManager(cfg.Swarm)),
+		fx.Provide(libp2p.ResourceManager(cfg.Swarm, userResourceOverrides)),
 		fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)),
 		fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.AppendAnnounce, cfg.Addresses.NoAnnounce)),
 		fx.Provide(libp2p.SmuxTransport(cfg.Swarm.Transports)),
@@ -249,7 +247,7 @@ var IPNS = fx.Options(
 )
 
 // Online groups online-only units
-func Online(bcfg *BuildCfg, cfg *config.Config) fx.Option {
+func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.PartialLimitConfig) fx.Option {
 
 	// Namesys params
 
@@ -303,7 +301,7 @@ func Online(bcfg *BuildCfg, cfg *config.Config) fx.Option {
 
 		fx.Provide(p2p.New),
 
-		LibP2P(bcfg, cfg),
+		LibP2P(bcfg, cfg, userResourceOverrides),
 		OnlineProviders(
 			cfg.Experimental.StrategicProviding,
 			cfg.Experimental.AcceleratedDHTClient,
@@ -340,9 +338,9 @@ var Core = fx.Options(
 	fx.Provide(Files),
 )
 
-func Networked(bcfg *BuildCfg, cfg *config.Config) fx.Option {
+func Networked(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.PartialLimitConfig) fx.Option {
 	if bcfg.Online {
-		return Online(bcfg, cfg)
+		return Online(bcfg, cfg, userResourceOverrides)
 	}
 	return Offline(cfg)
 }
@@ -358,6 +356,11 @@ func IPFS(ctx context.Context, bcfg *BuildCfg) fx.Option {
 		return bcfgOpts // error
 	}
 
+	userResourceOverrides, err := bcfg.Repo.UserResourceOverrides()
+	if err != nil {
+		return fx.Error(err)
+	}
+
 	// Auto-sharding settings
 	shardSizeString := cfg.Internal.UnixFSShardingSizeThreshold.WithDefault("256kiB")
 	shardSizeInt, err := humanize.ParseBytes(shardSizeString)
@@ -381,7 +384,7 @@ func IPFS(ctx context.Context, bcfg *BuildCfg) fx.Option {
 		Storage(bcfg, cfg),
 		Identity(cfg),
 		IPNS,
-		Networked(bcfg, cfg),
+		Networked(bcfg, cfg, userResourceOverrides),
 
 		Core,
 	)
diff --git a/core/node/libp2p/rcmgr.go b/core/node/libp2p/rcmgr.go
index e0ce4693be19940ae6a1c5885833fdad3240b6b4..c61f8dcfe569dc042746f4d69380176e8c66e787 100644
--- a/core/node/libp2p/rcmgr.go
+++ b/core/node/libp2p/rcmgr.go
@@ -2,10 +2,10 @@ package libp2p
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"os"
 	"path/filepath"
-	"strings"
 
 	"github.com/benbjohnson/clock"
 	logging "github.com/ipfs/go-log/v2"
@@ -16,7 +16,6 @@ import (
 	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 	rcmgrObs "github.com/libp2p/go-libp2p/p2p/host/resource-manager/obs"
 	"github.com/multiformats/go-multiaddr"
-	"go.opencensus.io/stats/view"
 	"go.uber.org/fx"
 
 	"github.com/ipfs/kubo/config"
@@ -24,12 +23,11 @@ import (
 	"github.com/ipfs/kubo/repo"
 )
 
-const NetLimitDefaultFilename = "limit.json"
 const NetLimitTraceFilename = "rcmgr.json.gz"
 
 var ErrNoResourceMgr = fmt.Errorf("missing ResourceMgr: make sure the daemon is running with Swarm.ResourceMgr.Enabled")
 
-func ResourceManager(cfg config.SwarmConfig) interface{} {
+func ResourceManager(cfg config.SwarmConfig, userResourceOverrides rcmgr.PartialLimitConfig) interface{} {
 	return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (network.ResourceManager, Libp2pOpts, error) {
 		var manager network.ResourceManager
 		var opts Libp2pOpts
@@ -52,33 +50,25 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
 				return nil, opts, fmt.Errorf("opening IPFS_PATH: %w", err)
 			}
 
-			var limitConfig rcmgr.LimitConfig
-			defaultComputedLimitConfig, err := createDefaultLimitConfig(cfg)
+			limitConfig, msg, err := LimitConfig(cfg, userResourceOverrides)
 			if err != nil {
-				return nil, opts, err
+				return nil, opts, fmt.Errorf("creating final Resource Manager config: %w", err)
 			}
 
-			// The logic for defaults and overriding with specified SwarmConfig.ResourceMgr.Limits
-			// is documented in docs/config.md.
-			// Any changes here should be reflected there.
-			if cfg.ResourceMgr.Limits != nil {
-				userSuppliedOverrideLimitConfig := *cfg.ResourceMgr.Limits
-				// This effectively overrides the computed default LimitConfig with any non-zero values from cfg.ResourceMgr.Limits.
-				// Because of how how Apply works, any 0 value for a user supplied override
-				// will be overriden with a computed default value.
-				// There currently isn't a way for a user to supply a 0-value override.
-				userSuppliedOverrideLimitConfig.Apply(defaultComputedLimitConfig)
-				limitConfig = userSuppliedOverrideLimitConfig
-			} else {
-				limitConfig = defaultComputedLimitConfig
+			if !isPartialConfigEmpty(userResourceOverrides) {
+				fmt.Print(`
+libp2p-resource-limit-overrides.json has been loaded, "default" fields will be
+filled in with autocomputed defaults.
+`)
 			}
 
-			if err := ensureConnMgrMakeSenseVsResourceMgr(limitConfig, cfg.ConnMgr); err != nil {
+			// We want to see this message on startup, that's why we are using fmt instead of log.
+			fmt.Print(msg)
+
+			if err := ensureConnMgrMakeSenseVsResourceMgr(limitConfig, cfg); err != nil {
 				return nil, opts, err
 			}
 
-			limiter := rcmgr.NewFixedLimiter(limitConfig)
-
 			str, err := rcmgrObs.NewStatsTraceReporter()
 			if err != nil {
 				return nil, opts, err
@@ -100,16 +90,13 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
 				log.Infof("Setting allowlist to: %v", mas)
 			}
 
-			err = view.Register(rcmgrObs.DefaultViews...)
-			if err != nil {
-				return nil, opts, fmt.Errorf("registering rcmgr obs views: %w", err)
-			}
-
 			if os.Getenv("LIBP2P_DEBUG_RCMGR") != "" {
 				traceFilePath := filepath.Join(repoPath, NetLimitTraceFilename)
 				ropts = append(ropts, rcmgr.WithTrace(traceFilePath))
 			}
 
+			limiter := rcmgr.NewFixedLimiter(limitConfig)
+
 			manager, err = rcmgr.NewResourceManager(limiter, ropts...)
 			if err != nil {
 				return nil, opts, fmt.Errorf("creating libp2p resource manager: %w", err)
@@ -137,512 +124,367 @@ func ResourceManager(cfg config.SwarmConfig) interface{} {
 	}
 }
 
-type NetStatOut struct {
-	System    *rcmgr.BaseLimit           `json:",omitempty"`
-	Transient *rcmgr.BaseLimit           `json:",omitempty"`
-	Services  map[string]rcmgr.BaseLimit `json:",omitempty"`
-	Protocols map[string]rcmgr.BaseLimit `json:",omitempty"`
-	Peers     map[string]rcmgr.BaseLimit `json:",omitempty"`
-}
-
-func NetStat(mgr network.ResourceManager, scope string, percentage int) (NetStatOut, error) {
-	var err error
-	var result NetStatOut
-	switch {
-	case scope == "all":
-		rapi, ok := mgr.(rcmgr.ResourceManagerState)
-		if !ok { // NullResourceManager
-			return result, ErrNoResourceMgr
-		}
-
-		limits, err := NetLimitAll(mgr)
-		if err != nil {
-			return result, err
-		}
-
-		stat := rapi.Stat()
-		result.System = compareLimits(scopeToLimit(&stat.System), limits.System, percentage)
-		result.Transient = compareLimits(scopeToLimit(&stat.Transient), limits.Transient, percentage)
-		if len(stat.Services) > 0 {
-			result.Services = make(map[string]rcmgr.BaseLimit, len(stat.Services))
-			for srv, stat := range stat.Services {
-				ls := limits.Services[srv]
-				fstat := compareLimits(scopeToLimit(&stat), &ls, percentage)
-				if fstat != nil {
-					result.Services[srv] = *fstat
-				}
-			}
+func isPartialConfigEmpty(cfg rcmgr.PartialLimitConfig) bool {
+	var emptyResourceConfig rcmgr.ResourceLimits
+	if cfg.System != emptyResourceConfig ||
+		cfg.Transient != emptyResourceConfig ||
+		cfg.AllowlistedSystem != emptyResourceConfig ||
+		cfg.AllowlistedTransient != emptyResourceConfig ||
+		cfg.ServiceDefault != emptyResourceConfig ||
+		cfg.ServicePeerDefault != emptyResourceConfig ||
+		cfg.ProtocolDefault != emptyResourceConfig ||
+		cfg.ProtocolPeerDefault != emptyResourceConfig ||
+		cfg.PeerDefault != emptyResourceConfig ||
+		cfg.Conn != emptyResourceConfig ||
+		cfg.Stream != emptyResourceConfig {
+		return false
+	}
+	for _, v := range cfg.Service {
+		if v != emptyResourceConfig {
+			return false
 		}
-		if len(stat.Protocols) > 0 {
-			result.Protocols = make(map[string]rcmgr.BaseLimit, len(stat.Protocols))
-			for proto, stat := range stat.Protocols {
-				ls := limits.Protocols[string(proto)]
-				fstat := compareLimits(scopeToLimit(&stat), &ls, percentage)
-				if fstat != nil {
-					result.Protocols[string(proto)] = *fstat
-				}
-			}
+	}
+	for _, v := range cfg.ServicePeer {
+		if v != emptyResourceConfig {
+			return false
 		}
-		if len(stat.Peers) > 0 {
-			result.Peers = make(map[string]rcmgr.BaseLimit, len(stat.Peers))
-			for p, stat := range stat.Peers {
-				ls := limits.Peers[p.Pretty()]
-				fstat := compareLimits(scopeToLimit(&stat), &ls, percentage)
-				if fstat != nil {
-					result.Peers[p.Pretty()] = *fstat
-				}
-			}
+	}
+	for _, v := range cfg.Protocol {
+		if v != emptyResourceConfig {
+			return false
 		}
-
-		return result, nil
-
-	case scope == config.ResourceMgrSystemScope:
-		err = mgr.ViewSystem(func(s network.ResourceScope) error {
-			stat := s.Stat()
-			result.System = scopeToLimit(&stat)
-			return nil
-		})
-		return result, err
-
-	case scope == config.ResourceMgrTransientScope:
-		err = mgr.ViewTransient(func(s network.ResourceScope) error {
-			stat := s.Stat()
-			result.Transient = scopeToLimit(&stat)
-			return nil
-		})
-		return result, err
-
-	case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix):
-		svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix)
-		err = mgr.ViewService(svc, func(s network.ServiceScope) error {
-			stat := s.Stat()
-			result.Services = map[string]rcmgr.BaseLimit{
-				svc: *scopeToLimit(&stat),
-			}
-			return nil
-		})
-		return result, err
-
-	case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix):
-		proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix)
-		err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error {
-			stat := s.Stat()
-			result.Protocols = map[string]rcmgr.BaseLimit{
-				proto: *scopeToLimit(&stat),
-			}
-			return nil
-		})
-		return result, err
-
-	case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix):
-		p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix)
-		pid, err := peer.Decode(p)
-		if err != nil {
-			return result, fmt.Errorf("invalid peer ID: %q: %w", p, err)
+	}
+	for _, v := range cfg.ProtocolPeer {
+		if v != emptyResourceConfig {
+			return false
 		}
-		err = mgr.ViewPeer(pid, func(s network.PeerScope) error {
-			stat := s.Stat()
-			result.Peers = map[string]rcmgr.BaseLimit{
-				p: *scopeToLimit(&stat),
-			}
-			return nil
-		})
-		return result, err
-
-	default:
-		return result, fmt.Errorf("invalid scope %q", scope)
 	}
-}
-
-var scopes = []string{
-	config.ResourceMgrSystemScope,
-	config.ResourceMgrTransientScope,
-	config.ResourceMgrServiceScopePrefix,
-	config.ResourceMgrProtocolScopePrefix,
-	config.ResourceMgrPeerScopePrefix,
-}
-
-func scopeToLimit(s *network.ScopeStat) *rcmgr.BaseLimit {
-	return &rcmgr.BaseLimit{
-		Streams:         s.NumStreamsInbound + s.NumStreamsOutbound,
-		StreamsInbound:  s.NumStreamsInbound,
-		StreamsOutbound: s.NumStreamsOutbound,
-		Conns:           s.NumConnsInbound + s.NumConnsOutbound,
-		ConnsInbound:    s.NumConnsInbound,
-		ConnsOutbound:   s.NumConnsOutbound,
-		FD:              s.NumFD,
-		Memory:          s.Memory,
+	for _, v := range cfg.Peer {
+		if v != emptyResourceConfig {
+			return false
+		}
 	}
+	return true
 }
 
-// compareLimits compares stat and limit.
-// If any of the stats value are equals or above the specified percentage,
-// stat object is returned.
-func compareLimits(stat, limit *rcmgr.BaseLimit, percentage int) *rcmgr.BaseLimit {
-	if stat == nil || limit == nil {
-		return nil
-	}
-	if abovePercentage(int(stat.Memory), int(limit.Memory), percentage) {
-		return stat
-	}
-	if abovePercentage(stat.ConnsInbound, limit.ConnsInbound, percentage) {
-		return stat
-	}
-	if abovePercentage(stat.ConnsOutbound, limit.ConnsOutbound, percentage) {
-		return stat
-	}
-	if abovePercentage(stat.Conns, limit.Conns, percentage) {
-		return stat
-	}
-	if abovePercentage(stat.FD, limit.FD, percentage) {
-		return stat
-	}
-	if abovePercentage(stat.StreamsInbound, limit.StreamsInbound, percentage) {
-		return stat
-	}
-	if abovePercentage(stat.StreamsOutbound, limit.StreamsOutbound, percentage) {
-		return stat
-	}
-	if abovePercentage(stat.Streams, limit.Streams, percentage) {
-		return stat
+// LimitConfig returns the union of the Computed Default Limits and the User Supplied Override Limits.
+func LimitConfig(cfg config.SwarmConfig, userResourceOverrides rcmgr.PartialLimitConfig) (limitConfig rcmgr.ConcreteLimitConfig, logMessageForStartup string, err error) {
+	limitConfig, msg, err := createDefaultLimitConfig(cfg)
+	if err != nil {
+		return rcmgr.ConcreteLimitConfig{}, msg, err
 	}
 
-	return nil
-}
+	// The logic for defaults and overriding with specified userResourceOverrides
+	// is documented in docs/libp2p-resource-management.md.
+	// Any changes here should be reflected there.
 
-func abovePercentage(v1, v2, percentage int) bool {
-	if percentage == 0 {
-		return true
-	}
+	// This effectively overrides the computed default LimitConfig with any non-"useDefault" values from the userResourceOverrides file.
+	// Because of how how Build works, any rcmgr.Default value in userResourceOverrides
+	// will be overriden with a computed default value.
+	limitConfig = userResourceOverrides.Build(limitConfig)
 
-	if v2 == 0 {
-		return false
-	}
+	return limitConfig, msg, nil
+}
 
-	return int((float64(v1)/float64(v2))*100) >= percentage
+type ResourceLimitsAndUsage struct {
+	// This is duplicated from rcmgr.ResourceResourceLimits but adding *Usage fields.
+	Memory               rcmgr.LimitVal64
+	MemoryUsage          int64
+	FD                   rcmgr.LimitVal
+	FDUsage              int
+	Conns                rcmgr.LimitVal
+	ConnsUsage           int
+	ConnsInbound         rcmgr.LimitVal
+	ConnsInboundUsage    int
+	ConnsOutbound        rcmgr.LimitVal
+	ConnsOutboundUsage   int
+	Streams              rcmgr.LimitVal
+	StreamsUsage         int
+	StreamsInbound       rcmgr.LimitVal
+	StreamsInboundUsage  int
+	StreamsOutbound      rcmgr.LimitVal
+	StreamsOutboundUsage int
 }
 
-func NetLimitAll(mgr network.ResourceManager) (*NetStatOut, error) {
-	var result = &NetStatOut{}
-	lister, ok := mgr.(rcmgr.ResourceManagerState)
-	if !ok { // NullResourceManager
-		return result, ErrNoResourceMgr
+func (u ResourceLimitsAndUsage) ToResourceLimits() rcmgr.ResourceLimits {
+	return rcmgr.ResourceLimits{
+		Memory:          u.Memory,
+		FD:              u.FD,
+		Conns:           u.Conns,
+		ConnsInbound:    u.ConnsInbound,
+		ConnsOutbound:   u.ConnsOutbound,
+		Streams:         u.Streams,
+		StreamsInbound:  u.StreamsInbound,
+		StreamsOutbound: u.StreamsOutbound,
 	}
+}
 
-	for _, s := range scopes {
-		switch s {
-		case config.ResourceMgrSystemScope:
-			s, err := NetLimit(mgr, config.ResourceMgrSystemScope)
-			if err != nil {
-				return nil, err
-			}
-			result.System = &s
-		case config.ResourceMgrTransientScope:
-			s, err := NetLimit(mgr, config.ResourceMgrSystemScope)
-			if err != nil {
-				return nil, err
-			}
-			result.Transient = &s
-		case config.ResourceMgrServiceScopePrefix:
-			result.Services = make(map[string]rcmgr.BaseLimit)
-			for _, serv := range lister.ListServices() {
-				s, err := NetLimit(mgr, config.ResourceMgrServiceScopePrefix+serv)
-				if err != nil {
-					return nil, err
-				}
-				result.Services[serv] = s
-			}
-		case config.ResourceMgrProtocolScopePrefix:
-			result.Protocols = make(map[string]rcmgr.BaseLimit)
-			for _, prot := range lister.ListProtocols() {
-				ps := string(prot)
-				s, err := NetLimit(mgr, config.ResourceMgrProtocolScopePrefix+ps)
-				if err != nil {
-					return nil, err
-				}
-				result.Protocols[ps] = s
-			}
-		case config.ResourceMgrPeerScopePrefix:
-			result.Peers = make(map[string]rcmgr.BaseLimit)
-			for _, peer := range lister.ListPeers() {
-				ps := peer.Pretty()
-				s, err := NetLimit(mgr, config.ResourceMgrPeerScopePrefix+ps)
-				if err != nil {
-					return nil, err
-				}
-				result.Peers[ps] = s
-			}
-		}
-	}
+type LimitsConfigAndUsage struct {
+	// This is duplicated from rcmgr.ResourceManagerStat but using ResourceLimitsAndUsage
+	// instead of network.ScopeStat.
+	System    ResourceLimitsAndUsage                 `json:",omitempty"`
+	Transient ResourceLimitsAndUsage                 `json:",omitempty"`
+	Services  map[string]ResourceLimitsAndUsage      `json:",omitempty"`
+	Protocols map[protocol.ID]ResourceLimitsAndUsage `json:",omitempty"`
+	Peers     map[peer.ID]ResourceLimitsAndUsage     `json:",omitempty"`
+}
 
-	return result, nil
+func (u LimitsConfigAndUsage) MarshalJSON() ([]byte, error) {
+	// we want to marshal the encoded peer id
+	encodedPeerMap := make(map[string]ResourceLimitsAndUsage, len(u.Peers))
+	for p, v := range u.Peers {
+		encodedPeerMap[p.String()] = v
+	}
+
+	type Alias LimitsConfigAndUsage
+	return json.Marshal(&struct {
+		*Alias
+		Peers map[string]ResourceLimitsAndUsage `json:",omitempty"`
+	}{
+		Alias: (*Alias)(&u),
+		Peers: encodedPeerMap,
+	})
 }
 
-func NetLimit(mgr network.ResourceManager, scope string) (rcmgr.BaseLimit, error) {
-	var result rcmgr.BaseLimit
-	getLimit := func(s network.ResourceScope) error {
-		limiter, ok := s.(rcmgr.ResourceScopeLimiter)
-		if !ok { // NullResourceManager
-			return ErrNoResourceMgr
-		}
-		limit := limiter.Limit()
-		switch l := limit.(type) {
-		case *rcmgr.BaseLimit:
-			result.Memory = l.Memory
-			result.Streams = l.Streams
-			result.StreamsInbound = l.StreamsInbound
-			result.StreamsOutbound = l.StreamsOutbound
-			result.Conns = l.Conns
-			result.ConnsInbound = l.ConnsInbound
-			result.ConnsOutbound = l.ConnsOutbound
-			result.FD = l.FD
-		default:
-			return fmt.Errorf("unknown limit type %T", limit)
-		}
+func (u LimitsConfigAndUsage) ToPartialLimitConfig() (result rcmgr.PartialLimitConfig) {
+	result.System = u.System.ToResourceLimits()
+	result.Transient = u.Transient.ToResourceLimits()
 
-		return nil
+	result.Service = make(map[string]rcmgr.ResourceLimits, len(u.Services))
+	for s, l := range u.Services {
+		result.Service[s] = l.ToResourceLimits()
 	}
-
-	switch {
-	case scope == config.ResourceMgrSystemScope:
-		return result, mgr.ViewSystem(func(s network.ResourceScope) error { return getLimit(s) })
-	case scope == config.ResourceMgrTransientScope:
-		return result, mgr.ViewTransient(func(s network.ResourceScope) error { return getLimit(s) })
-	case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix):
-		svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix)
-		return result, mgr.ViewService(svc, func(s network.ServiceScope) error { return getLimit(s) })
-	case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix):
-		proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix)
-		return result, mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { return getLimit(s) })
-	case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix):
-		p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix)
-		pid, err := peer.Decode(p)
-		if err != nil {
-			return result, fmt.Errorf("invalid peer ID: %q: %w", p, err)
-		}
-		return result, mgr.ViewPeer(pid, func(s network.PeerScope) error { return getLimit(s) })
-	default:
-		return result, fmt.Errorf("invalid scope %q", scope)
+	result.Protocol = make(map[protocol.ID]rcmgr.ResourceLimits, len(u.Protocols))
+	for p, l := range u.Protocols {
+		result.Protocol[p] = l.ToResourceLimits()
+	}
+	result.Peer = make(map[peer.ID]rcmgr.ResourceLimits, len(u.Peers))
+	for p, l := range u.Peers {
+		result.Peer[p] = l.ToResourceLimits()
 	}
-}
 
-// NetSetLimit sets new ResourceManager limits for the given scope. The limits take effect immediately, and are also persisted to the repo config.
-func NetSetLimit(mgr network.ResourceManager, repo repo.Repo, scope string, limit rcmgr.BaseLimit) error {
-	setLimit := func(s network.ResourceScope) error {
-		limiter, ok := s.(rcmgr.ResourceScopeLimiter)
-		if !ok { // NullResourceManager
-			return ErrNoResourceMgr
-		}
+	return
+}
 
-		limiter.SetLimit(&limit)
-		return nil
-	}
+func MergeLimitsAndStatsIntoLimitsConfigAndUsage(l rcmgr.ConcreteLimitConfig, stats rcmgr.ResourceManagerStat) LimitsConfigAndUsage {
+	limits := l.ToPartialLimitConfig()
 
-	cfg, err := repo.Config()
-	if err != nil {
-		return fmt.Errorf("reading config to set limit: %w", err)
+	return LimitsConfigAndUsage{
+		System:    mergeResourceLimitsAndScopeStatToResourceLimitsAndUsage(limits.System, stats.System),
+		Transient: mergeResourceLimitsAndScopeStatToResourceLimitsAndUsage(limits.Transient, stats.Transient),
+		Services:  mergeLimitsAndStatsMapIntoLimitsConfigAndUsageMap(limits.Service, stats.Services),
+		Protocols: mergeLimitsAndStatsMapIntoLimitsConfigAndUsageMap(limits.Protocol, stats.Protocols),
+		Peers:     mergeLimitsAndStatsMapIntoLimitsConfigAndUsageMap(limits.Peer, stats.Peers),
 	}
+}
 
-	if cfg.Swarm.ResourceMgr.Limits == nil {
-		cfg.Swarm.ResourceMgr.Limits = &rcmgr.LimitConfig{}
-	}
-	configLimits := cfg.Swarm.ResourceMgr.Limits
-
-	var setConfigFunc func()
-	switch {
-	case scope == config.ResourceMgrSystemScope:
-		err = mgr.ViewSystem(func(s network.ResourceScope) error { return setLimit(s) })
-		setConfigFunc = func() { configLimits.System = limit }
-	case scope == config.ResourceMgrTransientScope:
-		err = mgr.ViewTransient(func(s network.ResourceScope) error { return setLimit(s) })
-		setConfigFunc = func() { configLimits.Transient = limit }
-	case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix):
-		svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix)
-		err = mgr.ViewService(svc, func(s network.ServiceScope) error { return setLimit(s) })
-		setConfigFunc = func() {
-			if configLimits.Service == nil {
-				configLimits.Service = map[string]rcmgr.BaseLimit{}
-			}
-			configLimits.Service[svc] = limit
-		}
-	case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix):
-		proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix)
-		err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { return setLimit(s) })
-		setConfigFunc = func() {
-			if configLimits.Protocol == nil {
-				configLimits.Protocol = map[protocol.ID]rcmgr.BaseLimit{}
-			}
-			configLimits.Protocol[protocol.ID(proto)] = limit
-		}
-	case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix):
-		p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix)
-		var pid peer.ID
-		pid, err = peer.Decode(p)
-		if err != nil {
-			return fmt.Errorf("invalid peer ID: %q: %w", p, err)
-		}
-		err = mgr.ViewPeer(pid, func(s network.PeerScope) error { return setLimit(s) })
-		setConfigFunc = func() {
-			if configLimits.Peer == nil {
-				configLimits.Peer = map[peer.ID]rcmgr.BaseLimit{}
+func mergeLimitsAndStatsMapIntoLimitsConfigAndUsageMap[K comparable](limits map[K]rcmgr.ResourceLimits, stats map[K]network.ScopeStat) map[K]ResourceLimitsAndUsage {
+	r := make(map[K]ResourceLimitsAndUsage, maxInt(len(limits), len(stats)))
+	for p, s := range stats {
+		var l rcmgr.ResourceLimits
+		if limits != nil {
+			if rl, ok := limits[p]; ok {
+				l = rl
 			}
-			configLimits.Peer[pid] = limit
 		}
-	default:
-		return fmt.Errorf("invalid scope %q", scope)
+		r[p] = mergeResourceLimitsAndScopeStatToResourceLimitsAndUsage(l, s)
 	}
+	for p, s := range limits {
+		if _, ok := stats[p]; ok {
+			continue // we already processed this element in the loop above
+		}
 
-	if err != nil {
-		return fmt.Errorf("setting new limits on resource manager: %w", err)
+		r[p] = mergeResourceLimitsAndScopeStatToResourceLimitsAndUsage(s, network.ScopeStat{})
 	}
+	return r
+}
 
-	if cfg.Swarm.ResourceMgr.Limits == nil {
-		cfg.Swarm.ResourceMgr.Limits = &rcmgr.LimitConfig{}
+func maxInt(x, y int) int {
+	if x > y {
+		return x
 	}
-	setConfigFunc()
+	return y
+}
 
-	if err := repo.SetConfig(cfg); err != nil {
-		return fmt.Errorf("writing new limits to repo config: %w", err)
+func mergeResourceLimitsAndScopeStatToResourceLimitsAndUsage(rl rcmgr.ResourceLimits, ss network.ScopeStat) ResourceLimitsAndUsage {
+	return ResourceLimitsAndUsage{
+		Memory:               rl.Memory,
+		MemoryUsage:          ss.Memory,
+		FD:                   rl.FD,
+		FDUsage:              ss.NumFD,
+		Conns:                rl.Conns,
+		ConnsUsage:           ss.NumConnsOutbound + ss.NumConnsInbound,
+		ConnsOutbound:        rl.ConnsOutbound,
+		ConnsOutboundUsage:   ss.NumConnsOutbound,
+		ConnsInbound:         rl.ConnsInbound,
+		ConnsInboundUsage:    ss.NumConnsInbound,
+		Streams:              rl.Streams,
+		StreamsUsage:         ss.NumStreamsOutbound + ss.NumConnsInbound,
+		StreamsOutbound:      rl.StreamsOutbound,
+		StreamsOutboundUsage: ss.NumConnsOutbound,
+		StreamsInbound:       rl.StreamsInbound,
+		StreamsInboundUsage:  ss.NumConnsInbound,
 	}
+}
 
-	return nil
+type ResourceInfos []ResourceInfo
+
+type ResourceInfo struct {
+	ScopeName    string
+	LimitName    string
+	LimitValue   rcmgr.LimitVal64
+	CurrentUsage int64
 }
 
-// NetResetLimit resets ResourceManager limits to defaults. The limits take effect immediately, and are also persisted to the repo config.
-func NetResetLimit(mgr network.ResourceManager, repo repo.Repo, scope string) (rcmgr.BaseLimit, error) {
-	var result rcmgr.BaseLimit
+// LimitConfigsToInfo gets limits and stats and generates a list of scopes and limits to be printed.
+func LimitConfigsToInfo(stats LimitsConfigAndUsage) ResourceInfos {
+	result := ResourceInfos{}
 
-	setLimit := func(s network.ResourceScope, l rcmgr.Limit) error {
-		limiter, ok := s.(rcmgr.ResourceScopeLimiter)
-		if !ok {
-			return ErrNoResourceMgr
-		}
+	result = append(result, resourceLimitsAndUsageToResourceInfo(config.ResourceMgrSystemScope, stats.System)...)
+	result = append(result, resourceLimitsAndUsageToResourceInfo(config.ResourceMgrTransientScope, stats.Transient)...)
 
-		limiter.SetLimit(l)
-		return nil
+	for i, s := range stats.Services {
+		result = append(result, resourceLimitsAndUsageToResourceInfo(
+			config.ResourceMgrServiceScopePrefix+i,
+			s,
+		)...)
 	}
 
-	cfg, err := repo.Config()
-	if err != nil {
-		return result, fmt.Errorf("reading config to reset limit: %w", err)
+	for i, p := range stats.Protocols {
+		result = append(result, resourceLimitsAndUsageToResourceInfo(
+			config.ResourceMgrProtocolScopePrefix+string(i),
+			p,
+		)...)
 	}
 
-	defaults, err := createDefaultLimitConfig(cfg.Swarm)
-	if err != nil {
-		return result, fmt.Errorf("creating default limit config: %w", err)
+	for i, p := range stats.Peers {
+		result = append(result, resourceLimitsAndUsageToResourceInfo(
+			config.ResourceMgrPeerScopePrefix+i.Pretty(),
+			p,
+		)...)
 	}
 
-	if cfg.Swarm.ResourceMgr.Limits == nil {
-		cfg.Swarm.ResourceMgr.Limits = &rcmgr.LimitConfig{}
-	}
-	configLimits := cfg.Swarm.ResourceMgr.Limits
-
-	var setConfigFunc func() rcmgr.BaseLimit
-	switch {
-	case scope == config.ResourceMgrSystemScope:
-		err = mgr.ViewSystem(func(s network.ResourceScope) error { return setLimit(s, &defaults.System) })
-		setConfigFunc = func() rcmgr.BaseLimit {
-			configLimits.System = defaults.System
-			return defaults.System
-		}
-	case scope == config.ResourceMgrTransientScope:
-		err = mgr.ViewTransient(func(s network.ResourceScope) error { return setLimit(s, &defaults.Transient) })
-		setConfigFunc = func() rcmgr.BaseLimit {
-			configLimits.Transient = defaults.Transient
-			return defaults.Transient
-		}
-	case strings.HasPrefix(scope, config.ResourceMgrServiceScopePrefix):
-		svc := strings.TrimPrefix(scope, config.ResourceMgrServiceScopePrefix)
+	return result
+}
 
-		err = mgr.ViewService(svc, func(s network.ServiceScope) error { return setLimit(s, &defaults.ServiceDefault) })
-		setConfigFunc = func() rcmgr.BaseLimit {
-			if configLimits.Service == nil {
-				configLimits.Service = map[string]rcmgr.BaseLimit{}
-			}
-			configLimits.Service[svc] = defaults.ServiceDefault
-			return defaults.ServiceDefault
-		}
-	case strings.HasPrefix(scope, config.ResourceMgrProtocolScopePrefix):
-		proto := strings.TrimPrefix(scope, config.ResourceMgrProtocolScopePrefix)
+const (
+	limitNameMemory          = "Memory"
+	limitNameFD              = "FD"
+	limitNameConns           = "Conns"
+	limitNameConnsInbound    = "ConnsInbound"
+	limitNameConnsOutbound   = "ConnsOutbound"
+	limitNameStreams         = "Streams"
+	limitNameStreamsInbound  = "StreamsInbound"
+	limitNameStreamsOutbound = "StreamsOutbound"
+)
 
-		err = mgr.ViewProtocol(protocol.ID(proto), func(s network.ProtocolScope) error { return setLimit(s, &defaults.ProtocolDefault) })
-		setConfigFunc = func() rcmgr.BaseLimit {
-			if configLimits.Protocol == nil {
-				configLimits.Protocol = map[protocol.ID]rcmgr.BaseLimit{}
-			}
-			configLimits.Protocol[protocol.ID(proto)] = defaults.ProtocolDefault
+var limits = []string{
+	limitNameMemory,
+	limitNameFD,
+	limitNameConns,
+	limitNameConnsInbound,
+	limitNameConnsOutbound,
+	limitNameStreams,
+	limitNameStreamsInbound,
+	limitNameStreamsOutbound,
+}
 
-			return defaults.ProtocolDefault
+func resourceLimitsAndUsageToResourceInfo(scopeName string, stats ResourceLimitsAndUsage) ResourceInfos {
+	result := ResourceInfos{}
+	for _, l := range limits {
+		ri := ResourceInfo{
+			ScopeName: scopeName,
 		}
-	case strings.HasPrefix(scope, config.ResourceMgrPeerScopePrefix):
-		p := strings.TrimPrefix(scope, config.ResourceMgrPeerScopePrefix)
-
-		var pid peer.ID
-		pid, err = peer.Decode(p)
-		if err != nil {
-			return result, fmt.Errorf("invalid peer ID: %q: %w", p, err)
+		switch l {
+		case limitNameMemory:
+			ri.LimitName = limitNameMemory
+			ri.LimitValue = stats.Memory
+			ri.CurrentUsage = stats.MemoryUsage
+		case limitNameFD:
+			ri.LimitName = limitNameFD
+			ri.LimitValue = rcmgr.LimitVal64(stats.FD)
+			ri.CurrentUsage = int64(stats.FDUsage)
+		case limitNameConns:
+			ri.LimitName = limitNameConns
+			ri.LimitValue = rcmgr.LimitVal64(stats.Conns)
+			ri.CurrentUsage = int64(stats.ConnsUsage)
+		case limitNameConnsInbound:
+			ri.LimitName = limitNameConnsInbound
+			ri.LimitValue = rcmgr.LimitVal64(stats.ConnsInbound)
+			ri.CurrentUsage = int64(stats.ConnsInboundUsage)
+		case limitNameConnsOutbound:
+			ri.LimitName = limitNameConnsOutbound
+			ri.LimitValue = rcmgr.LimitVal64(stats.ConnsOutbound)
+			ri.CurrentUsage = int64(stats.ConnsOutboundUsage)
+		case limitNameStreams:
+			ri.LimitName = limitNameStreams
+			ri.LimitValue = rcmgr.LimitVal64(stats.Streams)
+			ri.CurrentUsage = int64(stats.StreamsUsage)
+		case limitNameStreamsInbound:
+			ri.LimitName = limitNameStreamsInbound
+			ri.LimitValue = rcmgr.LimitVal64(stats.StreamsInbound)
+			ri.CurrentUsage = int64(stats.StreamsInboundUsage)
+		case limitNameStreamsOutbound:
+			ri.LimitName = limitNameStreamsOutbound
+			ri.LimitValue = rcmgr.LimitVal64(stats.StreamsOutbound)
+			ri.CurrentUsage = int64(stats.StreamsOutboundUsage)
 		}
 
-		err = mgr.ViewPeer(pid, func(s network.PeerScope) error { return setLimit(s, &defaults.PeerDefault) })
-		setConfigFunc = func() rcmgr.BaseLimit {
-			if configLimits.Peer == nil {
-				configLimits.Peer = map[peer.ID]rcmgr.BaseLimit{}
-			}
-			configLimits.Peer[pid] = defaults.PeerDefault
-
-			return defaults.PeerDefault
+		if ri.LimitValue == rcmgr.Unlimited64 || ri.LimitValue == rcmgr.DefaultLimit64 {
+			// ignore unlimited and unset limits to remove noise from output.
+			continue
 		}
-	default:
-		return result, fmt.Errorf("invalid scope %q", scope)
-	}
 
-	if err != nil {
-		return result, fmt.Errorf("resetting new limits on resource manager: %w", err)
+		result = append(result, ri)
 	}
 
-	result = setConfigFunc()
+	return result
+}
 
-	if err := repo.SetConfig(cfg); err != nil {
-		return result, fmt.Errorf("writing new limits to repo config: %w", err)
+func ensureConnMgrMakeSenseVsResourceMgr(concreteLimits rcmgr.ConcreteLimitConfig, cfg config.SwarmConfig) error {
+	if cfg.ConnMgr.Type.WithDefault(config.DefaultConnMgrType) == "none" || len(cfg.ResourceMgr.Allowlist) != 0 {
+		// no connmgr OR
+		// If an allowlist is set, a user may be enacting some form of DoS defense.
+		// We don't want want to modify the System.ConnsInbound in that case for example
+		// as it may make sense for it to be (and stay) as "blockAll"
+		// so that only connections within the allowlist of multiaddrs get established.
+		return nil
 	}
 
-	return result, nil
-}
+	rcm := concreteLimits.ToPartialLimitConfig()
 
-func ensureConnMgrMakeSenseVsResourceMgr(rcm rcmgr.LimitConfig, cmgr config.ConnMgr) error {
-	if cmgr.Type.WithDefault(config.DefaultConnMgrType) == "none" {
-		return nil // none connmgr, no checks to do
-	}
-	highWater := cmgr.HighWater.WithDefault(config.DefaultConnMgrHighWater)
-	if rcm.System.ConnsInbound <= rcm.System.Conns {
-		if int64(rcm.System.ConnsInbound) <= highWater {
-			// nolint
-			return fmt.Errorf(`
-Unable to initialize libp2p due to conflicting limit configuration:
-ResourceMgr.Limits.System.ConnsInbound (%d) must be bigger than ConnMgr.HighWater (%d)
-`, rcm.System.ConnsInbound, highWater)
-		}
-	} else if int64(rcm.System.Conns) <= highWater {
+	highWater := cfg.ConnMgr.HighWater.WithDefault(config.DefaultConnMgrHighWater)
+	if (rcm.System.Conns > rcmgr.DefaultLimit || rcm.System.Conns == rcmgr.BlockAllLimit) && int64(rcm.System.Conns) <= highWater {
 		// nolint
 		return fmt.Errorf(`
-Unable to initialize libp2p due to conflicting limit configuration:
-ResourceMgr.Limits.System.Conns (%d) must be bigger than ConnMgr.HighWater (%d)
+Unable to initialize libp2p due to conflicting resource manager limit configuration.
+resource manager System.Conns (%d) must be bigger than ConnMgr.HighWater (%d)
+See: https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#how-does-the-resource-manager-resourcemgr-relate-to-the-connection-manager-connmgr
 `, rcm.System.Conns, highWater)
 	}
-	if rcm.System.StreamsInbound <= rcm.System.Streams {
-		if int64(rcm.System.StreamsInbound) <= highWater {
-			// nolint
-			return fmt.Errorf(`
-Unable to initialize libp2p due to conflicting limit configuration:
-ResourceMgr.Limits.System.StreamsInbound (%d) must be bigger than ConnMgr.HighWater (%d)
-`, rcm.System.StreamsInbound, highWater)
-		}
-	} else if int64(rcm.System.Streams) <= highWater {
+	if (rcm.System.ConnsInbound > rcmgr.DefaultLimit || rcm.System.ConnsInbound == rcmgr.BlockAllLimit) && int64(rcm.System.ConnsInbound) <= highWater {
 		// nolint
 		return fmt.Errorf(`
-Unable to initialize libp2p due to conflicting limit configuration:
-ResourceMgr.Limits.System.Streams (%d) must be bigger than ConnMgr.HighWater (%d)
+Unable to initialize libp2p due to conflicting resource manager limit configuration.
+resource manager System.ConnsInbound (%d) must be bigger than ConnMgr.HighWater (%d)
+See: https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#how-does-the-resource-manager-resourcemgr-relate-to-the-connection-manager-connmgr
+`, rcm.System.ConnsInbound, highWater)
+	}
+	if rcm.System.Streams > rcmgr.DefaultLimit || rcm.System.Streams == rcmgr.BlockAllLimit && int64(rcm.System.Streams) <= highWater {
+		// nolint
+		return fmt.Errorf(`
+Unable to initialize libp2p due to conflicting resource manager limit configuration.
+resource manager System.Streams (%d) must be bigger than ConnMgr.HighWater (%d)
+See: https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#how-does-the-resource-manager-resourcemgr-relate-to-the-connection-manager-connmgr
 `, rcm.System.Streams, highWater)
+	}
+	if (rcm.System.StreamsInbound > rcmgr.DefaultLimit || rcm.System.StreamsInbound == rcmgr.BlockAllLimit) && int64(rcm.System.StreamsInbound) <= highWater {
+		// nolint
+		return fmt.Errorf(`
+Unable to initialize libp2p due to conflicting resource manager limit configuration.
+resource manager System.StreamsInbound (%d) must be bigger than ConnMgr.HighWater (%d)
+See: https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#how-does-the-resource-manager-resourcemgr-relate-to-the-connection-manager-connmgr
+`, rcm.System.StreamsInbound, highWater)
 	}
 	return nil
 }
diff --git a/core/node/libp2p/rcmgr_defaults.go b/core/node/libp2p/rcmgr_defaults.go
index 9a3825108f392ca6471c6780ed19c50a2deff528..7a0e5a2823d2ce05e1e35a10e0ae7c228b30daa6 100644
--- a/core/node/libp2p/rcmgr_defaults.go
+++ b/core/node/libp2p/rcmgr_defaults.go
@@ -4,70 +4,31 @@ import (
 	"fmt"
 
 	"github.com/dustin/go-humanize"
+	"github.com/ipfs/kubo/config"
+	"github.com/ipfs/kubo/core/node/libp2p/fd"
 	"github.com/libp2p/go-libp2p"
 	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 	"github.com/pbnjay/memory"
-
-	"github.com/ipfs/kubo/config"
-	"github.com/ipfs/kubo/core/node/libp2p/fd"
 )
 
-// We are doing some magic when parsing config files (we are using a map[string]interface{} to compare config files).
-// When you don't have a type the JSON Parse function cast numbers to float64 by default,
-// losing precision when writing the final number. So if we use math.MaxInt as our infinite number,
-// after writing the config file we will have 9223372036854776000 instead of 9223372036854775807,
-// making the parsing process fail. Setting 1e9 (1000000000) as "no limit" value. It also avoids to overflow on 32 bit architectures.
-const bigEnough = 1e9
-
-var infiniteBaseLimit = rcmgr.BaseLimit{
-	Streams:         bigEnough,
-	StreamsInbound:  bigEnough,
-	StreamsOutbound: bigEnough,
-	Conns:           bigEnough,
-	ConnsInbound:    bigEnough,
-	ConnsOutbound:   bigEnough,
-	FD:              bigEnough,
-	Memory:          bigEnough,
-}
-
-var noLimitIncrease = rcmgr.BaseLimitIncrease{
-	ConnsInbound:    0,
-	ConnsOutbound:   0,
-	Conns:           0,
-	StreamsInbound:  0,
-	StreamsOutbound: 0,
-	Streams:         0,
-	Memory:          0,
-	FDFraction:      0,
-}
+var infiniteResourceLimits = rcmgr.InfiniteLimits.ToPartialLimitConfig().System
 
 // This file defines implicit limit defaults used when Swarm.ResourceMgr.Enabled
 
 // createDefaultLimitConfig creates LimitConfig to pass to libp2p's resource manager.
 // The defaults follow the documentation in docs/libp2p-resource-management.md.
 // Any changes in the logic here should be reflected there.
-func createDefaultLimitConfig(cfg config.SwarmConfig) (rcmgr.LimitConfig, error) {
+func createDefaultLimitConfig(cfg config.SwarmConfig) (limitConfig rcmgr.ConcreteLimitConfig, logMessageForStartup string, err error) {
 	maxMemoryDefaultString := humanize.Bytes(uint64(memory.TotalMemory()) / 2)
 	maxMemoryString := cfg.ResourceMgr.MaxMemory.WithDefault(maxMemoryDefaultString)
 	maxMemory, err := humanize.ParseBytes(maxMemoryString)
 	if err != nil {
-		return rcmgr.LimitConfig{}, err
+		return rcmgr.ConcreteLimitConfig{}, "", err
 	}
 
 	maxMemoryMB := maxMemory / (1024 * 1024)
 	maxFD := int(cfg.ResourceMgr.MaxFileDescriptors.WithDefault(int64(fd.GetNumFDs()) / 2))
 
-	// We want to see this message on startup, that's why we are using fmt instead of log.
-	fmt.Printf(`
-Computing default go-libp2p Resource Manager limits based on:
-    - 'Swarm.ResourceMgr.MaxMemory': %q
-    - 'Swarm.ResourceMgr.MaxFileDescriptors': %d
-
-Applying any user-supplied overrides on top.
-Run 'ipfs swarm limit all' to see the resulting limits.
-
-`, maxMemoryString, maxFD)
-
 	// At least as of 2023-01-25, it's possible to open a connection that
 	// doesn't ask for any memory usage with the libp2p Resource Manager/Accountant
 	// (see https://github.com/libp2p/go-libp2p/issues/2010#issuecomment-1404280736).
@@ -79,108 +40,86 @@ Run 'ipfs swarm limit all' to see the resulting limits.
 	// (see https://github.com/libp2p/go-libp2p/blob/master/p2p/host/resource-manager/limit_defaults.go#L357 ).
 	systemConnsInbound := int(1 * maxMemoryMB)
 
-	scalingLimitConfig := rcmgr.ScalingLimitConfig{
-		SystemBaseLimit: rcmgr.BaseLimit{
-			Memory: int64(maxMemory),
-			FD:     maxFD,
+	partialLimits := rcmgr.PartialLimitConfig{
+		System: rcmgr.ResourceLimits{
+			Memory: rcmgr.LimitVal64(maxMemory),
+			FD:     rcmgr.LimitVal(maxFD),
 
-			// By default, we just limit connections on the inbound side.
-			Conns:         bigEnough,
-			ConnsInbound:  systemConnsInbound,
-			ConnsOutbound: bigEnough,
+			Conns:         rcmgr.Unlimited,
+			ConnsInbound:  rcmgr.LimitVal(systemConnsInbound),
+			ConnsOutbound: rcmgr.Unlimited,
 
-			Streams:         bigEnough,
-			StreamsInbound:  bigEnough,
-			StreamsOutbound: bigEnough,
+			Streams:         rcmgr.Unlimited,
+			StreamsOutbound: rcmgr.Unlimited,
+			StreamsInbound:  rcmgr.Unlimited,
 		},
-		SystemLimitIncrease: noLimitIncrease,
 
-		// Transient connections won't cause any memory to accounted for by the resource manager.
+		// Transient connections won't cause any memory to be accounted for by the resource manager/accountant.
 		// Only established connections do.
 		// As a result, we can't rely on System.Memory to protect us from a bunch of transient connection being opened.
 		// We limit the same values as the System scope, but only allow the Transient scope to take 25% of what is allowed for the System scope.
-		TransientBaseLimit: rcmgr.BaseLimit{
-			Memory: int64(maxMemory / 4),
-			FD:     maxFD / 4,
+		Transient: rcmgr.ResourceLimits{
+			Memory: rcmgr.LimitVal64(maxMemory / 4),
+			FD:     rcmgr.LimitVal(maxFD / 4),
 
-			Conns:         bigEnough,
-			ConnsInbound:  systemConnsInbound / 4,
-			ConnsOutbound: bigEnough,
+			Conns:         rcmgr.Unlimited,
+			ConnsInbound:  rcmgr.LimitVal(systemConnsInbound / 4),
+			ConnsOutbound: rcmgr.Unlimited,
 
-			Streams:         bigEnough,
-			StreamsInbound:  bigEnough,
-			StreamsOutbound: bigEnough,
+			Streams:         rcmgr.Unlimited,
+			StreamsInbound:  rcmgr.Unlimited,
+			StreamsOutbound: rcmgr.Unlimited,
 		},
 
-		TransientLimitIncrease: noLimitIncrease,
-
 		// Lets get out of the way of the allow list functionality.
 		// If someone specified "Swarm.ResourceMgr.Allowlist" we should let it go through.
-		AllowlistedSystemBaseLimit:     infiniteBaseLimit,
-		AllowlistedSystemLimitIncrease: noLimitIncrease,
+		AllowlistedSystem: infiniteResourceLimits,
 
-		AllowlistedTransientBaseLimit:     infiniteBaseLimit,
-		AllowlistedTransientLimitIncrease: noLimitIncrease,
+		AllowlistedTransient: infiniteResourceLimits,
 
 		// Keep it simple by not having Service, ServicePeer, Protocol, ProtocolPeer, Conn, or Stream limits.
-		ServiceBaseLimit:     infiniteBaseLimit,
-		ServiceLimitIncrease: noLimitIncrease,
+		ServiceDefault: infiniteResourceLimits,
 
-		ServicePeerBaseLimit:     infiniteBaseLimit,
-		ServicePeerLimitIncrease: noLimitIncrease,
+		ServicePeerDefault: infiniteResourceLimits,
 
-		ProtocolBaseLimit:     infiniteBaseLimit,
-		ProtocolLimitIncrease: noLimitIncrease,
+		ProtocolDefault: infiniteResourceLimits,
 
-		ProtocolPeerBaseLimit:     infiniteBaseLimit,
-		ProtocolPeerLimitIncrease: noLimitIncrease,
+		ProtocolPeerDefault: infiniteResourceLimits,
 
-		ConnBaseLimit:     infiniteBaseLimit,
-		ConnLimitIncrease: noLimitIncrease,
+		Conn: infiniteResourceLimits,
 
-		StreamBaseLimit:     infiniteBaseLimit,
-		StreamLimitIncrease: noLimitIncrease,
+		Stream: infiniteResourceLimits,
 
 		// Limit the resources consumed by a peer.
 		// This doesn't protect us against intentional DoS attacks since an attacker can easily spin up multiple peers.
 		// We specify this limit against unintentional DoS attacks (e.g., a peer has a bug and is sending too much traffic intentionally).
 		// In that case we want to keep that peer's resource consumption contained.
 		// To keep this simple, we only constrain inbound connections and streams.
-		PeerBaseLimit: rcmgr.BaseLimit{
-			Memory:          bigEnough,
-			FD:              bigEnough,
-			Conns:           bigEnough,
-			ConnsInbound:    rcmgr.DefaultLimits.PeerBaseLimit.ConnsInbound,
-			ConnsOutbound:   bigEnough,
-			Streams:         bigEnough,
-			StreamsInbound:  rcmgr.DefaultLimits.PeerBaseLimit.StreamsInbound,
-			StreamsOutbound: bigEnough,
-		},
-		// Most limits don't see an increase because they're already infinite/bigEnough.
-		// The values that should scale based on the amount of memory allocated to libp2p need to increase accordingly.
-		PeerLimitIncrease: rcmgr.BaseLimitIncrease{
-			Memory:          0,
-			FDFraction:      0,
-			Conns:           0,
-			ConnsInbound:    rcmgr.DefaultLimits.PeerLimitIncrease.ConnsInbound,
-			ConnsOutbound:   0,
-			Streams:         0,
-			StreamsInbound:  rcmgr.DefaultLimits.PeerLimitIncrease.StreamsInbound,
-			StreamsOutbound: 0,
+		PeerDefault: rcmgr.ResourceLimits{
+			Memory:          rcmgr.Unlimited64,
+			FD:              rcmgr.Unlimited,
+			Conns:           rcmgr.Unlimited,
+			ConnsInbound:    rcmgr.DefaultLimit,
+			ConnsOutbound:   rcmgr.Unlimited,
+			Streams:         rcmgr.Unlimited,
+			StreamsInbound:  rcmgr.DefaultLimit,
+			StreamsOutbound: rcmgr.Unlimited,
 		},
 	}
 
-	// Whatever limits libp2p has specifically tuned for its protocols/services we'll apply.
+	scalingLimitConfig := rcmgr.DefaultLimits
 	libp2p.SetDefaultServiceLimits(&scalingLimitConfig)
 
-	defaultLimitConfig := scalingLimitConfig.Scale(int64(maxMemory), maxFD)
+	// Anything set above in partialLimits that had a value of rcmgr.DefaultLimit will be overridden.
+	// Anything in scalingLimitConfig that wasn't defined in partialLimits above will be added (e.g., libp2p's default service limits).
+	partialLimits = partialLimits.Build(scalingLimitConfig.Scale(int64(maxMemory), maxFD)).ToPartialLimitConfig()
 
 	// Simple checks to overide autoscaling ensuring limits make sense versus the connmgr values.
 	// There are ways to break this, but this should catch most problems already.
 	// We might improve this in the future.
 	// See: https://github.com/ipfs/kubo/issues/9545
-	if cfg.ConnMgr.Type.WithDefault(config.DefaultConnMgrType) != "none" {
-		maxInboundConns := int64(defaultLimitConfig.System.ConnsInbound)
+	if partialLimits.System.ConnsInbound > rcmgr.DefaultLimit && cfg.ConnMgr.Type.WithDefault(config.DefaultConnMgrType) != "none" {
+		maxInboundConns := int64(partialLimits.System.ConnsInbound)
 		if connmgrHighWaterTimesTwo := cfg.ConnMgr.HighWater.WithDefault(config.DefaultConnMgrHighWater) * 2; maxInboundConns < connmgrHighWaterTimesTwo {
 			maxInboundConns = connmgrHighWaterTimesTwo
 		}
@@ -190,9 +129,21 @@ Run 'ipfs swarm limit all' to see the resulting limits.
 		}
 
 		// Scale System.StreamsInbound as well, but use the existing ratio of StreamsInbound to ConnsInbound
-		defaultLimitConfig.System.StreamsInbound = int(maxInboundConns * int64(defaultLimitConfig.System.StreamsInbound) / int64(defaultLimitConfig.System.ConnsInbound))
-		defaultLimitConfig.System.ConnsInbound = int(maxInboundConns)
+		if partialLimits.System.StreamsInbound > rcmgr.DefaultLimit {
+			partialLimits.System.StreamsInbound = rcmgr.LimitVal(maxInboundConns * int64(partialLimits.System.StreamsInbound) / int64(partialLimits.System.ConnsInbound))
+		}
+		partialLimits.System.ConnsInbound = rcmgr.LimitVal(maxInboundConns)
 	}
 
-	return defaultLimitConfig, nil
+	msg := fmt.Sprintf(`
+Computed default go-libp2p Resource Manager limits based on:
+    - 'Swarm.ResourceMgr.MaxMemory': %q
+    - 'Swarm.ResourceMgr.MaxFileDescriptors': %d
+
+Theses can be inspected with 'ipfs swarm resources'.
+
+`, maxMemoryString, maxFD)
+
+	// We already have a complete value thus pass in an empty ConcreteLimitConfig.
+	return partialLimits.Build(rcmgr.ConcreteLimitConfig{}), msg, nil
 }
diff --git a/core/node/libp2p/rcmgr_logging_test.go b/core/node/libp2p/rcmgr_logging_test.go
index 512168d4a52fa5bb095a11998c43d8670bb0c36c..559a3fec33fc179fa2e12b65f53adfe461ad81c9 100644
--- a/core/node/libp2p/rcmgr_logging_test.go
+++ b/core/node/libp2p/rcmgr_logging_test.go
@@ -16,11 +16,12 @@ import (
 
 func TestLoggingResourceManager(t *testing.T) {
 	clock := clock.NewMock()
-	limits := rcmgr.DefaultLimits.AutoScale()
+	orig := rcmgr.DefaultLimits.AutoScale()
+	limits := orig.ToPartialLimitConfig()
 	limits.System.Conns = 1
 	limits.System.ConnsInbound = 1
 	limits.System.ConnsOutbound = 1
-	limiter := rcmgr.NewFixedLimiter(limits)
+	limiter := rcmgr.NewFixedLimiter(limits.Build(orig))
 	rm, err := rcmgr.NewResourceManager(limiter)
 	if err != nil {
 		t.Fatal(err)
diff --git a/core/node/libp2p/rcmgr_test.go b/core/node/libp2p/rcmgr_test.go
deleted file mode 100644
index e273ff756aa28ce7c4a4b90770c376ffd45af440..0000000000000000000000000000000000000000
--- a/core/node/libp2p/rcmgr_test.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package libp2p
-
-import (
-	"testing"
-
-	"github.com/stretchr/testify/require"
-)
-
-func TestPercentage(t *testing.T) {
-	require.True(t, abovePercentage(10, 100, 10))
-	require.True(t, abovePercentage(100, 100, 99))
-}
diff --git a/core/node/libp2p/relay.go b/core/node/libp2p/relay.go
index c39b2fae8ddbc71f2ea49deffc0cbda9704c5c7b..925fe7bd345f436b4e428f2e7346397ee6753f3e 100644
--- a/core/node/libp2p/relay.go
+++ b/core/node/libp2p/relay.go
@@ -63,10 +63,7 @@ func MaybeAutoRelay(staticRelays []string, cfgPeering config.Peering, enabled bo
 					}
 					static = append(static, *addr)
 				}
-				opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(
-					autorelay.WithStaticRelays(static),
-					autorelay.WithCircuitV1Support(),
-				))
+				opts.Opts = append(opts.Opts, libp2p.EnableAutoRelayWithStaticRelays(static))
 			}
 			return
 		})
@@ -76,29 +73,33 @@ func MaybeAutoRelay(staticRelays []string, cfgPeering config.Peering, enabled bo
 	return fx.Options(
 		// Provide AutoRelay option
 		fx.Provide(func() (opts Libp2pOpts, err error) {
-			opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay(autorelay.WithPeerSource(func(ctx context.Context, numPeers int) <-chan peer.AddrInfo {
-				// TODO(9257): make this code smarter (have a state and actually try to grow the search outward) instead of a long running task just polling our K cluster.
-				r := make(chan peer.AddrInfo)
-				go func() {
-					defer close(r)
-					for ; numPeers != 0; numPeers-- {
-						select {
-						case v, ok := <-peerChan:
-							if !ok {
-								return
-							}
-							select {
-							case r <- v:
-							case <-ctx.Done():
-								return
+			opts.Opts = append(opts.Opts,
+				libp2p.EnableAutoRelayWithPeerSource(
+					func(ctx context.Context, numPeers int) <-chan peer.AddrInfo {
+						// TODO(9257): make this code smarter (have a state and actually try to grow the search outward) instead of a long running task just polling our K cluster.
+						r := make(chan peer.AddrInfo)
+						go func() {
+							defer close(r)
+							for ; numPeers != 0; numPeers-- {
+								select {
+								case v, ok := <-peerChan:
+									if !ok {
+										return
+									}
+									select {
+									case r <- v:
+									case <-ctx.Done():
+										return
+									}
+								case <-ctx.Done():
+									return
+								}
 							}
-						case <-ctx.Done():
-							return
-						}
-					}
-				}()
-				return r
-			}, 0)))
+						}()
+						return r
+					},
+					autorelay.WithMinInterval(0),
+				))
 			return
 		}),
 		autoRelayFeeder(cfgPeering, peerChan),
diff --git a/core/node/libp2p/routingopt.go b/core/node/libp2p/routingopt.go
index bfb45971cc9ec02937dea04d18d4735960d908db..d54f37acc5c8553be791104a944b88c4d07a733a 100644
--- a/core/node/libp2p/routingopt.go
+++ b/core/node/libp2p/routingopt.go
@@ -40,7 +40,7 @@ func init() {
 }
 
 // ConstructDefaultRouting returns routers used when Routing.Type is unset or set to "auto"
-func ConstructDefaultRouting(peerID string, addrs []string, privKey string) func(
+func ConstructDefaultRouting(peerID string, addrs []string, privKey string, routingOpt RoutingOption) func(
 	ctx context.Context,
 	host host.Host,
 	dstore datastore.Batching,
@@ -58,8 +58,7 @@ func ConstructDefaultRouting(peerID string, addrs []string, privKey string) func
 		// Different trade-offs can be made by setting Routing.Type = "custom" with own Routing.Routers
 		var routers []*routinghelpers.ParallelRouter
 
-		// Run the default DHT routing (same as Routing.Type = "dht")
-		dhtRouting, err := DHTOption(ctx, host, dstore, validator, bootstrapPeers...)
+		dhtRouting, err := routingOpt(ctx, host, dstore, validator, bootstrapPeers...)
 		if err != nil {
 			return nil, err
 		}
diff --git a/core/node/storage.go b/core/node/storage.go
index 2e831fae22e9264a7dea3ceea935d389790915dc..d109210587db5749cc030fcb6f31802211d67871 100644
--- a/core/node/storage.go
+++ b/core/node/storage.go
@@ -14,7 +14,8 @@ import (
 
 // RepoConfig loads configuration from the repo
 func RepoConfig(repo repo.Repo) (*config.Config, error) {
-	return repo.Config()
+	cfg, err := repo.Config()
+	return cfg, err
 }
 
 // Datastore provides the datastore
diff --git a/docs/EARLY_TESTERS.md b/docs/EARLY_TESTERS.md
index fb2fedc2a339e026ba7d2d4bb9310281a6338e5f..d0dd4a8672ef35df3921646bd6e0e5e65598a1e4 100644
--- a/docs/EARLY_TESTERS.md
+++ b/docs/EARLY_TESTERS.md
@@ -22,15 +22,16 @@ We will ask early testers to participate at two points in the process:
 
 ## Who has signed up?
 
-- [ ] pacman.store (@RubenKelevra)
+- [ ] Charity Engine (@rytiss, @tristanolive)
+- [ ] Fission (@bmann)
 - [ ] Infura (@MichaelMure)
-- [ ] Textile (@sanderpick)
+- [ ] OrbitDB (@aphelionz)
+- [ ] pacman.store (@RubenKelevra)
 - [ ] Pinata (@obo20)
+- [ ] PL EngRes bifrost (@gmasgras)
 - [ ] RTrade (@postables)
 - [ ] Siderus (@koalalorenzo)
-- [ ] Charity Engine (@rytiss, @tristanolive)
-- [ ] Fission (@bmann)
-- [ ] OrbitDB (@aphelionz)
+- [ ] Textile (@sanderpick)
 
 ## How to sign up?
 
diff --git a/docs/RELEASE_ISSUE_TEMPLATE.md b/docs/RELEASE_ISSUE_TEMPLATE.md
index 13b14c8a4f91e86fac67c25eb0a13bda0974bf3e..da3ec3e18303efb69d75cca72c7d7e635186108c 100644
--- a/docs/RELEASE_ISSUE_TEMPLATE.md
+++ b/docs/RELEASE_ISSUE_TEMPLATE.md
@@ -41,7 +41,7 @@ As usual, this release includes important fixes, some of which may be critical f
 Checklist:
 
 - [ ] **Stage 0 - Prerequisites**
-  - [ ] Open an issue against [bifrost-infra](https://github.com/protocol/bifrost-infra) ahead of the release ([example](https://github.com/protocol/bifrost-infra/issues/2109)).  **Idealy, do this multiple days in advance of the RC** to give Bifrost the heads up that asks will be coming their way.
+  - [ ] Open an issue against [bifrost-infra](https://github.com/protocol/bifrost-infra) ahead of the release ([example](https://github.com/protocol/bifrost-infra/issues/2109)).  **Ideally, do this multiple days in advance of the RC** to give Bifrost the heads up that asks will be coming their way.
     - [ ] Spell out all that we want updated - gateways, the bootstraper and the cluster/preload nodes
     - [ ] Mention @protocol/bifrost-team in the issue and let them know the expected date of the release
       - Issue link:
@@ -74,7 +74,7 @@ Checklist:
   - [ ] If it's not a first RC, add new commits to the `release-vX.Y.Z` branch from `master` using `git cherry-pick -x ...`
       - Note: `release-*` branches are protected. You can do all needed updates on a separated branch (e.g. `wip-release-vX.Y.Z`) and when everything is settled push to `release-vX.Y.Z`
   - [ ] Bump the version in `version.go` in the `release-vX.Y.Z` branch to `vX.Y.Z-rcN`.
-  - [ ] If it's a first RC, create a draft PR targetting `release` branch if it doesn't exist yet ([example](https://github.com/ipfs/kubo/pull/9306)).
+  - [ ] If it's a first RC, create a draft PR targeting `release` branch if it doesn't exist yet ([example](https://github.com/ipfs/kubo/pull/9306)).
   - [ ] Wait for CI to run and complete PR checks. All checks should pass.
   - [ ] Create a signed tag for the release candidate.
     - [ ] This is a dangerous operation, as it is difficult to reverse due to Go modules and automated Docker image publishing. Remember to verify the commands you intend to run for items marked with ⚠️ with the release reviewer.
@@ -144,7 +144,7 @@ Checklist:
       - [ ] Commit the changelog changes.
     - [ ] Push the `release-vX.Y.Z` branch to GitHub (`git push origin release-vX.Y.Z`)
     - [ ] Mark the PR created from `release-vX.Y.Z` as ready for review.
-      - [ ] Ensure the PR is targetting `release` branch.
+      - [ ] Ensure the PR is targeting `release` branch.
       - [ ] Ensure that CI is green.
       - [ ] Have release reviewer review the PR.
     - [ ] Merge the PR into `release` branch using the `Create a merge commit` (do **NOT** use `Squash and merge` nor `Rebase and merge` because we need to be able to sign the merge commit).
diff --git a/docs/changelogs/v0.10.md b/docs/changelogs/v0.10.md
index b4bbf1047988ff8f75a14f8e13397795e8c2df8c..ea92201a9fff55f939e7410e7822790379685fbb 100644
--- a/docs/changelogs/v0.10.md
+++ b/docs/changelogs/v0.10.md
@@ -278,7 +278,7 @@ See `ipfs swarm peering --help` for more details.
     ([ipld/go-ipld-prime#228](https://github.com/ipld/go-ipld-prime/pull/228))
   - Fix ExploreRecursive stopAt condition, add tests, add error return to Explore (#229) ([ipld/go-ipld-prime#229](https://github.com/ipld/go-ipld-prime/pull/229))
   - selector: add tests which are driven by language-agnostic spec fixtures. ([ipld/go-ipld-prime#231](https://github.com/ipld/go-ipld-prime/pull/231))
-  - selector: Improve docs for implementors. (#227) ([ipld/go-ipld-prime#227](https://github.com/ipld/go-ipld-prime/pull/227))
+  - selector: Improve docs for implementers. (#227) ([ipld/go-ipld-prime#227](https://github.com/ipld/go-ipld-prime/pull/227))
   - Bindnode fixes of opportunity ([ipld/go-ipld-prime#226](https://github.com/ipld/go-ipld-prime/pull/226))
   - node/bindnode: redesign the shape of unions in Go ([ipld/go-ipld-prime#223](https://github.com/ipld/go-ipld-prime/pull/223))
   - summary of the v0.11.0 changelog should holler even more about how cool bindnode is.
diff --git a/docs/changelogs/v0.11.md b/docs/changelogs/v0.11.md
index 9a3d2b7c930eb150623f2ce002ef348d438556bc..98133052ab68d5b43bc8bc275a53858d58ad8450 100644
--- a/docs/changelogs/v0.11.md
+++ b/docs/changelogs/v0.11.md
@@ -260,7 +260,7 @@ This work was [contributed](https://github.com/ipfs/go-ipfs/pull/8569) by [Ceram
   - feat(queryexecutor): merge RunTraversal into QueryExecutor
   - feat(responsemanager): QueryExecutor to separate module - use TaskQueue, add tests
   - Merge branch 'release/v0.10.5'
-  - fix(responseassembler): dont hold block data reference in passed on subscribed block link (#268) ([ipfs/go-graphsync#268](https://github.com/ipfs/go-graphsync/pull/268))
+  - fix(responseassembler): don't hold block data reference in passed on subscribed block link (#268) ([ipfs/go-graphsync#268](https://github.com/ipfs/go-graphsync/pull/268))
   - sync: update CI config files (#266) ([ipfs/go-graphsync#266](https://github.com/ipfs/go-graphsync/pull/266))
   - Check IPLD context cancellation error type instead of string comparison
   - Use `context.CancelFunc` instead of `func()` (#257) ([ipfs/go-graphsync#257](https://github.com/ipfs/go-graphsync/pull/257))
@@ -622,7 +622,7 @@ This work was [contributed](https://github.com/ipfs/go-ipfs/pull/8569) by [Ceram
 - github.com/libp2p/go-libp2p-pubsub (v0.5.4 -> v0.6.0):
   - feat: plumb through context changes (#459) ([libp2p/go-libp2p-pubsub#459](https://github.com/libp2p/go-libp2p-pubsub/pull/459))
   - support MinTopicSize without a discovery mechanism
-  - clear peerPromises map when fullfilling a promise
+  - clear peerPromises map when fulfilling a promise
   - README: remove obsolete notice, fix example code for tracing.
   - remove peer filter check from subscriptions (#453) ([libp2p/go-libp2p-pubsub#453](https://github.com/libp2p/go-libp2p-pubsub/pull/453))
   - Create peer filter option
diff --git a/docs/changelogs/v0.12.md b/docs/changelogs/v0.12.md
index 85639dd2b8621b83d45d99ca8b0972d5d4db8642..def891271d31f355eba0798db6f24506d1cfedc2 100644
--- a/docs/changelogs/v0.12.md
+++ b/docs/changelogs/v0.12.md
@@ -166,7 +166,7 @@ For this migration, if your datastore has fast renames you may want to consider
   - Version 1.1.0 (#91) ([ipfs/go-ipfs-blockstore#91](https://github.com/ipfs/go-ipfs-blockstore/pull/91))
   - feat: add context to interfaces (#90) ([ipfs/go-ipfs-blockstore#90](https://github.com/ipfs/go-ipfs-blockstore/pull/90))
   - sync: update CI config files (#88) ([ipfs/go-ipfs-blockstore#88](https://github.com/ipfs/go-ipfs-blockstore/pull/88))
-  - add constructor that doesnt mess with datastore keys ([ipfs/go-ipfs-blockstore#83](https://github.com/ipfs/go-ipfs-blockstore/pull/83))
+  - add constructor that doesn't mess with datastore keys ([ipfs/go-ipfs-blockstore#83](https://github.com/ipfs/go-ipfs-blockstore/pull/83))
   - Use bloom filter in GetSize
   - fix staticcheck ([ipfs/go-ipfs-blockstore#73](https://github.com/ipfs/go-ipfs-blockstore/pull/73))
   - add BenchmarkARCCacheConcurrentOps ([ipfs/go-ipfs-blockstore#70](https://github.com/ipfs/go-ipfs-blockstore/pull/70))
diff --git a/docs/changelogs/v0.13.md b/docs/changelogs/v0.13.md
index d0635beb893b8a96ea6a65f8773bddf26ec7535a..9bf4ee88acfceba5982814e8dfebc417362d5e63 100644
--- a/docs/changelogs/v0.13.md
+++ b/docs/changelogs/v0.13.md
@@ -29,7 +29,7 @@ View the linked [security advisory](https://github.com/ipfs/go-ipfs/security/adv
   - Remove support for `ForEach` enumeration from car-index-sorted
   - Use a fix code as the multihash code for `CarIndexSorted`
   - Fix testutil assertion logic and update index generation tests
-  - fix: tighter constraint of singleWidthIndex width, add index recommentation docs
+  - fix: tighter constraint of singleWidthIndex width, add index recommendation docs
   - fix: explicitly disable serialization of insertionindex
   - feat: MaxAllowed{Header,Section}Size option
   - feat: MaxAllowedSectionSize default to 32M
@@ -66,7 +66,7 @@ View the linked [security advisory](https://github.com/ipfs/go-ipfs/security/adv
   - Traversal-based car creation (#269) ([ipld/go-car#269](https://github.com/ipld/go-car/pull/269))
   - Seek to start before index generation in `ReadOnly` blockstore
   - support extraction of unixfs content stored in car files (#263) ([ipld/go-car#263](https://github.com/ipld/go-car/pull/263))
-  - Add a barebones readme to the car CLI (#262) ([ipld/go-car#262](https://github.com/ipld/go-car/pull/262))
+  - Add a bare bones readme to the car CLI (#262) ([ipld/go-car#262](https://github.com/ipld/go-car/pull/262))
   - sync: update CI config files (#261) ([ipld/go-car#261](https://github.com/ipld/go-car/pull/261))
   - fix!: use -version=n instead of -v1 for index command
   - feat: fix get-dag and add version=1 option
@@ -223,7 +223,7 @@ Future releases will [add support for dag-json and dag-cbor responses](https://g
 There are two ways for requesting CID specific response format:
 1. HTTP header: `Accept: application/vnd.ipld.{format}`
 - Examples: [application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car), [application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw)
-2.  URL paramerer: `?format=`
+2.  URL parameter: `?format=`
 -  Useful for creating "Download CAR" links.
 
 *Usage examples:*
@@ -629,7 +629,7 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f
   - fix: cannot call SetPrimaryCore after using a Tee logger ([ipfs/go-log#121](https://github.com/ipfs/go-log/pull/121))
   - Document environment variables ([ipfs/go-log#120](https://github.com/ipfs/go-log/pull/120))
   - sync: update CI config files (#119) ([ipfs/go-log#119](https://github.com/ipfs/go-log/pull/119))
-  - Add WithStacktrace untility ([ipfs/go-log#118](https://github.com/ipfs/go-log/pull/118))
+  - Add WithStacktrace utility ([ipfs/go-log#118](https://github.com/ipfs/go-log/pull/118))
   - In addition to StdOut/Err check the outfile for TTYness ([ipfs/go-log#117](https://github.com/ipfs/go-log/pull/117))
 - github.com/ipfs/go-merkledag (v0.5.1 -> v0.6.0):
   - v0.6.0
@@ -659,7 +659,7 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f
   - add AsLargeBytes support to unixfs files (#24) ([ipfs/go-unixfsnode#24](https://github.com/ipfs/go-unixfsnode/pull/24))
   - fix: add extra test to span the shard/no-shard boundary
   - fix: more Tsize fixes, fix HAMT and make it match go-unixfs output
-  - fix: encode Tsize correctly everywhere (using wraped LinkSystem)
+  - fix: encode Tsize correctly everywhere (using wrapped LinkSystem)
   - docs(version): tag 1.2.0
   - Update deps for ADL selectors ([ipfs/go-unixfsnode#20](https://github.com/ipfs/go-unixfsnode/pull/20))
   - add license (#17) ([ipfs/go-unixfsnode#17](https://github.com/ipfs/go-unixfsnode/pull/17))
@@ -951,7 +951,7 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f
   - disable the incoming streams limit (#49) ([libp2p/go-libp2p-yamux#49](https://github.com/libp2p/go-libp2p-yamux/pull/49))
   - Release v0.8.1 ([libp2p/go-libp2p-yamux#48](https://github.com/libp2p/go-libp2p-yamux/pull/48))
   - release v0.8.0 (#47) ([libp2p/go-libp2p-yamux#47](https://github.com/libp2p/go-libp2p-yamux/pull/47))
-  - pass the PeerScope to yamux (satifiying its MemoryManger interface) (#46) ([libp2p/go-libp2p-yamux#46](https://github.com/libp2p/go-libp2p-yamux/pull/46))
+  - pass the PeerScope to yamux ( satisfying its MemoryManger interface) (#46) ([libp2p/go-libp2p-yamux#46](https://github.com/libp2p/go-libp2p-yamux/pull/46))
   - release v0.7.0 (#43) ([libp2p/go-libp2p-yamux#43](https://github.com/libp2p/go-libp2p-yamux/pull/43))
   - sync: update CI config files (#42) ([libp2p/go-libp2p-yamux#42](https://github.com/libp2p/go-libp2p-yamux/pull/42))
   - reduce the number of max incoming stream to 256 ([libp2p/go-libp2p-yamux#41](https://github.com/libp2p/go-libp2p-yamux/pull/41))
@@ -973,7 +973,7 @@ The more fully featured yamux stream multiplexer is now prioritized over mplex f
   - multiplex: add (*Multiplex).CloseChan ([libp2p/go-mplex#89](https://github.com/libp2p/go-mplex/pull/89))
   - add a Go Reference badge to the README ([libp2p/go-mplex#88](https://github.com/libp2p/go-mplex/pull/88))
   - sync: update CI config files ([libp2p/go-mplex#85](https://github.com/libp2p/go-mplex/pull/85))
-  - Fixup tests & vet ([libp2p/go-mplex#84](https://github.com/libp2p/go-mplex/pull/84))
+  - Fix up tests & vet ([libp2p/go-mplex#84](https://github.com/libp2p/go-mplex/pull/84))
   - Bump lodash from 4.17.19 to 4.17.21 in /interop/js ([libp2p/go-mplex#83](https://github.com/libp2p/go-mplex/pull/83))
 - github.com/libp2p/go-msgio (v0.1.0 -> v0.2.0):
   - release v0.2.0 (#34) ([libp2p/go-msgio#34](https://github.com/libp2p/go-msgio/pull/34))
diff --git a/docs/changelogs/v0.15.md b/docs/changelogs/v0.15.md
index 93033b26c0a2840049990059af5e9c5c7e0ccd1a..cc51aba1ac9290388da18d00ae9c57f453a57c0d 100644
--- a/docs/changelogs/v0.15.md
+++ b/docs/changelogs/v0.15.md
@@ -75,7 +75,7 @@ http://127.0.0.1:8080
   - docs(add): skip binary name in helptext
   - docs(cli): clarify CID determinism in add command
   - docs(cli): clarify CAR format in dag export|import
-  - test(gw): cors preflight with custom hearder
+  - test(gw): cors preflight with custom header
   - feat: make corehttp a reusable component ([ipfs/kubo#9070](https://github.com/ipfs/kubo/pull/9070))
   - feat: go-libp2p v0.21 (rcmgr auto scaling) ([ipfs/kubo#9074](https://github.com/ipfs/kubo/pull/9074))
   -  ([ipfs/kubo#9024](https://github.com/ipfs/kubo/pull/9024))
@@ -90,7 +90,7 @@ http://127.0.0.1:8080
   - feat: add $IPFS_PATH/gateway file
   - docs: replace `docs.ipfs.io` with `docs.ipfs.tech` (#9158) ([ipfs/kubo#9158](https://github.com/ipfs/kubo/pull/9158))
   - chore: fix markdown link syntax typo for AutoNAT.ServiceMode
-  - chore: bump go-blockservice to only do put onces
+  - chore: bump go-blockservice to only do put once
   - docs: update Arch Linux installation instructions
   - chore: update kubo-as-a-library example
   - docs(readme): add maintainer info (#9141) ([ipfs/kubo#9141](https://github.com/ipfs/kubo/pull/9141))
@@ -212,9 +212,9 @@ http://127.0.0.1:8080
   - Add package docs ([libp2p/go-libp2p-resource-manager#75](https://github.com/libp2p/go-libp2p-resource-manager/pull/75))
   - chore: Release v0.5.2 ([libp2p/go-libp2p-resource-manager#74](https://github.com/libp2p/go-libp2p-resource-manager/pull/74))
   - Record which direction the resource was blocked ([libp2p/go-libp2p-resource-manager#72](https://github.com/libp2p/go-libp2p-resource-manager/pull/72))
-  - Simplify mem graphs in stock grafana dashboard ([libp2p/go-libp2p-resource-manager#73](https://github.com/libp2p/go-libp2p-resource-manager/pull/73))
-  - feat: Handle multiple instances in stock grafana dashboard ([libp2p/go-libp2p-resource-manager#70](https://github.com/libp2p/go-libp2p-resource-manager/pull/70))
-  - Use templated version of grafana dashboard json ([libp2p/go-libp2p-resource-manager#69](https://github.com/libp2p/go-libp2p-resource-manager/pull/69))
+  - Simplify mem graphs in stock Grafana dashboard ([libp2p/go-libp2p-resource-manager#73](https://github.com/libp2p/go-libp2p-resource-manager/pull/73))
+  - feat: Handle multiple instances in stock Grafana dashboard ([libp2p/go-libp2p-resource-manager#70](https://github.com/libp2p/go-libp2p-resource-manager/pull/70))
+  - Use templated version of Grafana dashboard json ([libp2p/go-libp2p-resource-manager#69](https://github.com/libp2p/go-libp2p-resource-manager/pull/69))
   - Release v0.5.1 ([libp2p/go-libp2p-resource-manager#66](https://github.com/libp2p/go-libp2p-resource-manager/pull/66))
   - Implement `json.Marshaler` interface for LimitConfig ([libp2p/go-libp2p-resource-manager#67](https://github.com/libp2p/go-libp2p-resource-manager/pull/67))
   - Don't wait for a chan that will never close ([libp2p/go-libp2p-resource-manager#65](https://github.com/libp2p/go-libp2p-resource-manager/pull/65))
@@ -249,7 +249,7 @@ http://127.0.0.1:8080
   - remove Travis package (#57) ([libp2p/go-libp2p-testing#57](https://github.com/libp2p/go-libp2p-testing/pull/57))
 - github.com/lucas-clemente/quic-go (v0.27.1 -> v0.28.0):
   - update for Go 1.19beta1 (#3460) ([lucas-clemente/quic-go#3460](https://github.com/lucas-clemente/quic-go/pull/3460))
-  - dedupe Alt-Svc header values (#3461) ([lucas-clemente/quic-go#3461](https://github.com/lucas-clemente/quic-go/pull/3461))
+  - Deduplicate Alt-Svc header values (#3461) ([lucas-clemente/quic-go#3461](https://github.com/lucas-clemente/quic-go/pull/3461))
   - only set DF for sockets that can handle it (#3448) ([lucas-clemente/quic-go#3448](https://github.com/lucas-clemente/quic-go/pull/3448))
   - fix flaky HTTP/3 request body test (#3447) ([lucas-clemente/quic-go#3447](https://github.com/lucas-clemente/quic-go/pull/3447))
   - make the keep alive interval configurable (#3444) ([lucas-clemente/quic-go#3444](https://github.com/lucas-clemente/quic-go/pull/3444))
diff --git a/docs/changelogs/v0.17.md b/docs/changelogs/v0.17.md
index 867ddf3aefebae32bba523ba7cbb7a540bd08ecd..3c06cfc02ba271f4da82ae530076e20ae85923ff 100644
--- a/docs/changelogs/v0.17.md
+++ b/docs/changelogs/v0.17.md
@@ -40,7 +40,7 @@ and [Swarm.ResourceMgr.MaxFileDescriptors](https://github.com/ipfs/go-ipfs/blob/
 See [Swarm.ResourceMgr](https://github.com/ipfs/go-ipfs/blob/master/docs/config.md#swarmresourcemgr) for
 1. what limits are set by default,
 2. example override configuration, 
-3. how to access prometheus metrics and view grafana dashboards of resource usage, and 
+3. how to access Prometheus metrics and view Grafana dashboards of resource usage, and 
 4. how to set explicit "allow lists" to protect against eclipse attacks. 
 
 #### Implicit connection manager limits
diff --git a/docs/changelogs/v0.18.md b/docs/changelogs/v0.18.md
index 352077e6508b7309422a9c6c6636922348b74c3c..5b3b154392d11409d122553a32007f94f1d56715 100644
--- a/docs/changelogs/v0.18.md
+++ b/docs/changelogs/v0.18.md
@@ -35,19 +35,30 @@ first time a message is seen, you can set `Pubsub.SeenMessagesStrategy` to
 
 #### Improving libp2p resource management integration
 
-This builds on the default protection nodes get against DoS (resource exhaustion) and eclipse attacks
+TL;DR: limit autoscaling improved, most users should start with default settings.
+If you have old configuration, switch to implicit defaults:
+
+```
+ipfs config --json -- Swarm.ResourceMgr '{}'
+ipfs config --json -- Swarm.ConnMgr '{}'
+```
+
+IF you run a server and want to utilize more than half of memory and file descriptors to p2p work, adjust [`Swarm.ResourceMgr.MaxMemory`](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgrmaxmemory) and [`Swarm.ResourceMgr.MaxFileDescriptors`](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgrmaxfiledescriptors).
+
+The 0.18.1 builds on the default protection nodes get against DoS (resource exhaustion) and eclipse attacks
 with the [go-libp2p Network Resource Manager/Accountant](https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md)
 that was fine-tuned in [Kubo 0.18](https://github.com/ipfs/kubo/blob/biglep/resource-manager-example-of-what-want/docs/changelogs/v0.18.md#improving-libp2p-resource-management-integration).
 
 Adding default hard-limits from the Resource Manager/Accountant after the fact is tricky,
 and some additional improvements have been made to improve the [computed defaults](https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#computed-default-limits).
-As much as possible, the aim is for a user to only think about how much memory they want to bound libp2p to,
+
+As much as possible, the aim is for a user to only think about how much memory they want to bound libp2p to, 
 and not need to think about translating that to hard numbers for connections, streams, etc.
-More updates are likely in future Kubo releases, but with this release:
+More updates are likely in future Kubo releases, but with this release: 
 1. ``System.StreamsInbound`` is no longer bounded directly
 2. ``System.ConnsInbound``, ``Transient.Memory``, ``Transiet.ConnsInbound`` have higher default computed values.
 
-### Changelog
+### 📝 Changelog
 
 <details><summary>Full Changelog</summary>
 
@@ -61,7 +72,7 @@ More updates are likely in future Kubo releases, but with this release:
 
 </details>
 
-### Contributors
+### 👨‍👩‍👧‍👦 Contributors
 
 | Contributor | Commits | Lines ± | Files Changed |
 |-------------|---------|---------|---------------|
@@ -123,7 +134,7 @@ Learn more in the [`Routing` docs](https://github.com/ipfs/kubo/blob/master/docs
 Default `Reprovider.Interval` changed from 12h to 22h to match new defaults for the Provider Record Expiration (48h) in [go-libp2p-kad-dht v0.20.0](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.20.0).
 
 The rationale for increasing this can be found in
-[RFM 17: Provider Record Livenes Report](https://github.com/protocol/network-measurements/blob/master/results/rfm17-provider-record-liveness.md),
+[RFM 17: Provider Record Liveness Report](https://github.com/protocol/network-measurements/blob/master/results/rfm17-provider-record-liveness.md),
 [kubo#9326](https://github.com/ipfs/kubo/pull/9326),
 and the upstream DHT specifications at [libp2p/specs#451](https://github.com/libp2p/specs/pull/451).
 
@@ -274,7 +285,7 @@ go-libp2p do supports listening with both QUIC versions on one single listener.
 WebTransport has only supported QUICv1.
 `/webtransport` now needs to be prefixed by a `/quic-v1` component instead of a `/quic` component.
 
-Support for QUIC Draft-29 will be removed at some point in 2023 ([tracking issue](https://github.com/ipfs/kubo/issues/9496)).  As a result, new deployements should use `/quic-v1` instead of `/quic`.
+Support for QUIC Draft-29 will be removed at some point in 2023 ([tracking issue](https://github.com/ipfs/kubo/issues/9496)).  As a result, new deployments should use `/quic-v1` instead of `/quic`.
 
 ##### QUICv1 and WebTransport config migration
 To support QUICv1 and WebTransport by default a new config migration (`v13`) is run which automatically adds entries in addresses-related fields:
diff --git a/docs/changelogs/v0.19.md b/docs/changelogs/v0.19.md
new file mode 100644
index 0000000000000000000000000000000000000000..4663d132389cde11ef413c61b18db499edda5a6f
--- /dev/null
+++ b/docs/changelogs/v0.19.md
@@ -0,0 +1,551 @@
+<!-- omit in toc -->
+# Kubo changelog v0.19
+
+<!-- omit in toc -->
+## v0.19.0
+
+- [Overview](#overview)
+- [🔦 Highlights](#-highlights)
+  - [Improving the libp2p resource management integration](#improving-the-libp2p-resource-management-integration)
+  - [PubSub message caching improvements](#pubsub-message-caching-improvements)
+  - [Gateways](#gateways)
+    - [Signed IPNS Record response format](#signed-ipns-record-response-format)
+    - [Example fetch and inspect IPNS record](#example-fetch-and-inspect-ipns-record)
+  - [Addition of "autoclient" router type](#addition-of-autoclient-router-type)
+  - [Deprecation of the `ipfs pubsub` commands and matching HTTP endpoints](#deprecation-of-the-ipfs-pubsub-commands-and-matching-http-endpoints)
+- [📝 Changelog](#-changelog)
+- [👨‍👩‍👧‍👦 Contributors](#-contributors)
+
+### Overview
+
+### 🔦 Highlights
+
+#### Improving the libp2p resource management integration
+There are further followups up on libp2p resource manager improvements in Kubo [0.18.0](https://github.com/ipfs/kubo/blob/master/docs/changelogs/v0.18.md#improving-libp2p-resource-management-integration-1)
+and [0.18.1](https://github.com/ipfs/kubo/blob/master/docs/changelogs/v0.18.md#improving-libp2p-resource-management-integration):
+1. `ipfs swarm limits` and `ipfs swarm stats` have been replaced by `ipfs swarm resources` to provide a single/combined view for limits and their current usage in a more intuitive ordering.
+1. Removal of `Swarm.ResourceMgr.Limits` config.  Instead [the power user can specify limits in a .json file that are fed directly to go-libp2p](https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md#user-supplied-override-limits).  This allows the power user to take advantage of the [new resource manager types introduced in go-libp2p 0.25](https://github.com/libp2p/go-libp2p/blob/master/CHANGELOG.md#new-resource-manager-types-) including "use default", "unlimited", "block all".
+   - Note: we don't expect most users to need these capablities, but they are there if so.
+1. [Doc updates](https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md).
+
+#### PubSub message caching improvements
+
+The PubSub message cache will now [prune messages after TTL is exhausted](https://github.com/ipfs/kubo/blob/master/docs/config.md#pubsubseenmessagesttl), [either based on the last time a message was seen or the first time it was seen](https://github.com/ipfs/kubo/blob/master/docs/config.md#pubsubseenmessagesstrategy).
+
+#### Gateways
+
+##### Signed IPNS Record response format
+
+This release implements [IPIP-351](https://github.com/ipfs/specs/pull/351) and
+adds Gateway support for returning signed (verifiable) `ipns-record` (0x0300)
+when `/ipns/{libp2p-key}` is requested with either
+`Accept: application/vnd.ipfs.ipns-record` HTTP header
+or `?format=ipns-record` URL query parameter.
+
+
+The Gateway in Kubo already supported [trustless, verifiable retrieval](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval) of immutable `/ipfs/` namespace.
+With `?format=ipns-record`, light HTTP clients are now able to get the same level of verifiability for IPNS websites.
+
+Tooling is limited at the moment, but we are working on [go-libipfs](https://github.com/ipfs/go-libipfs/) examples that illustrate the verifiable HTTP client pattern.
+
+##### Example: fetch IPNS record over HTTP and inspect it with `ipfs name inspect --verify`
+
+```console
+$ FILE_CID=$(echo "Hello IPFS" | ipfs add --cid-version 1 -q)
+$ IPNS_KEY=$(ipfs key gen test)
+$ ipfs name publish /ipfs/$FILE_CID --key=test --ttl=30m
+Published to k51q..dvf1: /ipfs/bafk..z244
+$ curl "http://127.0.0.1:8080/ipns/$IPNS_KEY?format=ipns-record" > signed.ipns-record
+$ ipfs name inspect --verify $IPNS_KEY < signed.ipns-record
+Value:         "/ipfs/bafk..."
+Validity Type: "EOL"
+Validity:      2023-03-09T23:13:34.032977468Z
+Sequence:      0
+TTL:           1800000000000
+PublicKey:     ""
+Signature V1:  "m..."
+Signature V2:  "m..."
+Data:          {...}
+
+Validation results:
+ Valid:     true
+ PublicKey: 12D3...
+```
+
+#### Addition of "autoclient" router type
+A new routing type "autoclient" has been added. This mode is similar to "auto", in that it is a hybrid of content routers (including Kademlia and HTTP routers), but it does not run a DHT server. This is similar to the difference between "dhtclient" and "dht" router types.
+
+See the [Routing.Type documentation](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingtype) for more information.
+
+#### Deprecation of the `ipfs pubsub` commands and matching HTTP endpoints
+
+We are deprecating `ipfs pubsub` and all `/api/v0/pubsub/` RPC endpoints and will remove them in the next release.
+
+For more information and rational see [#9717](https://github.com/ipfs/kubo/issues/9717).
+
+### 📝 Changelog
+
+<details><summary>Full Changelog</summary>
+
+- github.com/ipfs/kubo:
+  - chore: update version
+  - docs: 0.19 changelog ([ipfs/kubo#9707](https://github.com/ipfs/kubo/pull/9707))
+  - fix: canonicalize user defined headers
+  - fix: apply API.HTTPHeaders to /webui redirect
+  - feat: add heap allocs to 'ipfs diag profile'
+  - fix: future proof with > rcmgr.DefaultLimit for new enum rcmgr values
+  - test: add test for presarvation of unlimited configs for inbound systems
+  - fix: preserve Unlimited StreamsInbound in connmgr reconciliation
+  - test: fix flaky rcmgr test
+  - chore: deprecate the pubsub api
+  - test: port peering test from sharness to Go
+  - test: use `T.TempDir` to create temporary test directory
+  - fix: --verify forgets the verified key
+  - test: name --verify forgets the verified key
+  - feat: add "autoclient" routing type
+  - test: parallelize more of rcmgr Go tests
+  - test: port legacy DHT tests to Go
+  - fix: t0116-gateway-cache.sh ([ipfs/kubo#9696](https://github.com/ipfs/kubo/pull/9696))
+  - docs: add bifrost to early testers ([ipfs/kubo#9699](https://github.com/ipfs/kubo/pull/9699))
+  - fix: typo in documentation for install path
+  - chore: update version
+  - feat: Reduce RM code footprint
+  - Doc updates/additions
+  - ci: replace junit html generation with gh action
+  - test: port rcmgr sharness tests to Go
+  - test(gateway): use deterministic CAR fixtures ([ipfs/kubo#9657](https://github.com/ipfs/kubo/pull/9657))
+  - feat(gateway): error handling improvements (500, 502, 504) (#9660) ([ipfs/kubo#9660](https://github.com/ipfs/kubo/pull/9660))
+  - docs: be clear about swarm.addrfilters (#9661) ([ipfs/kubo#9661](https://github.com/ipfs/kubo/pull/9661))
+  - chore: update go-libp2p to v0.26 (#9656) ([ipfs/kubo#9656](https://github.com/ipfs/kubo/pull/9656))
+  - feat(pinning): connect some missing go context (#9557) ([ipfs/kubo#9557](https://github.com/ipfs/kubo/pull/9557))
+  - fix(gateway): return HTTP 500 on ErrResolveFailed (#9589) ([ipfs/kubo#9589](https://github.com/ipfs/kubo/pull/9589))
+  - docs: bulk spelling edits (#9544) ([ipfs/kubo#9544](https://github.com/ipfs/kubo/pull/9544))
+  - docs: "remote" errors from resource manager (#9653) ([ipfs/kubo#9653](https://github.com/ipfs/kubo/pull/9653))
+  - test: remove gateway tests migrated to go-libipfs
+  - fix: update rcmgr for go-libp2p v0.25
+  - chore: update go-libp2p to v0.25.1
+  - docs(0.18.1): guide users to clean up limits (#9644) ([ipfs/kubo#9644](https://github.com/ipfs/kubo/pull/9644))
+  - feat: add NewOptionalInteger function
+  - fix: dereference int64 pointer in OptionalInteger.String() (#9640) ([ipfs/kubo#9640](https://github.com/ipfs/kubo/pull/9640))
+  - fix: restore wire format for /api/v0/routing/get|put (#9639) ([ipfs/kubo#9639](https://github.com/ipfs/kubo/pull/9639))
+  - refactor(gw): move Host (DNSLink and subdomain) handling to go-libipfs (#9624) ([ipfs/kubo#9624](https://github.com/ipfs/kubo/pull/9624))
+  - refactor: new go-libipfs/gateway API, deprecate Gateway.Writable (#9616) ([ipfs/kubo#9616](https://github.com/ipfs/kubo/pull/9616))
+  - Create Changelog: v0.19 ([ipfs/kubo#9617](https://github.com/ipfs/kubo/pull/9617))
+  - refactor: use gateway from go-libipfs (#9588) ([ipfs/kubo#9588](https://github.com/ipfs/kubo/pull/9588))
+  - Merge Release: v0.18.1 ([ipfs/kubo#9613](https://github.com/ipfs/kubo/pull/9613))
+  - Add overview section
+  - Adjust inbound connection limits depending on memory.
+  - feat: ipfs-webui 2.22.0
+  - chore: bump go-libipfs remove go-bitswap
+  - docs: DefaultResourceMgrMinInboundConns
+  - feat(gateway): IPNS record response format (IPIP-351) (#9399) ([ipfs/kubo#9399](https://github.com/ipfs/kubo/pull/9399))
+  - fix(ipns): honour --ttl flag in 'ipfs name publish' (#9471) ([ipfs/kubo#9471](https://github.com/ipfs/kubo/pull/9471))
+  - feat: Pubsub.SeenMessagesStrategy (#9543) ([ipfs/kubo#9543](https://github.com/ipfs/kubo/pull/9543))
+  - chore: bump go-libipfs to replace go-block-format
+  - Merge Kubo: v0.18 ([ipfs/kubo#9581](https://github.com/ipfs/kubo/pull/9581))
+  - fix: clarity: no user supplied rcmgr limits of 0 (#9563) ([ipfs/kubo#9563](https://github.com/ipfs/kubo/pull/9563))
+  - fix(gateway): undesired conversions to dag-json and friends (#9566) ([ipfs/kubo#9566](https://github.com/ipfs/kubo/pull/9566))
+  - fix: ensure connmgr is smaller then autoscalled ressource limits
+  - fix: typo in ensureConnMgrMakeSenseVsResourcesMgr
+  - docs: clarify browser descriptions for webtransport
+  - fix: update saxon download path
+  - fix: refuse to start if connmgr is smaller than ressource limits and not using none connmgr
+  - fix: User-Agent sent to HTTP routers
+  - test: port gateway sharness tests to Go tests
+  - fix: do not download saxon in parallel
+  - docs: improve docs/README (#9539) ([ipfs/kubo#9539](https://github.com/ipfs/kubo/pull/9539))
+  - test: port CircleCI to GH Actions and improve sharness reporting (#9355) ([ipfs/kubo#9355](https://github.com/ipfs/kubo/pull/9355))
+  - chore: migrate from go-ipfs-files to go-libipfs/files (#9535) ([ipfs/kubo#9535](https://github.com/ipfs/kubo/pull/9535))
+  - fix: stats dht command when Routing.Type=auto (#9538) ([ipfs/kubo#9538](https://github.com/ipfs/kubo/pull/9538))
+  - fix: hint people to changing from RSA peer ids
+  - fix(gateway): JSON when Accept is a list
+  - fix(test): retry flaky t0125-twonode.sh
+  - docs: fix Router config Godoc (#9528) ([ipfs/kubo#9528](https://github.com/ipfs/kubo/pull/9528))
+  - fix(ci): flaky sharness test
+  - docs(config): ProviderSearchDelay (#9526) ([ipfs/kubo#9526](https://github.com/ipfs/kubo/pull/9526))
+  - docs: clarify debug environment variables
+  - fix: disable provide over HTTP with Routing.Type=auto (#9511) ([ipfs/kubo#9511](https://github.com/ipfs/kubo/pull/9511))
+  - fix(test): stabilize flaky provider tests
+  - feat: port pins CLI test
+  - Removing QRI from early tester ([ipfs/kubo#9503](https://github.com/ipfs/kubo/pull/9503))
+  - Update Version (dev): v0.18 ([ipfs/kubo#9500](https://github.com/ipfs/kubo/pull/9500))
+- github.com/ipfs/go-bitfield (v1.0.0 -> v1.1.0):
+  - Merge pull request from GHSA-2h6c-j3gf-xp9r
+  - sync: update CI config files (#3) ([ipfs/go-bitfield#3](https://github.com/ipfs/go-bitfield/pull/3))
+- github.com/ipfs/go-block-format (v0.0.3 -> v0.1.1):
+  - chore: release v0.1.1
+  - docs: fix wrong copy paste in docs
+  - chore: release v0.1.0
+  - refactor: deprecate and add stub types to go-libipfs/blocks
+  - sync: update CI config files (#34) ([ipfs/go-block-format#34](https://github.com/ipfs/go-block-format/pull/34))
+  - remove Makefile ([ipfs/go-block-format#31](https://github.com/ipfs/go-block-format/pull/31))
+- github.com/ipfs/go-ipfs-files (v0.0.8 -> v0.3.0):
+  -  ([ipfs/go-ipfs-files#59](https://github.com/ipfs/go-ipfs-files/pull/59))
+  - docs: add moved noticed [ci skip]
+  - Release v0.2.0
+  - fix: error when TAR has files outside of root (#56) ([ipfs/go-ipfs-files#56](https://github.com/ipfs/go-ipfs-files/pull/56))
+  - sync: update CI config files ([ipfs/go-ipfs-files#55](https://github.com/ipfs/go-ipfs-files/pull/55))
+  - chore(Directory): add DirIterator API restriction: iterate only once
+  - Release v0.1.1
+  - fix: add dragonfly build option for filewriter flags
+  - fix: add freebsd build option for filewriter flags
+  - Release v0.1.0
+  - docs: fix community CONTRIBUTING.md link (#45) ([ipfs/go-ipfs-files#45](https://github.com/ipfs/go-ipfs-files/pull/45))
+  - chore(filewriter): cleanup writes (#43) ([ipfs/go-ipfs-files#43](https://github.com/ipfs/go-ipfs-files/pull/43))
+  - sync: update CI config files (#44) ([ipfs/go-ipfs-files#44](https://github.com/ipfs/go-ipfs-files/pull/44))
+  - sync: update CI config files ([ipfs/go-ipfs-files#40](https://github.com/ipfs/go-ipfs-files/pull/40))
+  - fix: manually parse the content disposition to preserve directories ([ipfs/go-ipfs-files#42](https://github.com/ipfs/go-ipfs-files/pull/42))
+  - fix: round timestamps down by truncating them to seconds ([ipfs/go-ipfs-files#41](https://github.com/ipfs/go-ipfs-files/pull/41))
+  - sync: update CI config files ([ipfs/go-ipfs-files#34](https://github.com/ipfs/go-ipfs-files/pull/34))
+  - Fix test failure on Windows caused by nil `sys` in mock `FileInfo` ([ipfs/go-ipfs-files#39](https://github.com/ipfs/go-ipfs-files/pull/39))
+  - fix staticcheck ([ipfs/go-ipfs-files#35](https://github.com/ipfs/go-ipfs-files/pull/35))
+  - fix linters ([ipfs/go-ipfs-files#33](https://github.com/ipfs/go-ipfs-files/pull/33))
+- github.com/ipfs/go-ipfs-pinner (v0.2.1 -> v0.3.0):
+  - chore: release v0.3.0 (#27) ([ipfs/go-ipfs-pinner#27](https://github.com/ipfs/go-ipfs-pinner/pull/27))
+  - feat!: add and connect missing context, remove RemovePinWithMode (#23) ([ipfs/go-ipfs-pinner#23](https://github.com/ipfs/go-ipfs-pinner/pull/23))
+  - sync: update CI config files ([ipfs/go-ipfs-pinner#16](https://github.com/ipfs/go-ipfs-pinner/pull/16))
+- github.com/ipfs/go-ipfs-pq (v0.0.2 -> v0.0.3):
+  - chore: release v0.0.3
+  - fix: enable early GC
+  - sync: update CI config files (#10) ([ipfs/go-ipfs-pq#10](https://github.com/ipfs/go-ipfs-pq/pull/10))
+  - sync: update CI config files ([ipfs/go-ipfs-pq#8](https://github.com/ipfs/go-ipfs-pq/pull/8))
+  - remove Makefile ([ipfs/go-ipfs-pq#7](https://github.com/ipfs/go-ipfs-pq/pull/7))
+- github.com/ipfs/go-libipfs (v0.2.0 -> v0.6.2):
+  - chore: release 0.6.2 (#211) ([ipfs/go-libipfs#211](https://github.com/ipfs/go-libipfs/pull/211))
+  - fix(gateway): 500 on panic, recover on WithHostname
+  - refactor: use assert in remaining gateway tests
+  - chore: release 0.6.1
+  - feat: support HTTP 429 with Retry-After (#194) ([ipfs/go-libipfs#194](https://github.com/ipfs/go-libipfs/pull/194))
+  - docs: fix typo in README.md
+  - fix(gateway): return 500 for all /ip[nf]s/id failures
+  - chore: make gocritic happier
+  - feat(gateway): improved error handling, support for 502 and 504 ([ipfs/go-libipfs#182](https://github.com/ipfs/go-libipfs/pull/182))
+  - feat: add content path in request context (#184) ([ipfs/go-libipfs#184](https://github.com/ipfs/go-libipfs/pull/184))
+  - sync: update CI config files ([ipfs/go-libipfs#159](https://github.com/ipfs/go-libipfs/pull/159))
+  - fix(gateway): return HTTP 500 on namesys.ErrResolveFailed (#150) ([ipfs/go-libipfs#150](https://github.com/ipfs/go-libipfs/pull/150))
+  - docs(examples): add UnixFS file download over Bitswap (#143) ([ipfs/go-libipfs#143](https://github.com/ipfs/go-libipfs/pull/143))
+  - bitswap/server/internal/decision: fix: remove unused private type
+  - chore: release v0.6.0
+  - bitswap/server/internal/decision: add more non flaky tests
+  - bitswap/server/internal/decision: add filtering on CIDs - Ignore cids that are too big. - Kill connection for peers that are using inline CIDs.
+  - bitswap/server/internal/decision: rewrite ledger inversion
+  - docs(readme): various updates for clarity (#171) ([ipfs/go-libipfs#171](https://github.com/ipfs/go-libipfs/pull/171))
+  - feat: metric for implicit index.html in dirs
+  - fix(gateway): ensure ipfs_http_gw_get_duration_seconds gets updated
+  - test(gateway): migrate Go tests from Kubo ([ipfs/go-libipfs#156](https://github.com/ipfs/go-libipfs/pull/156))
+  - docs: fix  link (#165) ([ipfs/go-libipfs#165](https://github.com/ipfs/go-libipfs/pull/165))
+  - fix: GetIPNSRecord example gateway implementation (#158) ([ipfs/go-libipfs#158](https://github.com/ipfs/go-libipfs/pull/158))
+  - chore: release v0.5.0
+  - chore: update go-libp2p to v0.25.1
+  - fix(gateway): display correct error with 500 (#160) ([ipfs/go-libipfs#160](https://github.com/ipfs/go-libipfs/pull/160))
+  - fix: gateway car example dnslink
+  - feat(gateway): add TAR, IPNS Record, DAG-* histograms and spans (#155) ([ipfs/go-libipfs#155](https://github.com/ipfs/go-libipfs/pull/155))
+  - feat(gateway): migrate subdomain and dnslink code (#153) ([ipfs/go-libipfs#153](https://github.com/ipfs/go-libipfs/pull/153))
+  - docs: add example of gateway that proxies to ?format=raw (#151) ([ipfs/go-libipfs#151](https://github.com/ipfs/go-libipfs/pull/151))
+  - docs: add example of gateway backed by CAR file (#147) ([ipfs/go-libipfs#147](https://github.com/ipfs/go-libipfs/pull/147))
+  - undefined ([ipfs/go-libipfs#145](https://github.com/ipfs/go-libipfs/pull/145))
+  - Extract Gateway Code From Kubo
+ ([ipfs/go-libipfs#65](https://github.com/ipfs/go-libipfs/pull/65))
+  - Migrate go-bitswap ([ipfs/go-libipfs#63](https://github.com/ipfs/go-libipfs/pull/63))
+  - Use `PUT` as method to insert provider records
+  - Migrate `go-block-format` ([ipfs/go-libipfs#58](https://github.com/ipfs/go-libipfs/pull/58))
+  - chore: add codecov PR comment
+  - chore: add a logo and some basics in the README (#37) ([ipfs/go-libipfs#37](https://github.com/ipfs/go-libipfs/pull/37))
+- github.com/ipfs/go-namesys (v0.6.0 -> v0.7.0):
+  - chore: release 0.7.0 (#36) ([ipfs/go-namesys#36](https://github.com/ipfs/go-namesys/pull/36))
+  - feat: use PublishOptions for publishing IPNS records (#35) ([ipfs/go-namesys#35](https://github.com/ipfs/go-namesys/pull/35))
+- github.com/ipfs/go-path (v0.3.0 -> v0.3.1):
+  - chore: release v0.3.1 (#67) ([ipfs/go-path#67](https://github.com/ipfs/go-path/pull/67))
+  - feat: expose ErrInvalidPath and implement .Is function (#66) ([ipfs/go-path#66](https://github.com/ipfs/go-path/pull/66))
+  - sync: update CI config files (#60) ([ipfs/go-path#60](https://github.com/ipfs/go-path/pull/60))
+  - feat: add basic tracing ([ipfs/go-path#59](https://github.com/ipfs/go-path/pull/59))
+- github.com/ipfs/go-peertaskqueue (v0.8.0 -> v0.8.1):
+  - chore: release v0.8.1
+  - feat: add PushTasksTruncated which only push a limited amount of tasks
+  - feat: add (*PeerTaskQueue).Clear which fully removes a peer
+  - sync: update CI config files (#26) ([ipfs/go-peertaskqueue#26](https://github.com/ipfs/go-peertaskqueue/pull/26))
+- github.com/ipfs/go-unixfs (v0.4.2 -> v0.4.4):
+  - chore: release v0.4.4
+  - fix: correctly handle return errors
+  - fix: correctly handle errors in balancedbuilder's Layout
+  - test: fix tests after hamt issues fixes
+  - Merge pull request from GHSA-q264-w97q-q778
+- github.com/ipfs/go-unixfsnode (v1.5.1 -> v1.5.2):
+  - Merge pull request from GHSA-4gj3-6r43-3wfc
+- github.com/ipfs/interface-go-ipfs-core (v0.8.2 -> v0.11.0):
+  - chore: release v0.11.0
+  - test: basic routing interface test
+  - chore: release v0.10.0 (#102) ([ipfs/interface-go-ipfs-core#102](https://github.com/ipfs/interface-go-ipfs-core/pull/102))
+  - feat: add RoutingAPI to CoreAPI
+  - chore: release 0.9.0 (#101) ([ipfs/interface-go-ipfs-core#101](https://github.com/ipfs/interface-go-ipfs-core/pull/101))
+  - feat: add namesys publish options (#94) ([ipfs/interface-go-ipfs-core#94](https://github.com/ipfs/interface-go-ipfs-core/pull/94))
+- github.com/ipld/go-car (v0.4.0 -> v0.5.0):
+  - chore: bump version to 0.5.0
+  - fix: remove use of ioutil
+  - run gofmt -s
+  - bump go.mod to Go 1.18 and run go fix
+  - bump go.mod to Go 1.18 and run go fix
+  - OpenReadWriteFile: add test
+  - blockstore: allow to pass a file to write in (#323) ([ipld/go-car#323](https://github.com/ipld/go-car/pull/323))
+  - feat: add `car inspect` command to cmd pkg (#320) ([ipld/go-car#320](https://github.com/ipld/go-car/pull/320))
+  - Separate `index.ReadFrom` tests
+  - Only read index codec during inspection
+  - Upgrade to the latest `go-car/v2`
+  - Empty identity CID should be indexed when options are set
+- github.com/libp2p/go-libp2p (v0.24.2 -> v0.26.3):
+  - Release v0.26.3 (#2197) ([libp2p/go-libp2p#2197](https://github.com/libp2p/go-libp2p/pull/2197))
+  - retract v0.26.1, release v0.26.2 (#2153) ([libp2p/go-libp2p#2153](https://github.com/libp2p/go-libp2p/pull/2153))
+  - rcmgr: fix JSON marshalling of ResourceManagerStat peer map (#2156) ([libp2p/go-libp2p#2156](https://github.com/libp2p/go-libp2p/pull/2156))
+  - release v0.26.1 ([libp2p/go-libp2p#2146](https://github.com/libp2p/go-libp2p/pull/2146))
+  - release v0.26.0 (#2133) ([libp2p/go-libp2p#2133](https://github.com/libp2p/go-libp2p/pull/2133))
+  - identify: add more detailed metrics (#2126) ([libp2p/go-libp2p#2126](https://github.com/libp2p/go-libp2p/pull/2126))
+  - autorelay: refactor relay finder and start autorelay after identify (#2120) ([libp2p/go-libp2p#2120](https://github.com/libp2p/go-libp2p/pull/2120))
+  - don't use the time value from the time.Ticker channel (#2127) ([libp2p/go-libp2p#2127](https://github.com/libp2p/go-libp2p/pull/2127))
+  - Wrap conn with metrics (#2131) ([libp2p/go-libp2p#2131](https://github.com/libp2p/go-libp2p/pull/2131))
+  - chore: update changelog for 0.26.0 (#2132) ([libp2p/go-libp2p#2132](https://github.com/libp2p/go-libp2p/pull/2132))
+  - circuitv2: Update proto files to proto3 (#2121) ([libp2p/go-libp2p#2121](https://github.com/libp2p/go-libp2p/pull/2121))
+  - swarm: remove parallel tests from swarm tests (#2130) ([libp2p/go-libp2p#2130](https://github.com/libp2p/go-libp2p/pull/2130))
+  - circuitv2: add a relay option to disable limits (#2125) ([libp2p/go-libp2p#2125](https://github.com/libp2p/go-libp2p/pull/2125))
+  - quic: fix stalled virtual listener (#2122) ([libp2p/go-libp2p#2122](https://github.com/libp2p/go-libp2p/pull/2122))
+  - swarm: add early muxer selection to swarm metrics (#2119) ([libp2p/go-libp2p#2119](https://github.com/libp2p/go-libp2p/pull/2119))
+  - metrics: add options to disable metrics and to set Prometheus registerer (#2116) ([libp2p/go-libp2p#2116](https://github.com/libp2p/go-libp2p/pull/2116))
+  - swarm: add ip_version to metrics (#2114) ([libp2p/go-libp2p#2114](https://github.com/libp2p/go-libp2p/pull/2114))
+  - Revert mistaken "Bump timeout"
+  - Bump timeout
+  - remove all circuit v1 related code (#2107) ([libp2p/go-libp2p#2107](https://github.com/libp2p/go-libp2p/pull/2107))
+  - quic: don't send detailed error messages when closing connections (#2112) ([libp2p/go-libp2p#2112](https://github.com/libp2p/go-libp2p/pull/2112))
+  - metrics: add no alloc metrics for eventbus, swarm, identify (#2108) ([libp2p/go-libp2p#2108](https://github.com/libp2p/go-libp2p/pull/2108))
+  - chore: fix typo in Changelog (#2111) ([libp2p/go-libp2p#2111](https://github.com/libp2p/go-libp2p/pull/2111))
+  - chore: update changelog (#2109) ([libp2p/go-libp2p#2109](https://github.com/libp2p/go-libp2p/pull/2109))
+  - chore: unify dashboard location (#2110) ([libp2p/go-libp2p#2110](https://github.com/libp2p/go-libp2p/pull/2110))
+  - autonat: add metrics (#2086) ([libp2p/go-libp2p#2086](https://github.com/libp2p/go-libp2p/pull/2086))
+  - relaymanager: do not start new relay if one already exists (#2093) ([libp2p/go-libp2p#2093](https://github.com/libp2p/go-libp2p/pull/2093))
+  - autonat: don't emit reachability changed events on address change (#2092) ([libp2p/go-libp2p#2092](https://github.com/libp2p/go-libp2p/pull/2092))
+  - chore: modify changelog entries (#2101) ([libp2p/go-libp2p#2101](https://github.com/libp2p/go-libp2p/pull/2101))
+  - Introduce a changelog (#2084) ([libp2p/go-libp2p#2084](https://github.com/libp2p/go-libp2p/pull/2084))
+  - use atomic.Int32 and atomic.Int64 (#2096) ([libp2p/go-libp2p#2096](https://github.com/libp2p/go-libp2p/pull/2096))
+  - change atomic.Value to atomic.Pointer (#2088) ([libp2p/go-libp2p#2088](https://github.com/libp2p/go-libp2p/pull/2088))
+  - use atomic.Bool instead of int32 operations (#2089) ([libp2p/go-libp2p#2089](https://github.com/libp2p/go-libp2p/pull/2089))
+  - sync: update CI config files (#2073) ([libp2p/go-libp2p#2073](https://github.com/libp2p/go-libp2p/pull/2073))
+  - chore: update examples to v0.25.1 (#2080) ([libp2p/go-libp2p#2080](https://github.com/libp2p/go-libp2p/pull/2080))
+  - v0.25.1 (#2082) ([libp2p/go-libp2p#2082](https://github.com/libp2p/go-libp2p/pull/2082))
+  - Start host in mocknet (#2078) ([libp2p/go-libp2p#2078](https://github.com/libp2p/go-libp2p/pull/2078))
+  - Release v0.25.0 (#2077) ([libp2p/go-libp2p#2077](https://github.com/libp2p/go-libp2p/pull/2077))
+  - identify: add some basic metrics (#2069) ([libp2p/go-libp2p#2069](https://github.com/libp2p/go-libp2p/pull/2069))
+  - p2p/test/quic: use contexts with a timeout for Connect calls (#2070) ([libp2p/go-libp2p#2070](https://github.com/libp2p/go-libp2p/pull/2070))
+  - feat!: rcmgr: Change LimitConfig to use LimitVal type (#2000) ([libp2p/go-libp2p#2000](https://github.com/libp2p/go-libp2p/pull/2000))
+  - identify: refactor sending of Identify pushes (#1984) ([libp2p/go-libp2p#1984](https://github.com/libp2p/go-libp2p/pull/1984))
+  - Update interop to match spec (#2049) ([libp2p/go-libp2p#2049](https://github.com/libp2p/go-libp2p/pull/2049))
+  - chore: git-ignore various flavors of qlog files (#2064) ([libp2p/go-libp2p#2064](https://github.com/libp2p/go-libp2p/pull/2064))
+  - rcmgr: add libp2p prefix to all metrics (#2063) ([libp2p/go-libp2p#2063](https://github.com/libp2p/go-libp2p/pull/2063))
+  - websocket: Replace gorilla websocket transport with nhooyr websocket transport (#1982) ([libp2p/go-libp2p#1982](https://github.com/libp2p/go-libp2p/pull/1982))
+  - rcmgr: Use prometheus SDK for rcmgr metrics (#2044) ([libp2p/go-libp2p#2044](https://github.com/libp2p/go-libp2p/pull/2044))
+  - autorelay: Split libp2p.EnableAutoRelay into 2 functions (#2022) ([libp2p/go-libp2p#2022](https://github.com/libp2p/go-libp2p/pull/2022))
+  - set names for eventbus event subscriptions (#2057) ([libp2p/go-libp2p#2057](https://github.com/libp2p/go-libp2p/pull/2057))
+  - Test cleanup (#2053) ([libp2p/go-libp2p#2053](https://github.com/libp2p/go-libp2p/pull/2053))
+  - metrics: use a single slice pool for all metrics tracer (#2054) ([libp2p/go-libp2p#2054](https://github.com/libp2p/go-libp2p/pull/2054))
+  - eventbus: add metrics (#2038) ([libp2p/go-libp2p#2038](https://github.com/libp2p/go-libp2p/pull/2038))
+  - quic: disable sending of Version Negotiation packets (#2015) ([libp2p/go-libp2p#2015](https://github.com/libp2p/go-libp2p/pull/2015))
+  - p2p/test: fix flaky notification test (#2051) ([libp2p/go-libp2p#2051](https://github.com/libp2p/go-libp2p/pull/2051))
+  - quic, tcp: only register Prometheus counters when metrics are enabled ([libp2p/go-libp2p#1971](https://github.com/libp2p/go-libp2p/pull/1971))
+  - p2p/test: add test for EvtLocalAddressesUpdated event (#2016) ([libp2p/go-libp2p#2016](https://github.com/libp2p/go-libp2p/pull/2016))
+  - quic / webtransport: extend test to test dialing draft-29 and v1 (#1957) ([libp2p/go-libp2p#1957](https://github.com/libp2p/go-libp2p/pull/1957))
+  - holepunch: fix flaky by not remove holepunch protocol handler (#1948) ([libp2p/go-libp2p#1948](https://github.com/libp2p/go-libp2p/pull/1948))
+  - use quic-go and webtransport-go from quic-go organization (#2040) ([libp2p/go-libp2p#2040](https://github.com/libp2p/go-libp2p/pull/2040))
+  - Migrate to test-plan composite action (#2039) ([libp2p/go-libp2p#2039](https://github.com/libp2p/go-libp2p/pull/2039))
+  - chore: remove license files from the eventbus package (#2042) ([libp2p/go-libp2p#2042](https://github.com/libp2p/go-libp2p/pull/2042))
+  - rcmgr: *: Always close connscope (#2037) ([libp2p/go-libp2p#2037](https://github.com/libp2p/go-libp2p/pull/2037))
+  - chore: remove textual roadmap in favor for Starmap (#2036) ([libp2p/go-libp2p#2036](https://github.com/libp2p/go-libp2p/pull/2036))
+  - swarm metrics: fix datasource for dashboard (#2024) ([libp2p/go-libp2p#2024](https://github.com/libp2p/go-libp2p/pull/2024))
+  - consistently use protocol.ID instead of strings (#2004) ([libp2p/go-libp2p#2004](https://github.com/libp2p/go-libp2p/pull/2004))
+  - swarm: add a basic metrics tracer (#1973) ([libp2p/go-libp2p#1973](https://github.com/libp2p/go-libp2p/pull/1973))
+  - Expose muxer ids (#2012) ([libp2p/go-libp2p#2012](https://github.com/libp2p/go-libp2p/pull/2012))
+  - Clean addresses with peer id before adding to addrbook (#2007) ([libp2p/go-libp2p#2007](https://github.com/libp2p/go-libp2p/pull/2007))
+  - feat: ci test-plans: Parse test timeout parameter for interop test (#2014) ([libp2p/go-libp2p#2014](https://github.com/libp2p/go-libp2p/pull/2014))
+  - Export resource manager errors (#2008) ([libp2p/go-libp2p#2008](https://github.com/libp2p/go-libp2p/pull/2008))
+  - peerstore: make it possible to use an empty peer ID (#2006) ([libp2p/go-libp2p#2006](https://github.com/libp2p/go-libp2p/pull/2006))
+  - Add ci flakiness score to readme (#2002) ([libp2p/go-libp2p#2002](https://github.com/libp2p/go-libp2p/pull/2002))
+  - rcmgr: fix: Ignore zero values when marshalling Limits. (#1998) ([libp2p/go-libp2p#1998](https://github.com/libp2p/go-libp2p/pull/1998))
+  - CI: Fast multidimensional Interop tests (#1991) ([libp2p/go-libp2p#1991](https://github.com/libp2p/go-libp2p/pull/1991))
+  - feat: add some users to the readme (#1981) ([libp2p/go-libp2p#1981](https://github.com/libp2p/go-libp2p/pull/1981))
+  - ci: run go generate as part of the go-check workflow (#1986) ([libp2p/go-libp2p#1986](https://github.com/libp2p/go-libp2p/pull/1986))
+  - switch to Google's Protobuf library, make protobufs compile with go generate ([libp2p/go-libp2p#1979](https://github.com/libp2p/go-libp2p/pull/1979))
+  - circuitv2: correctly set the transport in the ConnectionState (#1972) ([libp2p/go-libp2p#1972](https://github.com/libp2p/go-libp2p/pull/1972))
+  - roadmap: remove optimizations of the TCP-based handshake (#1959) ([libp2p/go-libp2p#1959](https://github.com/libp2p/go-libp2p/pull/1959))
+  - identify: remove support for Identify Delta ([libp2p/go-libp2p#1975](https://github.com/libp2p/go-libp2p/pull/1975))
+  - core: remove introspection package (#1978) ([libp2p/go-libp2p#1978](https://github.com/libp2p/go-libp2p/pull/1978))
+  - identify: remove old code targeting Go 1.17 (#1964) ([libp2p/go-libp2p#1964](https://github.com/libp2p/go-libp2p/pull/1964))
+  - add WebTransport to the list of default transports (#1915) ([libp2p/go-libp2p#1915](https://github.com/libp2p/go-libp2p/pull/1915))
+  - core/crypto: drop all OpenSSL code paths (#1953) ([libp2p/go-libp2p#1953](https://github.com/libp2p/go-libp2p/pull/1953))
+  - chore: use generic LRU cache (#1980) ([libp2p/go-libp2p#1980](https://github.com/libp2p/go-libp2p/pull/1980))
+- github.com/libp2p/go-libp2p-kad-dht (v0.20.0 -> v0.21.1):
+  - chore: bump to v0.21.1 (#821) ([libp2p/go-libp2p-kad-dht#821](https://github.com/libp2p/go-libp2p-kad-dht/pull/821))
+  - feat: send FIND_NODE request to peers on routing table refresh (#810) ([libp2p/go-libp2p-kad-dht#810](https://github.com/libp2p/go-libp2p-kad-dht/pull/810))
+  - chore: release v0.21.
+  - chore: Update to go libp2p v0.25 ([libp2p/go-libp2p-kad-dht#815](https://github.com/libp2p/go-libp2p-kad-dht/pull/815))
+- github.com/libp2p/go-libp2p-pubsub (v0.8.3 -> v0.9.0):
+  - chore: update to go-libp2p v0.25 (#517) ([libp2p/go-libp2p-pubsub#517](https://github.com/libp2p/go-libp2p-pubsub/pull/517))
+- github.com/libp2p/go-libp2p-routing-helpers (v0.6.0 -> v0.6.1):
+  - chore: release v0.6.1
+  - fix: cancel parallel routers
+- github.com/libp2p/go-msgio (v0.2.0 -> v0.3.0):
+  - release v0.3.0 (#39) ([libp2p/go-msgio#39](https://github.com/libp2p/go-msgio/pull/39))
+  - switch from deprecated gogo to google.golang.org/protobuf ([libp2p/go-msgio#38](https://github.com/libp2p/go-msgio/pull/38))
+  - sync: update CI config files (#36) ([libp2p/go-msgio#36](https://github.com/libp2p/go-msgio/pull/36))
+- github.com/lucas-clemente/quic-go (v0.31.1 -> v0.29.1):
+  - http3: fix double close of chan when using DontCloseRequestStream
+- github.com/multiformats/go-multistream (v0.3.3 -> v0.4.1):
+  - release v0.4.1 ([multiformats/go-multistream#101](https://github.com/multiformats/go-multistream/pull/101))
+  - Fix errors Is checking ([multiformats/go-multistream#100](https://github.com/multiformats/go-multistream/pull/100))
+  - release v0.4.0 (#93) ([multiformats/go-multistream#93](https://github.com/multiformats/go-multistream/pull/93))
+  - switch to Go's native fuzzing (#96) ([multiformats/go-multistream#96](https://github.com/multiformats/go-multistream/pull/96))
+  - Add not supported protocols to returned errors (#97) ([multiformats/go-multistream#97](https://github.com/multiformats/go-multistream/pull/97))
+  - Make MultistreamMuxer and Client APIs generic (#95) ([multiformats/go-multistream#95](https://github.com/multiformats/go-multistream/pull/95))
+  - remove MultistreamMuxer.NegotiateLazy (#92) ([multiformats/go-multistream#92](https://github.com/multiformats/go-multistream/pull/92))
+  - sync: update CI config files (#91) ([multiformats/go-multistream#91](https://github.com/multiformats/go-multistream/pull/91))
+- github.com/warpfork/go-wish (v0.0.0-20200122115046-b9ea61034e4a -> v0.0.0-20220906213052-39a1cc7a02d0):
+  - Update readme with deprecation info
+- github.com/whyrusleeping/cbor-gen (v0.0.0-20221220214510-0333c149dec0 -> v0.0.0-20230126041949-52956bd4c9aa):
+  - add setter to allow reuse of cborreader struct
+  - fix typo
+  - allow fields to be ignored ([whyrusleeping/cbor-gen#79](https://github.com/whyrusleeping/cbor-gen/pull/79))
+
+</details>
+
+### 👨‍👩‍👧‍👦 Contributors
+
+| Contributor | Commits | Lines ± | Files Changed |
+|-------------|---------|---------|---------------|
+| Dirk McCormick | 128 | +16757/-7211 | 387 |
+| Henrique Dias | 69 | +7599/-10016 | 316 |
+| hannahhoward | 88 | +8503/-4397 | 271 |
+| Jeromy Johnson | 244 | +6544/-4034 | 774 |
+| Marten Seemann | 64 | +4870/-5628 | 266 |
+| Steven Allen | 296 | +4769/-3517 | 972 |
+| Brian Tiger Chow | 250 | +5520/-2579 | 435 |
+| Jorropo | 64 | +4237/-3548 | 302 |
+| Sukun | 18 | +4327/-1093 | 132 |
+| Marco Munizaga | 35 | +2809/-1294 | 94 |
+| Gus Eggert | 20 | +2523/-1476 | 99 |
+| Adin Schmahmann | 15 | +683/-2625 | 69 |
+| Marcin Rataj | 73 | +2348/-882 | 133 |
+| whyrusleeping | 12 | +1683/-1338 | 23 |
+| Jeromy | 99 | +1754/-1181 | 453 |
+| Juan Batiz-Benet | 69 | +1182/-678 | 149 |
+| Lars Gierth | 31 | +827/-358 | 92 |
+| Paul Wolneykien | 2 | +670/-338 | 9 |
+| Laurent Senta | 16 | +806/-134 | 53 |
+| Henry | 19 | +438/-372 | 36 |
+| Michael Muré | 8 | +400/-387 | 19 |
+| Łukasz Magiera | 56 | +413/-354 | 117 |
+| Jakub Sztandera | 40 | +413/-251 | 100 |
+| Justin Johnson | 2 | +479/-165 | 5 |
+| Piotr Galar | 7 | +227/-378 | 24 |
+| Kevin Atkinson | 11 | +252/-232 | 49 |
+| web3-bot | 17 | +236/-240 | 59 |
+| Petar Maymounkov | 2 | +348/-84 | 11 |
+| Hector Sanjuan | 38 | +206/-223 | 85 |
+| Antonio Navarro Perez | 9 | +259/-95 | 17 |
+| keks | 22 | +233/-118 | 24 |
+| Ho-Sheng Hsiao | 3 | +170/-170 | 30 |
+| Lucas Molas | 6 | +266/-54 | 16 |
+| Mildred Ki'Lya | 4 | +280/-35 | 7 |
+| Steve Loeppky | 5 | +147/-156 | 9 |
+| rht | 14 | +97/-188 | 20 |
+| Prithvi Shahi | 6 | +89/-193 | 11 |
+| Ian Davis | 6 | +198/-75 | 11 |
+| taylor | 1 | +180/-89 | 8 |
+| ᴍᴀᴛᴛ ʙᴇʟʟ | 14 | +158/-104 | 18 |
+| Chris Boddy | 6 | +190/-45 | 8 |
+| Rod Vagg | 3 | +203/-28 | 15 |
+| Masih H. Derkani | 8 | +165/-61 | 16 |
+| Kevin Wallace | 4 | +194/-27 | 7 |
+| Mohsin Zaidi | 1 | +179/-41 | 5 |
+| ElPaisano | 1 | +110/-110 | 22 |
+| Simon Zhu | 6 | +177/-32 | 8 |
+| galargh | 9 | +80/-120 | 14 |
+| Tomasz Zdybał | 1 | +180/-1 | 4 |
+| dgrisham | 3 | +176/-2 | 4 |
+| Michael Avila | 3 | +116/-59 | 8 |
+| Raúl Kripalani | 2 | +85/-77 | 34 |
+| Dr Ian Preston | 11 | +101/-48 | 11 |
+| JP Hastings-Spital | 1 | +145/-0 | 2 |
+| George Antoniadis | 6 | +59/-58 | 43 |
+| Kevin Neaton | 2 | +97/-16 | 4 |
+| Adrian Lanzafame | 6 | +81/-25 | 7 |
+| Dennis Trautwein | 3 | +89/-9 | 5 |
+| mathew-cf | 2 | +82/-9 | 5 |
+| tg | 1 | +41/-33 | 1 |
+| Eng Zer Jun | 1 | +15/-54 | 5 |
+| zramsay | 4 | +15/-53 | 12 |
+| muXxer | 1 | +28/-33 | 4 |
+| Thomas Eizinger | 1 | +24/-37 | 4 |
+| Remco Bloemen | 2 | +28/-18 | 3 |
+| Manuel Alonso | 1 | +36/-9 | 1 |
+| vyzo | 4 | +26/-12 | 13 |
+| Djalil Dreamski | 3 | +27/-9 | 3 |
+| Thomas Gardner | 2 | +32/-3 | 4 |
+| Jan Winkelmann | 2 | +23/-12 | 8 |
+| Artem Andreenko | 1 | +16/-19 | 1 |
+| James Stanley | 1 | +34/-0 | 1 |
+| Brendan McMillion | 1 | +10/-17 | 3 |
+| Jack Loughran | 1 | +22/-0 | 3 |
+| Peter Wu | 2 | +12/-9 | 2 |
+| Gowtham G | 4 | +14/-7 | 4 |
+| Tor Arne Vestbø | 3 | +19/-1 | 3 |
+| Cory Schwartz | 1 | +8/-12 | 5 |
+| Peter Rabbitson | 1 | +15/-4 | 1 |
+| David Dias | 1 | +9/-9 | 1 |
+| Will Scott | 1 | +13/-4 | 2 |
+| Eric Myhre | 1 | +15/-2 | 1 |
+| Stephen Whitmore | 1 | +8/-8 | 1 |
+| Rafael Ramalho | 5 | +11/-5 | 5 |
+| Christian Couder | 1 | +14/-2 | 1 |
+| W. Trevor King | 2 | +9/-6 | 3 |
+| Steven Vandevelde | 1 | +11/-3 | 1 |
+| Knut Ahlers | 3 | +9/-5 | 3 |
+| Bob Potter | 1 | +3/-10 | 1 |
+| Russell Dempsey | 4 | +8/-4 | 4 |
+| Diogo Silva | 4 | +8/-4 | 4 |
+| Dave Justice | 1 | +8/-4 | 1 |
+| Andy Leap | 2 | +2/-10 | 2 |
+| divingpetrel | 1 | +7/-4 | 2 |
+| Iaroslav Gridin | 1 | +9/-2 | 1 |
+| Dominic Della Valle | 3 | +5/-5 | 3 |
+| Vijayee Kulkaa | 1 | +3/-6 | 1 |
+| Friedel Ziegelmayer | 3 | +6/-3 | 3 |
+| Stephen Solka | 1 | +1/-7 | 1 |
+| Richard Littauer | 3 | +4/-4 | 3 |
+| Franky W | 2 | +4/-4 | 2 |
+| Dimitris Apostolou | 2 | +4/-4 | 3 |
+| Adrian Ulrich | 1 | +8/-0 | 1 |
+| Masashi Salvador Mitsuzawa | 1 | +5/-1 | 1 |
+| Gabe | 1 | +3/-3 | 1 |
+| zuuluuz | 1 | +4/-1 | 1 |
+| myml | 1 | +5/-0 | 1 |
+| swedneck | 1 | +3/-1 | 1 |
+| Wayback Archiver | 1 | +2/-2 | 1 |
+| Vladimir Ivanov | 1 | +2/-2 | 1 |
+| Péter Szilágyi | 1 | +2/-2 | 1 |
+| Karthik Bala | 1 | +2/-2 | 1 |
+| Etienne Laurin | 1 | +1/-3 | 1 |
+| Shotaro Yamada | 1 | +2/-1 | 1 |
+| Robert Carlsen | 1 | +2/-1 | 1 |
+| Oli Evans | 1 | +2/-1 | 1 |
+| Dan McQuillan | 1 | +2/-1 | 1 |
+| susarlanikhilesh | 1 | +1/-1 | 1 |
+| mateon1 | 1 | +1/-1 | 1 |
+| kpcyrd | 1 | +1/-1 | 1 |
+| bbenshoof | 1 | +1/-1 | 1 |
+| ZenGround0 | 1 | +1/-1 | 1 |
+| Will Hawkins | 1 | +1/-1 | 1 |
+| Tommi Virtanen | 1 | +1/-1 | 1 |
+| Seungbae Yu | 1 | +1/-1 | 1 |
+| Riishab Joshi | 1 | +1/-1 | 1 |
+| Kubo Mage | 1 | +1/-1 | 1 |
+| Ivan | 1 | +1/-1 | 1 |
+| Guillaume Renault | 1 | +1/-1 | 1 |
+| Anjor Kanekar | 1 | +1/-1 | 1 |
+| Andrew Chin | 1 | +1/-1 | 1 |
+| Abdul Rauf | 1 | +1/-1 | 1 |
+| makeworld | 1 | +1/-0 | 1 |
diff --git a/docs/changelogs/v0.3.md b/docs/changelogs/v0.3.md
index 5d37a1b52ad7f8eb2d4c5e64d67c5f39c9fbffb4..61c2f431e976d7526ebb8343599ba11989c8730a 100644
--- a/docs/changelogs/v0.3.md
+++ b/docs/changelogs/v0.3.md
@@ -46,7 +46,7 @@ test coverage.
 ## v0.3.10 - 2015-12-07
 
 This patch update introduces the 'ipfs update' command which will be used for
-future ipfs updates along with a few other bugfixes and documentation
+future ipfs updates along with a few other bug fixes and documentation
 improvements.
 
 
@@ -156,7 +156,7 @@ NOTICE: Version 0.3.8 also requires golang version 1.5.1 or higher.
   * use go1.5's built in trailers, no more failures (@whyrusleeping)
   * fix random bitswap hangs (@whyrusleeping)
   * rate limit fd usage (@whyrusleeping)
-  * fix panic in bitswap ratelimiting (@whyrusleeping)
+  * fix panic in bitswap rate limiting (@whyrusleeping)
 
 * Tool Changes
   * --empty-repo option for init (@prusnak)
@@ -264,7 +264,7 @@ fixes (yet again) windows builds.
   * remove deadcode @lgierth @whyrusleeping
   * reduced number of logging libs to 2 (soon to be 1) @rht
   * dial address filtering @whyrusleeping
-  * prometheus metrics @lgierth
+  * Prometheus metrics @lgierth
   * new index page for gateway @krl @cryptix
   * move ping to separate protocol @whyrusleeping
   * add events to bitswap for a dashboard @whyrusleeping
@@ -340,9 +340,9 @@ This patch improves overall stability and performance
 
 This patch update fixes various issues, in particular:
 - windows support (0.3.0 had broken it)
-- commandline parses spaces correctly.
+- command line parses spaces correctly.
 
-* much improved commandline parsing by @AtnNn
+* much improved command line parsing by @AtnNn
 * improved dockerfile by @luzifer
 * add cmd cleanup by @wking
 * fix flatfs windows support by @tv42 and @gatesvp
@@ -354,7 +354,7 @@ This patch update fixes various issues, in particular:
 
 ## v0.3.2 - 2015-04-22
 
-This patch update implements multicast dns as well as fxing a few test issues.
+This patch update implements multicast dns as well as fixing a few test issues.
 
 * implement mdns peer discovery @whyrusleeping
 * fix mounting issues in sharness tests @chriscool
@@ -404,6 +404,6 @@ What to expect:
 
 * other
   * bash completion is now available
-  * ipfs stats bw -- bandwidth meetering
+  * ipfs stats bw -- bandwidth metering
 
 And many more things.
diff --git a/docs/changelogs/v0.4.md b/docs/changelogs/v0.4.md
index 7096d23272a73dd60085a5270fb1ade10333a78f..5abf5df67b532119684fe08ebacd8cf853263598 100644
--- a/docs/changelogs/v0.4.md
+++ b/docs/changelogs/v0.4.md
@@ -306,7 +306,7 @@ handshake).
 
 ### Commands
 
-This release brings no new commands but does introduce a few changes, bugfixes,
+This release brings no new commands but does introduce a few changes, bug fixes,
 and enhancements. This section is hardly complete but it lists the most
 noticeable changes.
 
@@ -1122,7 +1122,7 @@ earlier on start.
   - add function to marshal raw nodes to json ([ipfs/go-merkledag#36](https://github.com/ipfs/go-merkledag/pull/36))
   - fix some performance regressions when reading protobuf nodes ([ipfs/go-merkledag#34](https://github.com/ipfs/go-merkledag/pull/34))
 - github.com/ipfs/go-metrics-interface:
-  - update the counter interface to match prometheus ([ipfs/go-metrics-interface#2](https://github.com/ipfs/go-metrics-interface/pull/2))
+  - update the counter interface to match Prometheus ([ipfs/go-metrics-interface#2](https://github.com/ipfs/go-metrics-interface/pull/2))
 - github.com/ipfs/go-mfs:
   - Return node from FlushPath ([ipfs/go-mfs#72](https://github.com/ipfs/go-mfs/pull/72))
   - Wire up context to FlushPath ([ipfs/go-mfs#70](https://github.com/ipfs/go-mfs/pull/70))
@@ -1349,7 +1349,7 @@ Second up, `ipfs ls` now has a new `--stream` flag. In IPFS, very large
 directories (e.g., Wikipedia) are split up into multiple chunks (shards) as
 there are too many entries to fit in a single block. Unfortunately, `ipfs ls`
 buffers the _entire_ file list in memory and then sorts it. This means that
-`ipfs ls /ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki` (wikipedia)
+`ipfs ls /ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco/wiki` (Wikipedia)
 will take a _very_ long time to return anything (it'll also use quite a bit of
 memory).
 
@@ -1541,7 +1541,7 @@ The next steps are:
   - [CORS] Bubble go-ipfs-cmds 2.0.10 - Updates CORS library ([ipfs/go-ipfs#5919](https://github.com/ipfs/go-ipfs/pull/5919))
   - reduce verbosity of daemon start ([ipfs/go-ipfs#5904](https://github.com/ipfs/go-ipfs/pull/5904))
   - feat: update to Web UI v2.3.2 ([ipfs/go-ipfs#5899](https://github.com/ipfs/go-ipfs/pull/5899))
-  - CoreAPI: Don't panic when testing incomplete implementions ([ipfs/go-ipfs#5900](https://github.com/ipfs/go-ipfs/pull/5900))
+  - CoreAPI: Don't panic when testing incomplete implementations ([ipfs/go-ipfs#5900](https://github.com/ipfs/go-ipfs/pull/5900))
   - gateway: fix CORs headers ([ipfs/go-ipfs#5893](https://github.com/ipfs/go-ipfs/pull/5893))
   - Local Gateway option ([ipfs/go-ipfs#5649](https://github.com/ipfs/go-ipfs/pull/5649))
   - Show hash on gateway ([ipfs/go-ipfs#5830](https://github.com/ipfs/go-ipfs/pull/5830))
@@ -1590,7 +1590,7 @@ The next steps are:
   - cmds/bitswap: sort wantlist ([ipfs/go-ipfs#5759](https://github.com/ipfs/go-ipfs/pull/5759))
   - cmds/update: use new cmds lib ([ipfs/go-ipfs#5730](https://github.com/ipfs/go-ipfs/pull/5730))
   - cmds/file: use new cmds lib ([ipfs/go-ipfs#5756](https://github.com/ipfs/go-ipfs/pull/5756))
-  - cmds: remove reduntant func ([ipfs/go-ipfs#5750](https://github.com/ipfs/go-ipfs/pull/5750))
+  - cmds: remove redundant func ([ipfs/go-ipfs#5750](https://github.com/ipfs/go-ipfs/pull/5750))
   - commands/refs: use new cmds ([ipfs/go-ipfs#5679](https://github.com/ipfs/go-ipfs/pull/5679))
   - commands/pin: use new cmds lib ([ipfs/go-ipfs#5674](https://github.com/ipfs/go-ipfs/pull/5674))
   - commands/boostrap: use new cmds ([ipfs/go-ipfs#5678](https://github.com/ipfs/go-ipfs/pull/5678))
@@ -1656,7 +1656,7 @@ The next steps are:
   - add codecs for Dash blocks, tx ([ipfs/go-cid#78](https://github.com/ipfs/go-cid/pull/78))
 - github.com/ipfs/go-cidutil:
   - Fix Travis CI to run all tests. ([ipfs/go-cidutil#11](https://github.com/ipfs/go-cidutil/pull/11))
-  - Changes needed for `--cid-base` option in go-ipfs (simplified vesion) ([ipfs/go-cidutil#10](https://github.com/ipfs/go-cidutil/pull/10))
+  - Changes needed for `--cid-base` option in go-ipfs (simplified version) ([ipfs/go-cidutil#10](https://github.com/ipfs/go-cidutil/pull/10))
   - add a utility method for sorting CID slices ([ipfs/go-cidutil#5](https://github.com/ipfs/go-cidutil/pull/5))
 - github.com/libp2p/go-conn-security:
   - fix link to usage example in README ([libp2p/go-conn-security#4](https://github.com/libp2p/go-conn-security/pull/4))
@@ -1844,7 +1844,7 @@ The next steps are:
   - fix a fetch deadlock on error ([ipfs/go-merkledag#21](https://github.com/ipfs/go-merkledag/pull/21))
   - Wait for all go routines to finish before function returns ([ipfs/go-merkledag#19](https://github.com/ipfs/go-merkledag/pull/19))
 - github.com/ipfs/go-metrics-prometheus:
-  - use prometheus instead of gxed ([ipfs/go-metrics-prometheus#3](https://github.com/ipfs/go-metrics-prometheus/pull/3))
+  - use Prometheus instead of gxed ([ipfs/go-metrics-prometheus#3](https://github.com/ipfs/go-metrics-prometheus/pull/3))
 - github.com/ipfs/go-mfs:
   - fix(mv): dst filename error ([ipfs/go-mfs#62](https://github.com/ipfs/go-mfs/pull/62))
   - fix over-wait in WaitPub ([ipfs/go-mfs#53](https://github.com/ipfs/go-mfs/pull/53))
@@ -2096,7 +2096,7 @@ You can track progress in https://github.com/ipfs/go-ipfs/issues/4498
 We introduced new path type which introduces distinction between IPLD and
 IPFS (unixfs) paths. From now on paths prefixed with `/ipld/` will always
 use IPLD link traversal and `/ipfs/` will use unixfs path resolver, which
-takes things like shardnig into account.
+takes things like sharding into account.
 
 Note that this is only initial support and there likely are some bugs in
 how the paths are handled internally, so consider this feature
@@ -2203,7 +2203,7 @@ Fixes (i.e., users take note):
   - refactor(command): modify int to int64 ([ipfs/go-ipfs#5612](https://github.com/ipfs/go-ipfs/pull/5612))
   - fix(core): ipns config RecordLifetime panic ([ipfs/go-ipfs#5648](https://github.com/ipfs/go-ipfs/pull/5648))
   - simplify dag put and correctly take pin lock ([ipfs/go-ipfs#5667](https://github.com/ipfs/go-ipfs/pull/5667))
-  - fix prometheus concurrent map write bug ([ipfs/go-ipfs#5706](https://github.com/ipfs/go-ipfs/pull/5706))
+  - fix Prometheus concurrent map write bug ([ipfs/go-ipfs#5706](https://github.com/ipfs/go-ipfs/pull/5706))
 
 Regressions Fixes (fixes for bugs introduced since the last release):
   - namesys: properly attach path in name.Resolve ([ipfs/go-ipfs#5660](https://github.com/ipfs/go-ipfs/pull/5660))
@@ -2291,7 +2291,7 @@ Internal:
   - fix: maketarball.sh for OSX ([ipfs/go-ipfs#5575](https://github.com/ipfs/go-ipfs/pull/5575))
   - test the correct return value when checking directory size ([ipfs/go-ipfs#5580](https://github.com/ipfs/go-ipfs/pull/5580))
   - coreapi unixfs: remove Cat ([ipfs/go-ipfs#5574](https://github.com/ipfs/go-ipfs/pull/5574))
-  - Explicitally use BufferedDAG after removing Batch from importers ([ipfs/go-ipfs#5626](https://github.com/ipfs/go-ipfs/pull/5626))
+  - Explicitly use BufferedDAG after removing Batch from importers ([ipfs/go-ipfs#5626](https://github.com/ipfs/go-ipfs/pull/5626))
 
 Cleanup:
   - Fix some weird code in core/coreunix/add.go ([ipfs/go-ipfs#5354](https://github.com/ipfs/go-ipfs/pull/5354))
@@ -2337,7 +2337,7 @@ github.com/ipfs/go-datastore
 github.com/ipfs/go-cid
   - Add tests for Set type ([ipfs/go-cid#63](https://github.com/ipfs/go-cid/pull/63))
   - Create new Builder interface for creating CIDs. ([ipfs/go-cid#53](https://github.com/ipfs/go-cid/pull/53))
-  - cid-fmt Enhancments ([ipfs/go-cid#61](https://github.com/ipfs/go-cid/pull/61))
+  - cid-fmt enhancements ([ipfs/go-cid#61](https://github.com/ipfs/go-cid/pull/61))
   - add String benchmark ([ipfs/go-cid#44](https://github.com/ipfs/go-cid/pull/44))
   - add a streaming CID set ([ipfs/go-cid#67](https://github.com/ipfs/go-cid/pull/67))
   - Extract non-core functionality from go-cid into go-cidutil ([ipfs/go-cid#69](https://github.com/ipfs/go-cid/pull/69))
@@ -2362,7 +2362,7 @@ github.com/ipfs/go-metrics-prometheus
   - use an existing metric when it has already been registered ([ipfs/go-metrics-prometheus#1](https://github.com/ipfs/go-metrics-prometheus/pull/1))
 
 github.com/ipfs/go-metrics-interface
-  - update the counter interface to match prometheus ([ipfs/go-metrics-interface#2](https://github.com/ipfs/go-metrics-interface/pull/2))
+  - update the counter interface to match Prometheus ([ipfs/go-metrics-interface#2](https://github.com/ipfs/go-metrics-interface/pull/2))
 
 github.com/ipfs/go-ipld-format
   - add copy dagservice function ([ipfs/go-ipld-format#41](https://github.com/ipfs/go-ipld-format/pull/41))
@@ -2624,18 +2624,18 @@ add it yourself, but doing so was not easy). With this, ipfs can ingest and
 operate over Git repositories and commit graphs directly. For more information
 on this, see [the go-ipld-git repo](https://github.com/ipfs/go-ipld-git).
 
-Finally, we've included many smaller bugfixes, refactorings, improved
+Finally, we've included many smaller bug fixes, refactorings, improved
 documentation, and a good bit more. For the full details, see the changelog
 below.
 
 ## v0.4.16-rc3 2018-07-09
-- Bugfixes
+- Bug fixes
   - Fix dht commands when ipns over pubsub is enabled ([ipfs/go-ipfs#5200](https://github.com/ipfs/go-ipfs/pull/5200))
   - Fix content routing when ipns over pubsub is enabled ([ipfs/go-ipfs#5200](https://github.com/ipfs/go-ipfs/pull/5200))
   - Correctly handle multi-hop dnslink resolution ([ipfs/go-ipfs#5202](https://github.com/ipfs/go-ipfs/pull/5202))
 
 ## v0.4.16-rc2 2018-07-05
-- Bugfixes
+- Bug fixes
   - Fix usage of file name vs path name in adder ([ipfs/go-ipfs#5167](https://github.com/ipfs/go-ipfs/pull/5167))
   - Fix `ipfs update` working with migrations ([ipfs/go-ipfs#5194](https://github.com/ipfs/go-ipfs/pull/5194))
 - Documentation
@@ -2656,7 +2656,7 @@ below.
   - Add package overview comments to coreapi ([ipfs/go-ipfs#5108](https://github.com/ipfs/go-ipfs/pull/5108))
   - Add README to docs folder ([ipfs/go-ipfs#5095](https://github.com/ipfs/go-ipfs/pull/5095))
   - Add system requirements to README ([ipfs/go-ipfs#5137](https://github.com/ipfs/go-ipfs/pull/5137))
-- Bugfixes
+- Bug fixes
   - Fix goroutine leak in pin verify ([ipfs/go-ipfs#5011](https://github.com/ipfs/go-ipfs/pull/5011))
   - Fix commit string in version ([ipfs/go-ipfs#4982](https://github.com/ipfs/go-ipfs/pull/4982))
   - Fix `key rename` command output error ([ipfs/go-ipfs#4962](https://github.com/ipfs/go-ipfs/pull/4962))
@@ -2688,7 +2688,7 @@ below.
   - Disable the MacOS tests in jenkins ([ipfs/go-ipfs#5119](https://github.com/ipfs/go-ipfs/pull/5119))
   - Make republisher test robust against timing issues ([ipfs/go-ipfs#5125](https://github.com/ipfs/go-ipfs/pull/5125))
   - Archive sharness trash dirs in jenkins ([ipfs/go-ipfs#5071](https://github.com/ipfs/go-ipfs/pull/5071))
-  - Fixup DHT sharness tests ([ipfs/go-ipfs#5114](https://github.com/ipfs/go-ipfs/pull/5114))
+  - Fix up DHT sharness tests ([ipfs/go-ipfs#5114](https://github.com/ipfs/go-ipfs/pull/5114))
 - Dependencies
   - Update go-ipld-git to fix mergetag resolving ([ipfs/go-ipfs#4988](https://github.com/ipfs/go-ipfs/pull/4988))
   - Fix duplicate /x/sys imports ([ipfs/go-ipfs#5068](https://github.com/ipfs/go-ipfs/pull/5068))
@@ -2757,7 +2757,7 @@ access.
   - Add docs for --profile=lowpower ([ipfs/go-ipfs#4970](https://github.com/ipfs/go-ipfs/pull/4970))
   - Improve Windows build documentation ([ipfs/go-ipfs#4691](https://github.com/ipfs/go-ipfs/pull/4691))
 
-- Bugfixes
+- Bug fixes
   - Check CIDs in base case when diffing nodes ([ipfs/go-ipfs#4767](https://github.com/ipfs/go-ipfs/pull/4767))
   - Support for CIDv1 with custom mhtype in `ipfs block put` ([ipfs/go-ipfs#4563](https://github.com/ipfs/go-ipfs/pull/4563))
   - Clean path in DagArchive ([ipfs/go-ipfs#4743](https://github.com/ipfs/go-ipfs/pull/4743))
@@ -2806,7 +2806,7 @@ access.
 
 ## v0.4.14 2018-03-22
 
-Ipfs 0.4.14 is a big release with a large number of improvements and bugfixes.
+Ipfs 0.4.14 is a big release with a large number of improvements and bug fixes.
 It is also the first release of 2018, and our first release in over three
 months. The release took longer than expected due to our refactoring and
 extracting of our commands library. This refactor had two stages.  The first
@@ -2920,7 +2920,7 @@ remove them before updating.
   - Add godocs for path module ([ipfs/go-ipfs#4689](https://github.com/ipfs/go-ipfs/pull/4689))
   - Add godocs for pin module ([ipfs/go-ipfs#4696](https://github.com/ipfs/go-ipfs/pull/4696))
   - Update link to filestore experimental status ([ipfs/go-ipfs#4557](https://github.com/ipfs/go-ipfs/pull/4557))
-- Bugfixes
+- Bug fixes
   - Remove trailing slash in ipfs get paths, fixes #3729 ([ipfs/go-ipfs#4365](https://github.com/ipfs/go-ipfs/pull/4365))
   - fix deadlock in bitswap sessions ([ipfs/go-ipfs#4407](https://github.com/ipfs/go-ipfs/pull/4407))
   - Fix two race conditions (and possibly go routine leaks) in commands ([ipfs/go-ipfs#4406](https://github.com/ipfs/go-ipfs/pull/4406))
@@ -2973,7 +2973,7 @@ remove them before updating.
 Ipfs 0.4.13 is a patch release that fixes two high priority issues that were
 discovered in the 0.4.12 release.
 
-Bugfixes:
+Bug fixes:
   - Fix periodic bitswap deadlock ([ipfs/go-ipfs#4386](https://github.com/ipfs/go-ipfs/pull/4386))
   - Fix badgerds crash on startup ([ipfs/go-ipfs#4384](https://github.com/ipfs/go-ipfs/pull/4384))
 
@@ -3037,7 +3037,7 @@ filed pull requests, and contributed in any other way to this release!
   - Add more info about `ipfs add` chunker option ([ipfs/go-ipfs#4306](https://github.com/ipfs/go-ipfs/pull/4306))
   - Remove cruft in readme and mention discourse forum ([ipfs/go-ipfs#4345](https://github.com/ipfs/go-ipfs/pull/4345))
   - Add note about updating before reporting issues ([ipfs/go-ipfs#4361](https://github.com/ipfs/go-ipfs/pull/4361))
-- Bugfixes
+- Bug fixes
   - Fix FreeBSD build issues ([ipfs/go-ipfs#4275](https://github.com/ipfs/go-ipfs/pull/4275))
   - Don't crash when Datastore.StorageMax is not defined ([ipfs/go-ipfs#4246](https://github.com/ipfs/go-ipfs/pull/4246))
   - Do not call 'Connect' on NewStream in bitswap ([ipfs/go-ipfs#4317](https://github.com/ipfs/go-ipfs/pull/4317))
@@ -3176,7 +3176,7 @@ you.
   - Update release docs ([ipfs/go-ipfs#4165](https://github.com/ipfs/go-ipfs/pull/4165))
   - Add documentation for datastore configs ([ipfs/go-ipfs#4223](https://github.com/ipfs/go-ipfs/pull/4223))
   - General update and clean-up of docs ([ipfs/go-ipfs#4222](https://github.com/ipfs/go-ipfs/pull/4222))
-- Bugfixes
+- Bug fixes
   - Fix shutdown check in t0023 ([ipfs/go-ipfs#3969](https://github.com/ipfs/go-ipfs/pull/3969))
   - Fix pinning of unixfs sharded directories ([ipfs/go-ipfs#3975](https://github.com/ipfs/go-ipfs/pull/3975))
   - Show escaped url in gateway 404 message ([ipfs/go-ipfs#4005](https://github.com/ipfs/go-ipfs/pull/4005))
@@ -3197,7 +3197,7 @@ you.
 ### v0.4.10 - 2017-06-27
 
 Ipfs 0.4.10 is a patch release that contains several exciting new features,
-bugfixes and general improvements. Including new commands, easier corruption
+bug fixes and general improvements. Including new commands, easier corruption
 recovery, and a generally cleaner codebase.
 
 The `ipfs pin` command has two new subcommands, `verify` and `update`. `ipfs
@@ -3258,7 +3258,7 @@ other requested improvements. See below for the full list of changes.
   - Change 'neccessary' to 'necessary' ([ipfs/go-ipfs#3941](https://github.com/ipfs/go-ipfs/pull/3941))
   - README.md: add Nix to the linux package managers ([ipfs/go-ipfs#3939](https://github.com/ipfs/go-ipfs/pull/3939))
   - More verbose errors in filestore ([ipfs/go-ipfs#3964](https://github.com/ipfs/go-ipfs/pull/3964))
-- Bugfixes
+- Bug fixes
   - Fix typo in message when file size check fails ([ipfs/go-ipfs#3895](https://github.com/ipfs/go-ipfs/pull/3895))
   - Clean up bitswap ledgers when disconnecting ([ipfs/go-ipfs#3437](https://github.com/ipfs/go-ipfs/pull/3437))
   - Make odds of 'process added after close' panic less likely ([ipfs/go-ipfs#3940](https://github.com/ipfs/go-ipfs/pull/3940))
@@ -3270,7 +3270,7 @@ other requested improvements. See below for the full list of changes.
 
 ### v0.4.9 - 2017-04-30
 
-Ipfs 0.4.9 is a maintenance release that contains several useful bugfixes and
+Ipfs 0.4.9 is a maintenance release that contains several useful bug fixes and
 improvements. Notably, `ipfs add` has gained the ability to select which CID
 version will be output. The common ipfs hash that looks like this:
 `QmRjNgF2mRLDT8AzCPsQbw1EYF2hDTFgfUmJokJPhCApYP` is a multihash. Multihashes
@@ -3307,8 +3307,8 @@ Aside from the CID flag, there were many other changes as noted below:
   - Change issue template to use Severity instead of Priority ([ipfs/go-ipfs#3834](https://github.com/ipfs/go-ipfs/pull/3834))
   - Fix link to commit hook script in contribute.md ([ipfs/go-ipfs#3863](https://github.com/ipfs/go-ipfs/pull/3863))
   - Fix install_unsupported for openbsd, add docs ([ipfs/go-ipfs#3880](https://github.com/ipfs/go-ipfs/pull/3880))
-- Bugfixes
-  - Fix wanlist typo in prometheus metric name ([ipfs/go-ipfs#3841](https://github.com/ipfs/go-ipfs/pull/3841))
+- Bug fixes
+  - Fix wantlist typo in Prometheus metric name ([ipfs/go-ipfs#3841](https://github.com/ipfs/go-ipfs/pull/3841))
   - Fix `make install` not using ldflags for git hash ([ipfs/go-ipfs#3838](https://github.com/ipfs/go-ipfs/pull/3838))
   - Fix `make install` not installing dependencies ([ipfs/go-ipfs#3848](https://github.com/ipfs/go-ipfs/pull/3848))
   - Fix erroneous Cache-Control: immutable on dir listings ([ipfs/go-ipfs#3870](https://github.com/ipfs/go-ipfs/pull/3870))
@@ -3323,11 +3323,11 @@ Aside from the CID flag, there were many other changes as noted below:
 
 ### v0.4.8 - 2017-03-29
 
-Ipfs 0.4.8 brings with it several improvements, bugfixes, documentation
+Ipfs 0.4.8 brings with it several improvements, bug fixes, documentation
 improvements, and the long awaited directory sharding code.
 
 Currently, when too many items are added into a unixfs directory, the object
-gets too large and you may experience issues. To pervent this problem, and
+gets too large and you may experience issues. To prevent this problem, and
 generally make working really large directories more efficient, we have
 implemented a HAMT structure for unixfs. To enable this feature, run:
 ```
@@ -3357,7 +3357,7 @@ look at all the other cool things added in 0.4.8 below.
 	- Improve 'name' and 'key' helptexts ([ipfs/go-ipfs#3806](https://github.com/ipfs/go-ipfs/pull/3806))
 	- Update link to paper in dev.md ([ipfs/go-ipfs#3812](https://github.com/ipfs/go-ipfs/pull/3812))
 	- Add test to enforce helptext on commands ([ipfs/go-ipfs#2648](https://github.com/ipfs/go-ipfs/pull/2648))
-- Bugfixes
+- Bug fixes
 	- Remove bloom filter check on Put call in blockstore ([ipfs/go-ipfs#3782](https://github.com/ipfs/go-ipfs/pull/3782))
 	- Re-add the GOPATH checking functionality ([ipfs/go-ipfs#3787](https://github.com/ipfs/go-ipfs/pull/3787))
 	- Use fsrepo.IsInitialized to test for initialization ([ipfs/go-ipfs#3805](https://github.com/ipfs/go-ipfs/pull/3805))
@@ -3397,7 +3397,7 @@ stream multiplexing protocol was available previously via the
 `--enable-mplex-experiment` daemon flag, but has now graduated to being 'less
 experimental' and no longer requires the flag to use it.
 
-Aside from those, we have a good number of bugfixes, perf improvements and new
+Aside from those, we have a good number of bug fixes, perf improvements and new
 tests. Heres a list of highlights:
 
 - Features
@@ -3416,7 +3416,7 @@ tests. Heres a list of highlights:
 - Documentation
 	- Add Arch Linux install instructions to readme ([ipfs/go-ipfs#3742](https://github.com/ipfs/go-ipfs/pull/3742))
 	- Improve release checklist document ([ipfs/go-ipfs#3717](https://github.com/ipfs/go-ipfs/pull/3717))
-- Bugfixes
+- Bug fixes
 	- Fix drive root parsing on windows ([ipfs/go-ipfs#3328](https://github.com/ipfs/go-ipfs/pull/3328))
 	- Fix panic in ipfs get when passing no parameters to API ([ipfs/go-ipfs#3768](https://github.com/ipfs/go-ipfs/pull/3768))
 	- Fix breakage of `ipfs pin add` api output ([ipfs/go-ipfs#3760](https://github.com/ipfs/go-ipfs/pull/3760))
@@ -3437,7 +3437,7 @@ tests. Heres a list of highlights:
 
 ### v0.4.6 - 2017-02-21
 
-Ipfs 0.4.6 contains several bugfixes related to migrations and also contains a
+Ipfs 0.4.6 contains several bug fixes related to migrations and also contains a
 few other improvements to other parts of the codebase. Notably:
 
 - The default config will now contain some ipv6 addresses for bootstrap nodes.
@@ -3454,7 +3454,7 @@ few other improvements to other parts of the codebase. Notably:
 - Documentation
 	- Add the snap installation instructions ([ipfs/go-ipfs#3663](https://github.com/ipfs/go-ipfs/pull/3663))
 	- Add closed PRs, Issues throughput ([ipfs/go-ipfs#3602](https://github.com/ipfs/go-ipfs/pull/3602))
-- Bugfixes
+- Bug fixes
 	- Fix auto-migration on docker nodes ([ipfs/go-ipfs#3698](https://github.com/ipfs/go-ipfs/pull/3698))
 	- Update flatfs to v1.1.2, fixing directory fd issue ([ipfs/go-ipfs#3711](https://github.com/ipfs/go-ipfs/pull/3711))
 - General Changes and Refactorings
@@ -3529,7 +3529,7 @@ few other improvements to other parts of the codebase. Notably:
 	- Fix issue where wantlist fullness wasn't included in messages  ([ipfs/go-ipfs#3461](https://github.com/ipfs/go-ipfs/pull/3461))
 	- Only pass keys down newBlocks chan in bitswap   ([ipfs/go-ipfs#3271](https://github.com/ipfs/go-ipfs/pull/3271))
 
-- Bugfixes
+- Bug fixes
 	- gateway: fix --writable flag  ([ipfs/go-ipfs#3206](https://github.com/ipfs/go-ipfs/pull/3206))
 	- Fix relative seek in unixfs not expanding file properly   ([ipfs/go-ipfs#3095](https://github.com/ipfs/go-ipfs/pull/3095))
 	- Update multicodec service names for ipfs services  ([ipfs/go-ipfs#3132](https://github.com/ipfs/go-ipfs/pull/3132))
@@ -3676,7 +3676,7 @@ expected, but none was given: [ipfs/go-ipfs#3050](https://github.com/ipfs/go-ipf
 
 ## v0.4.3-rc2 - 2016-08-04
 
-This release includes bugfixes and fixes for regressions that were introduced
+This release includes bug fixes and fixes for regressions that were introduced
 between 0.4.2 and 0.4.3-rc1.
 
 - Regressions
@@ -3716,7 +3716,7 @@ This is the first Release Candidate. Unless there are vulnerabilities or regress
   - Content Providers are now stored on disk to gain savings on process memory. (@whyrusleeping, [ipfs/go-ipfs#2804](https://github.com/ipfs/go-ipfs/pull/2804), [ipfs/go-ipfs#2860](https://github.com/ipfs/go-ipfs/pull/2860))
   - Migrations of the fs-repo (usually stored at `~/.ipfs`) now run automatically. If there's a TTY available, you'll get prompted when running `ipfs daemon`, and in addition you can use the `--migrate=true` or `--migrate=false` options to avoid the prompt. (@whyrusleeping, @lgierth, [ipfs/go-ipfs#2939](https://github.com/ipfs/go-ipfs/pull/2939))
   - The internal naming of blocks in the blockstore has changed, which requires a migration of the fs-repo, from version 3 to 4. (@whyrusleeping, [ipfs/go-ipfs#2903](https://github.com/ipfs/go-ipfs/pull/2903))
-  - We now automatically raise the file descriptor limit to 1024 if neccessary. (@whyrusleeping, [ipfs/go-ipfs#2884](https://github.com/ipfs/go-ipfs/pull/2884), [ipfs/go-ipfs#2891](https://github.com/ipfs/go-ipfs/pull/2891))
+  - We now automatically raise the file descriptor limit to 1024 if necessary. (@whyrusleeping, [ipfs/go-ipfs#2884](https://github.com/ipfs/go-ipfs/pull/2884), [ipfs/go-ipfs#2891](https://github.com/ipfs/go-ipfs/pull/2891))
   - After a long struggle with deadlocks and hanging connections, we've decided to disable the uTP transport by default for now. (@whyrusleeping, [ipfs/go-ipfs#2840](https://github.com/ipfs/go-ipfs/pull/2840), [ipfs/go-libp2p-transport@88244000](https://github.com/ipfs/go-libp2p-transport/commit/88244000f0ce8851ffcfbac746ebc0794b71d2a4))
   - There is now documentation for the configuration options in `docs/config.md`. (@whyrusleeping, [ipfs/go-ipfs#2974](https://github.com/ipfs/go-ipfs/pull/2974))
   - All commands now sanely handle the combination of stdin and optional flags in certain edge cases. (@lgierth, [ipfs/go-ipfs#2952](https://github.com/ipfs/go-ipfs/pull/2952))
@@ -3727,7 +3727,7 @@ This is the first Release Candidate. Unless there are vulnerabilities or regress
   - Add `Datastore.HashOnRead` option for verifying block hashes on read access. (@Kubuxu, [ipfs/go-ipfs#2904](https://github.com/ipfs/go-ipfs/pull/2904))
   - Add `Datastore.BloomFilterSize` option for tuning the blockstore's new lookup bloom filter. (@Kubuxu, [ipfs/go-ipfs#2973](https://github.com/ipfs/go-ipfs/pull/2973))
 
-- Bugfixes
+- Bug fixes
 
   - Fix publishing of local IPNS entries, and more. (@whyrusleeping, [ipfs/go-ipfs#2943](https://github.com/ipfs/go-ipfs/pull/2943))
   - Fix progress bars in `ipfs add` and `ipfs get`. (@whyrusleeping, [ipfs/go-ipfs#2893](https://github.com/ipfs/go-ipfs/pull/2893), [ipfs/go-ipfs#2948](https://github.com/ipfs/go-ipfs/pull/2948))
@@ -3781,7 +3781,7 @@ This is the first Release Candidate. Unless there are vulnerabilities or regress
   - Consolidate `--verbose` description across commands. (@Kubuxu, [ipfs/go-ipfs#2746](https://github.com/ipfs/go-ipfs/pull/2746))
   - Allow setting position of default values in command option descriptions. (@Kubuxu, [ipfs/go-ipfs#2744](https://github.com/ipfs/go-ipfs/pull/2744))
   - Set explicit default values for boolean command options. (@RichardLitt, [ipfs/go-ipfs#2657](https://github.com/ipfs/go-ipfs/pull/2657))
-  - Autogenerate command synopsises. (@Kubuxu, [ipfs/go-ipfs#2785](https://github.com/ipfs/go-ipfs/pull/2785))
+  - Autogenerate command synopses. (@Kubuxu, [ipfs/go-ipfs#2785](https://github.com/ipfs/go-ipfs/pull/2785))
   - Fix and improve lots of documentation. (@RichardLitt, [ipfs/go-ipfs#2741](https://github.com/ipfs/go-ipfs/pull/2741), [ipfs/go-ipfs#2781](https://github.com/ipfs/go-ipfs/pull/2781))
   - Improve command descriptions to fit a width of 78 characters. (@RichardLitt, [ipfs/go-ipfs#2779](https://github.com/ipfs/go-ipfs/pull/2779), [ipfs/go-ipfs#2780](https://github.com/ipfs/go-ipfs/pull/2780), [ipfs/go-ipfs#2782](https://github.com/ipfs/go-ipfs/pull/2782))
   - Fix filename conflict in the debugging guide. (@Kubuxu, [ipfs/go-ipfs#2752](https://github.com/ipfs/go-ipfs/pull/2752))
@@ -3843,7 +3843,7 @@ There are also a few other nice improvements.
 * Removals
   * Remove -f option from `ipfs init` command. (@whyrusleeping)
 
-* Bugfixes
+* Bug fixes
   * Fix `ipfs object patch` argument handling and validation. (@jbenet)
   * Fix `ipfs config edit` command by running it client-side. (@Kubuxu)
   * Set default value for `ipfs refs` arguments. (@richardlitt)
@@ -3859,7 +3859,7 @@ There are also a few other nice improvements.
   * Use gx for iptb. (@chriscool)
   * Update gx and gx-go. (@chriscool)
   * Make blocks.Block an interface. (@kevina)
-  * Silence check for Docker existance. (@chriscool)
+  * Silence check for Docker existence. (@chriscool)
   * Add dist_get script for fetching tools from dist.ipfs.tech. (@whyrusleeping)
   * Add proper defaults to all `ipfs` commands. (@richardlitt)
   * Remove dead `count` option from `ipfs pin ls`. (@richardlitt)
@@ -3892,12 +3892,12 @@ hang bugfix that was shipped in the 0.4.0 release.
   * Fix package manifest fields (@lgierth)
   * remove incfusever dead-code (@whyrusleeping)
   * remove a ton of unused godeps (@whyrusleeping)
-  * metrics: add prometheus back (@lgierth)
+  * metrics: add Prometheus back (@lgierth)
   * clean up dead code and config fields (@whyrusleeping)
   * Add log events when blocks are added/removed from the blockstore (@michealmure)
   * repo: don't create logs directory, not used any longer (@lgierth)
 
-* Bugfixes
+* Bug fixes
   * fixed ipfs name resolve --local multihash error (@pfista)
   * ipfs patch commands won't return null links field anymore (@whyrusleeping)
   * Make non recursive resolve print the result (@Kubuxu)
@@ -3927,7 +3927,7 @@ hang bugfix that was shipped in the 0.4.0 release.
 
 ## v0.4.0 - 2016-04-05
 
-This is a major release with plenty of new features and bugfixes.
+This is a major release with plenty of new features and bug fixes.
 It also includes breaking changes which make it incompatible with v0.3.x
 on the networking layer.
 
diff --git a/docs/changelogs/v0.5.md b/docs/changelogs/v0.5.md
index 0fa488845295eb440066b152365d22bf391e04dc..dd154a6b4c20ac152c9e0c297413a6b068fec60b 100644
--- a/docs/changelogs/v0.5.md
+++ b/docs/changelogs/v0.5.md
@@ -564,7 +564,7 @@ As usual, this release contains several Windows specific fixes and improvements:
   - fix: update the dht to fix yggdrasil ([ipfs/go-ipfs#7186](https://github.com/ipfs/go-ipfs/pull/7186))
   - Choose architecture when download tini into docker container ([ipfs/go-ipfs#7187](https://github.com/ipfs/go-ipfs/pull/7187))
   - Fix typos and cleanup ([ipfs/go-ipfs#7181](https://github.com/ipfs/go-ipfs/pull/7181))
-  - Fixtypos ([ipfs/go-ipfs#7180](https://github.com/ipfs/go-ipfs/pull/7180))
+  - Fix typos ([ipfs/go-ipfs#7180](https://github.com/ipfs/go-ipfs/pull/7180))
   - feat: webui 2.7.5 ([ipfs/go-ipfs#7176](https://github.com/ipfs/go-ipfs/pull/7176))
   - integration test for the dual dht ([ipfs/go-ipfs#7151](https://github.com/ipfs/go-ipfs/pull/7151))
   - fix: subdomain redirect for dir CIDs ([ipfs/go-ipfs#7165](https://github.com/ipfs/go-ipfs/pull/7165))
@@ -640,7 +640,7 @@ As usual, this release contains several Windows specific fixes and improvements:
   - test(sharness): fix typo ([ipfs/go-ipfs#6835](https://github.com/ipfs/go-ipfs/pull/6835))
   - test: E2E tests against ipfs-webui HEAD ([ipfs/go-ipfs#6825](https://github.com/ipfs/go-ipfs/pull/6825))
   - mkreleaslog: improve edge-cases ([ipfs/go-ipfs#6833](https://github.com/ipfs/go-ipfs/pull/6833))
-  - fix: dont fail to collect profiles if no ipfs bin ([ipfs/go-ipfs#6829](https://github.com/ipfs/go-ipfs/pull/6829))
+  - fix: don't fail to collect profiles if no ipfs bin ([ipfs/go-ipfs#6829](https://github.com/ipfs/go-ipfs/pull/6829))
   - update dockerfile and use openssl ([ipfs/go-ipfs#6828](https://github.com/ipfs/go-ipfs/pull/6828))
   - docs: define Gateway.PathPrefixes ([ipfs/go-ipfs#6826](https://github.com/ipfs/go-ipfs/pull/6826))
   - fix(badgerds): turn off sync writes by default ([ipfs/go-ipfs#6819](https://github.com/ipfs/go-ipfs/pull/6819))
@@ -661,7 +661,7 @@ As usual, this release contains several Windows specific fixes and improvements:
   - extract the pinner to go-ipfs-pinner and dagutils into go-merkledag ([ipfs/go-ipfs#6771](https://github.com/ipfs/go-ipfs/pull/6771))
   - fix #2203: omit the charset attribute when Content-Type is text/html ([ipfs/go-ipfs#6743](https://github.com/ipfs/go-ipfs/pull/6743))
   - Pin ls traverses all indirect pins ([ipfs/go-ipfs#6705](https://github.com/ipfs/go-ipfs/pull/6705))
-  - fix: ignore nonexistant when force rm ([ipfs/go-ipfs#6773](https://github.com/ipfs/go-ipfs/pull/6773))
+  - fix: ignore nonexistent when force rm ([ipfs/go-ipfs#6773](https://github.com/ipfs/go-ipfs/pull/6773))
   - introduce IpfsNode Plugin ([ipfs/go-ipfs#6719](https://github.com/ipfs/go-ipfs/pull/6719))
   - improve documentation and fix dht put bug ([ipfs/go-ipfs#6750](https://github.com/ipfs/go-ipfs/pull/6750))
   - Adding alias for `ipfs repo stat`. ([ipfs/go-ipfs#6769](https://github.com/ipfs/go-ipfs/pull/6769))
@@ -673,7 +673,7 @@ As usual, this release contains several Windows specific fixes and improvements:
   - Add high-level go-ipfs architecture diagram ([ipfs/go-ipfs#6727](https://github.com/ipfs/go-ipfs/pull/6727))
   - docs: remove extra ) on the example README ([ipfs/go-ipfs#6733](https://github.com/ipfs/go-ipfs/pull/6733))
   - update maintainer label ([ipfs/go-ipfs#6735](https://github.com/ipfs/go-ipfs/pull/6735))
-  - ipfs namespace is now being provided to prometheus ([ipfs/go-ipfs#6643](https://github.com/ipfs/go-ipfs/pull/6643))
+  - ipfs namespace is now being provided to Prometheus ([ipfs/go-ipfs#6643](https://github.com/ipfs/go-ipfs/pull/6643))
   - feat: web ui 2.5.8 ([ipfs/go-ipfs#6718](https://github.com/ipfs/go-ipfs/pull/6718))
   - docs: add connmgr to config.md toc ([ipfs/go-ipfs#6712](https://github.com/ipfs/go-ipfs/pull/6712))
   - feat: web ui 2.5.7 ([ipfs/go-ipfs#6707](https://github.com/ipfs/go-ipfs/pull/6707))
@@ -815,7 +815,7 @@ As usual, this release contains several Windows specific fixes and improvements:
   - Feat: Track Session Peer Latency More Accurately ([ipfs/go-bitswap#149](https://github.com/ipfs/go-bitswap/pull/149))
   - ci(circleci): add benchmark comparisons ([ipfs/go-bitswap#147](https://github.com/ipfs/go-bitswap/pull/147))
   - aggressively free memory ([ipfs/go-bitswap#143](https://github.com/ipfs/go-bitswap/pull/143))
-  - Enchanced logging for bitswap ([ipfs/go-bitswap#137](https://github.com/ipfs/go-bitswap/pull/137))
+  - Enhanced logging for bitswap ([ipfs/go-bitswap#137](https://github.com/ipfs/go-bitswap/pull/137))
   - fix: rand.Intn(0) panics ([ipfs/go-bitswap#144](https://github.com/ipfs/go-bitswap/pull/144))
   - fix some naming nits and broadcast on search ([ipfs/go-bitswap#139](https://github.com/ipfs/go-bitswap/pull/139))
   - feat(sessions): add rebroadcasting, search backoff ([ipfs/go-bitswap#133](https://github.com/ipfs/go-bitswap/pull/133))
@@ -1075,7 +1075,7 @@ As usual, this release contains several Windows specific fixes and improvements:
   - fix: optimize isRelay ([libp2p/go-libp2p-kad-dht#585](https://github.com/libp2p/go-libp2p-kad-dht/pull/585))
   - feat: expose WANActive ([libp2p/go-libp2p-kad-dht#580](https://github.com/libp2p/go-libp2p-kad-dht/pull/580))
   - fix: improve error handling in dual dht ([libp2p/go-libp2p-kad-dht#582](https://github.com/libp2p/go-libp2p-kad-dht/pull/582))
-  - fix: dedup addresses ([libp2p/go-libp2p-kad-dht#581](https://github.com/libp2p/go-libp2p-kad-dht/pull/581))
+  - fix: deduplicate addresses ([libp2p/go-libp2p-kad-dht#581](https://github.com/libp2p/go-libp2p-kad-dht/pull/581))
   - Fix bug in periodic peer pinging ([libp2p/go-libp2p-kad-dht#579](https://github.com/libp2p/go-libp2p-kad-dht/pull/579))
   - Dual DHT scaffold ([libp2p/go-libp2p-kad-dht#570](https://github.com/libp2p/go-libp2p-kad-dht/pull/570))
   - fix: linting fixes ([libp2p/go-libp2p-kad-dht#578](https://github.com/libp2p/go-libp2p-kad-dht/pull/578))
diff --git a/docs/changelogs/v0.7.md b/docs/changelogs/v0.7.md
index f962a680081230112c051560502f796cc5a72d7a..0160916ba3eacb6e24eda6ce7723dc16b8ce8c2e 100644
--- a/docs/changelogs/v0.7.md
+++ b/docs/changelogs/v0.7.md
@@ -76,7 +76,7 @@ The scripts in https://github.com/ipfs/go-ipfs-example-plugin have been updated
   - fix: ipfs pin ls - ignore pins that have errors ([ipfs/go-ipfs#7612](https://github.com/ipfs/go-ipfs/pull/7612))
   - docs(config): fix Peering header ([ipfs/go-ipfs#7623](https://github.com/ipfs/go-ipfs/pull/7623))
   - sharness: use dnsaddr example in ipfs p2p command tests ([ipfs/go-ipfs#7620](https://github.com/ipfs/go-ipfs/pull/7620))
-  - fix(key): dont allow backup key to be named 'self' ([ipfs/go-ipfs#7615](https://github.com/ipfs/go-ipfs/pull/7615))
+  - fix(key): don't allow backup key to be named 'self' ([ipfs/go-ipfs#7615](https://github.com/ipfs/go-ipfs/pull/7615))
   - [BOUNTY] Directory page UI improvements ([ipfs/go-ipfs#7536](https://github.com/ipfs/go-ipfs/pull/7536))
   - fix: make assets deterministic ([ipfs/go-ipfs#7609](https://github.com/ipfs/go-ipfs/pull/7609))
   - use ed25519 keys by default ([ipfs/go-ipfs#7579](https://github.com/ipfs/go-ipfs/pull/7579))
@@ -157,7 +157,7 @@ The scripts in https://github.com/ipfs/go-ipfs-example-plugin have been updated
 - github.com/ipfs/go-graphsync (v0.0.5 -> v0.1.1):
   - docs(CHANGELOG): update for v0.1.1
   - docs(CHANGELOG): update for v0.1.0 release ([ipfs/go-graphsync#84](https://github.com/ipfs/go-graphsync/pull/84))
-  - Dedup by key extension (#83) ([ipfs/go-graphsync#83](https://github.com/ipfs/go-graphsync/pull/83))
+  - Deduplicate by key extension (#83) ([ipfs/go-graphsync#83](https://github.com/ipfs/go-graphsync/pull/83))
   - Release infrastructure (#81) ([ipfs/go-graphsync#81](https://github.com/ipfs/go-graphsync/pull/81))
   - feat(persistenceoptions): add unregister ability (#80) ([ipfs/go-graphsync#80](https://github.com/ipfs/go-graphsync/pull/80))
   - fix(message): regen protobuf code (#79) ([ipfs/go-graphsync#79](https://github.com/ipfs/go-graphsync/pull/79))
@@ -212,7 +212,7 @@ The scripts in https://github.com/ipfs/go-ipfs-example-plugin have been updated
   - Merge branch 'assembler-upgrade-to-codecs'
   - Path clarifications ([ipld/go-ipld-prime#47](https://github.com/ipld/go-ipld-prime/pull/47))
   - Merge branch 'research-admissions'
-  - Add a typed link node to allow traversal with code gen'd builders across links ([ipld/go-ipld-prime#41](https://github.com/ipld/go-ipld-prime/pull/41))
+  - Add a typed link node to allow traversal with code generated builders across links ([ipld/go-ipld-prime#41](https://github.com/ipld/go-ipld-prime/pull/41))
   - Merge branch 'research-admissions'
   - Library updates.
   - Feat/add code gen disclaimer ([ipld/go-ipld-prime#39](https://github.com/ipld/go-ipld-prime/pull/39))
@@ -276,7 +276,7 @@ The scripts in https://github.com/ipfs/go-ipfs-example-plugin have been updated
 - github.com/libp2p/go-libp2p-pubsub (v0.3.1 -> v0.3.5):
   - regenerate protobufs (#381) ([libp2p/go-libp2p-pubsub#381](https://github.com/libp2p/go-libp2p-pubsub/pull/381))
   - track validation time
-  - fullfill promise as soon as a message begins validation
+  - fulfill promise as soon as a message begins validation
   - don't apply penalty in self origin rejections
   - add behaviour penalty threshold
   - Add String() method to Topic.
diff --git a/docs/changelogs/v0.8.md b/docs/changelogs/v0.8.md
index fc5e61f51a93496c1df2438df68bb67f024f8e4c..7f4e1d7594cd7d06489594e465b7861c39cd7e0b 100644
--- a/docs/changelogs/v0.8.md
+++ b/docs/changelogs/v0.8.md
@@ -128,7 +128,7 @@ Go 1.15 (the latest version of Go) [no longer supports](https://github.com/golan
   - Response Assembler Refactor (#138) ([ipfs/go-graphsync#138](https://github.com/ipfs/go-graphsync/pull/138))
   - Add error listener on receiver (#136) ([ipfs/go-graphsync#136](https://github.com/ipfs/go-graphsync/pull/136))
   - Run testplan on in CI (#137) ([ipfs/go-graphsync#137](https://github.com/ipfs/go-graphsync/pull/137))
-  - fix(responsemanager): fix network error propogation (#133) ([ipfs/go-graphsync#133](https://github.com/ipfs/go-graphsync/pull/133))
+  - fix(responsemanager): fix network error propagation (#133) ([ipfs/go-graphsync#133](https://github.com/ipfs/go-graphsync/pull/133))
   - testground test for graphsync (#132) ([ipfs/go-graphsync#132](https://github.com/ipfs/go-graphsync/pull/132))
   - docs(CHANGELOG): update for v0.5.2 ([ipfs/go-graphsync#130](https://github.com/ipfs/go-graphsync/pull/130))
   - RegisterNetworkErrorListener should fire when there's an error connecting to the peer (#127) ([ipfs/go-graphsync#127](https://github.com/ipfs/go-graphsync/pull/127))
@@ -285,7 +285,7 @@ Go 1.15 (the latest version of Go) [no longer supports](https://github.com/golan
   - add support for priority topic delivery weights
   - tweak duplicate/reject weights
   - decay global counters after 2 min
-  - decouple global coutner decay from source counter decay
+  - decouple global counter decay from source counter decay
   - add warning for failure to parse IP out of remote multiaddr
   - more docs
   - configure the peer gater using a parameter object, docs and stuff
diff --git a/docs/changelogs/v0.9.md b/docs/changelogs/v0.9.md
index e210c7c248104c5764fab3414be65764d4b21a7d..7289adde7de1a6eac9051011ee9341e79302c25f 100644
--- a/docs/changelogs/v0.9.md
+++ b/docs/changelogs/v0.9.md
@@ -209,7 +209,7 @@ SECIO was deprecated and turned off by default given the prevalence of TLS and N
   - fix(gw): remove hardcoded hostnames ([ipfs/go-ipfs#8069](https://github.com/ipfs/go-ipfs/pull/8069))
   - Fix transposed words in docs/config.md ([ipfs/go-ipfs#8051](https://github.com/ipfs/go-ipfs/pull/8051))
   - fix: update root help ([ipfs/go-ipfs#8052](https://github.com/ipfs/go-ipfs/pull/8052))
-  - chore: dont docker tag rc as latest ([ipfs/go-ipfs#8055](https://github.com/ipfs/go-ipfs/pull/8055))
+  - chore: don't docker tag rc as latest ([ipfs/go-ipfs#8055](https://github.com/ipfs/go-ipfs/pull/8055))
   - Add info to "pin rm" help about how to tell if pin is indirect ([ipfs/go-ipfs#8044](https://github.com/ipfs/go-ipfs/pull/8044))
   - build(deps): bump contrib.go.opencensus.io/exporter/prometheus from 0.2.0 to 0.3.0 ([ipfs/go-ipfs#8020](https://github.com/ipfs/go-ipfs/pull/8020))
   - fix(gw): remove use of Clear-Site-Data in subdomain router ([ipfs/go-ipfs#7890](https://github.com/ipfs/go-ipfs/pull/7890))
@@ -223,7 +223,7 @@ SECIO was deprecated and turned off by default given the prevalence of TLS and N
   - fix: return an error if repo verify is canceled ([ipfs/go-ipfs#7973](https://github.com/ipfs/go-ipfs/pull/7973))
   - doc: document security fix policy ([ipfs/go-ipfs#7991](https://github.com/ipfs/go-ipfs/pull/7991))
   - feat(gw): /ipfs/ipfs/{cid} → /ipfs/{cid} ([ipfs/go-ipfs#7930](https://github.com/ipfs/go-ipfs/pull/7930))
-  - Fix: innacuracies in MFS command documentation. ([ipfs/go-ipfs#8001](https://github.com/ipfs/go-ipfs/pull/8001))
+  - Fix: inaccuracies in MFS command documentation. ([ipfs/go-ipfs#8001](https://github.com/ipfs/go-ipfs/pull/8001))
   - Feat: Re-import InitializeKeyspace code from go-namesys ([ipfs/go-ipfs#7984](https://github.com/ipfs/go-ipfs/pull/7984))
   - revert registration of metrics against unexposed prom registry ([ipfs/go-ipfs#7986](https://github.com/ipfs/go-ipfs/pull/7986))
   - Extract the namesys and the keystore submodules ([ipfs/go-ipfs#7925](https://github.com/ipfs/go-ipfs/pull/7925))
@@ -266,7 +266,7 @@ SECIO was deprecated and turned off by default given the prevalence of TLS and N
   - docs(architecture): update architecture docs (#154) ([ipfs/go-graphsync#154](https://github.com/ipfs/go-graphsync/pull/154))
   - release v0.7.0 ([ipfs/go-graphsync#152](https://github.com/ipfs/go-graphsync/pull/152))
   - chore: update deps (#151) ([ipfs/go-graphsync#151](https://github.com/ipfs/go-graphsync/pull/151))
-  - Automatically record heap profiles in testplans (#147) ([ipfs/go-graphsync#147](https://github.com/ipfs/go-graphsync/pull/147))
+  - Automatically record heap profiles in test plans (#147) ([ipfs/go-graphsync#147](https://github.com/ipfs/go-graphsync/pull/147))
   - feat(deps): update go-ipld-prime v0.7.0 (#145) ([ipfs/go-graphsync#145](https://github.com/ipfs/go-graphsync/pull/145))
   - Release/v0.6.0 ([ipfs/go-graphsync#144](https://github.com/ipfs/go-graphsync/pull/144))
 - github.com/ipfs/go-ipfs-blockstore (v0.1.4 -> v0.1.6):
@@ -360,7 +360,7 @@ SECIO was deprecated and turned off by default given the prevalence of TLS and N
   - node/gendemo: use the new code generator
   - Merge pull request #96 , originally known as ipld/cidlink-only-usable-as-ptr
   - Codec revamp ([ipld/go-ipld-prime#112](https://github.com/ipld/go-ipld-prime/pull/112))
-  - Allow overriden types (#116) ([ipld/go-ipld-prime#116](https://github.com/ipld/go-ipld-prime/pull/116))
+  - Allow overridden types (#116) ([ipld/go-ipld-prime#116](https://github.com/ipld/go-ipld-prime/pull/116))
   - add import to ipld in ipldsch_types.go ([ipld/go-ipld-prime#115](https://github.com/ipld/go-ipld-prime/pull/115))
   - Codegen output rearrange ([ipld/go-ipld-prime#105](https://github.com/ipld/go-ipld-prime/pull/105))
   - Validate struct builder sufficiency ([ipld/go-ipld-prime#111](https://github.com/ipld/go-ipld-prime/pull/111))
@@ -540,7 +540,7 @@ SECIO was deprecated and turned off by default given the prevalence of TLS and N
   - improve string representation of timeout errors ([lucas-clemente/quic-go#3118](https://github.com/lucas-clemente/quic-go/pull/3118))
   - fix flaky timeout test ([lucas-clemente/quic-go#3105](https://github.com/lucas-clemente/quic-go/pull/3105))
   - fix calculation of the time for the next keep alive
-  - add a 0-RTT test with different connecton ID lengths ([lucas-clemente/quic-go#3098](https://github.com/lucas-clemente/quic-go/pull/3098))
+  - add a 0-RTT test with different connection ID lengths ([lucas-clemente/quic-go#3098](https://github.com/lucas-clemente/quic-go/pull/3098))
   - only run Ginkgo focus detection in staged files in pre-commit hook ([lucas-clemente/quic-go#3099](https://github.com/lucas-clemente/quic-go/pull/3099))
   - allow 0-RTT when flow control windows are increased ([lucas-clemente/quic-go#3096](https://github.com/lucas-clemente/quic-go/pull/3096))
   - improve the 0-RTT rejection integration test ([lucas-clemente/quic-go#3097](https://github.com/lucas-clemente/quic-go/pull/3097))
@@ -705,7 +705,7 @@ SECIO was deprecated and turned off by default given the prevalence of TLS and N
   - Implement simultaneous open extension ([multiformats/go-multistream#42](https://github.com/multiformats/go-multistream/pull/42))
   - reduce the number of streams in the stress tests, fix error handling ([multiformats/go-multistream#54](https://github.com/multiformats/go-multistream/pull/54))
 - github.com/whyrusleeping/cbor-gen (v0.0.0-20200710004633-5379fc63235d -> v0.0.0-20210219115102-f37d292932f2):
-  - feat: allow unmarshaling of struct with more fields than marshaled struct ([whyrusleeping/cbor-gen#50](https://github.com/whyrusleeping/cbor-gen/pull/50))
+  - feat: allow unmarshalling of struct with more fields than marshaled struct ([whyrusleeping/cbor-gen#50](https://github.com/whyrusleeping/cbor-gen/pull/50))
   - chore: add a license file ([whyrusleeping/cbor-gen#49](https://github.com/whyrusleeping/cbor-gen/pull/49))
   - fix: enforce maxlen in ReadByteArray() ([whyrusleeping/cbor-gen#43](https://github.com/whyrusleeping/cbor-gen/pull/43))
   - use unix nanoseconds for encoding Cbortime ([whyrusleeping/cbor-gen#41](https://github.com/whyrusleeping/cbor-gen/pull/41))
diff --git a/docs/config.md b/docs/config.md
index 995872c4f37f6344f3d9f16069400d431f0b4d8c..28331c2aea2b9130a2c707680899c9f7b01e427f 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -146,7 +146,6 @@ config file at runtime.
       - [`Swarm.ResourceMgr.Enabled`](#swarmresourcemgrenabled)
       - [`Swarm.ResourceMgr.MaxMemory`](#swarmresourcemgrmaxmemory)
       - [`Swarm.ResourceMgr.MaxFileDescriptors`](#swarmresourcemgrmaxfiledescriptors)
-      - [`Swarm.ResourceMgr.Limits`](#swarmresourcemgrlimits)
       - [`Swarm.ResourceMgr.Allowlist`](#swarmresourcemgrallowlist)
     - [`Swarm.Transports`](#swarmtransports)
     - [`Swarm.Transports.Network`](#swarmtransportsnetwork)
@@ -682,7 +681,10 @@ Type: `string` (url)
 
 ### `Gateway.Writable`
 
-A boolean to configure whether the gateway is writeable or not.
+**DEPRECATED**: Enables legacy PUT/POST request handling. 
+
+This API is not standardized, and should not be used for new projects.
+We are working on a modern replacement. IPIP can be tracked in [ipfs/specs#375](https://github.com/ipfs/specs/issues/375).
 
 Default: `false`
 
@@ -911,7 +913,7 @@ based on the metrics `ipfs_bitswap_active_tasks`, `ipfs_bitswap_pending_tasks`,
 `ipfs_bitswap_pending_block_tasks` and `ipfs_bitswap_active_block_tasks`
 reported by bitswap.
 
-These metrics can be accessed as the prometheus endpoint at `{Addresses.API}/debug/metrics/prometheus` (default: `http://127.0.0.1:5001/debug/metrics/prometheus`)
+These metrics can be accessed as the Prometheus endpoint at `{Addresses.API}/debug/metrics/prometheus` (default: `http://127.0.0.1:5001/debug/metrics/prometheus`)
 
 The value of `ipfs_bitswap_active_tasks` is capped by `EngineTaskWorkerCount`.
 
@@ -935,7 +937,7 @@ while `ipfs_bitswap_active_block_tasks` is at its maximum, there is indication t
 available block tasks is creating a bottleneck (either due to high-latency block operations,
 or due to high number of block operations per bitswap peer task).
 In such cases, try increasing the `EngineBlockstoreWorkerCount`.
-If this adjustment still does not increase the throuput of the node, there might
+If this adjustment still does not increase the throughput of the node, there might
 be hardware limitations like I/O or CPU.
 
 #### `Internal.Bitswap.TaskWorkerCount`
@@ -1163,13 +1165,15 @@ Type: `duration`
 
 ## `Pubsub`
 
+**DEPRECATED**: See [#9717](https://github.com/ipfs/kubo/issues/9717)
+
 Pubsub configures the `ipfs pubsub` subsystem. To use, it must be enabled by
 passing the `--enable-pubsub-experiment` flag to the daemon
 or via the `Pubsub.Enabled` flag below.
 
 ### `Pubsub.Enabled`
 
-**EXPERIMENTAL:** read about current limitations at [experimental-features.md#ipfs-pubsub](./experimental-features.md#ipfs-pubsub).
+**DEPRECATED**: See [#9717](https://github.com/ipfs/kubo/issues/9717)
 
 Enables the pubsub system.
 
@@ -1179,6 +1183,8 @@ Type: `flag`
 
 ### `Pubsub.Router`
 
+**DEPRECATED**: See [#9717](https://github.com/ipfs/kubo/issues/9717)
+
 Sets the default router used by pubsub to route messages to peers. This can be one of:
 
 * `"floodsub"` - floodsub is a basic router that simply _floods_ messages to all
@@ -1194,6 +1200,8 @@ Type: `string` (one of `"floodsub"`, `"gossipsub"`, or `""` (apply default))
 
 ### `Pubsub.DisableSigning`
 
+**DEPRECATED**: See [#9717](https://github.com/ipfs/kubo/issues/9717)
+
 Disables message signing and signature verification. Enable this option if
 you're operating in a completely trusted network.
 
@@ -1207,6 +1215,8 @@ Type: `bool`
 
 ### `Pubsub.SeenMessagesTTL`
 
+**DEPRECATED**: See [#9717](https://github.com/ipfs/kubo/issues/9717)
+
 Controls the time window within which duplicate messages, identified by Message
 ID, will be identified and won't be emitted again.
 
@@ -1226,6 +1236,8 @@ Type: `optionalDuration`
 
 ### `Pubsub.SeenMessagesStrategy`
 
+**DEPRECATED**: See [#9717](https://github.com/ipfs/kubo/issues/9717)
+
 Determines how the time-to-live (TTL) countdown for deduplicating Pubsub
 messages is calculated.
 
@@ -1347,11 +1359,13 @@ Contains options for content, peer, and IPNS routing mechanisms.
 
 ### `Routing.Type`
 
-There are multiple routing options: "auto", "none", "dht" and "custom".
+There are multiple routing options: "auto", "autoclient", "none", "dht", "dhtclient", and "custom".
 
 * **DEFAULT:** If unset, or set to "auto", your node will use the IPFS DHT
   and parallel HTTP routers listed below for additional speed.
 
+* If set to "autoclient", your node will behave as in "auto" but without running a DHT server.
+
 * If set to "none", your node will use _no_ routing system. You'll have to
   explicitly connect to peers that have the content you're looking for.
 
@@ -1377,7 +1391,7 @@ To force a specific DHT-only mode, client or server, set `Routing.Type` to
 `dhtclient` or `dhtserver` respectively. Please do not set this to `dhtserver`
 unless you're sure your node is reachable from the public network.
 
-When `Routing.Type` is set to `auto` your node will accelerate some types of routing
+When `Routing.Type` is set to `auto` or `autoclient` your node will accelerate some types of routing
 by leveraging HTTP endpoints compatible with [IPIP-337](https://github.com/ipfs/specs/pull/337)
 in addition to the IPFS DHT.
 By default, an instance of [IPNI](https://github.com/ipni/specs/blob/main/IPNI.md#readme)
@@ -1539,9 +1553,9 @@ another node, even if this other node is on a different network. This may
 trigger netscan alerts on some hosting providers or cause strain in some setups.
 
 The `server` configuration profile fills up this list with sensible defaults,
-preventing dials to all non-routable IP addresses (e.g., `192.168.0.0/16`) but
-you should always check settings against your own network and/or hosting
-provider.
+preventing dials to all non-routable IP addresses (e.g., `/ip4/192.168.0.0/ipcidr/16`, 
+which is the multiaddress representation of `192.168.0.0/16`) but you should always
+check settings against your own network and/or hosting provider.
 
 Default: `[]`
 
@@ -1843,6 +1857,8 @@ This value is also used to scale the limit on various resources at various scope
 when the default limits (discussed in [libp2p resource management](./libp2p-resource-management.md)) are used.
 For example, increasing this value will increase the default limit for incoming connections.
 
+It is possible to inspect the runtime limits via `ipfs swarm resources --help`.
+
 Default: `[TOTAL_SYSTEM_MEMORY]/2`
 Type: `optionalBytes`
 
@@ -1856,65 +1872,6 @@ This param is ignored on Windows.
 Default `[TOTAL_SYSTEM_FILE_DESCRIPTORS]/2`
 Type: `optionalInteger`
 
-#### `Swarm.ResourceMgr.Limits`
-
-Map of resource limits [per scope](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#resource-scopes).
-
-The map supports fields from the [`LimitConfig` struct](https://github.com/libp2p/go-libp2p/blob/master/p2p/host/resource-manager/limit_defaults.go#L111).
-
-[`BaseLimit`s](https://github.com/libp2p/go-libp2p/blob/master/p2p/host/resource-manager/limit.go#L89) can be set for any scope, and within the `BaseLimit`, all limit <key,value>s are optional.
-
-The `Swarm.ResourceMgr.Limits` override the default limits described above.
-Any override `BaseLimits` or limit <key,value>s from `Swarm.ResourceMgr.Limits`
-that aren't specified will use the [computed default limits](./libp2p-resource-management.md#computed-default-limits).
-
-Until [ipfs/kubo#9564](https://github.com/ipfs/kubo/issues/9564) is addressed, there isn't a way to set an override limit of zero.
-0 is currently ignored.  0 currently means use to use the [computed default limits](./libp2p-resource-management.md#computed-default-limits).
-
-Example #1: setting limits for a specific scope
-```json
-{
-  "Swarm": {
-    "ResourceMgr": {
-      "Limits": {
-        "System": {
-          "Memory": 1073741824,
-          "FD": 512,
-          "Conns": 1024,
-          "ConnsInbound": 256,
-          "ConnsOutbound": 1024,
-          "Streams": 16384,
-          "StreamsInbound": 4096,
-          "StreamsOutbound": 16384
-        }
-      }
-    }
-  }
-}
-```
-
-Example #2: setting a specific <key,value> limit
-```json
-{
-  "Swarm": {
-    "ResourceMgr": {
-      "Limits": {
-        "Transient": {
-          "ConnsOutbound": 256,
-        }
-      }
-    }
-  }
-}
-```
-
-It is also possible to inspect and adjust some runtime limits via `ipfs swarm stats --help` and `ipfs swarm limit --help`.
-Changes made via `ipfs swarm limit` are persisted in `Swarm.ResourceMgr.Limits`.
-
-Default: `{}` (use the [computed defaults](./libp2p-resource-management.md#computed-default-limits))
-
-Type: `object[string->object]`
-
 #### `Swarm.ResourceMgr.Allowlist`
 
 A list of multiaddrs that can bypass normal system limits (but are still limited by the allowlist scope).
diff --git a/docs/delegated-routing.md b/docs/delegated-routing.md
index 9e2b9c48b2c1f61f60efbf7e117d2828c157c0c0..ff58aa8f97bf1e6bcaec139d8cc4954ae36aefcf 100644
--- a/docs/delegated-routing.md
+++ b/docs/delegated-routing.md
@@ -393,8 +393,7 @@ As test fixtures we can add different use cases here and see how the configurati
   }
 }
 ```
-
-Yaml representation for clarity:
+YAML representation for clarity:
 
 ```yaml
 ---
diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod
index 0a4a436d9fe9f54fda27f57d4765dc7374b37f80..5453ae1d581e0a4d58ee6c6a07fefd04d50e0b75 100644
--- a/docs/examples/kubo-as-a-library/go.mod
+++ b/docs/examples/kubo-as-a-library/go.mod
@@ -7,10 +7,10 @@ go 1.18
 replace github.com/ipfs/kubo => ./../../..
 
 require (
-	github.com/ipfs/go-libipfs v0.2.0
-	github.com/ipfs/interface-go-ipfs-core v0.8.2
-	github.com/ipfs/kubo v0.14.0-rc1
-	github.com/libp2p/go-libp2p v0.24.2
+	github.com/ipfs/go-libipfs v0.6.2
+	github.com/ipfs/interface-go-ipfs-core v0.11.0
+	github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
+	github.com/libp2p/go-libp2p v0.26.3
 	github.com/multiformats/go-multiaddr v0.8.0
 )
 
@@ -54,17 +54,16 @@ require (
 	github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/gorilla/mux v1.8.0 // indirect
-	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
 	github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-multierror v1.1.1 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
 	github.com/huin/goupnp v1.0.3 // indirect
 	github.com/ipfs/bbloom v0.0.4 // indirect
-	github.com/ipfs/go-bitfield v1.0.0 // indirect
-	github.com/ipfs/go-bitswap v0.11.0 // indirect
-	github.com/ipfs/go-block-format v0.0.3 // indirect
+	github.com/ipfs/go-bitfield v1.1.0 // indirect
+	github.com/ipfs/go-block-format v0.1.1 // indirect
 	github.com/ipfs/go-blockservice v0.5.0 // indirect
 	github.com/ipfs/go-cid v0.3.2 // indirect
 	github.com/ipfs/go-cidutil v0.1.0 // indirect
@@ -85,9 +84,9 @@ require (
 	github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect
 	github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect
 	github.com/ipfs/go-ipfs-keystore v0.1.0 // indirect
-	github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect
+	github.com/ipfs/go-ipfs-pinner v0.3.0 // indirect
 	github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
-	github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
+	github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
 	github.com/ipfs/go-ipfs-provider v0.8.1 // indirect
 	github.com/ipfs/go-ipfs-routing v0.3.0 // indirect
 	github.com/ipfs/go-ipfs-util v0.0.2 // indirect
@@ -101,11 +100,11 @@ require (
 	github.com/ipfs/go-merkledag v0.9.0 // indirect
 	github.com/ipfs/go-metrics-interface v0.0.1 // indirect
 	github.com/ipfs/go-mfs v0.2.1 // indirect
-	github.com/ipfs/go-namesys v0.6.0 // indirect
-	github.com/ipfs/go-path v0.3.0 // indirect
-	github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
-	github.com/ipfs/go-unixfs v0.4.2 // indirect
-	github.com/ipfs/go-unixfsnode v1.5.1 // indirect
+	github.com/ipfs/go-namesys v0.7.0 // indirect
+	github.com/ipfs/go-path v0.3.1 // indirect
+	github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
+	github.com/ipfs/go-unixfs v0.4.4 // indirect
+	github.com/ipfs/go-unixfsnode v1.5.2 // indirect
 	github.com/ipfs/go-verifcid v0.0.2 // indirect
 	github.com/ipld/edelweiss v0.2.0 // indirect
 	github.com/ipld/go-codec-dagpb v1.5.0 // indirect
@@ -114,36 +113,29 @@ require (
 	github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
 	github.com/jbenet/goprocess v0.1.4 // indirect
 	github.com/klauspost/compress v1.15.12 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.1 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.3 // indirect
 	github.com/koron/go-ssdp v0.0.3 // indirect
 	github.com/libp2p/go-buffer-pool v0.1.0 // indirect
 	github.com/libp2p/go-cidranger v1.1.0 // indirect
 	github.com/libp2p/go-doh-resolver v0.4.0 // indirect
 	github.com/libp2p/go-flow-metrics v0.1.0 // indirect
-	github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
-	github.com/libp2p/go-libp2p-kad-dht v0.20.0 // indirect
+	github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
+	github.com/libp2p/go-libp2p-kad-dht v0.21.1 // indirect
 	github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect
-	github.com/libp2p/go-libp2p-pubsub v0.8.3 // indirect
+	github.com/libp2p/go-libp2p-pubsub v0.9.0 // indirect
 	github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
 	github.com/libp2p/go-libp2p-record v0.2.0 // indirect
-	github.com/libp2p/go-libp2p-routing-helpers v0.6.0 // indirect
+	github.com/libp2p/go-libp2p-routing-helpers v0.6.1 // indirect
 	github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
 	github.com/libp2p/go-mplex v0.7.0 // indirect
-	github.com/libp2p/go-msgio v0.2.0 // indirect
+	github.com/libp2p/go-msgio v0.3.0 // indirect
 	github.com/libp2p/go-nat v0.1.0 // indirect
 	github.com/libp2p/go-netroute v0.2.1 // indirect
-	github.com/libp2p/go-openssl v0.1.0 // indirect
 	github.com/libp2p/go-reuseport v0.2.0 // indirect
 	github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
 	github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
-	github.com/lucas-clemente/quic-go v0.31.1 // indirect
-	github.com/marten-seemann/qpack v0.3.0 // indirect
-	github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
-	github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
 	github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
-	github.com/marten-seemann/webtransport-go v0.4.3 // indirect
 	github.com/mattn/go-isatty v0.0.17 // indirect
-	github.com/mattn/go-pointer v0.0.1 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/miekg/dns v1.1.50 // indirect
 	github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
@@ -158,7 +150,7 @@ require (
 	github.com/multiformats/go-multibase v0.1.1 // indirect
 	github.com/multiformats/go-multicodec v0.7.0 // indirect
 	github.com/multiformats/go-multihash v0.2.1 // indirect
-	github.com/multiformats/go-multistream v0.3.3 // indirect
+	github.com/multiformats/go-multistream v0.4.1 // indirect
 	github.com/multiformats/go-varint v0.0.7 // indirect
 	github.com/onsi/ginkgo/v2 v2.5.1 // indirect
 	github.com/opencontainers/runtime-spec v1.0.2 // indirect
@@ -166,18 +158,22 @@ require (
 	github.com/openzipkin/zipkin-go v0.4.0 // indirect
 	github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
-	github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
+	github.com/polydawn/refmt v0.89.0 // indirect
 	github.com/prometheus/client_golang v1.14.0 // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
 	github.com/prometheus/common v0.37.0 // indirect
 	github.com/prometheus/procfs v0.8.0 // indirect
+	github.com/quic-go/qpack v0.4.0 // indirect
+	github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
+	github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
+	github.com/quic-go/quic-go v0.33.0 // indirect
+	github.com/quic-go/webtransport-go v0.5.2 // indirect
 	github.com/raulk/go-watchdog v1.3.0 // indirect
 	github.com/samber/lo v1.36.0 // indirect
-	github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
 	github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
-	github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 // indirect
+	github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect
 	github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
 	github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
 	github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
@@ -199,18 +195,19 @@ require (
 	go.uber.org/multierr v1.9.0 // indirect
 	go.uber.org/zap v1.24.0 // indirect
 	go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
-	golang.org/x/crypto v0.3.0 // indirect
-	golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
+	golang.org/x/crypto v0.5.0 // indirect
+	golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 // indirect
 	golang.org/x/mod v0.7.0 // indirect
-	golang.org/x/net v0.3.0 // indirect
+	golang.org/x/net v0.7.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
-	golang.org/x/sys v0.4.0 // indirect
-	golang.org/x/text v0.5.0 // indirect
+	golang.org/x/sys v0.5.0 // indirect
+	golang.org/x/text v0.7.0 // indirect
 	golang.org/x/tools v0.3.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect
-	google.golang.org/grpc v1.47.0 // indirect
+	google.golang.org/grpc v1.46.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/square/go-jose.v2 v2.5.1 // indirect
 	lukechampine.com/blake3 v1.1.7 // indirect
+	nhooyr.io/websocket v1.8.7 // indirect
 )
diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum
index eb52ab5e864d6b491c0cb3112d98731925f1e866..6f7e7f253b354d1ef454261027454f0798a13401 100644
--- a/docs/examples/kubo-as-a-library/go.sum
+++ b/docs/examples/kubo-as-a-library/go.sum
@@ -227,6 +227,10 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
 github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@@ -247,10 +251,24 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
 github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
+github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
@@ -362,7 +380,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -398,6 +415,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4=
+github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
 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.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
@@ -415,18 +434,19 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod
 github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI=
 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ=
 github.com/ipfs/go-bitfield v1.0.0/go.mod h1:N/UiujQy+K+ceU1EF5EkVd1TNqevLrCQMIcAEPrdtus=
+github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
+github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
 github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0=
 github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs=
 github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo=
 github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA=
 github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
-github.com/ipfs/go-bitswap v0.11.0/go.mod h1:05aE8H3XOU+LXpTedeAS0OZpcO1WFsj5niYQH9a1Tmk=
 github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc=
 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
-github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc=
 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
+github.com/ipfs/go-block-format v0.1.1 h1:129vSO3zwbsYADcyQWcOYiuCpAqt462SFfqFHdFJhhI=
+github.com/ipfs/go-block-format v0.1.1/go.mod h1:+McEIT+g52p+zz5xGAABGSOKrzmrdX97bc0USBdWPUs=
 github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M=
 github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8=
 github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk=
@@ -514,13 +534,14 @@ github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB
 github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
 github.com/ipfs/go-ipfs-keystore v0.1.0 h1:gfuQUO/cyGZgZIHE6OrJas4OnwuxXCqJG7tI0lrB5Qc=
 github.com/ipfs/go-ipfs-keystore v0.1.0/go.mod h1:LvLw7Qhnb0RlMOfCzK6OmyWxICip6lQ06CCmdbee75U=
-github.com/ipfs/go-ipfs-pinner v0.2.1 h1:kw9hiqh2p8TatILYZ3WAfQQABby7SQARdrdA+5Z5QfY=
-github.com/ipfs/go-ipfs-pinner v0.2.1/go.mod h1:l1AtLL5bovb7opnG77sh4Y10waINz3Y1ni6CvTzx7oo=
+github.com/ipfs/go-ipfs-pinner v0.3.0 h1:jwe5ViX3BON3KgOAYrrhav2+1ONB0QzFAWQd7HUlbuM=
+github.com/ipfs/go-ipfs-pinner v0.3.0/go.mod h1:oX0I0nC6zlNIh0LslSrUnjfNKPq8ufoFtqV1/wcJvyo=
 github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
 github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=
 github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
-github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY=
 github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
+github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE=
+github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4=
 github.com/ipfs/go-ipfs-provider v0.8.1 h1:qt670pYmcNH3BCjyXDgg07o2WsTRsOdMwYc25ukCdjQ=
 github.com/ipfs/go-ipfs-provider v0.8.1/go.mod h1:qCpwpoohIRVXvNzkygzsM3qdqP/sXlrogtA5I45tClc=
 github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY=
@@ -548,8 +569,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2
 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg=
 github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
 github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
-github.com/ipfs/go-libipfs v0.2.0 h1:MedvelDEddPYL3iDLoqAsviLeXUiwB1F2t8fkzx9/EU=
-github.com/ipfs/go-libipfs v0.2.0/go.mod h1:qX0d9h+wu53PFtCTXxdXVBakd6ZCvGDdkZUKmdLMLx0=
+github.com/ipfs/go-libipfs v0.6.2 h1:QUf3kS3RrCjgtE0QW2d18PFFfOLeEt24Ft892ipLzRI=
+github.com/ipfs/go-libipfs v0.6.2/go.mod h1:FmhKgxMOQA572TK5DA3MZ5GL44ZqsMHIrkgK4gLn4A8=
 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
 github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
 github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
@@ -574,30 +595,30 @@ github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fG
 github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
 github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8=
 github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88=
-github.com/ipfs/go-namesys v0.6.0 h1:w4+Wq9bCILnuZRT1RBBdzZQFqtJeDG1duzN8mIDnHZ0=
-github.com/ipfs/go-namesys v0.6.0/go.mod h1:0L+3CHBgHxr08Cg+chVo9Ew285PGQfToThjll4g0/d4=
+github.com/ipfs/go-namesys v0.7.0 h1:xqosk71GIVRkFDtF2UNRcXn4LdNeo7tzuy8feHD6NbU=
+github.com/ipfs/go-namesys v0.7.0/go.mod h1:KYSZBVZG3VJC34EfqqJPG7T48aWgxseoMPAPA5gLyyQ=
 github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I=
-github.com/ipfs/go-path v0.3.0 h1:tkjga3MtpXyM5v+3EbRvOHEoo+frwi4oumw5K+KYWyA=
-github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I=
+github.com/ipfs/go-path v0.3.1 h1:wkeaCWE/NTuuPGlEkLTsED5UkzfKYZpxaFFPgk8ZVLE=
+github.com/ipfs/go-path v0.3.1/go.mod h1:eNLsxJEEMxn/CDzUJ6wuNl+6No6tEUhOZcPKsZsYX0E=
 github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U=
 github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
-github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU=
-github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM=
+github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg=
+github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU=
 github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
 github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o=
-github.com/ipfs/go-unixfs v0.4.2 h1:hdQlsHHK5tek9gC9mjGVua8xyTqC+eopGseCRcbCZNg=
-github.com/ipfs/go-unixfs v0.4.2/go.mod h1:L+x6JRlFE0PfyMqeoLYVOKLhn5IeZHvNT7ZI51Y9Qyc=
+github.com/ipfs/go-unixfs v0.4.4 h1:D/dLBOJgny5ZLIur2vIXVQVW0EyDHdOMBDEhgHrt6rY=
+github.com/ipfs/go-unixfs v0.4.4/go.mod h1:TSG7G1UuT+l4pNj91raXAPkX0BhJi3jST1FDTfQ5QyM=
 github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s=
-github.com/ipfs/go-unixfsnode v1.5.1 h1:JcR3t5C2nM1V7PMzhJ/Qmo19NkoFIKweDSZyDx+CjkI=
-github.com/ipfs/go-unixfsnode v1.5.1/go.mod h1:ed79DaG9IEuZITJVQn4U6MZDftv6I3ygUBLPfhEbHvk=
+github.com/ipfs/go-unixfsnode v1.5.2 h1:CvsiTt58W2uR5dD8bqQv+aAY0c1qolmXmSyNbPHYiew=
+github.com/ipfs/go-unixfsnode v1.5.2/go.mod h1:NlOebRwYx8lMCNMdhAhEspYPBD3obp7TE0LvBqHY+ks=
 github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
 github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs=
 github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU=
-github.com/ipfs/interface-go-ipfs-core v0.8.2 h1:WDeCBnE4MENVOXbtfwwdAPJ2nBBS8PTmhZWWpm24HRM=
-github.com/ipfs/interface-go-ipfs-core v0.8.2/go.mod h1:F3EcmDy53GFkF0H3iEJpfJC320fZ/4G60eftnItrrJ0=
+github.com/ipfs/interface-go-ipfs-core v0.11.0 h1:n1tplrwsz7oZXkpkZM5a3MDBxksMfSQ103ej4e+l7NA=
+github.com/ipfs/interface-go-ipfs-core v0.11.0/go.mod h1:xmnoccUXY7N/Q8AIx0vFqgW926/FAZ8+do/1NTEHKsU=
 github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
 github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
-github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
+github.com/ipld/go-car v0.5.0 h1:kcCEa3CvYMs0iE5BzD5sV7O2EwMiCIp3uF8tA6APQT8=
 github.com/ipld/go-car/v2 v2.5.1 h1:U2ux9JS23upEgrJScW8VQuxmE94560kYxj9CQUpcfmk=
 github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA=
 github.com/ipld/go-codec-dagpb v1.5.0 h1:RspDRdsJpLfgCI0ONhTAnbHdySGD4t+LHSPK4X1+R0k=
@@ -638,8 +659,10 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+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 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@@ -654,13 +677,14 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
 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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
 github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
-github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
+github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 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/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
@@ -678,6 +702,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
 github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=
 github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
@@ -704,10 +730,10 @@ github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xS
 github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
 github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=
 github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0=
-github.com/libp2p/go-libp2p v0.24.2 h1:iMViPIcLY0D6zr/f+1Yq9EavCZu2i7eDstsr1nEwSAk=
-github.com/libp2p/go-libp2p v0.24.2/go.mod h1:WuxtL2V8yGjam03D93ZBC19tvOUiPpewYv1xdFGWu1k=
-github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw=
-github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI=
+github.com/libp2p/go-libp2p v0.26.3 h1:6g/psubqwdaBqNNoidbRKSTBEYgaOuKBhHl8Q5tO+PM=
+github.com/libp2p/go-libp2p v0.26.3/go.mod h1:x75BN32YbwuY0Awm2Uix4d4KOz+/4piInkp4Wr3yOo8=
+github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s=
+github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w=
 github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8=
 github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
 github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI=
@@ -748,8 +774,8 @@ github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFT
 github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg=
 github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw=
 github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
-github.com/libp2p/go-libp2p-kad-dht v0.20.0 h1:1bcMa74JFwExCHZMFEmjtHzxX5DovhJ07EtR6UOTEpc=
-github.com/libp2p/go-libp2p-kad-dht v0.20.0/go.mod h1:qPIXdiZsLczhV4/+4EO1jE8ae0YCW4ZOogc4WVIyTEU=
+github.com/libp2p/go-libp2p-kad-dht v0.21.1 h1:xpfp8/t9+X2ip1l8Umap1/UGNnJ3RHJgKGAEsnRAlTo=
+github.com/libp2p/go-libp2p-kad-dht v0.21.1/go.mod h1:Oy8wvbdjpB70eS5AaFaI68tOtrdo3KylTvXDjikxqFo=
 github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
 github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA=
 github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aDK/A02xeZp9QeFC4U=
@@ -775,16 +801,16 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj
 github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
 github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
 github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
-github.com/libp2p/go-libp2p-pubsub v0.8.3 h1:T4+pcfcFm1K2v5oFyk68peSjVroaoM8zFygf6Y5WOww=
-github.com/libp2p/go-libp2p-pubsub v0.8.3/go.mod h1:eje970FXxjhtFbVEoiae+VUw24ZoSlk67BsiZPLRzlw=
+github.com/libp2p/go-libp2p-pubsub v0.9.0 h1:mcLb4WzwhUG4OKb0rp1/bYMd/DYhvMyzJheQH3LMd1s=
+github.com/libp2p/go-libp2p-pubsub v0.9.0/go.mod h1:OEsj0Cc/BpkqikXRTrVspWU/Hx7bMZwHP+6vNMd+c7I=
 github.com/libp2p/go-libp2p-pubsub-router v0.6.0 h1:D30iKdlqDt5ZmLEYhHELCMRj8b4sFAqrUcshIUvVP/s=
 github.com/libp2p/go-libp2p-pubsub-router v0.6.0/go.mod h1:FY/q0/RBTKsLA7l4vqC2cbRbOvyDotg8PJQ7j8FDudE=
 github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA=
 github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q=
 github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
 github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
-github.com/libp2p/go-libp2p-routing-helpers v0.6.0 h1:Rfyd+wp/cU0PjNjCphGzLYzd7Q51fjOMs5Sjj6zWGT0=
-github.com/libp2p/go-libp2p-routing-helpers v0.6.0/go.mod h1:wwK/XSLt6njjO7sRbjhf8w7PGBOfdntMQ2mOQPZ5s/Q=
+github.com/libp2p/go-libp2p-routing-helpers v0.6.1 h1:tI3rHOf/FDQsxC2pHBaOZiqPJ0MZYyzGAf4V45xla4U=
+github.com/libp2p/go-libp2p-routing-helpers v0.6.1/go.mod h1:R289GUxUMzRXIbWGSuUUTPrlVJZ3Y/pPz495+qgXJX8=
 github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
 github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
 github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
@@ -835,8 +861,8 @@ github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+
 github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
 github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
 github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
-github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU=
-github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY=
+github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
+github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
 github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI=
 github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=
 github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=
@@ -853,8 +879,6 @@ github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO
 github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
 github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
 github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
-github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo=
-github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc=
 github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
 github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
 github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560=
@@ -893,26 +917,16 @@ github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8=
-github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4=
-github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
-github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
 github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
 github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
-github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
-github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
-github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
-github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
-github.com/marten-seemann/webtransport-go v0.4.3 h1:vkt5o/Ci+luknRteWdYGYH1KcB7ziup+J+1PzZJIvmg=
-github.com/marten-seemann/webtransport-go v0.4.3/go.mod h1:4xcfySgZMLP4aG5GBGj1egP7NlpfwgYJ1WJMvPPiVMU=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -920,12 +934,11 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
 github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
-github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
@@ -963,9 +976,11 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
 github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
@@ -1030,8 +1045,8 @@ github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wS
 github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=
 github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
 github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs=
-github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o=
-github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg=
+github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo=
+github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q=
 github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
 github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
 github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
@@ -1111,8 +1126,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
 github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
 github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
-github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls=
 github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
+github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
+github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1153,6 +1169,16 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
+github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
+github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
+github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
+github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
+github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
+github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
+github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
+github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
+github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk=
+github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU=
 github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
 github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
 github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
@@ -1201,19 +1227,20 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
 github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
+github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
 github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
+github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
 github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
-github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
 github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
@@ -1253,10 +1280,15 @@ github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
@@ -1266,14 +1298,15 @@ github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2r
 github.com/warpfork/go-testmark v0.10.0 h1:E86YlUMYfwIacEsQGlnTvjk1IgYkyTGjPhF0RnwTCmw=
 github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
 github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
-github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=
 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=
 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
 github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
-github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 h1:obKzQ1ey5AJg5NKjgtTo/CKwLImVP4ETLRcsmzFJ4Qw=
-github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
+github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZAkuaCLoxVX4r1TZMPy1d31fM6hbfQ4OU4I5o=
+github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
 github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
@@ -1397,8 +1430,8 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
 golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
+golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
 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=
@@ -1409,8 +1442,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
-golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 h1:5sPMf9HJXrvBWIamTw+rTST0bZ3Mho2n1p58M0+W99c=
+golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1493,8 +1526,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
-golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1602,8 +1635,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 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=
@@ -1615,8 +1648,8 @@ golang.org/x/text v0.3.3/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/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1778,9 +1811,8 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
 google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8=
 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
-google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
 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=
@@ -1842,6 +1874,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
 lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
 lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
 lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
+nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
+nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
 pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
 pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/docs/experimental-features.md b/docs/experimental-features.md
index cd85cb200f5245665dff43515a5f71d983132ca0..296f6ca1e79e01137de9b0b4e110184edeee1d74 100644
--- a/docs/experimental-features.md
+++ b/docs/experimental-features.md
@@ -12,7 +12,6 @@ When you add a new experimental feature to kubo or change an experimental
 feature, you MUST please make a PR updating this document, and link the PR in
 the above issue.
 
-- [ipfs pubsub](#ipfs-pubsub)
 - [Raw leaves for unixfs files](#raw-leaves-for-unixfs-files)
 - [ipfs filestore](#ipfs-filestore)
 - [ipfs urlstore](#ipfs-urlstore)
@@ -31,36 +30,6 @@ the above issue.
 
 ---
 
-## ipfs pubsub
-
-### State
-
-Candidate, disabled by default but will be enabled by default in 0.6.0.
-
-### In Version
-
-0.4.5 (`--enable-pubsub-experiment`)
-0.11.0 (`Pubsub.Enabled` flag in config)
-
-### How to enable
-
-Run your daemon with the `--enable-pubsub-experiment` flag
-or modify your ipfs config and restart the daemon:
-```
-ipfs config --json Pubsub.Enabled true
-```
-
-Then use the `ipfs pubsub` commands.
-
-NOTE: `--enable-pubsub-experiment` CLI flag overrides `Pubsub.Enabled` config.
-
-Configuration documentation can be found in [kubo/docs/config.md](./config.md#pubsub)
-
-### Road to being a real feature
-
-- [ ] Needs to not impact peers who don't use pubsub:
-      https://github.com/libp2p/go-libp2p-pubsub/issues/332
-
 ## Raw Leaves for unixfs files
 
 Allows files to be added with no formatting in the leaf nodes of the graph.
@@ -390,7 +359,7 @@ We also support the use of protocol names of the form /x/$NAME/http where $NAME
 ## FUSE
 
 FUSE makes it possible to mount `/ipfs` and `/ipns` namespaces in your OS,
-allowing argitrary apps access to IPFS using a subset of filesystem abstractions.
+allowing arbitrary apps access to IPFS using a subset of filesystem abstractions.
 
 It is considered  EXPERIMENTAL due to limited (and buggy) support on some platforms.
 
diff --git a/docs/http-rpc-clients.md b/docs/http-rpc-clients.md
index c011b98f72f63baacf2af0f8b67f2af200499728..b77c90a564705512e7f54dd83e58a595bf672dee 100644
--- a/docs/http-rpc-clients.md
+++ b/docs/http-rpc-clients.md
@@ -1,6 +1,6 @@
 # HTTP/RPC Clients
 
-Kubo provides official HTTP RPC  (`/api/v0`) clients for selected lanaguages:
+Kubo provides official HTTP RPC  (`/api/v0`) clients for selected languages:
 
 - [js-kubo-rpc-client](https://github.com/ipfs/js-kubo-rpc-client) - Official JS client for talking to Kubo RPC over HTTP
 - [go-ipfs-api](https://github.com/ipfs/go-ipfs-api) - The go interface to ipfs's HTTP RPC - Follow https://github.com/ipfs/kubo/issues/9124 for coming changes.
diff --git a/docs/libp2p-resource-management.md b/docs/libp2p-resource-management.md
index 7924849d8913b793d35d8671a22ff727d2732645..b7dbf4baef808c29365435ece1d558f6f82b479b 100644
--- a/docs/libp2p-resource-management.md
+++ b/docs/libp2p-resource-management.md
@@ -1,3 +1,4 @@
+<!-- omit in toc -->
 # libp2p Network Resource Manager <small>(`Swarm.ResourceMgr`)</small>
 
 ## Purpose
@@ -13,27 +14,26 @@ Good places to start are:
 
 ## Table of Contents
 
-- [libp2p Network Resource Manager <small>(`Swarm.ResourceMgr`)</small>](#libp2p-network-resource-manager-smallswarmresourcemgrsmall)
-  - [Purpose](#purpose)
-  - [Levels of Configuration](#levels-of-configuration)
-    - [Approach](#approach)
-    - [Computed Default Limits](#computed-default-limits)
-    - [User Supplied Override Limits](#user-supplied-override-limits)
-    - [Infinite limits](#infinite-limits)
-  - [FAQ](#faq)
-    - [What do these "Protected from exceeding resource limits" log messages mean?](#what-do-these-protected-from-exceeding-resource-limits-log-messages-mean)
-    - [What are the "Application error ... cannot reserve ..." messages?](#what-are-the-application-error--cannot-reserve--messages)
-    - [How does the resource manager (ResourceMgr) relate to the connection manager (ConnMgr)?](#how-does-the-resource-manager-resourcemgr-relate-to-the-connection-manager-connmgr)
-    - [How does one see the Active Limits?](#how-does-one-see-the-active-limits)
-    - [How does one see the Computed Default Limits?](#how-does-one-see-the-computed-default-limits)
-    - [How does one monitor libp2p resource usage?](#how-does-one-monitor-libp2p-resource-usage)
-  - [History](#history)
+- [Purpose](#purpose)
+- [🙋 Help!  The resource manager is protecting my node but I want to understand more](#-help--the-resource-manager-is-protecting-my-node-but-i-want-to-understand-more)
+- [Table of Contents](#table-of-contents)
+- [Levels of Configuration](#levels-of-configuration)
+  - [Approach](#approach)
+  - [Computed Default Limits](#computed-default-limits)
+  - [User Supplied Override Limits](#user-supplied-override-limits)
+- [FAQ](#faq)
+  - [What do these "Protected from exceeding resource limits" log messages mean?](#what-do-these-protected-from-exceeding-resource-limits-log-messages-mean)
+  - [How does one see the Active Limits?](#how-does-one-see-the-active-limits)
+  - [How does one see the Computed Default Limits?](#how-does-one-see-the-computed-default-limits)
+  - [How does one monitor libp2p resource usage?](#how-does-one-monitor-libp2p-resource-usage)
+  - [How does the resource manager (ResourceMgr) relate to the connection manager (ConnMgr)?](#how-does-the-resource-manager-resourcemgr-relate-to-the-connection-manager-connmgr)
+  - [What are the "Application error 0x0 (remote) ... cannot reserve ..." messages?](#what-are-the-application-error-0x0-remote--cannot-reserve--messages)
+- [History](#history)
 
 ## Levels of Configuration
 
 See also the [`Swarm.ResourceMgr` config docs](./config.md#swarmresourcemgr).
 
-
 ### Approach
 libp2p's resource manager provides tremendous flexibility but also adds complexity.  There are these levels of limit configuration for resource management protection:
 
@@ -41,12 +41,11 @@ libp2p's resource manager provides tremendous flexibility but also adds complexi
    based on the amount of memory and file descriptors their system has.
    This should protect the node from many attacks.
 
-1. "Slightly more advanced user" - They can tweak the default limits discussed below.  
-   Where the defaults aren't good enough, a good set of higher-level "knobs" are exposed to satisfy most use cases
+2. "Slightly more advanced user" - Where the defaults aren't good enough, a good set of higher-level "knobs" are exposed to satisfy most use cases
    without requiring users to wade into all the intricacies of libp2p's resource manager.
    The "knobs"/inputs are `Swarm.ResourceMgr.MaxMemory` and `Swarm.ResourceMgr.MaxFileDescriptors` as described below.
 
-1. "Power user" - They specify overrides to computed default limits via `ipfs swarm limit` and `Swarm.ResourceMgr.Limits`;
+3. "Power user" - They [specify override limits](#user-supplied-override-limits) and own their own destiny without Kubo getting in the way.
 
 ### Computed Default Limits
 With the `Swarm.ResourceMgr.MaxMemory` and `Swarm.ResourceMgr.MaxFileDescriptors` inputs defined,
@@ -54,7 +53,7 @@ With the `Swarm.ResourceMgr.MaxMemory` and `Swarm.ResourceMgr.MaxFileDescriptors
 [system](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#the-system-scope),
 [transient](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#the-transient-scope),
 and [peer](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#peer-scopes) scopes.
-Other scopes are ignored (by being set to "[~infinity](#infinite-limits])".
+Other scopes are ignored (by being set to "unlimited").
 
 The reason these scopes are chosen is because:
 - `system` - This gives us the coarse-grained control we want so we can reason about the system as a whole.
@@ -66,15 +65,16 @@ The reason these scopes are chosen is because:
   We are reliant on the system scope for protection here in the malicious case.
   The reason for having a peer scope is to protect against unintentional DoS attacks
   (e.g., bug in a peer which is causing it to "misbehave").
-  In the unintional case, we want to make sure a "misbehaving" node doesn't consume more resources than necessary.
+  In the unintentional case, we want to make sure a "misbehaving" node doesn't consume more resources than necessary.
 
-Within these scopes, limits are just set on
-[memory](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#memory),
-[file descriptors (FD)](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#file-descriptors), and [*inbound* connections](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#connections).
+Within these scopes, limits are set on:
+1. [memory](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#memory)
+2. [file descriptors (FD)](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#file-descriptors)
+3. [*inbound* connections](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#connections).
 Limits are set based on the `Swarm.ResourceMgr.MaxMemory` and `Swarm.ResourceMgr.MaxFileDescriptors` inputs above.
 
 There are also some special cases where minimum values are enforced.
-For example, Kubo maintainers have found in practice that it's a footgun to have too low of a value for `Swarm.ResourceMgr.Limits.System.ConnsInbound` and a default minimum is used. (See [core/node/libp2p/rcmgr_defaults.go](https://github.com/ipfs/kubo/blob/master/core/node/libp2p/rcmgr_defaults.go) for specifics.)
+For example, Kubo maintainers have found in practice that it's a footgun to have too low of a value for `System.ConnsInbound` and a default minimum is used. (See [core/node/libp2p/rcmgr_defaults.go](https://github.com/ipfs/kubo/blob/master/core/node/libp2p/rcmgr_defaults.go) for specifics.)
 
 We trust this node to behave properly and thus don't limit *outbound* connection/stream limits.
 We apply any limits that libp2p has for its protocols/services
@@ -83,29 +83,10 @@ since we assume libp2p knows best here.
 Source: [core/node/libp2p/rcmgr_defaults.go](https://github.com/ipfs/kubo/blob/master/core/node/libp2p/rcmgr_defaults.go)
 
 ### User Supplied Override Limits
-Once Kubo has the [Computed Default Limits](#computed-default-limits), it then applies any user-supplied [`Swarm.ResourceMgr.Limits`](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgrlimits) on top.
-These become the [active limits](#how-does-one-see-the-active-limits).
-
-While `Swarm.ResourceMgr.Limits` can be edited directly, it is also possible to use `ipfs swarm limit` command to inspect and tweak specific limits at runtime.
-
-To see all resources that are close to hitting their respective limit:
-
-```console
-$ ipfs swarm stats --min-used-limit-perc=90 all
-```
-
-To modify limits for specific scope (e.g. `system`):
-
-```console
-$ ipfs swarm limit system > change.json
-$ vi change.json
-$ ipfs swarm limit system change.json
-```
-
-Learn more: `ipfs swarm limit --help`
-
-### Infinite limits
-There isn't a way via config to specify infinite limits (see [go-libp2p#1935](https://github.com/libp2p/go-libp2p/issues/1935)).  For example, "-1" is not infinity.  To work around this, Kubo uses a magic number of "1000000000" to denote infinity since it's effectively infinite.  
+A user who wants fine control over the limits used by the go-libp2p resoure manager can specify overrides to the [computed default limits](#computed-default-limits).
+This is done by defining limits in ``$IPFS_PATH/libp2p-resource-limit-overrides.json``.
+These values trump anything else and are parsed directly by go-libp2p.
+(See the [go-libp2p Resource Manager README](https://github.com/libp2p/go-libp2p/blob/master/p2p/host/resource-manager/README.md) for formatting.) 
 
 ## FAQ
 
@@ -116,58 +97,61 @@ As an example:
 
 > Protected from exceeding resource limits 2 times: "system: cannot reserve inbound connection: resource limit exceeded"
 
-This means that there were 2 recent occurences where the libp2p resource manager prevented an inbound connection at the "system" [scope](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#resource-scopes).  
-Specificaly the ``Swarm.ResourceMgr.Limits.System.ConnsInbound`` [active limit](#how-does-one-see-the-active-limits) was hit.  
+This means that there were 2 recent occurrences where the libp2p resource manager prevented an inbound connection at the "system" [scope](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#resource-scopes).  
+Specificaly the ``System.ConnsInbound`` limit was hit.  
 
-This can be analyzed by viewing the limit with `ipfs swarm limit system` and comparing the usage with `ipfs swarm stats system`.
-`ConnsInbound` is likely close or at the limit value.
+This can be analyzed by viewing the limit and current usage with `ipfs swarm resources`.
+`System.ConnsInbound` is likely close or at the limit value.
 
-The simiplest way to identify all resources across all scopes that are close to exceeding their limit is with a command like `ipfs swarm stats --min-used-limit-perc=90 all`.
+The simplest way to identify all resources across all scopes that are close to exceeding their limit (>90% usage) is with a command like `ipfs swarm resources | egrep "9.\..%"` 
 
 Sources:
 * [kubo resource manager logging](https://github.com/ipfs/kubo/blob/master/core/node/libp2p/rcmgr_logging.go)
 * [libp2p resource manager messages](https://github.com/libp2p/go-libp2p/blob/master/p2p/host/resource-manager/scope.go)
 
-### What are the "Application error ... cannot reserve ..." messages?
-These are messages from a *remote* go-libp2p peer (likely another Kubo node) with the resource manager enabled on why it failed to establish a connection.  
+### How does one see the Active Limits?
+A dump of what limits are actually being used by the resource manager ([Computed Default Limits](#computed-default-limits) + [User Supplied Override Limits](#user-supplied-override-limits))
+can be obtained by `ipfs swarm resources`.
 
-This can be confusing, but these `Application error ... cannot reserve ...` messages can occur even if your local node has the resoure manager disabled.
+### How does one see the Computed Default Limits?
+This can be observed [seeing the active limits](#how-does-one-see-the-active-limits) assuming one hasn't detoured into "power user" mode with [User Supplied Override Limits](#user-supplied-override-limits).
 
-You can distinguish resource manager messages originating from your local node if they're from the `resourcemanager` / `libp2p/rcmgr_logging.go` logger
-or you see the string that is unique to Kubo (and not in go-libp2p): "Protected from exceeding resource limits".
+### How does one monitor libp2p resource usage?
 
-There is a go-libp2p issue ([#1928](https://github.com/libp2p/go-libp2p/issues/1928)) to make it clearer that this is an error message originating from a remote peer.
+For [monitoring libp2p resource usage](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#monitoring), 
+various `*rcmgr_*` metrics can be accessed as the Prometheus endpoint at `{Addresses.API}/debug/metrics/prometheus` (default: `http://127.0.0.1:5001/debug/metrics/prometheus`).  
+There are also [pre-built Grafana dashboards](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager/obs/grafana-dashboards) that can be added to a Grafana instance. 
+
+A textual view of current resource usage and a list of services, protocols, and peers can be
+obtained via `ipfs swarm stats --help`
 
 ### How does the resource manager (ResourceMgr) relate to the connection manager (ConnMgr)?
 As discussed [here](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#connmanager-vs-resource-manager)
 these are separate systems in go-libp2p.
 Kubo performs sanity checks to ensure that some of the hard limits of the ResourceMgr are sufficiently greater than the soft limits of the ConnMgr.
 
-The soft limit of `Swarm.ConnMgr.HighWater` needs to be less than the hard limit `Swarm.ResourceMgr.Limits.System.ConnsInbound` for the configuration to make sense.
+The soft limit of `Swarm.ConnMgr.HighWater` needs to be less than the resource manager hard limit `System.ConnsInbound` for the configuration to make sense.
 This ensures the ConnMgr cleans up connections based on connection priorities before the hard limits of the ResourceMgr are applied.
-If `Swarm.ConnMgr.HighWater` is greater than `Swarm.ResourceMgr.Limits.System.ConnsInbound`,
+If `Swarm.ConnMgr.HighWater` is greater than resource manager's `System.ConnsInbound`,
 existing low priority idle connections can prevent new high priority connections from being established.
 The ResourceMgr doesn't know that the new connection is high priority and simply blocks it because of the limit its enforcing.
 
 To ensure the ConnMgr and ResourceMgr are congruent, the ResourceMgr [computed default limts](#computed-default-limits) are adjusted such that:
-1. `Swarm.ResourceMgr.Limits.System.ConnsInbound` >= `max(Swarm.ConnMgr.HighWater * 2, 800)` AND
-2. `Swarm.ResourceMgr.Limits.System.StreamsInbound` is greater than any new/adjusted `Swarm.ResourceMgr.Limits.System.ConnsInbound` value so that there's enough streams per connection.
+1. `System.ConnsInbound` >= `max(Swarm.ConnMgr.HighWater * 2, DefaultResourceMgrMinInboundConns)` AND
+2. `System.StreamsInbound` is greater than any new/adjusted `Swarm.ResourceMgr.Limits.System.ConnsInbound` value so that there's enough streams per connection.
 
-### How does one see the Active Limits?
-A dump of what limits are actually being used by the resource manager ([Computed Default Limits](#computed-default-limits) + [User Supplied Override Limits](#user-supplied-override-limits))
-can be obtained by `ipfs swarm limit all`.
+Source: [core/node/libp2p/rcmgr_defaults.go](https://github.com/ipfs/kubo/blob/master/core/node/libp2p/rcmgr_defaults.go)
 
-### How does one see the Computed Default Limits?
-This can be observed with an empty [`Swarm.ResourceMgr.Limits`](https://github.com/ipfs/kubo/blob/master/docs/config.md#swarmresourcemgrlimits)
-and then [seeing the active limits](#how-does-one-see-the-active-limits).
+### What are the "Application error 0x0 (remote) ... cannot reserve ..." messages?
+These are messages coming from old (pre go-libp2p 0.26) *remote* go-libp2p peers (likely another older Kubo node) with the resource manager enabled on why it failed to establish a connection.  
 
-### How does one monitor libp2p resource usage?
-For [monitoring libp2p resource usage](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager#monitoring),
-various `*rcmgr_*` metrics can be accessed as the prometheus endpoint at `{Addresses.API}/debug/metrics/prometheus` (default: `http://127.0.0.1:5001/debug/metrics/prometheus`).  
-There are also [pre-built Grafana dashboards](https://github.com/libp2p/go-libp2p/tree/master/p2p/host/resource-manager/obs/grafana-dashboards) that can be added to a Grafana instance.
+This can be confusing, but these `Application error 0x0 (remote) ... cannot reserve ...` messages can occur even if your local node has the resource manager disabled.
+
+You can distinguish resource manager messages originating from your local node if they're from the `resourcemanager` / `libp2p/rcmgr_logging.go` logger
+or you see the string that is unique to Kubo (and not in go-libp2p): "Protected from exceeding resource limits".
+
+See more info in this go-libp2p issue ([#1928](https://github.com/libp2p/go-libp2p/issues/1928)).  go-libp2p 0.26 / Kubo 0.19 onwards this confusing error message was removed.
 
-A textual view of current resource usage and a list of services, protocols, and peers can be
-obtained via `ipfs swarm stats --help`
 
 ## History
-Kubo first [exposed this functionality in Kubo 0.13](./changelogs/v0.13.md#-libp2p-network-resource-manager-swarmresourcemgr), but it was disabled by default.  It was then enabled by default in [Kubo 0.17](./changelogs/v0.17.md#libp2p-resource-management-enabled-by-default).  Until that point, Kubo was vulnerable to unbound resource usage which could bring down nodes.  Introducing limits like this by default after the fact is tricky, which is why there have been changes and improvements afterwards.
+Kubo first [exposed this functionality in Kubo 0.13](./changelogs/v0.13.md#-libp2p-network-resource-manager-swarmresourcemgr), but it was disabled by default.  It was then enabled by default in [Kubo 0.17](./changelogs/v0.17.md#libp2p-resource-management-enabled-by-default).  Until that point, Kubo was vulnerable to unbound resource usage which could bring down nodes.  Introducing limits like this by default after the fact is tricky, which is why there have been changes and improvements afterwards.  The general trend since 0.17 with (0.18)[./changeloges/v0.18.md#improving-libp2p-resource-management-integration] and 0.19 has been to simplify and provide less options (and footguns!) for users and better documentation.
diff --git a/fuse/node/mount_test.go b/fuse/node/mount_test.go
index 12313ae3ea65243c91aec4adfa20d2a01bcf14f4..1691cfa5ba26688c23f78dff6021f214e97b0a8c 100644
--- a/fuse/node/mount_test.go
+++ b/fuse/node/mount_test.go
@@ -4,6 +4,7 @@
 package node
 
 import (
+	"context"
 	"os"
 	"strings"
 	"testing"
@@ -11,8 +12,6 @@ import (
 
 	"bazil.org/fuse"
 
-	"context"
-
 	core "github.com/ipfs/kubo/core"
 	ipns "github.com/ipfs/kubo/fuse/ipns"
 	mount "github.com/ipfs/kubo/fuse/mount"
@@ -52,11 +51,8 @@ func TestExternalUnmount(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	// get the test dir paths (/tmp/fusetestXXXX)
-	dir, err := os.MkdirTemp("", "fusetest")
-	if err != nil {
-		t.Fatal(err)
-	}
+	// get the test dir paths (/tmp/TestExternalUnmount)
+	dir := t.TempDir()
 
 	ipfsDir := dir + "/ipfs"
 	ipnsDir := dir + "/ipns"
diff --git a/go.mod b/go.mod
index 5120159fdfeffeed164aa27c151ef45c8a12740d..f7237b46a745df009c9760210755615da0b0cce4 100644
--- a/go.mod
+++ b/go.mod
@@ -7,18 +7,15 @@ require (
 	github.com/blang/semver/v4 v4.0.0
 	github.com/cenkalti/backoff/v4 v4.1.3
 	github.com/ceramicnetwork/go-dag-jose v0.1.0
-	github.com/cespare/xxhash v1.1.0
 	github.com/cheggaaa/pb v1.0.29
 	github.com/coreos/go-systemd/v22 v22.5.0
 	github.com/dustin/go-humanize v1.0.0
 	github.com/elgris/jsondiff v0.0.0-20160530203242-765b5c24c302
 	github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5
 	github.com/fsnotify/fsnotify v1.6.0
-	github.com/gabriel-vasile/mimetype v1.4.1
+	github.com/gogo/protobuf v1.3.2
 	github.com/google/uuid v1.3.0
 	github.com/hashicorp/go-multierror v1.1.1
-	github.com/ipfs/go-bitswap v0.11.0
-	github.com/ipfs/go-block-format v0.0.3
 	github.com/ipfs/go-blockservice v0.5.0
 	github.com/ipfs/go-cid v0.3.2
 	github.com/ipfs/go-cidutil v0.1.0
@@ -39,31 +36,30 @@ require (
 	github.com/ipfs/go-ipfs-exchange-interface v0.2.0
 	github.com/ipfs/go-ipfs-exchange-offline v0.3.0
 	github.com/ipfs/go-ipfs-keystore v0.1.0
-	github.com/ipfs/go-ipfs-pinner v0.2.1
+	github.com/ipfs/go-ipfs-pinner v0.3.0
 	github.com/ipfs/go-ipfs-posinfo v0.0.1
 	github.com/ipfs/go-ipfs-provider v0.8.1
-	github.com/ipfs/go-ipfs-redirects-file v0.1.1
 	github.com/ipfs/go-ipfs-routing v0.3.0
 	github.com/ipfs/go-ipfs-util v0.0.2
 	github.com/ipfs/go-ipld-format v0.4.0
 	github.com/ipfs/go-ipld-git v0.1.1
 	github.com/ipfs/go-ipld-legacy v0.1.1
 	github.com/ipfs/go-ipns v0.3.0
-	github.com/ipfs/go-libipfs v0.2.0
+	github.com/ipfs/go-libipfs v0.6.2
 	github.com/ipfs/go-log v1.0.5
 	github.com/ipfs/go-log/v2 v2.5.1
 	github.com/ipfs/go-merkledag v0.9.0
 	github.com/ipfs/go-metrics-interface v0.0.1
 	github.com/ipfs/go-metrics-prometheus v0.0.2
 	github.com/ipfs/go-mfs v0.2.1
-	github.com/ipfs/go-namesys v0.6.0
-	github.com/ipfs/go-path v0.3.0
+	github.com/ipfs/go-namesys v0.7.0
+	github.com/ipfs/go-path v0.3.1
 	github.com/ipfs/go-pinning-service-http-client v0.1.2
-	github.com/ipfs/go-unixfs v0.4.2
-	github.com/ipfs/go-unixfsnode v1.5.1
+	github.com/ipfs/go-unixfs v0.4.4
+	github.com/ipfs/go-unixfsnode v1.5.2
 	github.com/ipfs/go-verifcid v0.0.2
-	github.com/ipfs/interface-go-ipfs-core v0.8.2
-	github.com/ipld/go-car v0.4.0
+	github.com/ipfs/interface-go-ipfs-core v0.11.0
+	github.com/ipld/go-car v0.5.0
 	github.com/ipld/go-car/v2 v2.5.1
 	github.com/ipld/go-codec-dagpb v1.5.0
 	github.com/ipld/go-ipld-prime v0.19.0
@@ -71,14 +67,14 @@ require (
 	github.com/jbenet/go-temp-err-catcher v0.1.0
 	github.com/jbenet/goprocess v0.1.4
 	github.com/libp2p/go-doh-resolver v0.4.0
-	github.com/libp2p/go-libp2p v0.24.2
+	github.com/libp2p/go-libp2p v0.26.3
 	github.com/libp2p/go-libp2p-http v0.4.0
-	github.com/libp2p/go-libp2p-kad-dht v0.20.0
+	github.com/libp2p/go-libp2p-kad-dht v0.21.1
 	github.com/libp2p/go-libp2p-kbucket v0.5.0
-	github.com/libp2p/go-libp2p-pubsub v0.8.3
+	github.com/libp2p/go-libp2p-pubsub v0.9.0
 	github.com/libp2p/go-libp2p-pubsub-router v0.6.0
 	github.com/libp2p/go-libp2p-record v0.2.0
-	github.com/libp2p/go-libp2p-routing-helpers v0.6.0
+	github.com/libp2p/go-libp2p-routing-helpers v0.6.1
 	github.com/libp2p/go-libp2p-testing v0.12.0
 	github.com/libp2p/go-socket-activation v0.1.0
 	github.com/miekg/dns v1.1.50
@@ -109,10 +105,10 @@ require (
 	go.uber.org/dig v1.15.0
 	go.uber.org/fx v1.18.2
 	go.uber.org/zap v1.24.0
-	golang.org/x/crypto v0.3.0
+	golang.org/x/crypto v0.5.0
 	golang.org/x/mod v0.7.0
 	golang.org/x/sync v0.1.0
-	golang.org/x/sys v0.4.0
+	golang.org/x/sys v0.5.0
 )
 
 require (
@@ -122,6 +118,7 @@ require (
 	github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cenkalti/backoff v2.2.1+incompatible // indirect
+	github.com/cespare/xxhash v1.1.0 // indirect
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/containerd/cgroups v1.0.4 // indirect
 	github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
@@ -137,13 +134,13 @@ require (
 	github.com/felixge/httpsnoop v1.0.2 // indirect
 	github.com/flynn/noise v1.0.0 // indirect
 	github.com/francoispqt/gojay v1.2.13 // indirect
+	github.com/gabriel-vasile/mimetype v1.4.1 // indirect
 	github.com/go-kit/log v0.2.0 // indirect
 	github.com/go-logfmt/logfmt v0.5.1 // indirect
 	github.com/go-logr/logr v1.2.3 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
 	github.com/godbus/dbus/v5 v5.1.0 // indirect
-	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/golang/mock v1.6.0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
@@ -151,23 +148,25 @@ require (
 	github.com/google/gopacket v1.1.19 // indirect
 	github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
 	github.com/gorilla/mux v1.8.0 // indirect
-	github.com/gorilla/websocket v1.5.0 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
 	github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/hashicorp/golang-lru/v2 v2.0.1 // indirect
 	github.com/huin/goupnp v1.0.3 // indirect
 	github.com/ipfs/bbloom v0.0.4 // indirect
-	github.com/ipfs/go-bitfield v1.0.0 // indirect
+	github.com/ipfs/go-bitfield v1.1.0 // indirect
+	github.com/ipfs/go-block-format v0.1.1 // indirect
 	github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
 	github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
-	github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
+	github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
+	github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect
 	github.com/ipfs/go-ipld-cbor v0.0.6 // indirect
-	github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
+	github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
 	github.com/ipld/edelweiss v0.2.0 // indirect
 	github.com/jackpal/go-nat-pmp v1.0.2 // indirect
 	github.com/klauspost/compress v1.15.12 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.1 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.3 // indirect
 	github.com/koron/go-ssdp v0.0.3 // indirect
 	github.com/libp2p/go-buffer-pool v0.1.0 // indirect
 	github.com/libp2p/go-cidranger v1.1.0 // indirect
@@ -176,22 +175,15 @@ require (
 	github.com/libp2p/go-libp2p-gostream v0.5.0 // indirect
 	github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
 	github.com/libp2p/go-mplex v0.7.0 // indirect
-	github.com/libp2p/go-msgio v0.2.0 // indirect
+	github.com/libp2p/go-msgio v0.3.0 // indirect
 	github.com/libp2p/go-nat v0.1.0 // indirect
 	github.com/libp2p/go-netroute v0.2.1 // indirect
-	github.com/libp2p/go-openssl v0.1.0 // indirect
 	github.com/libp2p/go-reuseport v0.2.0 // indirect
 	github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
 	github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
-	github.com/lucas-clemente/quic-go v0.31.1 // indirect
-	github.com/marten-seemann/qpack v0.3.0 // indirect
-	github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
-	github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
 	github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
-	github.com/marten-seemann/webtransport-go v0.4.3 // indirect
 	github.com/mattn/go-colorable v0.1.4 // indirect
 	github.com/mattn/go-isatty v0.0.17 // indirect
-	github.com/mattn/go-pointer v0.0.1 // indirect
 	github.com/mattn/go-runewidth v0.0.4 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
@@ -202,26 +194,30 @@ require (
 	github.com/multiformats/go-base32 v0.1.0 // indirect
 	github.com/multiformats/go-base36 v0.2.0 // indirect
 	github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
-	github.com/multiformats/go-multistream v0.3.3 // indirect
+	github.com/multiformats/go-multistream v0.4.1 // indirect
 	github.com/multiformats/go-varint v0.0.7 // indirect
 	github.com/onsi/ginkgo/v2 v2.5.1 // indirect
 	github.com/opencontainers/runtime-spec v1.0.2 // indirect
 	github.com/openzipkin/zipkin-go v0.4.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
+	github.com/polydawn/refmt v0.89.0 // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
 	github.com/prometheus/common v0.37.0 // indirect
 	github.com/prometheus/procfs v0.8.0 // indirect
 	github.com/prometheus/statsd_exporter v0.21.0 // indirect
+	github.com/quic-go/qpack v0.4.0 // indirect
+	github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
+	github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
+	github.com/quic-go/quic-go v0.33.0 // indirect
+	github.com/quic-go/webtransport-go v0.5.2 // indirect
 	github.com/raulk/go-watchdog v1.3.0 // indirect
 	github.com/rs/cors v1.7.0 // indirect
 	github.com/samber/lo v1.36.0 // indirect
-	github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
 	github.com/spaolacci/murmur3 v1.1.0 // indirect
 	github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e // indirect
 	github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
 	github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
-	github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 // indirect
+	github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa // indirect
 	github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
 	github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
 	go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.7.0 // indirect
@@ -231,11 +227,11 @@ require (
 	go.uber.org/atomic v1.10.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
 	go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
-	golang.org/x/exp v0.0.0-20221205204356-47842c84f3db // indirect
-	golang.org/x/net v0.3.0 // indirect
+	golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 // indirect
+	golang.org/x/net v0.7.0 // indirect
 	golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
-	golang.org/x/term v0.4.0 // indirect
-	golang.org/x/text v0.5.0 // indirect
+	golang.org/x/term v0.5.0 // indirect
+	golang.org/x/text v0.7.0 // indirect
 	golang.org/x/tools v0.3.0 // indirect
 	golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
 	google.golang.org/appengine v1.6.6 // indirect
@@ -246,6 +242,7 @@ require (
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	lukechampine.com/blake3 v1.1.7 // indirect
+	nhooyr.io/websocket v1.8.7 // indirect
 )
 
 go 1.18
diff --git a/go.sum b/go.sum
index e044b9a00464da7f731dbb3f61ad8ca6a32404a1..27e101e1c8a6c070d561e9d7dbd2368f222f741b 100644
--- a/go.sum
+++ b/go.sum
@@ -242,6 +242,10 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS
 github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
 github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
 github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@@ -264,10 +268,24 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
 github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
+github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
 github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
 github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
@@ -380,7 +398,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
 github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -416,6 +433,8 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/golang-lru/v2 v2.0.1 h1:5pv5N1lT1fjLg2VQ5KWc7kmucp2x/kvFOnxuVTqZ6x4=
+github.com/hashicorp/golang-lru/v2 v2.0.1/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
 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.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
@@ -433,18 +452,19 @@ github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod
 github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI=
 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ=
 github.com/ipfs/go-bitfield v1.0.0/go.mod h1:N/UiujQy+K+ceU1EF5EkVd1TNqevLrCQMIcAEPrdtus=
+github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
+github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
 github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0=
 github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs=
 github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo=
 github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA=
 github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
-github.com/ipfs/go-bitswap v0.11.0/go.mod h1:05aE8H3XOU+LXpTedeAS0OZpcO1WFsj5niYQH9a1Tmk=
 github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc=
 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
-github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc=
 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
+github.com/ipfs/go-block-format v0.1.1 h1:129vSO3zwbsYADcyQWcOYiuCpAqt462SFfqFHdFJhhI=
+github.com/ipfs/go-block-format v0.1.1/go.mod h1:+McEIT+g52p+zz5xGAABGSOKrzmrdX97bc0USBdWPUs=
 github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M=
 github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8=
 github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk=
@@ -534,13 +554,14 @@ github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB
 github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4=
 github.com/ipfs/go-ipfs-keystore v0.1.0 h1:gfuQUO/cyGZgZIHE6OrJas4OnwuxXCqJG7tI0lrB5Qc=
 github.com/ipfs/go-ipfs-keystore v0.1.0/go.mod h1:LvLw7Qhnb0RlMOfCzK6OmyWxICip6lQ06CCmdbee75U=
-github.com/ipfs/go-ipfs-pinner v0.2.1 h1:kw9hiqh2p8TatILYZ3WAfQQABby7SQARdrdA+5Z5QfY=
-github.com/ipfs/go-ipfs-pinner v0.2.1/go.mod h1:l1AtLL5bovb7opnG77sh4Y10waINz3Y1ni6CvTzx7oo=
+github.com/ipfs/go-ipfs-pinner v0.3.0 h1:jwe5ViX3BON3KgOAYrrhav2+1ONB0QzFAWQd7HUlbuM=
+github.com/ipfs/go-ipfs-pinner v0.3.0/go.mod h1:oX0I0nC6zlNIh0LslSrUnjfNKPq8ufoFtqV1/wcJvyo=
 github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
 github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=
 github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
-github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY=
 github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
+github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE=
+github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4=
 github.com/ipfs/go-ipfs-provider v0.8.1 h1:qt670pYmcNH3BCjyXDgg07o2WsTRsOdMwYc25ukCdjQ=
 github.com/ipfs/go-ipfs-provider v0.8.1/go.mod h1:qCpwpoohIRVXvNzkygzsM3qdqP/sXlrogtA5I45tClc=
 github.com/ipfs/go-ipfs-redirects-file v0.1.1 h1:Io++k0Vf/wK+tfnhEh63Yte1oQK5VGT2hIEYpD0Rzx8=
@@ -570,8 +591,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2
 github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg=
 github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
 github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
-github.com/ipfs/go-libipfs v0.2.0 h1:MedvelDEddPYL3iDLoqAsviLeXUiwB1F2t8fkzx9/EU=
-github.com/ipfs/go-libipfs v0.2.0/go.mod h1:qX0d9h+wu53PFtCTXxdXVBakd6ZCvGDdkZUKmdLMLx0=
+github.com/ipfs/go-libipfs v0.6.2 h1:QUf3kS3RrCjgtE0QW2d18PFFfOLeEt24Ft892ipLzRI=
+github.com/ipfs/go-libipfs v0.6.2/go.mod h1:FmhKgxMOQA572TK5DA3MZ5GL44ZqsMHIrkgK4gLn4A8=
 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
 github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk=
 github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
@@ -598,33 +619,33 @@ github.com/ipfs/go-metrics-prometheus v0.0.2 h1:9i2iljLg12S78OhC6UAiXi176xvQGiZa
 github.com/ipfs/go-metrics-prometheus v0.0.2/go.mod h1:ELLU99AQQNi+zX6GCGm2lAgnzdSH3u5UVlCdqSXnEks=
 github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8=
 github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88=
-github.com/ipfs/go-namesys v0.6.0 h1:w4+Wq9bCILnuZRT1RBBdzZQFqtJeDG1duzN8mIDnHZ0=
-github.com/ipfs/go-namesys v0.6.0/go.mod h1:0L+3CHBgHxr08Cg+chVo9Ew285PGQfToThjll4g0/d4=
+github.com/ipfs/go-namesys v0.7.0 h1:xqosk71GIVRkFDtF2UNRcXn4LdNeo7tzuy8feHD6NbU=
+github.com/ipfs/go-namesys v0.7.0/go.mod h1:KYSZBVZG3VJC34EfqqJPG7T48aWgxseoMPAPA5gLyyQ=
 github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I=
-github.com/ipfs/go-path v0.3.0 h1:tkjga3MtpXyM5v+3EbRvOHEoo+frwi4oumw5K+KYWyA=
-github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I=
+github.com/ipfs/go-path v0.3.1 h1:wkeaCWE/NTuuPGlEkLTsED5UkzfKYZpxaFFPgk8ZVLE=
+github.com/ipfs/go-path v0.3.1/go.mod h1:eNLsxJEEMxn/CDzUJ6wuNl+6No6tEUhOZcPKsZsYX0E=
 github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U=
 github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
-github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU=
-github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM=
+github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg=
+github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU=
 github.com/ipfs/go-pinning-service-http-client v0.1.2 h1:jdr7KelhL9gNHTU8jbqPMwIexSZXgZzxNGkycCwmbXI=
 github.com/ipfs/go-pinning-service-http-client v0.1.2/go.mod h1:6wd5mjYhXJTiWU8b4RSWPpWdlzE5/csoXV0dWWMjun4=
 github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
 github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o=
-github.com/ipfs/go-unixfs v0.4.2 h1:hdQlsHHK5tek9gC9mjGVua8xyTqC+eopGseCRcbCZNg=
-github.com/ipfs/go-unixfs v0.4.2/go.mod h1:L+x6JRlFE0PfyMqeoLYVOKLhn5IeZHvNT7ZI51Y9Qyc=
+github.com/ipfs/go-unixfs v0.4.4 h1:D/dLBOJgny5ZLIur2vIXVQVW0EyDHdOMBDEhgHrt6rY=
+github.com/ipfs/go-unixfs v0.4.4/go.mod h1:TSG7G1UuT+l4pNj91raXAPkX0BhJi3jST1FDTfQ5QyM=
 github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s=
-github.com/ipfs/go-unixfsnode v1.5.1 h1:JcR3t5C2nM1V7PMzhJ/Qmo19NkoFIKweDSZyDx+CjkI=
-github.com/ipfs/go-unixfsnode v1.5.1/go.mod h1:ed79DaG9IEuZITJVQn4U6MZDftv6I3ygUBLPfhEbHvk=
+github.com/ipfs/go-unixfsnode v1.5.2 h1:CvsiTt58W2uR5dD8bqQv+aAY0c1qolmXmSyNbPHYiew=
+github.com/ipfs/go-unixfsnode v1.5.2/go.mod h1:NlOebRwYx8lMCNMdhAhEspYPBD3obp7TE0LvBqHY+ks=
 github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
 github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs=
 github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU=
-github.com/ipfs/interface-go-ipfs-core v0.8.2 h1:WDeCBnE4MENVOXbtfwwdAPJ2nBBS8PTmhZWWpm24HRM=
-github.com/ipfs/interface-go-ipfs-core v0.8.2/go.mod h1:F3EcmDy53GFkF0H3iEJpfJC320fZ/4G60eftnItrrJ0=
+github.com/ipfs/interface-go-ipfs-core v0.11.0 h1:n1tplrwsz7oZXkpkZM5a3MDBxksMfSQ103ej4e+l7NA=
+github.com/ipfs/interface-go-ipfs-core v0.11.0/go.mod h1:xmnoccUXY7N/Q8AIx0vFqgW926/FAZ8+do/1NTEHKsU=
 github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
 github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
-github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
-github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4=
+github.com/ipld/go-car v0.5.0 h1:kcCEa3CvYMs0iE5BzD5sV7O2EwMiCIp3uF8tA6APQT8=
+github.com/ipld/go-car v0.5.0/go.mod h1:ppiN5GWpjOZU9PgpAZ9HbZd9ZgSpwPMr48fGRJOWmvE=
 github.com/ipld/go-car/v2 v2.5.1 h1:U2ux9JS23upEgrJScW8VQuxmE94560kYxj9CQUpcfmk=
 github.com/ipld/go-car/v2 v2.5.1/go.mod h1:jKjGOqoCj5zn6KjnabD6JbnCsMntqU2hLiU6baZVO3E=
 github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA=
@@ -668,8 +689,10 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+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 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
@@ -684,13 +707,14 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
 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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
 github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.1 h1:U33DW0aiEj633gHYw3LoDNfkDiYnE5Q8M/TKJn2f2jI=
-github.com/klauspost/cpuid/v2 v2.2.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
+github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 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/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
@@ -708,6 +732,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
 github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
 github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E=
 github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
@@ -734,8 +760,8 @@ github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xS
 github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw=
 github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o=
 github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0=
-github.com/libp2p/go-libp2p v0.24.2 h1:iMViPIcLY0D6zr/f+1Yq9EavCZu2i7eDstsr1nEwSAk=
-github.com/libp2p/go-libp2p v0.24.2/go.mod h1:WuxtL2V8yGjam03D93ZBC19tvOUiPpewYv1xdFGWu1k=
+github.com/libp2p/go-libp2p v0.26.3 h1:6g/psubqwdaBqNNoidbRKSTBEYgaOuKBhHl8Q5tO+PM=
+github.com/libp2p/go-libp2p v0.26.3/go.mod h1:x75BN32YbwuY0Awm2Uix4d4KOz+/4piInkp4Wr3yOo8=
 github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw=
 github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI=
 github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8=
@@ -782,8 +808,8 @@ github.com/libp2p/go-libp2p-gostream v0.5.0 h1:niNGTUrFoUDP/8jxMgu97zngMO+UGYBpV
 github.com/libp2p/go-libp2p-gostream v0.5.0/go.mod h1:rXrb0CqfcRRxa7m3RSKORQiKiWgk3IPeXWda66ZXKsA=
 github.com/libp2p/go-libp2p-http v0.4.0 h1:V+f9Rhe/8GkColmXoyJyA0NVsN9F3TCLZgW2hwjoX5w=
 github.com/libp2p/go-libp2p-http v0.4.0/go.mod h1:92tmLGrlBliQFDlZRpBXT3BJM7rGFONy0vsNrG/bMPg=
-github.com/libp2p/go-libp2p-kad-dht v0.20.0 h1:1bcMa74JFwExCHZMFEmjtHzxX5DovhJ07EtR6UOTEpc=
-github.com/libp2p/go-libp2p-kad-dht v0.20.0/go.mod h1:qPIXdiZsLczhV4/+4EO1jE8ae0YCW4ZOogc4WVIyTEU=
+github.com/libp2p/go-libp2p-kad-dht v0.21.1 h1:xpfp8/t9+X2ip1l8Umap1/UGNnJ3RHJgKGAEsnRAlTo=
+github.com/libp2p/go-libp2p-kad-dht v0.21.1/go.mod h1:Oy8wvbdjpB70eS5AaFaI68tOtrdo3KylTvXDjikxqFo=
 github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
 github.com/libp2p/go-libp2p-kbucket v0.5.0 h1:g/7tVm8ACHDxH29BGrpsQlnNeu+6OF1A9bno/4/U1oA=
 github.com/libp2p/go-libp2p-kbucket v0.5.0/go.mod h1:zGzGCpQd78b5BNTDGHNDLaTt9aDK/A02xeZp9QeFC4U=
@@ -809,16 +835,16 @@ github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRj
 github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
 github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
 github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
-github.com/libp2p/go-libp2p-pubsub v0.8.3 h1:T4+pcfcFm1K2v5oFyk68peSjVroaoM8zFygf6Y5WOww=
-github.com/libp2p/go-libp2p-pubsub v0.8.3/go.mod h1:eje970FXxjhtFbVEoiae+VUw24ZoSlk67BsiZPLRzlw=
+github.com/libp2p/go-libp2p-pubsub v0.9.0 h1:mcLb4WzwhUG4OKb0rp1/bYMd/DYhvMyzJheQH3LMd1s=
+github.com/libp2p/go-libp2p-pubsub v0.9.0/go.mod h1:OEsj0Cc/BpkqikXRTrVspWU/Hx7bMZwHP+6vNMd+c7I=
 github.com/libp2p/go-libp2p-pubsub-router v0.6.0 h1:D30iKdlqDt5ZmLEYhHELCMRj8b4sFAqrUcshIUvVP/s=
 github.com/libp2p/go-libp2p-pubsub-router v0.6.0/go.mod h1:FY/q0/RBTKsLA7l4vqC2cbRbOvyDotg8PJQ7j8FDudE=
 github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA=
 github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q=
 github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
 github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
-github.com/libp2p/go-libp2p-routing-helpers v0.6.0 h1:Rfyd+wp/cU0PjNjCphGzLYzd7Q51fjOMs5Sjj6zWGT0=
-github.com/libp2p/go-libp2p-routing-helpers v0.6.0/go.mod h1:wwK/XSLt6njjO7sRbjhf8w7PGBOfdntMQ2mOQPZ5s/Q=
+github.com/libp2p/go-libp2p-routing-helpers v0.6.1 h1:tI3rHOf/FDQsxC2pHBaOZiqPJ0MZYyzGAf4V45xla4U=
+github.com/libp2p/go-libp2p-routing-helpers v0.6.1/go.mod h1:R289GUxUMzRXIbWGSuUUTPrlVJZ3Y/pPz495+qgXJX8=
 github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
 github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
 github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
@@ -870,8 +896,8 @@ github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+
 github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
 github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
 github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
-github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU=
-github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY=
+github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
+github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
 github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI=
 github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=
 github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU=
@@ -888,8 +914,6 @@ github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO
 github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
 github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
 github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
-github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo=
-github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc=
 github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
 github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ=
 github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560=
@@ -930,26 +954,16 @@ github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8=
-github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4=
-github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
-github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
 github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs=
 github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I=
-github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
-github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
-github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
-github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
-github.com/marten-seemann/webtransport-go v0.4.3 h1:vkt5o/Ci+luknRteWdYGYH1KcB7ziup+J+1PzZJIvmg=
-github.com/marten-seemann/webtransport-go v0.4.3/go.mod h1:4xcfySgZMLP4aG5GBGj1egP7NlpfwgYJ1WJMvPPiVMU=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -960,12 +974,11 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 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.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
 github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
 github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
-github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
 github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
@@ -1006,9 +1019,11 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
 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/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
 github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
@@ -1074,8 +1089,8 @@ github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wS
 github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38=
 github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k=
 github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs=
-github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o=
-github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg=
+github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo=
+github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q=
 github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
 github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
 github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
@@ -1155,8 +1170,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
 github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
 github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
-github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls=
 github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
+github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
+github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -1203,6 +1219,16 @@ github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5
 github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
 github.com/prometheus/statsd_exporter v0.21.0 h1:hA05Q5RFeIjgwKIYEdFd59xu5Wwaznf33yKI+pyX6T8=
 github.com/prometheus/statsd_exporter v0.21.0/go.mod h1:rbT83sZq2V+p73lHhPZfMc3MLCHmSHelCh9hSGYNLTQ=
+github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
+github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
+github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
+github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
+github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
+github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
+github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
+github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
+github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk=
+github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU=
 github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM=
 github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
 github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
@@ -1253,19 +1279,20 @@ github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrf
 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
-github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
 github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
+github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
 github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
+github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
 github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
 github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
 github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
-github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
 github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
@@ -1310,10 +1337,15 @@ github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDH
 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
 github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ=
 github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
 github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
@@ -1323,14 +1355,15 @@ github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2r
 github.com/warpfork/go-testmark v0.10.0 h1:E86YlUMYfwIacEsQGlnTvjk1IgYkyTGjPhF0RnwTCmw=
 github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
 github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
-github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
 github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4=
 github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM=
 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
 github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI=
-github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 h1:obKzQ1ey5AJg5NKjgtTo/CKwLImVP4ETLRcsmzFJ4Qw=
-github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
+github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa h1:EyA027ZAkuaCLoxVX4r1TZMPy1d31fM6hbfQ4OU4I5o=
+github.com/whyrusleeping/cbor-gen v0.0.0-20230126041949-52956bd4c9aa/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ=
 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
 github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
 github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
@@ -1460,8 +1493,8 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP
 golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
 golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
-golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
+golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
 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=
@@ -1472,8 +1505,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o=
-golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2 h1:5sPMf9HJXrvBWIamTw+rTST0bZ3Mho2n1p58M0+W99c=
+golang.org/x/exp v0.0.0-20230129154200-a960b3787bd2/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1557,8 +1590,8 @@ golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
-golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1669,13 +1702,13 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
-golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1684,8 +1717,8 @@ golang.org/x/text v0.3.3/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/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1911,6 +1944,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
 lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
 lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
 lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
+nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
+nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
 pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g=
 pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/p2p/listener.go b/p2p/listener.go
index 9b140023b441c03b18c99236c34e5d1197a90bf0..906137ea1f33fabccc776ffd2b4887ce2238817d 100644
--- a/p2p/listener.go
+++ b/p2p/listener.go
@@ -16,7 +16,7 @@ type Listener interface {
 	ListenAddress() ma.Multiaddr
 	TargetAddress() ma.Multiaddr
 
-	key() string
+	key() protocol.ID
 
 	// close closes the listener. Does not affect child streams
 	close()
@@ -27,21 +27,21 @@ type Listener interface {
 type Listeners struct {
 	sync.RWMutex
 
-	Listeners map[string]Listener
+	Listeners map[protocol.ID]Listener
 }
 
 func newListenersLocal() *Listeners {
 	return &Listeners{
-		Listeners: map[string]Listener{},
+		Listeners: map[protocol.ID]Listener{},
 	}
 }
 
 func newListenersP2P(host p2phost.Host) *Listeners {
 	reg := &Listeners{
-		Listeners: map[string]Listener{},
+		Listeners: map[protocol.ID]Listener{},
 	}
 
-	host.SetStreamHandlerMatch("/x/", func(p string) bool {
+	host.SetStreamHandlerMatch("/x/", func(p protocol.ID) bool {
 		reg.RLock()
 		defer reg.RUnlock()
 
@@ -51,7 +51,7 @@ func newListenersP2P(host p2phost.Host) *Listeners {
 		reg.RLock()
 		defer reg.RUnlock()
 
-		l := reg.Listeners[string(stream.Protocol())]
+		l := reg.Listeners[stream.Protocol()]
 		if l != nil {
 			go l.(*remoteListener).handleStream(stream)
 		}
diff --git a/p2p/local.go b/p2p/local.go
index 17e1f1aeece13d2d54bb1a26f9f63e62ab4706fc..85baf948b4c8157d10953b661a7fefac05413163 100644
--- a/p2p/local.go
+++ b/p2p/local.go
@@ -9,7 +9,7 @@ import (
 	"github.com/libp2p/go-libp2p/core/peer"
 	"github.com/libp2p/go-libp2p/core/protocol"
 	ma "github.com/multiformats/go-multiaddr"
-	"github.com/multiformats/go-multiaddr/net"
+	manet "github.com/multiformats/go-multiaddr/net"
 )
 
 // localListener manet streams and proxies them to libp2p services
@@ -52,7 +52,7 @@ func (p2p *P2P) ForwardLocal(ctx context.Context, peer peer.ID, proto protocol.I
 }
 
 func (l *localListener) dial(ctx context.Context) (net.Stream, error) {
-	cctx, cancel := context.WithTimeout(ctx, time.Second*30) //TODO: configurable?
+	cctx, cancel := context.WithTimeout(ctx, time.Second*30) // TODO: configurable?
 	defer cancel()
 
 	return l.p2p.peerHost.NewStream(cctx, l.peer, l.proto)
@@ -116,6 +116,6 @@ func (l *localListener) TargetAddress() ma.Multiaddr {
 	return addr
 }
 
-func (l *localListener) key() string {
-	return l.ListenAddress().String()
+func (l *localListener) key() protocol.ID {
+	return protocol.ID(l.ListenAddress().String())
 }
diff --git a/p2p/p2p.go b/p2p/p2p.go
index c429760b0c81363e69e024db081af6836ddb959d..e18488c2d6a76fa95a5ed92c551d59c07067f7ff 100644
--- a/p2p/p2p.go
+++ b/p2p/p2p.go
@@ -3,8 +3,9 @@ package p2p
 import (
 	logging "github.com/ipfs/go-log"
 	p2phost "github.com/libp2p/go-libp2p/core/host"
-	peer "github.com/libp2p/go-libp2p/core/peer"
+	"github.com/libp2p/go-libp2p/core/peer"
 	pstore "github.com/libp2p/go-libp2p/core/peerstore"
+	"github.com/libp2p/go-libp2p/core/protocol"
 )
 
 var log = logging.Logger("p2p-mount")
@@ -40,7 +41,7 @@ func New(identity peer.ID, peerHost p2phost.Host, peerstore pstore.Peerstore) *P
 
 // CheckProtoExists checks whether a proto handler is registered to
 // mux handler
-func (p2p *P2P) CheckProtoExists(proto string) bool {
+func (p2p *P2P) CheckProtoExists(proto protocol.ID) bool {
 	protos := p2p.peerHost.Mux().Protocols()
 
 	for _, p := range protos {
diff --git a/p2p/remote.go b/p2p/remote.go
index d106004865c78149e42201e3ca11ca9a85c9eba7..ac540e9a5511da70148e9518f725fcd2c04f1f0f 100644
--- a/p2p/remote.go
+++ b/p2p/remote.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 
 	net "github.com/libp2p/go-libp2p/core/network"
-	protocol "github.com/libp2p/go-libp2p/core/protocol"
+	"github.com/libp2p/go-libp2p/core/protocol"
 	ma "github.com/multiformats/go-multiaddr"
 	manet "github.com/multiformats/go-multiaddr/net"
 )
@@ -101,6 +101,6 @@ func (l *remoteListener) TargetAddress() ma.Multiaddr {
 
 func (l *remoteListener) close() {}
 
-func (l *remoteListener) key() string {
-	return string(l.proto)
+func (l *remoteListener) key() protocol.ID {
+	return l.proto
 }
diff --git a/profile/profile.go b/profile/profile.go
index d15d512514032b3d0e05597d095b0c736a88450b..b9ad86d2f53e32426534423f740baca57e9b7e96 100644
--- a/profile/profile.go
+++ b/profile/profile.go
@@ -22,6 +22,7 @@ const (
 	CollectorGoroutinesPprof = "goroutines-pprof"
 	CollectorVersion         = "version"
 	CollectorHeap            = "heap"
+	CollectorAllocs          = "allocs"
 	CollectorBin             = "bin"
 	CollectorCPU             = "cpu"
 	CollectorMutex           = "mutex"
@@ -71,6 +72,11 @@ var collectors = map[string]collector{
 		collectFunc: heapProfile,
 		enabledFunc: func(opts Options) bool { return true },
 	},
+	CollectorAllocs: {
+		outputFile:  "allocs.pprof",
+		collectFunc: allocsProfile,
+		enabledFunc: func(opts Options) bool { return true },
+	},
 	CollectorBin: {
 		outputFile:   "ipfs",
 		isExecutable: true,
@@ -197,6 +203,10 @@ func heapProfile(ctx context.Context, _ Options, w io.Writer) error {
 	return pprof.Lookup("heap").WriteTo(w, 0)
 }
 
+func allocsProfile(ctx context.Context, _ Options, w io.Writer) error {
+	return pprof.Lookup("allocs").WriteTo(w, 0)
+}
+
 func versionInfo(ctx context.Context, _ Options, w io.Writer) error {
 	return json.NewEncoder(w).Encode(version.GetVersionInfo())
 }
diff --git a/profile/profile_test.go b/profile/profile_test.go
index 8da00d0181ab29a3fde1d0a14edbd9df149edfc0..a2fe0b51d59982fc7c2db091392fc72dbe252dd0 100644
--- a/profile/profile_test.go
+++ b/profile/profile_test.go
@@ -17,6 +17,7 @@ func TestProfiler(t *testing.T) {
 		CollectorGoroutinesPprof,
 		CollectorVersion,
 		CollectorHeap,
+		CollectorAllocs,
 		CollectorBin,
 		CollectorCPU,
 		CollectorMutex,
@@ -43,6 +44,7 @@ func TestProfiler(t *testing.T) {
 				"goroutines.pprof",
 				"version.json",
 				"heap.pprof",
+				"allocs.pprof",
 				"ipfs",
 				"cpu.pprof",
 				"mutex.pprof",
@@ -63,6 +65,7 @@ func TestProfiler(t *testing.T) {
 				"goroutines.pprof",
 				"version.json",
 				"heap.pprof",
+				"allocs.pprof",
 				"ipfs.exe",
 				"cpu.pprof",
 				"mutex.pprof",
@@ -81,6 +84,7 @@ func TestProfiler(t *testing.T) {
 				"goroutines.pprof",
 				"version.json",
 				"heap.pprof",
+				"allocs.pprof",
 				"ipfs",
 			},
 		},
@@ -96,6 +100,7 @@ func TestProfiler(t *testing.T) {
 				"goroutines.pprof",
 				"version.json",
 				"heap.pprof",
+				"allocs.pprof",
 				"ipfs",
 				"cpu.pprof",
 				"block.pprof",
@@ -114,6 +119,7 @@ func TestProfiler(t *testing.T) {
 				"goroutines.pprof",
 				"version.json",
 				"heap.pprof",
+				"allocs.pprof",
 				"ipfs",
 				"cpu.pprof",
 				"mutex.pprof",
diff --git a/repo/fsrepo/config_test.go b/repo/fsrepo/config_test.go
index 03af75a9631b6cf0e2c45d7bde3e19249b3e0551..060d0222adac289068d763a5999fbfc2f14c57a8 100644
--- a/repo/fsrepo/config_test.go
+++ b/repo/fsrepo/config_test.go
@@ -2,7 +2,6 @@ package fsrepo_test
 
 import (
 	"encoding/json"
-	"os"
 	"reflect"
 	"testing"
 
@@ -88,11 +87,7 @@ func TestDefaultDatastoreConfig(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	dir, err := os.MkdirTemp("", "ipfs-datastore-config-test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir) // clean up
+	dir := t.TempDir()
 
 	config := new(config.Datastore)
 	err = json.Unmarshal(defaultConfig, config)
@@ -126,11 +121,7 @@ func TestLevelDbConfig(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	dir, err := os.MkdirTemp("", "ipfs-datastore-config-test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir) // clean up
+	dir := t.TempDir()
 
 	spec := make(map[string]interface{})
 	err = json.Unmarshal(leveldbConfig, &spec)
@@ -164,11 +155,7 @@ func TestFlatfsConfig(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	dir, err := os.MkdirTemp("", "ipfs-datastore-config-test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir) // clean up
+	dir := t.TempDir()
 
 	spec := make(map[string]interface{})
 	err = json.Unmarshal(flatfsConfig, &spec)
@@ -202,11 +189,7 @@ func TestMeasureConfig(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	dir, err := os.MkdirTemp("", "ipfs-datastore-config-test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(dir) // clean up
+	dir := t.TempDir()
 
 	spec := make(map[string]interface{})
 	err = json.Unmarshal(measureConfig, &spec)
diff --git a/repo/fsrepo/fsrepo.go b/repo/fsrepo/fsrepo.go
index 99104b08318f8cee5d2aaecac71a449c4092a225..6a7da9a0694f85cc29b45354ee23133c772bc6d3 100644
--- a/repo/fsrepo/fsrepo.go
+++ b/repo/fsrepo/fsrepo.go
@@ -16,6 +16,7 @@ import (
 	repo "github.com/ipfs/kubo/repo"
 	"github.com/ipfs/kubo/repo/common"
 	dir "github.com/ipfs/kubo/thirdparty/dir"
+	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 
 	ds "github.com/ipfs/go-datastore"
 	measure "github.com/ipfs/go-ds-measure"
@@ -102,11 +103,12 @@ type FSRepo struct {
 	configFilePath string
 	// lockfile is the file system lock to prevent others from opening
 	// the same fsrepo path concurrently
-	lockfile io.Closer
-	config   *config.Config
-	ds       repo.Datastore
-	keystore keystore.Keystore
-	filemgr  *filestore.FileManager
+	lockfile              io.Closer
+	config                *config.Config
+	userResourceOverrides rcmgr.PartialLimitConfig
+	ds                    repo.Datastore
+	keystore              keystore.Keystore
+	filemgr               *filestore.FileManager
 }
 
 var _ repo.Repo = (*FSRepo)(nil)
@@ -180,6 +182,10 @@ func open(repoPath string, userConfigFilePath string) (repo.Repo, error) {
 		return nil, err
 	}
 
+	if err := r.openUserResourceOverrides(); err != nil {
+		return nil, err
+	}
+
 	if err := r.openDatastore(); err != nil {
 		return nil, err
 	}
@@ -437,6 +443,17 @@ func (r *FSRepo) openConfig() error {
 	return nil
 }
 
+// openUserResourceOverrides will remove all overrides if the file is not present.
+// It will error if the decoding fails.
+func (r *FSRepo) openUserResourceOverrides() error {
+	// This filepath is documented in docs/libp2p-resource-management.md and be kept in sync.
+	err := serialize.ReadConfigFile(filepath.Join(r.path, "libp2p-resource-limit-overrides.json"), &r.userResourceOverrides)
+	if err == serialize.ErrNotInitialized {
+		err = nil
+	}
+	return err
+}
+
 func (r *FSRepo) openKeystore() error {
 	ksp := filepath.Join(r.path, "keystore")
 	ks, err := keystore.NewFSKeystore(ksp)
@@ -554,6 +571,21 @@ func (r *FSRepo) Config() (*config.Config, error) {
 	return r.config, nil
 }
 
+func (r *FSRepo) UserResourceOverrides() (rcmgr.PartialLimitConfig, error) {
+	// It is not necessary to hold the package lock since the repo is in an
+	// opened state. The package lock is _not_ meant to ensure that the repo is
+	// thread-safe. The package lock is only meant to guard against removal and
+	// coordinate the lockfile. However, we provide thread-safety to keep
+	// things simple.
+	packageLock.Lock()
+	defer packageLock.Unlock()
+
+	if r.closed {
+		return rcmgr.PartialLimitConfig{}, errors.New("cannot access config, repo not open")
+	}
+	return r.userResourceOverrides, nil
+}
+
 func (r *FSRepo) FileManager() *filestore.FileManager {
 	return r.filemgr
 }
diff --git a/repo/fsrepo/fsrepo_test.go b/repo/fsrepo/fsrepo_test.go
index 7c7551d205d56fa3a63b1aaaf47bc4c92a2c2b76..6b30b107adb575ed7e3d66e9e8e80777e1f77220 100644
--- a/repo/fsrepo/fsrepo_test.go
+++ b/repo/fsrepo/fsrepo_test.go
@@ -13,18 +13,9 @@ import (
 	config "github.com/ipfs/kubo/config"
 )
 
-// swap arg order
-func testRepoPath(p string, t *testing.T) string {
-	name, err := os.MkdirTemp("", p)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return name
-}
-
 func TestInitIdempotence(t *testing.T) {
 	t.Parallel()
-	path := testRepoPath("", t)
+	path := t.TempDir()
 	for i := 0; i < 10; i++ {
 		assert.Nil(Init(path, &config.Config{Datastore: config.DefaultDatastoreConfig()}), t, "multiple calls to init should succeed")
 	}
@@ -37,8 +28,8 @@ func Remove(repoPath string) error {
 
 func TestCanManageReposIndependently(t *testing.T) {
 	t.Parallel()
-	pathA := testRepoPath("a", t)
-	pathB := testRepoPath("b", t)
+	pathA := t.TempDir()
+	pathB := t.TempDir()
 
 	t.Log("initialize two repos")
 	assert.Nil(Init(pathA, &config.Config{Datastore: config.DefaultDatastoreConfig()}), t, "a", "should initialize successfully")
@@ -65,7 +56,7 @@ func TestCanManageReposIndependently(t *testing.T) {
 
 func TestDatastoreGetNotAllowedAfterClose(t *testing.T) {
 	t.Parallel()
-	path := testRepoPath("test", t)
+	path := t.TempDir()
 
 	assert.True(!IsInitialized(path), t, "should NOT be initialized")
 	assert.Nil(Init(path, &config.Config{Datastore: config.DefaultDatastoreConfig()}), t, "should initialize successfully")
@@ -83,7 +74,7 @@ func TestDatastoreGetNotAllowedAfterClose(t *testing.T) {
 
 func TestDatastorePersistsFromRepoToRepo(t *testing.T) {
 	t.Parallel()
-	path := testRepoPath("test", t)
+	path := t.TempDir()
 
 	assert.Nil(Init(path, &config.Config{Datastore: config.DefaultDatastoreConfig()}), t)
 	r1, err := Open(path)
@@ -104,7 +95,7 @@ func TestDatastorePersistsFromRepoToRepo(t *testing.T) {
 
 func TestOpenMoreThanOnceInSameProcess(t *testing.T) {
 	t.Parallel()
-	path := testRepoPath("", t)
+	path := t.TempDir()
 	assert.Nil(Init(path, &config.Config{Datastore: config.DefaultDatastoreConfig()}), t)
 
 	r1, err := Open(path)
diff --git a/repo/mock.go b/repo/mock.go
index a50d448ed0241358a7b3fa7b7c357ff463ae2798..6f128d2631c8b4758891df1f806aa0fe7ed07dc2 100644
--- a/repo/mock.go
+++ b/repo/mock.go
@@ -7,6 +7,7 @@ import (
 
 	filestore "github.com/ipfs/go-filestore"
 	keystore "github.com/ipfs/go-ipfs-keystore"
+	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 
 	config "github.com/ipfs/kubo/config"
 	ma "github.com/multiformats/go-multiaddr"
@@ -26,6 +27,10 @@ func (m *Mock) Config() (*config.Config, error) {
 	return &m.C, nil // FIXME threadsafety
 }
 
+func (m *Mock) UserResourceOverrides() (rcmgr.PartialLimitConfig, error) {
+	return rcmgr.PartialLimitConfig{}, nil
+}
+
 func (m *Mock) SetConfig(updated *config.Config) error {
 	m.C = *updated // FIXME threadsafety
 	return nil
diff --git a/repo/repo.go b/repo/repo.go
index bec02049d1819b29a2f011e9aec43125c73a57fe..6767dda722653f8bf86e43e2682dd81c2425cbb1 100644
--- a/repo/repo.go
+++ b/repo/repo.go
@@ -8,6 +8,7 @@ import (
 
 	filestore "github.com/ipfs/go-filestore"
 	keystore "github.com/ipfs/go-ipfs-keystore"
+	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 
 	ds "github.com/ipfs/go-datastore"
 	config "github.com/ipfs/kubo/config"
@@ -24,6 +25,10 @@ type Repo interface {
 	// to the returned config are not automatically persisted.
 	Config() (*config.Config, error)
 
+	// UserResourceOverrides returns optional user resource overrides for the
+	// libp2p resource manager.
+	UserResourceOverrides() (rcmgr.PartialLimitConfig, error)
+
 	// BackupConfig creates a backup of the current configuration file using
 	// the given prefix for naming.
 	BackupConfig(prefix string) (string, error)
diff --git a/test/bench/bench_cli_ipfs_add/main.go b/test/bench/bench_cli_ipfs_add/main.go
index a089410ef39015ec5d03036858fc2eccf9bf1af9..e7fe90e0407d5a3dfe2cc87dde824db3129a50c7 100644
--- a/test/bench/bench_cli_ipfs_add/main.go
+++ b/test/bench/bench_cli_ipfs_add/main.go
@@ -45,12 +45,7 @@ func benchmarkAdd(amount int64) (*testing.BenchmarkResult, error) {
 		b.SetBytes(amount)
 		for i := 0; i < b.N; i++ {
 			b.StopTimer()
-			tmpDir, err := os.MkdirTemp("", "")
-			if err != nil {
-				benchmarkError = err
-				b.Fatal(err)
-			}
-			defer os.RemoveAll(tmpDir)
+			tmpDir := b.TempDir()
 
 			env := append(
 				[]string{fmt.Sprintf("%s=%s", config.EnvDir, path.Join(tmpDir, config.DefaultPathName))}, // first in order to override
diff --git a/test/bench/offline_add/main.go b/test/bench/offline_add/main.go
index a15ebcffda2c68a78eb7dee901e4f8bf222c4b0f..338a5f6ac24162c5f06658fc4a062b3af2cb612d 100644
--- a/test/bench/offline_add/main.go
+++ b/test/bench/offline_add/main.go
@@ -37,11 +37,7 @@ func benchmarkAdd(amount int64) (*testing.BenchmarkResult, error) {
 		b.SetBytes(amount)
 		for i := 0; i < b.N; i++ {
 			b.StopTimer()
-			tmpDir, err := os.MkdirTemp("", "")
-			if err != nil {
-				b.Fatal(err)
-			}
-			defer os.RemoveAll(tmpDir)
+			tmpDir := b.TempDir()
 
 			env := append(os.Environ(), fmt.Sprintf("%s=%s", config.EnvDir, path.Join(tmpDir, config.DefaultPathName)))
 			setupCmd := func(cmd *exec.Cmd) {
diff --git a/test/cli/basic_commands_test.go b/test/cli/basic_commands_test.go
index 30c1f1f9a9a408ae2cc331919e91e4ec04f56f2e..220ef285452976f1142044f5c5148d38cad92263 100644
--- a/test/cli/basic_commands_test.go
+++ b/test/cli/basic_commands_test.go
@@ -88,6 +88,7 @@ func TestAllSubcommandsAcceptHelp(t *testing.T) {
 	t.Parallel()
 	node := harness.NewT(t).NewNode()
 	for _, cmd := range node.IPFSCommands() {
+		cmd := cmd
 		t.Run(fmt.Sprintf("command %q accepts help", cmd), func(t *testing.T) {
 			t.Parallel()
 			splitCmd := strings.Split(cmd, " ")[1:]
diff --git a/test/cli/delegated_routing_http_test.go b/test/cli/delegated_routing_http_test.go
index 0b39a9b12e675865a5b4c96131c4b67ae3e7ef8f..446ea515049e7e0f92aaea753781a1b6395d38d7 100644
--- a/test/cli/delegated_routing_http_test.go
+++ b/test/cli/delegated_routing_http_test.go
@@ -94,7 +94,7 @@ func TestHTTPDelegatedRouting(t *testing.T) {
 		}))
 		t.Cleanup(server.Close)
 
-		node.IPFS("config", "Routing.Type", "--json", `"custom"`)
+		node.IPFS("config", "Routing.Type", "custom")
 		node.IPFS("config", "Routing.Routers.TestDelegatedRouter", "--json", ToJSONStr(JSONObj{
 			"Type": "http",
 			"Parameters": JSONObj{
diff --git a/test/cli/dht_autoclient_test.go b/test/cli/dht_autoclient_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..749e34b348ec3f59eb8a125831cadf316b7f3b16
--- /dev/null
+++ b/test/cli/dht_autoclient_test.go
@@ -0,0 +1,39 @@
+package cli
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/ipfs/kubo/test/cli/harness"
+	"github.com/ipfs/kubo/test/cli/testutils"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDHTAutoclient(t *testing.T) {
+	t.Parallel()
+	nodes := harness.NewT(t).NewNodes(10).Init()
+	harness.Nodes(nodes[8:]).ForEachPar(func(node *harness.Node) {
+		node.IPFS("config", "Routing.Type", "autoclient")
+	})
+	nodes.StartDaemons().Connect()
+
+	t.Run("file added on node in client mode is retrievable from node in client mode", func(t *testing.T) {
+		t.Parallel()
+		randomBytes := testutils.RandomBytes(1000)
+		hash := nodes[8].IPFSAdd(bytes.NewReader(randomBytes))
+
+		res := nodes[9].IPFS("cat", hash)
+		assert.Equal(t, randomBytes, []byte(res.Stdout.Trimmed()))
+	})
+
+	t.Run("file added on node in server mode is retrievable from all nodes", func(t *testing.T) {
+		t.Parallel()
+		randomBytes := testutils.RandomBytes(1000)
+		hash := nodes[0].IPFSAdd(bytes.NewReader(randomBytes))
+
+		for i := 0; i < 10; i++ {
+			res := nodes[i].IPFS("cat", hash)
+			assert.Equal(t, randomBytes, []byte(res.Stdout.Trimmed()))
+		}
+	})
+}
diff --git a/test/cli/dht_legacy_test.go b/test/cli/dht_legacy_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..437b62ae4eae401663e3a3898b3a9c5569ec3905
--- /dev/null
+++ b/test/cli/dht_legacy_test.go
@@ -0,0 +1,137 @@
+package cli
+
+import (
+	"sort"
+	"sync"
+	"testing"
+
+	"github.com/ipfs/kubo/test/cli/harness"
+	"github.com/ipfs/kubo/test/cli/testutils"
+	"github.com/libp2p/go-libp2p/core/peer"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestLegacyDHT(t *testing.T) {
+	nodes := harness.NewT(t).NewNodes(5).Init()
+	nodes.ForEachPar(func(node *harness.Node) {
+		node.IPFS("config", "Routing.Type", "dht")
+	})
+	nodes.StartDaemons().Connect()
+
+	t.Run("ipfs dht findpeer", func(t *testing.T) {
+		t.Parallel()
+		res := nodes[1].RunIPFS("dht", "findpeer", nodes[0].PeerID().String())
+		assert.Equal(t, 0, res.ExitCode())
+
+		swarmAddr := nodes[0].SwarmAddrsWithoutPeerIDs()[0]
+		require.Equal(t, swarmAddr.String(), res.Stdout.Trimmed())
+	})
+
+	t.Run("ipfs dht get <key>", func(t *testing.T) {
+		t.Parallel()
+		hash := nodes[2].IPFSAddStr("hello world")
+		nodes[2].IPFS("name", "publish", "/ipfs/"+hash)
+
+		res := nodes[1].IPFS("dht", "get", "/ipns/"+nodes[2].PeerID().String())
+		assert.Contains(t, res.Stdout.String(), "/ipfs/"+hash)
+
+		t.Run("put round trips (#3124)", func(t *testing.T) {
+			t.Parallel()
+			nodes[0].WriteBytes("get_result", res.Stdout.Bytes())
+			res := nodes[0].IPFS("dht", "put", "/ipns/"+nodes[2].PeerID().String(), "get_result")
+			assert.Greater(t, len(res.Stdout.Lines()), 0, "should put to at least one node")
+		})
+
+		t.Run("put with bad keys fails (issue #5113, #4611)", func(t *testing.T) {
+			t.Parallel()
+			keys := []string{"foo", "/pk/foo", "/ipns/foo"}
+			for _, key := range keys {
+				key := key
+				t.Run(key, func(t *testing.T) {
+					t.Parallel()
+					res := nodes[0].RunIPFS("dht", "put", key)
+					assert.Equal(t, 1, res.ExitCode())
+					assert.Contains(t, res.Stderr.String(), "invalid")
+					assert.Empty(t, res.Stdout.String())
+				})
+			}
+		})
+
+		t.Run("get with bad keys (issue #4611)", func(t *testing.T) {
+			for _, key := range []string{"foo", "/pk/foo"} {
+				key := key
+				t.Run(key, func(t *testing.T) {
+					t.Parallel()
+					res := nodes[0].RunIPFS("dht", "get", key)
+					assert.Equal(t, 1, res.ExitCode())
+					assert.Contains(t, res.Stderr.String(), "invalid")
+					assert.Empty(t, res.Stdout.String())
+				})
+			}
+		})
+	})
+
+	t.Run("ipfs dht findprovs", func(t *testing.T) {
+		t.Parallel()
+		hash := nodes[3].IPFSAddStr("some stuff")
+		res := nodes[4].IPFS("dht", "findprovs", hash)
+		assert.Equal(t, nodes[3].PeerID().String(), res.Stdout.Trimmed())
+	})
+
+	t.Run("ipfs dht query <peerID>", func(t *testing.T) {
+		t.Parallel()
+		t.Run("normal DHT configuration", func(t *testing.T) {
+			t.Parallel()
+			hash := nodes[0].IPFSAddStr("some other stuff")
+			peerCounts := map[string]int{}
+			peerCountsMut := sync.Mutex{}
+			harness.Nodes(nodes).ForEachPar(func(node *harness.Node) {
+				res := node.IPFS("dht", "query", hash)
+				closestPeer := res.Stdout.Lines()[0]
+				// check that it's a valid peer ID
+				_, err := peer.Decode(closestPeer)
+				require.NoError(t, err)
+
+				peerCountsMut.Lock()
+				peerCounts[closestPeer]++
+				peerCountsMut.Unlock()
+			})
+			// 4 nodes should see the same peer ID
+			// 1 node (the closest) should see a different one
+			var counts []int
+			for _, count := range peerCounts {
+				counts = append(counts, count)
+			}
+			sort.IntSlice(counts).Sort()
+			assert.Equal(t, []int{1, 4}, counts)
+		})
+
+	})
+
+	t.Run("dht commands fail when offline", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+
+		// these cannot be run in parallel due to repo locking (seems like a bug)
+
+		t.Run("dht findprovs", func(t *testing.T) {
+			res := node.RunIPFS("dht", "findprovs", testutils.CIDEmptyDir)
+			assert.Equal(t, 1, res.ExitCode())
+			assert.Contains(t, res.Stderr.String(), "this command must be run in online mode")
+		})
+
+		t.Run("dht findpeer", func(t *testing.T) {
+			res := node.RunIPFS("dht", "findpeer", testutils.CIDEmptyDir)
+			assert.Equal(t, 1, res.ExitCode())
+			assert.Contains(t, res.Stderr.String(), "this command must be run in online mode")
+		})
+
+		t.Run("dht put", func(t *testing.T) {
+			node.WriteBytes("foo", []byte("foo"))
+			res := node.RunIPFS("dht", "put", "/ipns/"+node.PeerID().String(), "foo")
+			assert.Equal(t, 1, res.ExitCode())
+			assert.Contains(t, res.Stderr.String(), "this action must be run in online mode")
+		})
+	})
+}
diff --git a/test/cli/gateway_test.go b/test/cli/gateway_test.go
index 6e8ef516a1317eb40f4e9a3f1ca190075299ff47..d2a90b04ae4a742f909cca05942fa866bbb9bdfc 100644
--- a/test/cli/gateway_test.go
+++ b/test/cli/gateway_test.go
@@ -126,10 +126,10 @@ func TestGateway(t *testing.T) {
 			assert.Equal(t, 404, resp.StatusCode)
 		})
 
-		t.Run("GET IPFS invalid CID returns 400 (Bad Request)", func(t *testing.T) {
+		t.Run("GET IPFS invalid CID returns 500 (Internal Server Error)", func(t *testing.T) {
 			t.Parallel()
 			resp := client.Get("/ipfs/QmInvalid/pleaseDontAddMe")
-			assert.Equal(t, 400, resp.StatusCode)
+			assert.Equal(t, 500, resp.StatusCode)
 		})
 
 		t.Run("GET IPFS inlined zero-length data object returns ok code (200)", func(t *testing.T) {
@@ -166,10 +166,10 @@ func TestGateway(t *testing.T) {
 		t.Parallel()
 		node.IPFS("name", "publish", "--allow-offline", cid)
 
-		t.Run("GET invalid IPNS root returns 400 (Bad Request)", func(t *testing.T) {
+		t.Run("GET invalid IPNS root returns 500 (Internal Server Error)", func(t *testing.T) {
 			t.Parallel()
 			resp := client.Get("/ipns/QmInvalid/pleaseDontAddMe")
-			assert.Equal(t, 400, resp.StatusCode)
+			assert.Equal(t, 500, resp.StatusCode)
 		})
 
 		t.Run("GET IPNS path succeeds", func(t *testing.T) {
@@ -198,7 +198,7 @@ func TestGateway(t *testing.T) {
 
 	t.Run("GET invalid IPFS path errors", func(t *testing.T) {
 		t.Parallel()
-		assert.Equal(t, 400, client.Get("/ipfs/12345").StatusCode)
+		assert.Equal(t, 500, client.Get("/ipfs/12345").StatusCode)
 	})
 
 	t.Run("GET invalid path errors", func(t *testing.T) {
@@ -219,6 +219,23 @@ func TestGateway(t *testing.T) {
 		assert.Contains(t, []int{302, 301}, resp.StatusCode)
 	})
 
+	t.Run("GET /webui/ returns user-specified headers", func(t *testing.T) {
+		t.Parallel()
+
+		header := "Access-Control-Allow-Origin"
+		values := []string{"http://localhost:3000", "https://webui.ipfs.io"}
+
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateConfig(func(cfg *config.Config) {
+			cfg.API.HTTPHeaders = map[string][]string{header: values}
+		})
+		node.StartDaemon()
+
+		resp := node.APIClient().DisableRedirects().Get("/webui/")
+		assert.Equal(t, resp.Headers.Values(header), values)
+		assert.Contains(t, []int{302, 301}, resp.StatusCode)
+	})
+
 	t.Run("GET /logs returns logs", func(t *testing.T) {
 		t.Parallel()
 		apiClient := node.APIClient()
@@ -469,7 +486,7 @@ func TestGateway(t *testing.T) {
 
 			t.Run("not present IPNS key from node 1", func(t *testing.T) {
 				t.Parallel()
-				assert.Equal(t, 400, node1.GatewayClient().Get("/ipns/"+node2.PeerID().String()).StatusCode)
+				assert.Equal(t, 500, node1.GatewayClient().Get("/ipns/"+node2.PeerID().String()).StatusCode)
 			})
 		})
 
diff --git a/test/cli/harness/harness.go b/test/cli/harness/harness.go
index de962e1c120644b7889b588573c782f8afcb372d..e68116b5efce6575a1f83c0d41ced264df0b093f 100644
--- a/test/cli/harness/harness.go
+++ b/test/cli/harness/harness.go
@@ -11,6 +11,8 @@ import (
 
 	logging "github.com/ipfs/go-log/v2"
 	. "github.com/ipfs/kubo/test/cli/testutils"
+	"github.com/libp2p/go-libp2p/core/peer"
+	"github.com/multiformats/go-multiaddr"
 )
 
 // Harness tracks state for a test, such as temp dirs and IFPS nodes, and cleans them up after the test.
@@ -171,7 +173,7 @@ func (h *Harness) Mkdirs(paths ...string) {
 	}
 }
 
-func (h *Harness) Sh(expr string) RunResult {
+func (h *Harness) Sh(expr string) *RunResult {
 	return h.Runner.Run(RunRequest{
 		Path: "bash",
 		Args: []string{"-c", expr},
@@ -188,3 +190,22 @@ func (h *Harness) Cleanup() {
 		log.Panicf("removing temp dir %s: %s", h.Dir, err)
 	}
 }
+
+// ExtractPeerID extracts a peer ID from the given multiaddr, and fatals if it does not contain a peer ID.
+func (h *Harness) ExtractPeerID(m multiaddr.Multiaddr) peer.ID {
+	var peerIDStr string
+	multiaddr.ForEach(m, func(c multiaddr.Component) bool {
+		if c.Protocol().Code == multiaddr.P_P2P {
+			peerIDStr = c.Value()
+		}
+		return true
+	})
+	if peerIDStr == "" {
+		panic(multiaddr.ErrProtocolNotFound)
+	}
+	peerID, err := peer.Decode(peerIDStr)
+	if err != nil {
+		panic(err)
+	}
+	return peerID
+}
diff --git a/test/cli/harness/log.go b/test/cli/harness/log.go
new file mode 100644
index 0000000000000000000000000000000000000000..d76bb2747c10fa0261554835280df3c789330162
--- /dev/null
+++ b/test/cli/harness/log.go
@@ -0,0 +1,155 @@
+package harness
+
+import (
+	"fmt"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+)
+
+type event struct {
+	timestamp time.Time
+	msg       string
+}
+
+type events []*event
+
+func (e events) Len() int           { return len(e) }
+func (e events) Less(i, j int) bool { return e[i].timestamp.Before(e[j].timestamp) }
+func (e events) Swap(i, j int)      { e[i], e[j] = e[j], e[i] }
+
+// TestLogger is a logger for tests.
+// It buffers output and only writes the output if the test fails or output is explicitly turned on.
+// The purpose of this logger is to allow Go test to run with the verbose flag without printing logs.
+// The verbose flag is useful since it streams test progress, but also printing logs makes the output too verbose.
+//
+// You can also add prefixes that are prepended to each log message, for extra logging context.
+//
+// This is implemented as a hierarchy of loggers, with children flushing log entries back to parents.
+// This works because t.Cleanup() processes entries in LIFO order, so children always flush first.
+//
+// Obviously this logger should never be used in production systems.
+type TestLogger struct {
+	parent        *TestLogger
+	children      []*TestLogger
+	prefixes      []string
+	prefixesIface []any
+	t             *testing.T
+	buf           events
+	m             sync.Mutex
+	logsEnabled   bool
+}
+
+func NewTestLogger(t *testing.T) *TestLogger {
+	l := &TestLogger{t: t, buf: make(events, 0)}
+	t.Cleanup(l.flush)
+	return l
+}
+
+func (t *TestLogger) buildPrefix(timestamp time.Time) string {
+	d := timestamp.Format("2006-01-02T15:04:05.999999")
+	_, file, lineno, _ := runtime.Caller(2)
+	file = filepath.Base(file)
+	caller := fmt.Sprintf("%s:%d", file, lineno)
+
+	if len(t.prefixes) == 0 {
+		return fmt.Sprintf("%s\t%s\t", d, caller)
+	}
+
+	prefixes := strings.Join(t.prefixes, ":")
+	return fmt.Sprintf("%s\t%s\t%s: ", d, caller, prefixes)
+}
+
+func (t *TestLogger) Log(args ...any) {
+	timestamp := time.Now()
+	e := t.buildPrefix(timestamp) + fmt.Sprint(args...)
+	t.add(&event{timestamp: timestamp, msg: e})
+}
+
+func (t *TestLogger) Logf(format string, args ...any) {
+	timestamp := time.Now()
+	e := t.buildPrefix(timestamp) + fmt.Sprintf(format, args...)
+	t.add(&event{timestamp: timestamp, msg: e})
+}
+
+func (t *TestLogger) Fatal(args ...any) {
+	timestamp := time.Now()
+	e := t.buildPrefix(timestamp) + fmt.Sprint(append([]any{"fatal: "}, args...)...)
+	t.add(&event{timestamp: timestamp, msg: e})
+	t.t.FailNow()
+}
+
+func (t *TestLogger) Fatalf(format string, args ...any) {
+	timestamp := time.Now()
+	e := t.buildPrefix(timestamp) + fmt.Sprintf(fmt.Sprintf("fatal: %s", format), args...)
+	t.add(&event{timestamp: timestamp, msg: e})
+	t.t.FailNow()
+}
+
+func (t *TestLogger) add(e *event) {
+	t.m.Lock()
+	defer t.m.Unlock()
+	t.buf = append(t.buf, e)
+}
+
+func (t *TestLogger) AddPrefix(prefix string) *TestLogger {
+	l := &TestLogger{
+		prefixes:      append(t.prefixes, prefix),
+		prefixesIface: append(t.prefixesIface, prefix),
+		t:             t.t,
+		parent:        t,
+		logsEnabled:   t.logsEnabled,
+	}
+	t.m.Lock()
+	defer t.m.Unlock()
+
+	t.children = append(t.children, l)
+	t.t.Cleanup(l.flush)
+
+	return l
+}
+
+func (t *TestLogger) EnableLogs() {
+	t.m.Lock()
+	defer t.m.Unlock()
+	t.logsEnabled = true
+	if t.parent != nil {
+		if t.parent.logsEnabled {
+			t.parent.EnableLogs()
+		}
+	}
+	fmt.Printf("enabling %d children\n", len(t.children))
+	for _, c := range t.children {
+		if !c.logsEnabled {
+			c.EnableLogs()
+		}
+	}
+}
+
+func (t *TestLogger) flush() {
+	if t.t.Failed() || t.logsEnabled {
+		t.m.Lock()
+		defer t.m.Unlock()
+		// if this is a child, send the events to the parent
+		// the root parent will print all the events in sorted order
+		if t.parent != nil {
+			for _, e := range t.buf {
+				t.parent.add(e)
+			}
+		} else {
+			// we're the root, sort all the events and then print them
+			sort.Sort(t.buf)
+			fmt.Println()
+			fmt.Printf("Logs for test %q:\n\n", t.t.Name())
+			for _, e := range t.buf {
+				fmt.Println(e.msg)
+			}
+			fmt.Println()
+		}
+		t.buf = nil
+	}
+}
diff --git a/test/cli/harness/node.go b/test/cli/harness/node.go
index 26a66ddd9fdd33b383aa41ee27fada09da5f7308..f740ab1b19f16b47a4582ad7f5151e3eaf128b33 100644
--- a/test/cli/harness/node.go
+++ b/test/cli/harness/node.go
@@ -1,6 +1,7 @@
 package harness
 
 import (
+	"bytes"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -19,6 +20,7 @@ import (
 	"github.com/ipfs/kubo/config"
 	serial "github.com/ipfs/kubo/config/serialize"
 	"github.com/libp2p/go-libp2p/core/peer"
+	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
 	"github.com/multiformats/go-multiaddr"
 	manet "github.com/multiformats/go-multiaddr/net"
 )
@@ -62,6 +64,18 @@ func BuildNode(ipfsBin, baseDir string, id int) *Node {
 	}
 }
 
+func (n *Node) WriteBytes(filename string, b []byte) {
+	f, err := os.Create(filepath.Join(n.Dir, filename))
+	if err != nil {
+		panic(err)
+	}
+	defer f.Close()
+	_, err = io.Copy(f, bytes.NewReader(b))
+	if err != nil {
+		panic(err)
+	}
+}
+
 func (n *Node) ReadConfig() *config.Config {
 	cfg, err := serial.Load(filepath.Join(n.Dir, "config"))
 	if err != nil {
@@ -83,23 +97,47 @@ func (n *Node) UpdateConfig(f func(cfg *config.Config)) {
 	n.WriteConfig(cfg)
 }
 
-func (n *Node) IPFS(args ...string) RunResult {
+func (n *Node) ReadUserResourceOverrides() *rcmgr.PartialLimitConfig {
+	var r rcmgr.PartialLimitConfig
+	err := serial.ReadConfigFile(filepath.Join(n.Dir, "libp2p-resource-limit-overrides.json"), &r)
+	switch err {
+	case nil, serial.ErrNotInitialized:
+		return &r
+	default:
+		panic(err)
+	}
+}
+
+func (n *Node) WriteUserSuppliedResourceOverrides(c *rcmgr.PartialLimitConfig) {
+	err := serial.WriteConfigFile(filepath.Join(n.Dir, "libp2p-resource-limit-overrides.json"), c)
+	if err != nil {
+		panic(err)
+	}
+}
+
+func (n *Node) UpdateUserSuppliedResourceManagerOverrides(f func(overrides *rcmgr.PartialLimitConfig)) {
+	overrides := n.ReadUserResourceOverrides()
+	f(overrides)
+	n.WriteUserSuppliedResourceOverrides(overrides)
+}
+
+func (n *Node) IPFS(args ...string) *RunResult {
 	res := n.RunIPFS(args...)
 	n.Runner.AssertNoError(res)
 	return res
 }
 
-func (n *Node) PipeStrToIPFS(s string, args ...string) RunResult {
+func (n *Node) PipeStrToIPFS(s string, args ...string) *RunResult {
 	return n.PipeToIPFS(strings.NewReader(s), args...)
 }
 
-func (n *Node) PipeToIPFS(reader io.Reader, args ...string) RunResult {
+func (n *Node) PipeToIPFS(reader io.Reader, args ...string) *RunResult {
 	res := n.RunPipeToIPFS(reader, args...)
 	n.Runner.AssertNoError(res)
 	return res
 }
 
-func (n *Node) RunPipeToIPFS(reader io.Reader, args ...string) RunResult {
+func (n *Node) RunPipeToIPFS(reader io.Reader, args ...string) *RunResult {
 	return n.Runner.Run(RunRequest{
 		Path:    n.IPFSBin,
 		Args:    args,
@@ -107,7 +145,7 @@ func (n *Node) RunPipeToIPFS(reader io.Reader, args ...string) RunResult {
 	})
 }
 
-func (n *Node) RunIPFS(args ...string) RunResult {
+func (n *Node) RunIPFS(args ...string) *RunResult {
 	return n.Runner.Run(RunRequest{
 		Path: n.IPFSBin,
 		Args: args,
@@ -170,7 +208,7 @@ func (n *Node) StartDaemon(ipfsArgs ...string) *Node {
 		RunFunc: (*exec.Cmd).Start,
 	})
 
-	n.Daemon = &res
+	n.Daemon = res
 
 	log.Debugf("node %d started, checking API", n.ID)
 	n.WaitOnAPI()
@@ -353,8 +391,6 @@ func (n *Node) SwarmAddrs() []multiaddr.Multiaddr {
 		Path: n.IPFSBin,
 		Args: []string{"swarm", "addrs", "local"},
 	})
-	ipfsProtocol := multiaddr.ProtocolWithCode(multiaddr.P_IPFS).Name
-	peerID := n.PeerID()
 	out := strings.TrimSpace(res.Stdout.String())
 	outLines := strings.Split(out, "\n")
 	var addrs []multiaddr.Multiaddr
@@ -363,9 +399,18 @@ func (n *Node) SwarmAddrs() []multiaddr.Multiaddr {
 		if err != nil {
 			panic(err)
 		}
+		addrs = append(addrs, ma)
+	}
+	return addrs
+}
 
+func (n *Node) SwarmAddrsWithPeerIDs() []multiaddr.Multiaddr {
+	ipfsProtocol := multiaddr.ProtocolWithCode(multiaddr.P_IPFS).Name
+	peerID := n.PeerID()
+	var addrs []multiaddr.Multiaddr
+	for _, ma := range n.SwarmAddrs() {
 		// add the peer ID to the multiaddr if it doesn't have it
-		_, err = ma.ValueForProtocol(multiaddr.P_IPFS)
+		_, err := ma.ValueForProtocol(multiaddr.P_IPFS)
 		if errors.Is(err, multiaddr.ErrProtocolNotFound) {
 			comp, err := multiaddr.NewComponent(ipfsProtocol, peerID.String())
 			if err != nil {
@@ -378,10 +423,27 @@ func (n *Node) SwarmAddrs() []multiaddr.Multiaddr {
 	return addrs
 }
 
+func (n *Node) SwarmAddrsWithoutPeerIDs() []multiaddr.Multiaddr {
+	var addrs []multiaddr.Multiaddr
+	for _, ma := range n.SwarmAddrs() {
+		var components []multiaddr.Multiaddr
+		multiaddr.ForEach(ma, func(c multiaddr.Component) bool {
+			if c.Protocol().Code == multiaddr.P_IPFS {
+				return true
+			}
+			components = append(components, &c)
+			return true
+		})
+		ma = multiaddr.Join(components...)
+		addrs = append(addrs, ma)
+	}
+	return addrs
+}
+
 func (n *Node) Connect(other *Node) *Node {
 	n.Runner.MustRun(RunRequest{
 		Path: n.IPFSBin,
-		Args: []string{"swarm", "connect", other.SwarmAddrs()[0].String()},
+		Args: []string{"swarm", "connect", other.SwarmAddrsWithPeerIDs()[0].String()},
 	})
 	return n
 }
@@ -391,9 +453,8 @@ func (n *Node) Peers() []multiaddr.Multiaddr {
 		Path: n.IPFSBin,
 		Args: []string{"swarm", "peers"},
 	})
-	lines := strings.Split(strings.TrimSpace(res.Stdout.String()), "\n")
 	var addrs []multiaddr.Multiaddr
-	for _, line := range lines {
+	for _, line := range res.Stdout.Lines() {
 		ma, err := multiaddr.NewMultiaddr(line)
 		if err != nil {
 			panic(err)
@@ -403,6 +464,28 @@ func (n *Node) Peers() []multiaddr.Multiaddr {
 	return addrs
 }
 
+func (n *Node) PeerWith(other *Node) {
+	n.UpdateConfig(func(cfg *config.Config) {
+		var addrs []multiaddr.Multiaddr
+		for _, addrStr := range other.ReadConfig().Addresses.Swarm {
+			ma, err := multiaddr.NewMultiaddr(addrStr)
+			if err != nil {
+				panic(err)
+			}
+			addrs = append(addrs, ma)
+		}
+
+		cfg.Peering.Peers = append(cfg.Peering.Peers, peer.AddrInfo{
+			ID:    other.PeerID(),
+			Addrs: addrs,
+		})
+	})
+}
+
+func (n *Node) Disconnect(other *Node) {
+	n.IPFS("swarm", "disconnect", "/p2p/"+other.PeerID().String())
+}
+
 // GatewayURL waits for the gateway file and then returns its contents or times out.
 func (n *Node) GatewayURL() string {
 	timer := time.NewTimer(1 * time.Second)
diff --git a/test/cli/harness/nodes.go b/test/cli/harness/nodes.go
index dbc7de16ba1cf3d02d150fa2ac51457a9e8af6b0..78662afbbeaa95bf68d4933505fc135d09fb86a0 100644
--- a/test/cli/harness/nodes.go
+++ b/test/cli/harness/nodes.go
@@ -3,17 +3,32 @@ package harness
 import (
 	"sync"
 
+	. "github.com/ipfs/kubo/test/cli/testutils"
 	"github.com/multiformats/go-multiaddr"
+	"golang.org/x/sync/errgroup"
 )
 
 // Nodes is a collection of Kubo nodes along with operations on groups of nodes.
 type Nodes []*Node
 
 func (n Nodes) Init(args ...string) Nodes {
+	ForEachPar(n, func(node *Node) { node.Init(args...) })
+	return n
+}
+
+func (n Nodes) ForEachPar(f func(*Node)) {
+	group := &errgroup.Group{}
 	for _, node := range n {
-		node.Init()
+		node := node
+		group.Go(func() error {
+			f(node)
+			return nil
+		})
+	}
+	err := group.Wait()
+	if err != nil {
+		panic(err)
 	}
-	return n
 }
 
 func (n Nodes) Connect() Nodes {
@@ -43,22 +58,11 @@ func (n Nodes) Connect() Nodes {
 }
 
 func (n Nodes) StartDaemons() Nodes {
-	wg := sync.WaitGroup{}
-	for _, node := range n {
-		wg.Add(1)
-		node := node
-		go func() {
-			defer wg.Done()
-			node.StartDaemon()
-		}()
-	}
-	wg.Wait()
+	ForEachPar(n, func(node *Node) { node.StartDaemon() })
 	return n
 }
 
 func (n Nodes) StopDaemons() Nodes {
-	for _, node := range n {
-		node.StopDaemon()
-	}
+	ForEachPar(n, func(node *Node) { node.StopDaemon() })
 	return n
 }
diff --git a/test/cli/harness/run.go b/test/cli/harness/run.go
index 1a6b32fc2f1f21f4c6b91219992653c12af9c403..c2a3662be8bd4512e8fa5304319a4487278f1973 100644
--- a/test/cli/harness/run.go
+++ b/test/cli/harness/run.go
@@ -38,6 +38,10 @@ type RunResult struct {
 	Cmd     *exec.Cmd
 }
 
+func (r *RunResult) ExitCode() int {
+	return r.Cmd.ProcessState.ExitCode()
+}
+
 func environToMap(environ []string) map[string]string {
 	m := map[string]string{}
 	for _, e := range environ {
@@ -47,7 +51,7 @@ func environToMap(environ []string) map[string]string {
 	return m
 }
 
-func (r *Runner) Run(req RunRequest) RunResult {
+func (r *Runner) Run(req RunRequest) *RunResult {
 	cmd := exec.Command(req.Path, req.Args...)
 	stdout := &Buffer{}
 	stderr := &Buffer{}
@@ -82,17 +86,17 @@ func (r *Runner) Run(req RunRequest) RunResult {
 		result.ExitErr = exitErr
 	}
 
-	return result
+	return &result
 }
 
 // MustRun runs the command and fails the test if the command fails.
-func (r *Runner) MustRun(req RunRequest) RunResult {
+func (r *Runner) MustRun(req RunRequest) *RunResult {
 	result := r.Run(req)
 	r.AssertNoError(result)
 	return result
 }
 
-func (r *Runner) AssertNoError(result RunResult) {
+func (r *Runner) AssertNoError(result *RunResult) {
 	if result.ExitErr != nil {
 		log.Panicf("'%s' returned error, code: %d, err: %s\nstdout:%s\nstderr:%s\n",
 			result.Cmd.Args, result.ExitErr.ExitCode(), result.ExitErr.Error(), result.Stdout.String(), result.Stderr.String())
diff --git a/test/cli/peering_test.go b/test/cli/peering_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..f3e797fae802363ce9ff35675de5885568abd043
--- /dev/null
+++ b/test/cli/peering_test.go
@@ -0,0 +1,141 @@
+package cli
+
+import (
+	"fmt"
+	"math/rand"
+	"testing"
+	"time"
+
+	"github.com/ipfs/kubo/config"
+	"github.com/ipfs/kubo/test/cli/harness"
+	. "github.com/ipfs/kubo/test/cli/testutils"
+	"github.com/libp2p/go-libp2p/core/peer"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestPeering(t *testing.T) {
+	t.Parallel()
+
+	type peering struct {
+		from int
+		to   int
+	}
+
+	newRandPort := func() int {
+		n := rand.Int()
+		return 3000 + (n % 1000)
+	}
+
+	containsPeerID := func(p peer.ID, peers []peer.ID) bool {
+		for _, peerID := range peers {
+			if p == peerID {
+				return true
+			}
+		}
+		return false
+	}
+
+	assertPeered := func(h *harness.Harness, from *harness.Node, to *harness.Node) {
+		assert.Eventuallyf(t, func() bool {
+			fromPeers := from.Peers()
+			if len(fromPeers) == 0 {
+				return false
+			}
+			var fromPeerIDs []peer.ID
+			for _, p := range fromPeers {
+				fromPeerIDs = append(fromPeerIDs, h.ExtractPeerID(p))
+			}
+			return containsPeerID(to.PeerID(), fromPeerIDs)
+		}, 20*time.Second, 10*time.Millisecond, "%d -> %d not peered", from.ID, to.ID)
+	}
+
+	assertNotPeered := func(h *harness.Harness, from *harness.Node, to *harness.Node) {
+		assert.Eventuallyf(t, func() bool {
+			fromPeers := from.Peers()
+			if len(fromPeers) == 0 {
+				return false
+			}
+			var fromPeerIDs []peer.ID
+			for _, p := range fromPeers {
+				fromPeerIDs = append(fromPeerIDs, h.ExtractPeerID(p))
+			}
+			return !containsPeerID(to.PeerID(), fromPeerIDs)
+		}, 20*time.Second, 10*time.Millisecond, "%d -> %d peered", from.ID, to.ID)
+	}
+
+	assertPeerings := func(h *harness.Harness, nodes []*harness.Node, peerings []peering) {
+		ForEachPar(peerings, func(peering peering) {
+			assertPeered(h, nodes[peering.from], nodes[peering.to])
+		})
+	}
+
+	createNodes := func(t *testing.T, n int, peerings []peering) (*harness.Harness, harness.Nodes) {
+		h := harness.NewT(t)
+		nodes := h.NewNodes(n).Init()
+		nodes.ForEachPar(func(node *harness.Node) {
+			node.UpdateConfig(func(cfg *config.Config) {
+				cfg.Routing.Type = config.NewOptionalString("none")
+				cfg.Addresses.Swarm = []string{fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", newRandPort())}
+			})
+
+		})
+
+		for _, peering := range peerings {
+			nodes[peering.from].PeerWith(nodes[peering.to])
+		}
+
+		return h, nodes
+	}
+
+	t.Run("bidirectional peering should work (simultaneous connect)", func(t *testing.T) {
+		t.Parallel()
+		peerings := []peering{{from: 0, to: 1}, {from: 1, to: 0}, {from: 1, to: 2}}
+		h, nodes := createNodes(t, 3, peerings)
+
+		nodes.StartDaemons()
+		assertPeerings(h, nodes, peerings)
+
+		nodes[0].Disconnect(nodes[1])
+		assertPeerings(h, nodes, peerings)
+	})
+
+	t.Run("1 should reconnect to 2 when 2 disconnects from 1", func(t *testing.T) {
+		t.Parallel()
+		peerings := []peering{{from: 0, to: 1}, {from: 1, to: 0}, {from: 1, to: 2}}
+		h, nodes := createNodes(t, 3, peerings)
+
+		nodes.StartDaemons()
+		assertPeerings(h, nodes, peerings)
+
+		nodes[2].Disconnect(nodes[1])
+		assertPeerings(h, nodes, peerings)
+	})
+
+	t.Run("1 will peer with 2 when it comes online", func(t *testing.T) {
+		t.Parallel()
+		peerings := []peering{{from: 0, to: 1}, {from: 1, to: 0}, {from: 1, to: 2}}
+		h, nodes := createNodes(t, 3, peerings)
+
+		nodes[0].StartDaemon()
+		nodes[1].StartDaemon()
+		assertPeerings(h, nodes, []peering{{from: 0, to: 1}, {from: 1, to: 0}})
+
+		nodes[2].StartDaemon()
+		assertPeerings(h, nodes, peerings)
+	})
+
+	t.Run("1 will re-peer with 2 when it disconnects and then comes back online", func(t *testing.T) {
+		t.Parallel()
+		peerings := []peering{{from: 0, to: 1}, {from: 1, to: 0}, {from: 1, to: 2}}
+		h, nodes := createNodes(t, 3, peerings)
+
+		nodes.StartDaemons()
+		assertPeerings(h, nodes, peerings)
+
+		nodes[2].StopDaemon()
+		assertNotPeered(h, nodes[1], nodes[2])
+
+		nodes[2].StartDaemon()
+		assertPeerings(h, nodes, peerings)
+	})
+}
diff --git a/test/cli/rcmgr_test.go b/test/cli/rcmgr_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..50ea269793d35e2124fdb0bae1e32c98dad8752c
--- /dev/null
+++ b/test/cli/rcmgr_test.go
@@ -0,0 +1,325 @@
+package cli
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/ipfs/kubo/config"
+	"github.com/ipfs/kubo/core/node/libp2p"
+	"github.com/ipfs/kubo/test/cli/harness"
+	"github.com/ipfs/kubo/test/cli/testutils"
+	"github.com/libp2p/go-libp2p/core/peer"
+	"github.com/libp2p/go-libp2p/core/protocol"
+	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestRcmgr(t *testing.T) {
+	t.Parallel()
+
+	t.Run("Resource manager disabled", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateConfig(func(cfg *config.Config) {
+			cfg.Swarm.ResourceMgr.Enabled = config.False
+		})
+
+		node.StartDaemon()
+
+		t.Run("swarm resources should fail", func(t *testing.T) {
+			res := node.RunIPFS("swarm", "resources")
+			assert.Equal(t, 1, res.ExitCode())
+			assert.Contains(t, res.Stderr.String(), "missing ResourceMgr")
+		})
+	})
+
+	t.Run("Node with resource manager disabled", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateConfig(func(cfg *config.Config) {
+			cfg.Swarm.ResourceMgr.Enabled = config.False
+		})
+		node.StartDaemon()
+
+		t.Run("swarm resources should fail", func(t *testing.T) {
+			res := node.RunIPFS("swarm", "resources")
+			assert.Equal(t, 1, res.ExitCode())
+			assert.Contains(t, res.Stderr.String(), "missing ResourceMgr")
+		})
+	})
+
+	t.Run("Very high connmgr highwater", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateConfig(func(cfg *config.Config) {
+			cfg.Swarm.ConnMgr.HighWater = config.NewOptionalInteger(1000)
+		})
+		node.StartDaemon()
+
+		res := node.RunIPFS("swarm", "resources", "--enc=json")
+		require.Equal(t, 0, res.ExitCode())
+		limits := unmarshalLimits(t, res.Stdout.Bytes())
+
+		rl := limits.System.ToResourceLimits()
+		s := rl.Build(rcmgr.BaseLimit{})
+		assert.GreaterOrEqual(t, s.ConnsInbound, 2000)
+		assert.GreaterOrEqual(t, s.StreamsInbound, 2000)
+	})
+
+	t.Run("default configuration", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateConfig(func(cfg *config.Config) {
+			cfg.Swarm.ConnMgr.HighWater = config.NewOptionalInteger(1000)
+		})
+		node.StartDaemon()
+
+		t.Run("conns and streams are above 800 for default connmgr settings", func(t *testing.T) {
+			t.Parallel()
+			res := node.RunIPFS("swarm", "resources", "--enc=json")
+			require.Equal(t, 0, res.ExitCode())
+			limits := unmarshalLimits(t, res.Stdout.Bytes())
+
+			if limits.System.ConnsInbound > rcmgr.DefaultLimit {
+				assert.GreaterOrEqual(t, limits.System.ConnsInbound, 800)
+			}
+			if limits.System.StreamsInbound > rcmgr.DefaultLimit {
+				assert.GreaterOrEqual(t, limits.System.StreamsInbound, 800)
+			}
+		})
+
+		t.Run("limits should succeed", func(t *testing.T) {
+			t.Parallel()
+			res := node.RunIPFS("swarm", "resources", "--enc=json")
+			assert.Equal(t, 0, res.ExitCode())
+
+			limits := rcmgr.PartialLimitConfig{}
+			err := json.Unmarshal(res.Stdout.Bytes(), &limits)
+			require.NoError(t, err)
+
+			assert.NotEqual(t, limits.Transient.Memory, rcmgr.BlockAllLimit64)
+			assert.NotEqual(t, limits.System.Memory, rcmgr.BlockAllLimit64)
+			assert.NotEqual(t, limits.System.FD, rcmgr.BlockAllLimit)
+			assert.NotEqual(t, limits.System.Conns, rcmgr.BlockAllLimit)
+			assert.NotEqual(t, limits.System.ConnsInbound, rcmgr.BlockAllLimit)
+			assert.NotEqual(t, limits.System.ConnsOutbound, rcmgr.BlockAllLimit)
+			assert.NotEqual(t, limits.System.Streams, rcmgr.BlockAllLimit)
+			assert.NotEqual(t, limits.System.StreamsInbound, rcmgr.BlockAllLimit)
+			assert.NotEqual(t, limits.System.StreamsOutbound, rcmgr.BlockAllLimit)
+		})
+
+		t.Run("swarm stats works", func(t *testing.T) {
+			t.Parallel()
+			res := node.RunIPFS("swarm", "resources", "--enc=json")
+			require.Equal(t, 0, res.ExitCode())
+
+			limits := unmarshalLimits(t, res.Stdout.Bytes())
+
+			// every scope has the same fields, so we only inspect system
+			assert.Zero(t, limits.System.MemoryUsage)
+			assert.Zero(t, limits.System.FDUsage)
+			assert.Zero(t, limits.System.ConnsInboundUsage)
+			assert.Zero(t, limits.System.ConnsOutboundUsage)
+			assert.Zero(t, limits.System.StreamsInboundUsage)
+			assert.Zero(t, limits.System.StreamsOutboundUsage)
+			assert.Zero(t, limits.Transient.MemoryUsage)
+		})
+	})
+
+	t.Run("smoke test unlimited System inbounds", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+			overrides.System.StreamsInbound = rcmgr.Unlimited
+			overrides.System.ConnsInbound = rcmgr.Unlimited
+		})
+		node.StartDaemon()
+
+		res := node.RunIPFS("swarm", "resources", "--enc=json")
+		limits := unmarshalLimits(t, res.Stdout.Bytes())
+
+		assert.Equal(t, rcmgr.Unlimited, limits.System.ConnsInbound)
+		assert.Equal(t, rcmgr.Unlimited, limits.System.StreamsInbound)
+	})
+
+	t.Run("smoke test transient scope", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+			overrides.Transient.Memory = 88888
+		})
+		node.StartDaemon()
+
+		res := node.RunIPFS("swarm", "resources", "--enc=json")
+		limits := unmarshalLimits(t, res.Stdout.Bytes())
+		assert.Equal(t, rcmgr.LimitVal64(88888), limits.Transient.Memory)
+	})
+
+	t.Run("smoke test service scope", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+			overrides.Service = map[string]rcmgr.ResourceLimits{"foo": {Memory: 77777}}
+		})
+		node.StartDaemon()
+
+		res := node.RunIPFS("swarm", "resources", "--enc=json")
+		limits := unmarshalLimits(t, res.Stdout.Bytes())
+		assert.Equal(t, rcmgr.LimitVal64(77777), limits.Services["foo"].Memory)
+	})
+
+	t.Run("smoke test protocol scope", func(t *testing.T) {
+		t.Parallel()
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+			overrides.Protocol = map[protocol.ID]rcmgr.ResourceLimits{"foo": {Memory: 66666}}
+		})
+		node.StartDaemon()
+
+		res := node.RunIPFS("swarm", "resources", "--enc=json")
+		limits := unmarshalLimits(t, res.Stdout.Bytes())
+		assert.Equal(t, rcmgr.LimitVal64(66666), limits.Protocols["foo"].Memory)
+	})
+
+	t.Run("smoke test peer scope", func(t *testing.T) {
+		t.Parallel()
+		validPeerID, err := peer.Decode("QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN")
+		assert.NoError(t, err)
+		node := harness.NewT(t).NewNode().Init()
+		node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+			overrides.Peer = map[peer.ID]rcmgr.ResourceLimits{validPeerID: {Memory: 55555}}
+		})
+		node.StartDaemon()
+
+		res := node.RunIPFS("swarm", "resources", "--enc=json")
+		limits := unmarshalLimits(t, res.Stdout.Bytes())
+		assert.Equal(t, rcmgr.LimitVal64(55555), limits.Peers[validPeerID].Memory)
+	})
+
+	t.Run("blocking and allowlists", func(t *testing.T) {
+		t.Parallel()
+		nodes := harness.NewT(t).NewNodes(3).Init()
+		node0, node1, node2 := nodes[0], nodes[1], nodes[2]
+		peerID1, peerID2 := node1.PeerID().String(), node2.PeerID().String()
+
+		node0.UpdateConfig(func(cfg *config.Config) {
+			cfg.Swarm.ResourceMgr.Enabled = config.True
+			cfg.Swarm.ResourceMgr.Allowlist = []string{"/ip4/0.0.0.0/ipcidr/0/p2p/" + peerID2}
+		})
+		node0.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+			*overrides = rcmgr.PartialLimitConfig{
+				System: rcmgr.ResourceLimits{
+					Conns:         rcmgr.BlockAllLimit,
+					ConnsInbound:  rcmgr.BlockAllLimit,
+					ConnsOutbound: rcmgr.BlockAllLimit,
+				},
+			}
+		})
+
+		nodes.StartDaemons()
+
+		t.Run("node 0 should fail to connect to and ping node 1", func(t *testing.T) {
+			t.Parallel()
+			res := node0.Runner.Run(harness.RunRequest{
+				Path: node0.IPFSBin,
+				Args: []string{"swarm", "connect", node1.SwarmAddrsWithPeerIDs()[0].String()},
+			})
+			assert.Equal(t, 1, res.ExitCode())
+			testutils.AssertStringContainsOneOf(t, res.Stderr.String(),
+				"failed to find any peer in table",
+				"resource limit exceeded",
+			)
+
+			res = node0.RunIPFS("ping", "-n2", peerID1)
+			assert.Equal(t, 1, res.ExitCode())
+			assert.Contains(t, res.Stderr.String(), "Error: ping failed")
+		})
+
+		t.Run("node 0 should connect to and ping node 2 since it is allowlisted", func(t *testing.T) {
+			t.Parallel()
+			res := node0.Runner.Run(harness.RunRequest{
+				Path: node0.IPFSBin,
+				Args: []string{"swarm", "connect", node2.SwarmAddrsWithPeerIDs()[0].String()},
+			})
+			assert.Equal(t, 0, res.ExitCode())
+
+			res = node0.RunIPFS("ping", "-n2", peerID2)
+			assert.Equal(t, 0, res.ExitCode())
+		})
+	})
+
+	t.Run("daemon should refuse to start if connmgr.highwater < resources inbound", func(t *testing.T) {
+		t.Run("system conns", func(t *testing.T) {
+			t.Parallel()
+			node := harness.NewT(t).NewNode().Init()
+			node.UpdateConfig(func(cfg *config.Config) {
+				cfg.Swarm.ConnMgr.HighWater = config.NewOptionalInteger(128)
+				cfg.Swarm.ConnMgr.LowWater = config.NewOptionalInteger(64)
+			})
+			node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+				*overrides = rcmgr.PartialLimitConfig{
+					System: rcmgr.ResourceLimits{Conns: 128},
+				}
+			})
+
+			res := node.RunIPFS("daemon")
+			assert.Equal(t, 1, res.ExitCode())
+		})
+		t.Run("system conns inbound", func(t *testing.T) {
+			t.Parallel()
+			node := harness.NewT(t).NewNode().Init()
+			node.UpdateConfig(func(cfg *config.Config) {
+				cfg.Swarm.ConnMgr.HighWater = config.NewOptionalInteger(128)
+				cfg.Swarm.ConnMgr.LowWater = config.NewOptionalInteger(64)
+			})
+			node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+				*overrides = rcmgr.PartialLimitConfig{
+					System: rcmgr.ResourceLimits{ConnsInbound: 128},
+				}
+			})
+
+			res := node.RunIPFS("daemon")
+			assert.Equal(t, 1, res.ExitCode())
+		})
+		t.Run("system streams", func(t *testing.T) {
+			t.Parallel()
+			node := harness.NewT(t).NewNode().Init()
+			node.UpdateConfig(func(cfg *config.Config) {
+				cfg.Swarm.ConnMgr.HighWater = config.NewOptionalInteger(128)
+				cfg.Swarm.ConnMgr.LowWater = config.NewOptionalInteger(64)
+			})
+			node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+				*overrides = rcmgr.PartialLimitConfig{
+					System: rcmgr.ResourceLimits{Streams: 128},
+				}
+			})
+
+			res := node.RunIPFS("daemon")
+			assert.Equal(t, 1, res.ExitCode())
+		})
+		t.Run("system streams inbound", func(t *testing.T) {
+			t.Parallel()
+			node := harness.NewT(t).NewNode().Init()
+			node.UpdateConfig(func(cfg *config.Config) {
+				cfg.Swarm.ConnMgr.HighWater = config.NewOptionalInteger(128)
+				cfg.Swarm.ConnMgr.LowWater = config.NewOptionalInteger(64)
+			})
+			node.UpdateUserSuppliedResourceManagerOverrides(func(overrides *rcmgr.PartialLimitConfig) {
+				*overrides = rcmgr.PartialLimitConfig{
+					System: rcmgr.ResourceLimits{StreamsInbound: 128},
+				}
+			})
+
+			res := node.RunIPFS("daemon")
+			assert.Equal(t, 1, res.ExitCode())
+		})
+	})
+}
+
+func unmarshalLimits(t *testing.T, b []byte) *libp2p.LimitsConfigAndUsage {
+	limits := &libp2p.LimitsConfigAndUsage{}
+	err := json.Unmarshal(b, limits)
+	require.NoError(t, err)
+	return limits
+}
diff --git a/test/cli/testutils/asserts.go b/test/cli/testutils/asserts.go
new file mode 100644
index 0000000000000000000000000000000000000000..cf840c20ee73066f3e40975278b566418eb39147
--- /dev/null
+++ b/test/cli/testutils/asserts.go
@@ -0,0 +1,15 @@
+package testutils
+
+import (
+	"strings"
+	"testing"
+)
+
+func AssertStringContainsOneOf(t *testing.T, str string, ss ...string) {
+	for _, s := range ss {
+		if strings.Contains(str, s) {
+			return
+		}
+	}
+	t.Errorf("%q does not contain one of %v", str, ss)
+}
diff --git a/test/cli/testutils/strings.go b/test/cli/testutils/strings.go
index 1fb1512485ea9e49ccc6a321b8aa329df73c1207..110051e679f9481349b09395f3934968e645bef1 100644
--- a/test/cli/testutils/strings.go
+++ b/test/cli/testutils/strings.go
@@ -7,6 +7,7 @@ import (
 	"net/netip"
 	"net/url"
 	"strings"
+	"sync"
 
 	"github.com/multiformats/go-multiaddr"
 	manet "github.com/multiformats/go-multiaddr/net"
@@ -75,3 +76,16 @@ func URLStrToMultiaddr(u string) multiaddr.Multiaddr {
 	}
 	return ma
 }
+
+// ForEachPar invokes f in a new goroutine for each element of s and waits for all to complete.
+func ForEachPar[T any](s []T, f func(T)) {
+	wg := sync.WaitGroup{}
+	wg.Add(len(s))
+	for _, x := range s {
+		go func(x T) {
+			defer wg.Done()
+			f(x)
+		}(x)
+	}
+	wg.Wait()
+}
diff --git a/test/integration/bitswap_wo_routing_test.go b/test/integration/bitswap_wo_routing_test.go
index fa4e8d5139ea2e96ffbd05208f065db1cb5ede12..6a6fca4b7a9cd86ebc9bb7f634c76cb11aa45c02 100644
--- a/test/integration/bitswap_wo_routing_test.go
+++ b/test/integration/bitswap_wo_routing_test.go
@@ -5,8 +5,8 @@ import (
 	"context"
 	"testing"
 
-	blocks "github.com/ipfs/go-block-format"
 	"github.com/ipfs/go-cid"
+	blocks "github.com/ipfs/go-libipfs/blocks"
 	"github.com/ipfs/kubo/core"
 	coremock "github.com/ipfs/kubo/core/mock"
 	"github.com/ipfs/kubo/core/node/libp2p"
diff --git a/test/sharness/README.md b/test/sharness/README.md
index 9358fcf9caf741f05d4d6ef26692ec20489294fa..6ab8539da2cf4f27381083303b4fa66764e8839b 100644
--- a/test/sharness/README.md
+++ b/test/sharness/README.md
@@ -46,7 +46,7 @@ $ ./t0010-basic-commands.sh -v -i
 
 When running sharness tests from main Makefile or when `test_sharness_deps`
 target is run dependencies for sharness
-will be downloaded from its github repo and installed in a "lib/sharness"
+will be downloaded from its GitHub repo and installed in a "lib/sharness"
 directory.
 
 Please do not change anything in the "lib/sharness" directory.
diff --git a/test/sharness/Rules.mk b/test/sharness/Rules.mk
index 20b2634dbb67de52fb17478b2b49be86a2c80b16..f95aee15e0dc8fb3dae4299f311bed8c0e3b0772 100644
--- a/test/sharness/Rules.mk
+++ b/test/sharness/Rules.mk
@@ -47,21 +47,6 @@ $(d)/test-results/sharness.xml: $(T_$(d))
 	@(cd $(@D)/.. && ./lib/test-aggregate-junit-reports.sh)
 .PHONY: $(d)/test-results/sharness.xml
 
-$(d)/download-saxon:
-	@echo "*** $@ ***"
-	@(cd $(@D) && ./lib/download-saxon.sh)
-.PHONY: $(d)/download-saxon
-
-$(d)/test-results/sharness-html: $(d)/test-results/sharness.xml $(d)/download-saxon
-	@echo "*** $@ ***"
-	@(cd $(@D)/.. && ./lib/test-generate-junit-html.sh frames)
-.PHONY: $(d)/test-results/sharness-html
-
-$(d)/test-results/sharness.html: $(d)/test-results/sharness.xml $(d)/download-saxon
-	@echo "*** $@ ***"
-	@(cd $(@D)/.. && ./lib/test-generate-junit-html.sh no-frames)
-.PHONY: $(d)/test-results/sharness.html
-
 $(d)/clean-test-results:
 	rm -rf $(@D)/test-results
 .PHONY: $(d)/clean-test-results
diff --git a/test/sharness/lib/download-saxon.sh b/test/sharness/lib/download-saxon.sh
deleted file mode 100755
index cc645238f12cf3269f3ec14724fda9b942e108bc..0000000000000000000000000000000000000000
--- a/test/sharness/lib/download-saxon.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-
-dependencies=(
-  "url=https://raw.githubusercontent.com/pl-strflt/Saxon-HE/3e039cdbccf4efb9643736f34c839a3bae3402ae/11/Java/SaxonHE11-4J.zip;md5=8a4783d307c32c898f8995b8f337fd6b"
-  "url=https://raw.githubusercontent.com/pl-strflt/ant/c781f7d79b92cc55530245d9554682a47f46851e/src/etc/junit-frames-saxon.xsl;md5=6eb013566903a91e4959413f6ff144d0"
-  "url=https://raw.githubusercontent.com/pl-strflt/ant/c781f7d79b92cc55530245d9554682a47f46851e/src/etc/junit-noframes-saxon.xsl;md5=8d54882d5f9d32a7743ec675cc2e30ac"
-)
-
-dependenciesdir="lib/dependencies"
-mkdir -p "$dependenciesdir"
-
-get_md5() {
-  md5sum "$1" | cut -d ' ' -f 1
-}
-
-for dependency in "${dependencies[@]}"; do
-  url="$(echo "$dependency" | cut -d ';' -f 1 | cut -d '=' -f 2)"
-  md5="$(echo "$dependency" | cut -d ';' -f 2 | cut -d '=' -f 2)"
-  filename="$(basename "$url")"
-  if test -f "$dependenciesdir/$filename" && test "$(get_md5 "$dependenciesdir/$filename")" = "$md5"; then
-    echo "Using cached $filename"
-  else
-    echo "Downloading $filename"
-    curl -L --max-redirs 5 --retry 5 --no-progress-meter --output "$dependenciesdir/$filename" "$url"
-    actual_md5="$(get_md5 "$dependenciesdir/$filename")"
-    if test "$actual_md5" != "$md5"; then
-      echo "Downloaded $filename has wrong md5sum ('$actual_md5' != '$md5')"
-      exit 1
-    fi
-    dirname=${filename%.*}
-    extension=${filename#$dirname.}
-    if test "$extension" = "zip"; then
-      echo "Removing old $dependenciesdir/$dirname"
-      rm -rf "$dependenciesdir/$dirname"
-      echo "Unzipping $dependenciesdir/$filename"
-      unzip "$dependenciesdir/$filename" -d "$dependenciesdir/$dirname"
-    fi
-  fi
-done
diff --git a/test/sharness/lib/test-generate-junit-html.sh b/test/sharness/lib/test-generate-junit-html.sh
deleted file mode 100755
index 2790a7b9d0cc34b6ee7a8f7aa22d412362c2451c..0000000000000000000000000000000000000000
--- a/test/sharness/lib/test-generate-junit-html.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-case "$1" in
-  "frames")
-    java -jar lib/dependencies/SaxonHE11-4J/saxon-he-11.4.jar \
-      -s:test-results/sharness.xml \
-      -xsl:lib/dependencies/junit-frames-saxon.xsl \
-      output.dir=$(pwd)/test-results/sharness-html
-    ;;
-  "no-frames")
-    java -jar lib/dependencies/SaxonHE11-4J/saxon-he-11.4.jar \
-      -s:test-results/sharness.xml \
-      -xsl:lib/dependencies/junit-noframes-saxon.xsl \
-      -o:test-results/sharness.html
-    ;;
-  *)
-    echo "Usage: $0 [frames|no-frames]"
-    exit 1
-    ;;
-esac
diff --git a/test/sharness/t0054-dag-car-import-export-data/README.md b/test/sharness/t0054-dag-car-import-export-data/README.md
index 2b6b5c00f2465d2a1e6b19256fe19c30339122e3..033f837a092f9ecdb4c55ca92b9ff1f42bb3baa9 100644
--- a/test/sharness/t0054-dag-car-import-export-data/README.md
+++ b/test/sharness/t0054-dag-car-import-export-data/README.md
@@ -20,7 +20,7 @@
   - versions identical to the above, but with a single "empty-block" root each ( in order to work around go-car not following the current "roots can be empty" spec )
 
 - combined_naked_roots_genesis_and_128.car
-  - only the roots of `lotus_devnet_genesis.car` and `lotus_testnet_export_128.car`, to to be used in combination with the root-less parts to validate "transactional" pinning
+  - only the roots of `lotus_devnet_genesis.car` and `lotus_testnet_export_128.car`,to be used in combination with the root-less parts to validate "transactional" pinning
 
 - lotus_testnet_export_128_v2.car
 - lotus_devnet_genesis_v2.car
diff --git a/test/sharness/t0060-daemon.sh b/test/sharness/t0060-daemon.sh
index ca40fd0d110d1f34a7d0fe1df978b677f74b5235..b237e143f6682755f16c530b62229ab59f6bcdf2 100755
--- a/test/sharness/t0060-daemon.sh
+++ b/test/sharness/t0060-daemon.sh
@@ -81,12 +81,11 @@ test_expect_success "ipfs daemon output looks good" '
   echo "Initializing daemon..." >expected_daemon &&
   ipfs version --all >> expected_daemon &&
   echo "" >>expected_daemon &&
-  echo "Computing default go-libp2p Resource Manager limits based on:" >>expected_daemon &&
+  echo "Computed default go-libp2p Resource Manager limits based on:" >>expected_daemon &&
   echo "    - '"'"'Swarm.ResourceMgr.MaxMemory'"'"': \"4GB\"" >>expected_daemon &&
   echo "    - '"'"'Swarm.ResourceMgr.MaxFileDescriptors'"'"': 1024" >>expected_daemon &&
   echo "" >>expected_daemon &&
-  echo "Applying any user-supplied overrides on top." >>expected_daemon &&
-  echo "Run '"'"'ipfs swarm limit all'"'"' to see the resulting limits." >>expected_daemon &&
+  echo "Theses can be inspected with '"'"'ipfs swarm resources'"'"'." >>expected_daemon &&
   echo "" >>expected_daemon &&
   sed "s/^/Swarm listening on /" listen_addrs >>expected_daemon &&
   sed "s/^/Swarm announcing /" local_addrs >>expected_daemon &&
diff --git a/test/sharness/t0100-name.sh b/test/sharness/t0100-name.sh
index 934cc012740fc496fb19f95dca1c753f701275a4..34f33ea4d89b7430d3179cf2ec62ada7d2588f54 100755
--- a/test/sharness/t0100-name.sh
+++ b/test/sharness/t0100-name.sh
@@ -225,6 +225,30 @@ test_name_with_self() {
         grep "argument \"ipfs-path\" is required" curl_out
         '
 
+        # Test Publishing with TTL and Inspecting Records
+        test_expect_success "'ipfs name publish --ttl=30m' succeeds" '
+        ipfs name publish --ttl=30m --allow-offline "/ipfs/$HASH_WELCOME_DOCS"
+        '
+
+        test_expect_success "retrieve IPNS key for further inspection" '
+        ipfs routing get "/ipns/$PEERID" > ipns_record
+        '
+
+        test_expect_success "'ipfs name inspect' has correct TTL (30m)" '
+        ipfs name inspect < ipns_record > verify_output &&
+        test_should_contain "This record was not validated." verify_output &&
+        test_should_contain "$HASH_WELCOME_DOCS" verify_output &&
+        test_should_contain "1800000000000" verify_output
+        '
+
+        test_expect_success "'ipfs name inspect --verify' has '.Validation.Validity' set to 'true' with correct Peer ID" '
+        ipfs name inspect --verify $PEERID --enc json < ipns_record | jq -e ".Validation.Valid == true and .Entry.TTL == .Entry.Data.TTL"
+        '
+
+        test_expect_success "'ipfs name inspect --verify' has '.Validation.Validity' set to 'false' with incorrect Peer ID" '
+        ipfs name inspect --verify 12D3KooWRirYjmmQATx2kgHBfky6DADsLP7ex1t7BRxJ6nqLs9WH --enc json < ipns_record | jq -e ".Validation.Valid == false"
+        '
+
         test_kill_ipfs_daemon
 
         # Test daemon in offline mode
@@ -290,4 +314,32 @@ test_name_with_key 'rsa'
 test_name_with_key 'ed25519_b58'
 test_name_with_key 'ed25519_b36'
 
+
+# `ipfs name inspect --verify` using the wrong RSA key should not succeed
+
+test_init_ipfs
+test_launch_ipfs_daemon
+
+test_expect_success "prepare RSA keys" '
+  export KEY_1=`ipfs key gen --type=rsa --size=4096 key1` &&
+  export KEY_2=`ipfs key gen --type=rsa --size=4096 key2` &&
+  export PEERID_1=`ipfs key list --ipns-base=base36 -l | grep key1 | cut -d " " -f1` &&
+  export PEERID_2=`ipfs key list --ipns-base=base36 -l | grep key2 | cut -d " " -f1`
+'
+
+test_expect_success "ipfs name publish --allow-offline --key=<peer-id> <hash>' succeeds" '
+  ipfs name publish --allow-offline  --key=${KEY_1} "/ipfs/$( echo "helloworld" | ipfs add --inline -q )" &&
+  ipfs routing get "/ipns/$PEERID_1" > ipns_record
+'
+
+test_expect_success "ipfs name inspect --verify' has '.Validation.Validity' set to 'true' with correct Peer ID" '
+  ipfs name inspect --verify $PEERID_1 --enc json < ipns_record | jq -e ".Validation.Valid == true"
+'
+
+test_expect_success "ipfs name inspect --verify' has '.Validation.Validity' set to 'false' when we verify the wrong Peer ID" '
+  ipfs name inspect --verify $PEERID_2 --enc json < ipns_record | jq -e ".Validation.Valid == false"
+'
+
+test_kill_ipfs_daemon
+
 test_done
diff --git a/test/sharness/t0111-gateway-writeable.sh b/test/sharness/t0111-gateway-writeable.sh
index 53d4fc1aa408943e9c31aafb381369317a218ac2..115114c890a612a360086ad6fdb831924d1c4f03 100755
--- a/test/sharness/t0111-gateway-writeable.sh
+++ b/test/sharness/t0111-gateway-writeable.sh
@@ -34,6 +34,10 @@ test_expect_success "ipfs daemon up" '
   test_fsh cat poll_apierr || test_fsh cat poll_apiout
 '
 
+test_expect_success "deprecation notice is printed when Gateway.Writable=true" '
+   test_should_contain "legacy Gateway.Writable is DEPRECATED and will be removed or changed in future versions. If you are still using this, provide feedback in https://github.com/ipfs/specs/issues/375" daemon_err
+'
+
 test_expect_success "HTTP gateway gives access to sample file" '
   curl -s -o welcome "http://$GWAY_ADDR/ipfs/$HASH_WELCOME_DOCS/readme" &&
   grep "Hello and Welcome to IPFS!" welcome
diff --git a/test/sharness/t0113-gateway-symlink.sh b/test/sharness/t0113-gateway-symlink.sh
index 9fa7ffa6edf544b8b9c8e9b511768868b493f75b..29e5b960de3c4c6848e855e883e2d72cf058997e 100755
--- a/test/sharness/t0113-gateway-symlink.sh
+++ b/test/sharness/t0113-gateway-symlink.sh
@@ -9,26 +9,21 @@ test_description="Test symlink support on the HTTP gateway"
 test_init_ipfs
 test_launch_ipfs_daemon
 
-
-test_expect_success "Create a test directory with symlinks" '
-  mkdir testfiles &&
-  echo "content" > testfiles/foo &&
-  ln -s foo testfiles/bar &&
-  test_cmp testfiles/foo testfiles/bar
-'
-
-test_expect_success "Add the test directory" '
-  HASH=$(ipfs add -Qr testfiles)
+# Import test case
+# See the static fixtures in ./t0113-gateway-symlink/
+test_expect_success "Add the test directory with symlinks" '
+  ipfs dag import ../t0113-gateway-symlink/testfiles.car
 '
+ROOT_DIR_CID=QmWvY6FaqFMS89YAQ9NAPjVP4WZKA1qbHbicc9HeSKQTgt # ./testfiles/
 
 test_expect_success "Test the directory listing" '
-  curl "$GWAY_ADDR/ipfs/$HASH/" > list_response &&
+  curl "$GWAY_ADDR/ipfs/$ROOT_DIR_CID/" > list_response &&
   test_should_contain ">foo<" list_response &&
   test_should_contain ">bar<" list_response
 '
 
 test_expect_success "Test the symlink" '
-  curl "$GWAY_ADDR/ipfs/$HASH/bar" > bar_actual &&
+  curl "$GWAY_ADDR/ipfs/$ROOT_DIR_CID/bar" > bar_actual &&
   echo -n "foo" > bar_expected &&
   test_cmp bar_expected bar_actual
 '
diff --git a/test/sharness/t0113-gateway-symlink/README.md b/test/sharness/t0113-gateway-symlink/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..31a257bdded99d2e12cbeeef526ef4bc47046b67
--- /dev/null
+++ b/test/sharness/t0113-gateway-symlink/README.md
@@ -0,0 +1,17 @@
+# Dataset description/sources
+
+- testfiles.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+mkdir testfiles &&
+echo "content" > testfiles/foo &&
+ln -s foo testfiles/bar &&
+ROOT_DIR_CID=$(ipfs add -Qr testfiles) &&
+ipfs dag export $ROOT_DIR_CID > testfiles.car
+
+# ROOT_DIR_CID=QmWvY6FaqFMS89YAQ9NAPjVP4WZKA1qbHbicc9HeSKQTgt
+```
diff --git a/test/sharness/t0113-gateway-symlink/testfiles.car b/test/sharness/t0113-gateway-symlink/testfiles.car
new file mode 100644
index 0000000000000000000000000000000000000000..88e5825f3029ceb158138812c946825544704d26
Binary files /dev/null and b/test/sharness/t0113-gateway-symlink/testfiles.car differ
diff --git a/test/sharness/t0114-gateway-subdomains.sh b/test/sharness/t0114-gateway-subdomains.sh
index a7e5a59c938268605587094af2e15c8a848a4109..04f762ad68e65084f7748f543bd1182a6993b9c0 100755
--- a/test/sharness/t0114-gateway-subdomains.sh
+++ b/test/sharness/t0114-gateway-subdomains.sh
@@ -91,27 +91,19 @@ test_expect_success "ipfs init" '
 
 test_launch_ipfs_daemon_without_network
 
+# Import test case
+# See the static fixtures in ./t0114-gateway-subdomains/
+test_expect_success "Add the test fixtures" '
+  ipfs dag import ../t0114-gateway-subdomains/fixtures.car
+'
+CID_VAL="hello"
+CIDv1=bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am
+CIDv0=QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN
 # CIDv0to1 is necessary because raw-leaves are enabled by default during
 # "ipfs add" with CIDv1 and disabled with CIDv0
-test_expect_success "Add test text file" '
-  CID_VAL="hello"
-  CIDv1=$(echo $CID_VAL | ipfs add --cid-version 1 -Q)
-  CIDv0=$(echo $CID_VAL | ipfs add --cid-version 0 -Q)
-  CIDv0to1=$(echo "$CIDv0" | ipfs cid base32)
-  echo CIDv0to1=${CIDv0to1}
-'
-
-# Directory tree crafted to test for edge cases like "/ipfs/ipfs/ipns/bar"
-test_expect_success "Add the test directory" '
-  mkdir -p testdirlisting/ipfs/ipns &&
-  echo "hello" > testdirlisting/hello &&
-  echo "text-file-content" > testdirlisting/ipfs/ipns/bar &&
-  mkdir -p testdirlisting/api &&
-  mkdir -p testdirlisting/ipfs &&
-  echo "I am a txt file" > testdirlisting/api/file.txt &&
-  echo "I am a txt file" > testdirlisting/ipfs/file.txt &&
-  DIR_CID=$(ipfs add -Qr --cid-version 1 testdirlisting)
-'
+CIDv0to1=bafybeiffndsajwhk3lwjewwdxqntmjm4b5wxaaanokonsggenkbw6slwk4
+CIDv1_TOO_LONG=bafkrgqhhyivzstcz3hhswshfjgy6ertgmnqeleynhwt4dlfsthi4hn7zgh4uvlsb5xncykzapi3ocd4lzogukir6ksdy6wzrnz6ohnv4aglcs
+DIR_CID=bafybeiht6dtwk3les7vqm6ibpvz6qpohidvlshsfyr7l5mpysdw2vmbbhe # ./testdirlisting
 
 test_expect_success "Publish test text file to IPNS using RSA keys" '
   RSA_KEY=$(ipfs key gen --ipns-base=b58mh --type=rsa --size=2048 test_key_rsa | head -n1 | tr -d "\n")
@@ -600,8 +592,6 @@ test_expect_success \
 IPNS_KEY="test_key_ed25519"
 IPNS_ED25519_B58MH=$(ipfs key list -l --ipns-base b58mh | grep $IPNS_KEY | cut -d" " -f1 | tr -d "\n")
 IPNS_ED25519_B36CID=$(ipfs key list -l --ipns-base base36 | grep $IPNS_KEY | cut -d" " -f1 | tr -d "\n")
-# sha512 will be over 63char limit, even when represented in Base36
-CIDv1_TOO_LONG=$(echo $CID_VAL | ipfs add --cid-version 1 --hash sha2-512 -Q)
 
 # local: *.localhost
 test_localhost_gateway_response_should_contain \
diff --git a/test/sharness/t0114-gateway-subdomains/README.md b/test/sharness/t0114-gateway-subdomains/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..611bd0ed5adaab817af55cfe626bceffa7f1951b
--- /dev/null
+++ b/test/sharness/t0114-gateway-subdomains/README.md
@@ -0,0 +1,54 @@
+# Dataset description/sources
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+
+# CIDv0to1 is necessary because raw-leaves are enabled by default during
+# "ipfs add" with CIDv1 and disabled with CIDv0
+CID_VAL="hello"
+CIDv1=$(echo $CID_VAL | ipfs add --cid-version 1 -Q)
+CIDv0=$(echo $CID_VAL | ipfs add --cid-version 0 -Q)
+CIDv0to1=$(echo "$CIDv0" | ipfs cid base32)
+# sha512 will be over 63char limit, even when represented in Base36
+CIDv1_TOO_LONG=$(echo $CID_VAL | ipfs add --cid-version 1 --hash sha2-512 -Q)
+
+echo CIDv1=${CIDv1}
+echo CIDv0=${CIDv0}
+echo CIDv0to1=${CIDv0to1}
+echo CIDv1_TOO_LONG=${CIDv1_TOO_LONG}
+
+# Directory tree crafted to test for edge cases like "/ipfs/ipfs/ipns/bar"
+mkdir -p testdirlisting/ipfs/ipns &&
+echo "hello" > testdirlisting/hello &&
+echo "text-file-content" > testdirlisting/ipfs/ipns/bar &&
+mkdir -p testdirlisting/api &&
+mkdir -p testdirlisting/ipfs &&
+echo "I am a txt file" > testdirlisting/api/file.txt &&
+echo "I am a txt file" > testdirlisting/ipfs/file.txt &&
+DIR_CID=$(ipfs add -Qr --cid-version 1 testdirlisting)
+
+echo DIR_CID=${DIR_CID}
+
+ipfs files mkdir /t0114/
+ipfs files cp /ipfs/${CIDv1} /t0114/
+ipfs files cp /ipfs/${CIDv0} /t0114/
+ipfs files cp /ipfs/${CIDv0to1} /t0114/
+ipfs files cp /ipfs/${DIR_CID} /t0114/
+ipfs files cp /ipfs/${CIDv1_TOO_LONG} /t0114/
+
+ROOT=`ipfs files stat /t0114/ --hash`
+
+ipfs dag export ${ROOT} > ./fixtures.car
+
+# CID_VAL="hello"
+# CIDv1=bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am
+# CIDv0=QmZULkCELmmk5XNfCgTnCyFgAVxBRBXyDHGGMVoLFLiXEN
+# CIDv0to1=bafybeiffndsajwhk3lwjewwdxqntmjm4b5wxaaanokonsggenkbw6slwk4
+# CIDv1_TOO_LONG=bafkrgqhhyivzstcz3hhswshfjgy6ertgmnqeleynhwt4dlfsthi4hn7zgh4uvlsb5xncykzapi3ocd4lzogukir6ksdy6wzrnz6ohnv4aglcs
+# DIR_CID=bafybeiht6dtwk3les7vqm6ibpvz6qpohidvlshsfyr7l5mpysdw2vmbbhe # ./testdirlisting
+```
diff --git a/test/sharness/t0114-gateway-subdomains/fixtures.car b/test/sharness/t0114-gateway-subdomains/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..bc7b913dfa27573c76673744a7d15df6a885e891
Binary files /dev/null and b/test/sharness/t0114-gateway-subdomains/fixtures.car differ
diff --git a/test/sharness/t0115-gateway-dir-listing.sh b/test/sharness/t0115-gateway-dir-listing.sh
index 708e0c4cf8b98eeb4d22a810782ac95f0961c403..cf95bf4b05e709ec94de5ca93f60178dfbbad804 100755
--- a/test/sharness/t0115-gateway-dir-listing.sh
+++ b/test/sharness/t0115-gateway-dir-listing.sh
@@ -18,20 +18,14 @@ test_expect_success "ipfs init" '
 
 test_launch_ipfs_daemon_without_network
 
+# Import test case
+# See the static fixtures in ./t0115-gateway-dir-listing/
 test_expect_success "Add the test directory" '
-  mkdir -p rootDir/ipfs &&
-  mkdir -p rootDir/ipns &&
-  mkdir -p rootDir/api &&
-  mkdir -p rootDir/ą/ę &&
-  echo "I am a txt file on path with utf8" > rootDir/ą/ę/file-źł.txt &&
-  echo "I am a txt file in confusing /api dir" > rootDir/api/file.txt &&
-  echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt &&
-  echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt &&
-  DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) &&
-  FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) &&
-  FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size)
-  echo "$FILE_CID / $FILE_SIZE"
+  ipfs dag import ../t0115-gateway-dir-listing/fixtures.car
 '
+DIR_CID=bafybeig6ka5mlwkl4subqhaiatalkcleo4jgnr3hqwvpmsqfca27cijp3i # ./rootDir/
+FILE_CID=bafkreialihlqnf5uwo4byh4n3cmwlntwqzxxs2fg5vanqdi3d7tb2l5xkm # ./rootDir/ą/ę/file-źł.txt
+FILE_SIZE=34
 
 ## ============================================================================
 ## Test dir listing on path gateway (eg. 127.0.0.1:8080/ipfs/)
diff --git a/test/sharness/t0115-gateway-dir-listing/README.md b/test/sharness/t0115-gateway-dir-listing/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..937438bcd657cb6ac17c16962e0870c257c12c11
--- /dev/null
+++ b/test/sharness/t0115-gateway-dir-listing/README.md
@@ -0,0 +1,32 @@
+# Dataset description/sources
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+mkdir -p rootDir/ipfs &&
+mkdir -p rootDir/ipns &&
+mkdir -p rootDir/api &&
+mkdir -p rootDir/ą/ę &&
+echo "I am a txt file on path with utf8" > rootDir/ą/ę/file-źł.txt &&
+echo "I am a txt file in confusing /api dir" > rootDir/api/file.txt &&
+echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt &&
+echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt &&
+DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) &&
+FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) &&
+FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size)
+echo "$FILE_CID / $FILE_SIZE"
+
+echo DIR_CID=${DIR_CID}
+echo FILE_CID=${FILE_CID}
+echo FILE_SIZE=${FILE_SIZE}
+
+ipfs dag export ${DIR_CID} > ./fixtures.car
+
+# DIR_CID=bafybeig6ka5mlwkl4subqhaiatalkcleo4jgnr3hqwvpmsqfca27cijp3i # ./rootDir/
+# FILE_CID=bafkreialihlqnf5uwo4byh4n3cmwlntwqzxxs2fg5vanqdi3d7tb2l5xkm # ./rootDir/ą/ę/file-źł.txt
+# FILE_SIZE=34
+```
diff --git a/test/sharness/t0115-gateway-dir-listing/fixtures.car b/test/sharness/t0115-gateway-dir-listing/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..71a5603822741f25320438bd70823589120e313c
Binary files /dev/null and b/test/sharness/t0115-gateway-dir-listing/fixtures.car differ
diff --git a/test/sharness/t0116-gateway-cache.sh b/test/sharness/t0116-gateway-cache.sh
index 0af4ec0eb7108aa7df4e19a49c224013e3305243..0cb1a94eb00e6435231d319021a67c0950d692f8 100755
--- a/test/sharness/t0116-gateway-cache.sh
+++ b/test/sharness/t0116-gateway-cache.sh
@@ -25,15 +25,16 @@ test_launch_ipfs_daemon_without_network
 # Caching of things like raw blocks, CARs, dag-json and dag-cbor
 # is tested in their respective suites.
 
+# Import test case
+# See the static fixtures in ./t0116-gateway-cache/
 test_expect_success "Add the test directory" '
-  mkdir -p root2/root3/root4 &&
-  echo "hello" > root2/root3/root4/index.html &&
-  ROOT1_CID=$(ipfs add -Qrw --cid-version 1 root2)
-  ROOT2_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2 | cut -d "/" -f3)
-  ROOT3_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3 | cut -d "/" -f3)
-  ROOT4_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3/root4 | cut -d "/" -f3)
-  FILE_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3/root4/index.html | cut -d "/" -f3)
+  ipfs dag import ../t0116-gateway-cache/fixtures.car
 '
+ROOT1_CID=bafybeib3ffl2teiqdncv3mkz4r23b5ctrwkzrrhctdbne6iboayxuxk5ui # ./
+ROOT2_CID=bafybeih2w7hjocxjg6g2ku25hvmd53zj7og4txpby3vsusfefw5rrg5sii # ./root2
+ROOT3_CID=bafybeiawdvhmjcz65x5egzx4iukxc72hg4woks6v6fvgyupiyt3oczk5ja # ./root2/root3
+ROOT4_CID=bafybeifq2rzpqnqrsdupncmkmhs3ckxxjhuvdcbvydkgvch3ms24k5lo7q # ./root2/root3/root4
+FILE_CID=bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am # ./root2/root3/root4/index.html
 
 test_expect_success "Prepare IPNS unixfs content path for testing" '
   TEST_IPNS_ID=$(ipfs key gen --ipns-base=base36 --type=ed25519 cache_test_key | head -n1 | tr -d "\n")
@@ -203,7 +204,7 @@ test_expect_success "Prepare IPNS unixfs content path for testing" '
     grep -E "< Etag: \"DirIndex-.+_CID-${ROOT3_CID}\"" curl_ipfs_dir_listing_output
     '
     test_expect_success "GET /ipns/ dir response has special Etag for generated dir listing" '
-    test_should_contain "< Etag: \"DirIndex" curl_ipfs_dir_listing_output &&
+    test_should_contain "< Etag: \"DirIndex" curl_ipns_dir_listing_output &&
     grep -E "< Etag: \"DirIndex-.+_CID-${ROOT3_CID}\"" curl_ipns_dir_listing_output
     '
 
diff --git a/test/sharness/t0116-gateway-cache/README.md b/test/sharness/t0116-gateway-cache/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8b44fe640b748c160bf6b3f40a385dc190b985db
--- /dev/null
+++ b/test/sharness/t0116-gateway-cache/README.md
@@ -0,0 +1,31 @@
+# Dataset description/sources
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+mkdir -p root2/root3/root4 &&
+echo "hello" > root2/root3/root4/index.html &&
+ROOT1_CID=$(ipfs add -Qrw --cid-version 1 root2)
+ROOT2_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2 | cut -d "/" -f3)
+ROOT3_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3 | cut -d "/" -f3)
+ROOT4_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3/root4 | cut -d "/" -f3)
+FILE_CID=$(ipfs resolve -r /ipfs/$ROOT1_CID/root2/root3/root4/index.html | cut -d "/" -f3)
+
+echo ROOT1_CID=${ROOT1_CID}
+echo ROOT2_CID=${ROOT2_CID}
+echo ROOT3_CID=${ROOT3_CID}
+echo ROOT4_CID=${ROOT4_CID}
+echo FILE_CID=${FILE_CID}
+
+ipfs dag export ${ROOT1_CID} > ./fixtures.car
+
+# ROOT1_CID=bafybeib3ffl2teiqdncv3mkz4r23b5ctrwkzrrhctdbne6iboayxuxk5ui # ./
+# ROOT2_CID=bafybeih2w7hjocxjg6g2ku25hvmd53zj7og4txpby3vsusfefw5rrg5sii # ./root2
+# ROOT3_CID=bafybeiawdvhmjcz65x5egzx4iukxc72hg4woks6v6fvgyupiyt3oczk5ja # ./root2/root3
+# ROOT4_CID=bafybeifq2rzpqnqrsdupncmkmhs3ckxxjhuvdcbvydkgvch3ms24k5lo7q # ./root2/root3/root4
+# FILE_CID=bafkreicysg23kiwv34eg2d7qweipxwosdo2py4ldv42nbauguluen5v6am # ./root2/root3/root4/index.html
+```
diff --git a/test/sharness/t0116-gateway-cache/fixtures.car b/test/sharness/t0116-gateway-cache/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..43e570e1d6acb0a03531b47feb540318f5027204
Binary files /dev/null and b/test/sharness/t0116-gateway-cache/fixtures.car differ
diff --git a/test/sharness/t0117-gateway-block.sh b/test/sharness/t0117-gateway-block.sh
index 5f1d080a3d424b4aad48c74e65c708e8fbe3357d..d5e40bb830b132197650dffa256691a8a3c2b514 100755
--- a/test/sharness/t0117-gateway-block.sh
+++ b/test/sharness/t0117-gateway-block.sh
@@ -7,12 +7,13 @@ test_description="Test HTTP Gateway Raw Block (application/vnd.ipld.raw) Support
 test_init_ipfs
 test_launch_ipfs_daemon_without_network
 
-test_expect_success "Create text fixtures" '
-  mkdir -p dir &&
-  echo "hello application/vnd.ipld.raw" > dir/ascii.txt &&
-  ROOT_DIR_CID=$(ipfs add -Qrw --cid-version 1 dir) &&
-  FILE_CID=$(ipfs resolve -r /ipfs/$ROOT_DIR_CID/dir/ascii.txt | cut -d "/" -f3)
+# Import test case
+# See the static fixtures in ./t0117-gateway-block/
+test_expect_success "Add the dir test directory" '
+  ipfs dag import ../t0117-gateway-block/fixtures.car
 '
+ROOT_DIR_CID=bafybeie72edlprgtlwwctzljf6gkn2wnlrddqjbkxo3jomh4n7omwblxly # ./
+FILE_CID=bafkreihhpc5y2pqvl5rbe5uuyhqjouybfs3rvlmisccgzue2kkt5zq6upq # ./dir/ascii.txt
 
 # GET unixfs dir root block and compare it with `ipfs block get` output
 
diff --git a/test/sharness/t0117-gateway-block/README.md b/test/sharness/t0117-gateway-block/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4ce37ae086f190b94229d7e37275d76180d429f8
--- /dev/null
+++ b/test/sharness/t0117-gateway-block/README.md
@@ -0,0 +1,21 @@
+# Dataset description/sources
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+mkdir -p dir &&
+echo "hello application/vnd.ipld.raw" > dir/ascii.txt &&
+ROOT_DIR_CID=$(ipfs add -Qrw --cid-version 1 dir) &&
+FILE_CID=$(ipfs resolve -r /ipfs/$ROOT_DIR_CID/dir/ascii.txt | cut -d "/" -f3) &&
+ipfs dag export $ROOT_DIR_CID > fixtures.car
+
+echo ROOT_DIR_CID=${ROOT_DIR_CID} # ./
+echo FILE_CID=${FILE_CID} # ./dir/ascii.txt
+
+# ROOT_DIR_CID=bafybeie72edlprgtlwwctzljf6gkn2wnlrddqjbkxo3jomh4n7omwblxly # ./
+# FILE_CID=bafkreihhpc5y2pqvl5rbe5uuyhqjouybfs3rvlmisccgzue2kkt5zq6upq # ./dir/ascii.txt
+```
diff --git a/test/sharness/t0117-gateway-block/fixtures.car b/test/sharness/t0117-gateway-block/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..77da1b5542e281eb1c80a4a8763c85bd7424b60b
Binary files /dev/null and b/test/sharness/t0117-gateway-block/fixtures.car differ
diff --git a/test/sharness/t0118-gateway-car.sh b/test/sharness/t0118-gateway-car.sh
index 62b2725d0cd5ee304ff7bf28e015e447935964b6..7b7d998eef84f7bdd180fcfc565956999bcf8d60 100755
--- a/test/sharness/t0118-gateway-car.sh
+++ b/test/sharness/t0118-gateway-car.sh
@@ -11,15 +11,14 @@ test_launch_ipfs_daemon_without_network
 # but if we have a small file that fits into a single block, and export its CID
 # we will get a CAR that is a deterministic array of bytes.
 
-    test_expect_success "Create a deterministic CAR for testing" '
-    mkdir -p subdir &&
-    echo "hello application/vnd.ipld.car" > subdir/ascii.txt &&
-    ROOT_DIR_CID=$(ipfs add -Qrw --cid-version 1 subdir) &&
-    FILE_CID=$(ipfs resolve -r /ipfs/$ROOT_DIR_CID/subdir/ascii.txt | cut -d "/" -f3) &&
-    ipfs dag export $ROOT_DIR_CID > test-dag.car &&
-    ipfs dag export $FILE_CID > deterministic.car &&
-    purge_blockstore
-    '
+# Import test case
+# See the static fixtures in ./t0118-gateway-car/
+test_expect_success "Add the dir test directory" '
+    cp ../t0118-gateway-car/test-dag.car ./test-dag.car &&
+    cp ../t0118-gateway-car/deterministic.car ./deterministic.car
+'
+ROOT_DIR_CID=bafybeiefu3d7oytdumk5v7gn6s7whpornueaw7m7u46v2o6omsqcrhhkzi # ./
+FILE_CID=bafkreifkam6ns4aoolg3wedr4uzrs3kvq66p4pecirz6y2vlrngla62mxm # /subdir/ascii.txt
 
 # GET a reference DAG with dag-cbor+dag-pb+raw blocks as CAR
 
diff --git a/test/sharness/t0118-gateway-car/README.md b/test/sharness/t0118-gateway-car/README.md
index 2efccc18544c6a4ffdaa53fab84f45f0772e91b0..7b81e543bc1b99331eb30f6727d15eeba38d64c8 100644
--- a/test/sharness/t0118-gateway-car/README.md
+++ b/test/sharness/t0118-gateway-car/README.md
@@ -8,3 +8,23 @@
   - description of the contents and layout of the raw CAR, encoded in DAG-JSON
   - Source: https://ipld.io/specs/transport/car/fixture/carv1-basic/carv1-basic.json
 
+- test-dag.car + deterministic.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+mkdir -p subdir &&
+echo "hello application/vnd.ipld.car" > subdir/ascii.txt &&
+ROOT_DIR_CID=$(ipfs add -Qrw --cid-version 1 subdir) &&
+FILE_CID=$(ipfs resolve -r /ipfs/$ROOT_DIR_CID/subdir/ascii.txt | cut -d "/" -f3) &&
+ipfs dag export $ROOT_DIR_CID > test-dag.car &&
+ipfs dag export $FILE_CID > deterministic.car &&
+
+echo ROOT_DIR_CID=${ROOT_DIR_CID} # ./
+echo FILE_CID=${FILE_CID} # /\subdir/ascii.txt
+
+# ROOT_DIR_CID=bafybeiefu3d7oytdumk5v7gn6s7whpornueaw7m7u46v2o6omsqcrhhkzi # ./
+# FILE_CID=bafkreifkam6ns4aoolg3wedr4uzrs3kvq66p4pecirz6y2vlrngla62mxm # /subdir/ascii.txt
+```
diff --git a/test/sharness/t0118-gateway-car/deterministic.car b/test/sharness/t0118-gateway-car/deterministic.car
new file mode 100644
index 0000000000000000000000000000000000000000..3967f909dce9b45cc3109ef1bccb0febfaf3c964
Binary files /dev/null and b/test/sharness/t0118-gateway-car/deterministic.car differ
diff --git a/test/sharness/t0118-gateway-car/test-dag.car b/test/sharness/t0118-gateway-car/test-dag.car
new file mode 100644
index 0000000000000000000000000000000000000000..e80fa4b0756cb7c9f5ebc44242424506fb7283cb
Binary files /dev/null and b/test/sharness/t0118-gateway-car/test-dag.car differ
diff --git a/test/sharness/t0116-prometheus-data/prometheus_metrics b/test/sharness/t0119-prometheus-data/prometheus_metrics
similarity index 84%
rename from test/sharness/t0116-prometheus-data/prometheus_metrics
rename to test/sharness/t0119-prometheus-data/prometheus_metrics
index 32c0d8e4343b9332a65a5e82d5fb09c117338e60..192e526c1fab242f53ed16a6311baaf8a5d8bcc3 100644
--- a/test/sharness/t0116-prometheus-data/prometheus_metrics
+++ b/test/sharness/t0119-prometheus-data/prometheus_metrics
@@ -576,6 +576,108 @@ leveldb_datastore_sync_latency_seconds_bucket
 leveldb_datastore_sync_latency_seconds_count
 leveldb_datastore_sync_latency_seconds_sum
 leveldb_datastore_sync_total
+libp2p_autonat_next_probe_timestamp
+libp2p_autonat_reachability_status
+libp2p_autonat_reachability_status_confidence
+libp2p_eventbus_events_emitted_total
+libp2p_eventbus_events_emitted_total
+libp2p_eventbus_subscriber_event_queued
+libp2p_eventbus_subscriber_event_queued
+libp2p_eventbus_subscriber_event_queued
+libp2p_eventbus_subscriber_queue_full
+libp2p_eventbus_subscriber_queue_full
+libp2p_eventbus_subscriber_queue_full
+libp2p_eventbus_subscriber_queue_length
+libp2p_eventbus_subscriber_queue_length
+libp2p_eventbus_subscriber_queue_length
+libp2p_eventbus_subscribers_total
+libp2p_eventbus_subscribers_total
+libp2p_eventbus_subscribers_total
+libp2p_eventbus_subscribers_total
+libp2p_eventbus_subscribers_total
+libp2p_eventbus_subscribers_total
+libp2p_identify_addrs_count
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_bucket
+libp2p_identify_addrs_received_count
+libp2p_identify_addrs_received_sum
+libp2p_identify_identify_pushes_triggered_total
+libp2p_identify_identify_pushes_triggered_total
+libp2p_identify_protocols_count
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_bucket
+libp2p_identify_protocols_received_count
+libp2p_identify_protocols_received_sum
 process_cpu_seconds_total
 process_max_fds
 process_open_fds
@@ -583,177 +685,3 @@ process_resident_memory_bytes
 process_start_time_seconds
 process_virtual_memory_bytes
 process_virtual_memory_max_bytes
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_bucket
-quic_connection_duration_count
-quic_connection_duration_sum
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_bucket
-quic_smoothed_rtt_count
-quic_smoothed_rtt_sum
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_bucket
-tcp_connection_duration_count
-tcp_connection_duration_sum
-tcp_rcvd_segments_total
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_bucket
-tcp_rtt_count
-tcp_rtt_sum
-tcp_sent_segments_total
diff --git a/test/sharness/t0116-prometheus-data/prometheus_metrics_added_by_enabling_rcmgr b/test/sharness/t0119-prometheus-data/prometheus_metrics_added_by_enabling_rcmgr
similarity index 100%
rename from test/sharness/t0116-prometheus-data/prometheus_metrics_added_by_enabling_rcmgr
rename to test/sharness/t0119-prometheus-data/prometheus_metrics_added_by_enabling_rcmgr
diff --git a/test/sharness/t0119-prometheus.sh b/test/sharness/t0119-prometheus.sh
index e96b8b96f8a0a3cdfdceef3f73a36a4be0d6601a..3387f4feb3b4d74c73c88a594c50863749335dee 100755
--- a/test/sharness/t0119-prometheus.sh
+++ b/test/sharness/t0119-prometheus.sh
@@ -27,7 +27,7 @@ test_expect_success "filter metrics" '
 '
 
 test_expect_success "make sure metrics haven't changed" '
-  diff -u ../t0116-prometheus-data/prometheus_metrics filtered_metrics
+  diff -u ../t0119-prometheus-data/prometheus_metrics filtered_metrics
 '
 
 # Check what was added by enabling ResourceMgr.Enabled
@@ -50,11 +50,11 @@ test_kill_ipfs_daemon
 
 test_expect_success "filter metrics and find ones added by enabling ResourceMgr" '
   sed -ne "s/^\([a-z0-9_]\+\).*/\1/p" raw_metrics | LC_ALL=C sort > filtered_metrics &&
-  grep -v -x -f ../t0116-prometheus-data/prometheus_metrics filtered_metrics > rcmgr_metrics
+  grep -v -x -f ../t0119-prometheus-data/prometheus_metrics filtered_metrics > rcmgr_metrics
 '
 
 test_expect_success "make sure initial metrics added by setting ResourceMgr.Enabled haven't changed" '
-  diff -u ../t0116-prometheus-data/prometheus_metrics_added_by_enabling_rcmgr rcmgr_metrics
+  diff -u ../t0119-prometheus-data/prometheus_metrics_added_by_enabling_rcmgr rcmgr_metrics
 '
 
 test_done
diff --git a/test/sharness/t0122-gateway-tar.sh b/test/sharness/t0122-gateway-tar.sh
index 34dc1ba12c85a1f109197b8837d0fd7ed3ffb67f..20cc1bf4cdc91235bc2f17f2fcd6db77d369463b 100755
--- a/test/sharness/t0122-gateway-tar.sh
+++ b/test/sharness/t0122-gateway-tar.sh
@@ -10,20 +10,14 @@ test_launch_ipfs_daemon_without_network
 OUTSIDE_ROOT_CID="bafybeicaj7kvxpcv4neaqzwhrqqmdstu4dhrwfpknrgebq6nzcecfucvyu"
 INSIDE_ROOT_CID="bafybeibfevfxlvxp5vxobr5oapczpf7resxnleb7tkqmdorc4gl5cdva3y"
 
+# Import test case
+# See the static fixtures in ./t0122-gateway-tar/
 test_expect_success "Add the test directory" '
-  mkdir -p rootDir/ipfs &&
-  mkdir -p rootDir/ipns &&
-  mkdir -p rootDir/api &&
-  mkdir -p rootDir/ą/ę &&
-  echo "I am a txt file on path with utf8" > rootDir/ą/ę/file-źł.txt &&
-  echo "I am a txt file in confusing /api dir" > rootDir/api/file.txt &&
-  echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt &&
-  echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt &&
-  DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) &&
-  FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) &&
-  FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size)
-  echo "$FILE_CID / $FILE_SIZE"
+  ipfs dag import ../t0122-gateway-tar/fixtures.car
 '
+DIR_CID=bafybeig6ka5mlwkl4subqhaiatalkcleo4jgnr3hqwvpmsqfca27cijp3i # ./rootDir
+FILE_CID=bafkreialihlqnf5uwo4byh4n3cmwlntwqzxxs2fg5vanqdi3d7tb2l5xkm # ./rootDir/ą/ę/file-źł.txt
+FILE_SIZE=34
 
 test_expect_success "GET TAR with format=tar and extract" '
   curl "http://127.0.0.1:$GWAY_PORT/ipfs/$FILE_CID?format=tar" | tar -x
@@ -69,9 +63,9 @@ test_expect_success "GET TAR with explicit ?filename= succeeds with modified Con
 "
 
 test_expect_success "Add CARs with relative paths to test with" '
-  ipfs dag import ../t0122-gateway-tar-data/outside-root.car > import_output &&
+  ipfs dag import ../t0122-gateway-tar/outside-root.car > import_output &&
   test_should_contain $OUTSIDE_ROOT_CID import_output &&
-  ipfs dag import ../t0122-gateway-tar-data/inside-root.car > import_output &&
+  ipfs dag import ../t0122-gateway-tar/inside-root.car > import_output &&
   test_should_contain $INSIDE_ROOT_CID import_output
 '
 
diff --git a/test/sharness/t0122-gateway-tar/README.md b/test/sharness/t0122-gateway-tar/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..8b9311277cca9a22cca89999c5ee8c21024414d6
--- /dev/null
+++ b/test/sharness/t0122-gateway-tar/README.md
@@ -0,0 +1,37 @@
+# Dataset description/sources
+
+- inside-root.car
+
+- outside-root.car
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# ipfs version 0.18.1
+
+mkdir -p rootDir/ipfs &&
+mkdir -p rootDir/ipns &&
+mkdir -p rootDir/api &&
+mkdir -p rootDir/ą/ę &&
+echo "I am a txt file on path with utf8" > rootDir/ą/ę/file-źł.txt &&
+echo "I am a txt file in confusing /api dir" > rootDir/api/file.txt &&
+echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt &&
+echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt &&
+DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) &&
+FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) &&
+FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size)
+echo "$FILE_CID / $FILE_SIZE"
+
+echo DIR_CID=${DIR_CID} # ./rootDir
+echo FILE_CID=${FILE_CID} # ./rootDir/ą/ę/file-źł.txt
+echo FILE_SIZE=${FILE_SIZE}
+
+ipfs dag export ${DIR_CID} > ./fixtures.car
+
+# DIR_CID=bafybeig6ka5mlwkl4subqhaiatalkcleo4jgnr3hqwvpmsqfca27cijp3i # ./rootDir
+# FILE_CID=bafkreialihlqnf5uwo4byh4n3cmwlntwqzxxs2fg5vanqdi3d7tb2l5xkm # ./rootDir/ą/ę/file-źł.txt
+# FILE_SIZE=34
+```
diff --git a/test/sharness/t0122-gateway-tar/fixtures.car b/test/sharness/t0122-gateway-tar/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..71a5603822741f25320438bd70823589120e313c
Binary files /dev/null and b/test/sharness/t0122-gateway-tar/fixtures.car differ
diff --git a/test/sharness/t0122-gateway-tar-data/inside-root.car b/test/sharness/t0122-gateway-tar/inside-root.car
similarity index 100%
rename from test/sharness/t0122-gateway-tar-data/inside-root.car
rename to test/sharness/t0122-gateway-tar/inside-root.car
diff --git a/test/sharness/t0122-gateway-tar-data/outside-root.car b/test/sharness/t0122-gateway-tar/outside-root.car
similarity index 100%
rename from test/sharness/t0122-gateway-tar-data/outside-root.car
rename to test/sharness/t0122-gateway-tar/outside-root.car
diff --git a/test/sharness/t0123-gateway-json-cbor.sh b/test/sharness/t0123-gateway-json-cbor.sh
index 704d075f940a1a0a64856a2f6ce3c3ca377cf3a9..b22c056de7876a1d0ba46201151594a0c24451f1 100755
--- a/test/sharness/t0123-gateway-json-cbor.sh
+++ b/test/sharness/t0123-gateway-json-cbor.sh
@@ -7,22 +7,15 @@ test_description="Test HTTP Gateway DAG-JSON (application/vnd.ipld.dag-json) and
 test_init_ipfs
 test_launch_ipfs_daemon_without_network
 
+# Import test case
+# See the static fixtures in ./t0123-gateway-json-cbor/
 test_expect_success "Add the test directory" '
-  mkdir -p rootDir/ipfs &&
-  mkdir -p rootDir/ipns &&
-  mkdir -p rootDir/api &&
-  mkdir -p rootDir/ą/ę &&
-  echo "{ \"test\": \"i am a plain json file\" }" > rootDir/ą/ę/t.json &&
-  echo "I am a txt file on path with utf8" > rootDir/ą/ę/file-źł.txt &&
-  echo "I am a txt file in confusing /api dir" > rootDir/api/file.txt &&
-  echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt &&
-  echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt &&
-  DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) &&
-  FILE_JSON_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/t.json | jq -r .Hash) &&
-  FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) &&
-  FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size)
-  echo "$FILE_CID / $FILE_SIZE"
+  ipfs dag import ../t0123-gateway-json-cbor/fixtures.car
 '
+DIR_CID=bafybeiafyvqlazbbbtjnn6how5d6h6l6rxbqc4qgpbmteaiskjrffmyy4a # ./rootDir
+FILE_JSON_CID=bafkreibrppizs3g7axs2jdlnjua6vgpmltv7k72l7v7sa6mmht6mne3qqe # ./rootDir/ą/ę/t.json
+FILE_CID=bafkreialihlqnf5uwo4byh4n3cmwlntwqzxxs2fg5vanqdi3d7tb2l5xkm # ./rootDir/ą/ę/file-źł.txt
+FILE_SIZE=34
 
 ## Quick regression check for JSON stored on UnixFS:
 ## it has nothing to do with DAG-JSON and JSON codecs,
diff --git a/test/sharness/t0123-gateway-json-cbor/README.md b/test/sharness/t0123-gateway-json-cbor/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4e83f42a1618936acff9b92c93f83319ca7b0fd0
--- /dev/null
+++ b/test/sharness/t0123-gateway-json-cbor/README.md
@@ -0,0 +1,44 @@
+# Dataset description/sources
+
+- dag-cbor-traversal.car
+
+- dag-json-traversal.car
+
+- dag-pb.car
+
+- dag-pb.json
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+mkdir -p rootDir/ipfs &&
+mkdir -p rootDir/ipns &&
+mkdir -p rootDir/api &&
+mkdir -p rootDir/ą/ę &&
+echo "{ \"test\": \"i am a plain json file\" }" > rootDir/ą/ę/t.json &&
+echo "I am a txt file on path with utf8" > rootDir/ą/ę/file-źł.txt &&
+echo "I am a txt file in confusing /api dir" > rootDir/api/file.txt &&
+echo "I am a txt file in confusing /ipfs dir" > rootDir/ipfs/file.txt &&
+echo "I am a txt file in confusing /ipns dir" > rootDir/ipns/file.txt &&
+DIR_CID=$(ipfs add -Qr --cid-version 1 rootDir) &&
+FILE_JSON_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/t.json | jq -r .Hash) &&
+FILE_CID=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Hash) &&
+FILE_SIZE=$(ipfs files stat --enc=json /ipfs/$DIR_CID/ą/ę/file-źł.txt | jq -r .Size)
+echo "$FILE_CID / $FILE_SIZE"
+
+echo DIR_CID=${DIR_CID} # ./rootDir
+echo FILE_JSON_CID=${FILE_JSON_CID} # ./rootDir/ą/ę/t.json
+echo FILE_CID=${FILE_CID} # ./rootDir/ą/ę/file-źł.txt
+echo FILE_SIZE=${FILE_SIZE}
+
+ipfs dag export ${DIR_CID} > fixtures.car
+
+# DIR_CID=bafybeiafyvqlazbbbtjnn6how5d6h6l6rxbqc4qgpbmteaiskjrffmyy4a # ./rootDir
+# FILE_JSON_CID=bafkreibrppizs3g7axs2jdlnjua6vgpmltv7k72l7v7sa6mmht6mne3qqe # ./rootDir/ą/ę/t.json
+# FILE_CID=bafkreialihlqnf5uwo4byh4n3cmwlntwqzxxs2fg5vanqdi3d7tb2l5xkm # ./rootDir/ą/ę/file-źł.txt
+# FILE_SIZE=34
+```
diff --git a/test/sharness/t0123-gateway-json-cbor/fixtures.car b/test/sharness/t0123-gateway-json-cbor/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..8663730f2fed608271d33fd2e205c68d544e89b7
Binary files /dev/null and b/test/sharness/t0123-gateway-json-cbor/fixtures.car differ
diff --git a/test/sharness/t0124-gateway-ipns-record.sh b/test/sharness/t0124-gateway-ipns-record.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cff00aa84d63e32df6d73fbce599787071962df8
--- /dev/null
+++ b/test/sharness/t0124-gateway-ipns-record.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+test_description="Test HTTP Gateway IPNS Record (application/vnd.ipfs.ipns-record) Support"
+
+. lib/test-lib.sh
+
+test_init_ipfs
+test_launch_ipfs_daemon
+
+test_expect_success "Create and Publish IPNS Key" '
+  FILE_CID=$(echo "Hello IPFS" | ipfs add --cid-version 1 -q) &&
+  IPNS_KEY=$(ipfs key gen ipns-record) &&
+  ipfs name publish /ipfs/$FILE_CID --key=ipns-record --ttl=30m &&
+  curl "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_KEY" > curl_output_filename &&
+  test_should_contain "Hello IPFS" curl_output_filename
+'
+
+test_expect_success "GET KEY with format=ipns-record and validate key" '
+  curl "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_KEY?format=ipns-record" > curl_output_filename &&
+  ipfs name inspect --verify $IPNS_KEY < curl_output_filename > verify_output &&
+  test_should_contain "$FILE_CID" verify_output
+'
+
+test_expect_success "GET KEY with 'Accept: application/vnd.ipfs.ipns-record' and validate key" '
+  curl -H "Accept: application/vnd.ipfs.ipns-record" "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_KEY" > curl_output_filename &&
+  ipfs name inspect --verify $IPNS_KEY < curl_output_filename > verify_output &&
+  test_should_contain "$FILE_CID" verify_output
+'
+
+test_expect_success "GET KEY with format=ipns-record has expected HTTP headers" '
+  curl -sD - "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_KEY?format=ipns-record" > curl_output_filename 2>&1 &&
+  test_should_contain "Content-Disposition: attachment;" curl_output_filename &&
+  test_should_contain "Content-Type: application/vnd.ipfs.ipns-record" curl_output_filename &&
+  test_should_contain "Cache-Control: public, max-age=1800" curl_output_filename
+'
+
+test_expect_success "GET KEY with 'Accept: application/vnd.ipfs.ipns-record' has expected HTTP headers" '
+  curl -H "Accept: application/vnd.ipfs.ipns-record" -sD - "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_KEY" > curl_output_filename 2>&1 &&
+  test_should_contain "Content-Disposition: attachment;" curl_output_filename &&
+  test_should_contain "Content-Type: application/vnd.ipfs.ipns-record" curl_output_filename &&
+  test_should_contain "Cache-Control: public, max-age=1800" curl_output_filename
+'
+
+test_expect_success "GET KEY with expliciy ?filename= succeeds with modified Content-Disposition header" '
+  curl -sD - "http://127.0.0.1:$GWAY_PORT/ipns/$IPNS_KEY?format=ipns-record&filename=testтест.ipns-record" > curl_output_filename 2>&1 &&
+  grep -F "Content-Disposition: attachment; filename=\"test____.ipns-record\"; filename*=UTF-8'\'\''test%D1%82%D0%B5%D1%81%D1%82.ipns-record" curl_output_filename &&
+  test_should_contain "Content-Type: application/vnd.ipfs.ipns-record" curl_output_filename
+'
+
+test_kill_ipfs_daemon
+
+test_done
diff --git a/test/sharness/t0139-swarm-rcmgr.sh b/test/sharness/t0139-swarm-rcmgr.sh
deleted file mode 100755
index 1b870abb787d8c11980fe50bd3da7d9722c9fd5c..0000000000000000000000000000000000000000
--- a/test/sharness/t0139-swarm-rcmgr.sh
+++ /dev/null
@@ -1,284 +0,0 @@
-#!/usr/bin/env bash
-#
-test_description="Test ipfs swarm ResourceMgr config and commands"
-
-. lib/test-lib.sh
-
-test_init_ipfs
-
-test_expect_success 'Disable resource manager' '
-  ipfs config --bool Swarm.ResourceMgr.Enabled false
-'
-
-# test correct behavior when resource manager is disabled
-test_launch_ipfs_daemon
-
-test_expect_success 'Swarm limit should fail since RM is disabled' '
-  test_expect_code 1 ipfs swarm limit system 2> actual &&
-  test_should_contain "missing ResourceMgr" actual
-'
-
-test_expect_success 'Swarm stats should fail since RM is disabled' '
-  test_expect_code 1 ipfs swarm stats all 2> actual &&
-  test_should_contain "missing ResourceMgr" actual
-'
-
-test_kill_ipfs_daemon
-
-test_expect_success 'Enable resource manager' '
-  ipfs config --bool Swarm.ResourceMgr.Enabled true
-'
-
-# swarm limit|stats should fail in offline mode
-
-test_expect_success 'disconnected: swarm limit requires running daemon' '
-  test_expect_code 1 ipfs swarm limit system 2> actual &&
-  test_should_contain "missing ResourceMgr" actual
-'
-test_expect_success 'disconnected: swarm stats requires running daemon' '
-  test_expect_code 1 ipfs swarm stats all 2> actual &&
-  test_should_contain "missing ResourceMgr" actual
-'
-
-# test sanity scaling
-test_expect_success 'set very high connmgr highwater' '
-  ipfs config --json Swarm.ConnMgr.HighWater 1000
-'
-
-test_launch_ipfs_daemon
-
-test_expect_success 'conns and streams are above 2000' '
-  ipfs swarm limit system --enc=json | tee json &&
-  [ "$(jq -r .ConnsInbound < json)" -ge 2000 ] &&
-  [ "$(jq -r .StreamsInbound < json)" -ge 2000 ]
-'
-
-test_kill_ipfs_daemon
-
-test_expect_success 'set previous connmgr highwater' '
-  ipfs config --json Swarm.ConnMgr.HighWater 96
-'
-
-test_launch_ipfs_daemon
-
-test_expect_success 'conns and streams are above 800' '
-  ipfs swarm limit system --enc=json | tee json &&
-  [ "$(jq -r .ConnsInbound < json)" -ge 800 ] &&
-  [ "$(jq -r .StreamsInbound < json)" -ge 800 ]
-'
-
-# swarm limit|stats should succeed in online mode by default
-# because Resource Manager is opt-out
-
-# every scope has the same fields, so we only inspect System
-test_expect_success 'ResourceMgr enabled: swarm limit' '
-  ipfs swarm limit system --enc=json | tee json &&
-  jq -e .Conns < json &&
-  jq -e .ConnsInbound < json &&
-  jq -e .ConnsOutbound < json &&
-  jq -e .FD < json &&
-  jq -e .Memory < json &&
-  jq -e .Streams < json &&
-  jq -e .StreamsInbound < json &&
-  jq -e .StreamsOutbound < json
-'
-test_expect_success 'ResourceMgr enabled: swarm limit reset' '
-  ipfs swarm limit system --reset --enc=json 2> reset &&
-  ipfs swarm limit system --enc=json 2> actual &&
-  test_cmp reset actual
-'
-
-test_expect_success 'Swarm stats system with filter should fail' '
-  test_expect_code 1 ipfs swarm stats system --min-used-limit-perc=99 2> actual &&
-  test_should_contain "Error: \"min-used-limit-perc\" can only be used when scope is \"all\"" actual
-'
-
-test_expect_success 'ResourceMgr enabled: swarm limit reset on map values' '
-  ipfs swarm limit peer:12D3KooWL7i1T9VSPeF8AgQApbyM51GNKZsYPvNvL347aMDmvNzG --reset --enc=json 2> reset &&
-  ipfs swarm limit peer:12D3KooWL7i1T9VSPeF8AgQApbyM51GNKZsYPvNvL347aMDmvNzG --enc=json 2> actual &&
-  test_cmp reset actual
-'
-
-test_expect_success 'ResourceMgr enabled: scope is required using reset flag' '
-  test_expect_code 1 ipfs swarm limit --reset 2> actual &&
-  test_should_contain "Error: argument \"scope\" is required" actual
-'
-
-test_expect_success 'connected: swarm stats all working properly' '
-  test_expect_code 0 ipfs swarm stats all
-'
-
-# every scope has the same fields, so we only inspect System
-test_expect_success 'ResourceMgr enabled: swarm stats' '
-  ipfs swarm stats all --enc=json | tee json &&
-  jq -e .System.Memory < json &&
-  jq -e .System.FD < json &&
-  jq -e .System.Conns < json &&
-  jq -e .System.ConnsInbound < json &&
-  jq -e .System.ConnsOutbound < json &&
-  jq -e .System.Streams < json &&
-  jq -e .System.StreamsInbound < json &&
-  jq -e .System.StreamsOutbound < json &&
-  jq -e .Transient.Memory < json
-'
-
-# shut down the daemon, set a limit in the config, and verify that it's applied
-test_kill_ipfs_daemon
-
-test_expect_success "Set system conns limit while daemon is not running" "
-  ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 99999
-"
-
-test_expect_success "Set an invalid limit, which should result in a failure" "
-  test_expect_code 1 ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 'asdf' 2> actual &&
-  test_should_contain 'failed to unmarshal' actual
-"
-
-test_launch_ipfs_daemon
-
-test_expect_success 'Ensure the new system conns limit is applied' '
-  ipfs swarm limit system --enc=json | tee json &&
-  jq -e ".Conns == 99999" < json
-'
-
-test_expect_success 'Set system memory limit while the daemon is running' '
-  ipfs swarm limit system | jq ".Memory = 99998" > system.json &&
-  ipfs swarm limit system system.json
-'
-
-test_expect_success 'The new system limits were written to the config' '
-  jq -e ".Swarm.ResourceMgr.Limits.System.Memory == 99998" < "$IPFS_PATH/config"
-'
-
-test_expect_success 'The new system limits are in the swarm limit output' '
-  ipfs swarm limit system --enc=json | jq -e ".Memory == 99998"
-'
-
-# now test all the other scopes
-test_expect_success 'Set limit on transient scope' '
-  ipfs swarm limit transient | jq ".Memory = 88888" > transient.json &&
-  ipfs swarm limit transient transient.json &&
-  jq -e ".Swarm.ResourceMgr.Limits.Transient.Memory == 88888" < "$IPFS_PATH/config" &&
-  ipfs swarm limit transient --enc=json | tee limits &&
-  jq -e ".Memory == 88888" < limits
-'
-
-test_expect_success 'Set limit on service scope' '
-  ipfs swarm limit svc:foo | jq ".Memory = 77777" > service-foo.json &&
-  ipfs swarm limit svc:foo service-foo.json --enc=json &&
-  jq -e ".Swarm.ResourceMgr.Limits.Service.foo.Memory == 77777" < "$IPFS_PATH/config" &&
-  ipfs swarm limit svc:foo --enc=json | tee limits &&
-  jq -e ".Memory == 77777" < limits
-'
-
-test_expect_success 'Set limit on protocol scope' '
-  ipfs swarm limit proto:foo | jq ".Memory = 66666" > proto-foo.json &&
-  ipfs swarm limit proto:foo proto-foo.json --enc=json &&
-  jq -e ".Swarm.ResourceMgr.Limits.Protocol.foo.Memory == 66666" < "$IPFS_PATH/config" &&
-  ipfs swarm limit proto:foo --enc=json | tee limits &&
-  jq -e ".Memory == 66666" < limits
-'
-
-# any valid peer id
-PEER_ID=QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
-
-test_expect_success 'Set limit on peer scope' '
-  ipfs swarm limit peer:$PEER_ID | jq ".Memory = 66666" > peer-$PEER_ID.json &&
-  ipfs swarm limit peer:$PEER_ID peer-$PEER_ID.json --enc=json &&
-  jq -e ".Swarm.ResourceMgr.Limits.Peer.${PEER_ID}.Memory == 66666" < "$IPFS_PATH/config" &&
-  ipfs swarm limit peer:$PEER_ID --enc=json | tee limits &&
-  jq -e ".Memory == 66666" < limits
-'
-
-test_expect_success 'Get limit for peer scope with an invalid peer ID' '
-  test_expect_code 1 ipfs swarm limit peer:foo 2> actual &&
-  test_should_contain "invalid peer ID" actual
-'
-
-test_expect_success 'Set limit for peer scope with an invalid peer ID' '
-  echo "{\"Memory\": 99}" > invalid-peer-id.json &&
-  test_expect_code 1 ipfs swarm limit peer:foo invalid-peer-id.json 2> actual &&
-  test_should_contain "invalid peer ID" actual
-'
-
-test_kill_ipfs_daemon
-
-## Test allowlist
-
-test_expect_success 'init iptb' '
-  iptb testbed create -type localipfs -count 3 -init
-'
-
-test_expect_success 'peer ids' '
-  PEERID_0=$(iptb attr get 0 id) &&
-  PEERID_1=$(iptb attr get 1 id) &&
-  PEERID_2=$(iptb attr get 2 id)
-'
-
-#enable resource manager
-test_expect_success 'enable RCMGR' '
-  ipfsi 0 config --bool Swarm.ResourceMgr.Enabled true &&
-  ipfsi 0 config --json Swarm.ResourceMgr.Allowlist "[\"/ip4/0.0.0.0/ipcidr/0/p2p/$PEERID_2\"]"
-'
-
-test_expect_success 'start nodes' '
-  iptb start -wait [0-2]
-'
-
-test_expect_success "change system limits on node 0" '
- ipfsi 0 swarm limit system | jq ". + {Conns: 0,ConnsInbound: 0, ConnsOutbound: 0}" > system.json &&
- ipfsi 0 swarm limit system system.json
-'
-
-test_expect_success "node 0 fails to connect to 1" '
-  test_expect_code 1 iptb connect 0 1
-'
-
-test_expect_success "node 0 connects to 2 because it's allowlisted" '
-  iptb connect 0 2
-'
-
-test_expect_success "node 0 fails to ping 1" '
-  test_expect_code 1 ipfsi 0 ping -n2 -- "$PEERID_1" 2> actual &&
-  test_should_contain "Error: ping failed" actual
-'
-
-test_expect_success "node 1 can ping 2" '
-  ipfsi 0 ping -n2 -- "$PEERID_2"
-'
-
-test_expect_success 'stop iptb' '
-  iptb stop 0 &&
-  iptb stop 1 &&
-  iptb stop 2
-'
-
-## Test daemon refuse to start if connmgr.highwater < ressources inbound
-
-test_expect_success "node refuse to start if Swarm.ResourceMgr.Limits.System.Conns <= Swarm.ConnMgr.HighWater" '
-  ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 128 &&
-  ipfs config --json Swarm.ConnMgr.HighWater 128 &&
-  ipfs config --json Swarm.ConnMgr.LowWater 64 &&
-  test_expect_code 1 ipfs daemon &&
-  ipfs config --json Swarm.ResourceMgr.Limits.System.Conns 256
-'
-
-test_expect_success "node refuse to start if Swarm.ResourceMgr.Limits.System.ConnsInbound <= Swarm.ConnMgr.HighWater" '
-  ipfs config --json Swarm.ResourceMgr.Limits.System.ConnsInbound 128 &&
-  test_expect_code 1 ipfs daemon &&
-  ipfs config --json Swarm.ResourceMgr.Limits.System.ConnsInbound 256
-'
-
-test_expect_success "node refuse to start if Swarm.ResourceMgr.Limits.System.Streams <= Swarm.ConnMgr.HighWater" '
-  ipfs config --json Swarm.ResourceMgr.Limits.System.Streams 128 &&
-  test_expect_code 1 ipfs daemon &&
-  ipfs config --json Swarm.ResourceMgr.Limits.System.Streams 256
-'
-
-test_expect_success "node refuse to start if Swarm.ResourceMgr.Limits.System.StreamsInbound <= Swarm.ConnMgr.HighWater" '
-  ipfs config --json Swarm.ResourceMgr.Limits.System.StreamsInbound 128 &&
-  test_expect_code 1 ipfs daemon &&
-  ipfs config --json Swarm.ResourceMgr.Limits.System.StreamsInbound 256
-'
-
-test_done
diff --git a/test/sharness/t0170-legacy-dht.sh b/test/sharness/t0170-legacy-dht.sh
deleted file mode 100755
index a4dffb34c6e41a004799ef08e585adaff7c9c892..0000000000000000000000000000000000000000
--- a/test/sharness/t0170-legacy-dht.sh
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/env bash
-
-# Legacy / deprecated, see: t0170-routing-dht.sh
-test_description="Test dht command"
-
-. lib/test-lib.sh
-
-test_dht() {
-  NUM_NODES=5
-
-  test_expect_success 'init iptb' '
-    rm -rf .iptb/ &&
-    iptb testbed create -type localipfs -count $NUM_NODES -init
-  '
-
-  test_expect_success 'DHT-only routing' '
-    iptb run -- ipfs config Routing.Type dht
-  '
-
-  startup_cluster $NUM_NODES $@
-
-  test_expect_success 'peer ids' '
-    PEERID_0=$(iptb attr get 0 id) &&
-    PEERID_2=$(iptb attr get 2 id)
-  '
-  
-  # ipfs dht findpeer <peerID>
-  test_expect_success 'findpeer' '
-    ipfsi 1 dht findpeer $PEERID_0 | sort >actual &&
-    ipfsi 0 id -f "<addrs>" | cut -d / -f 1-5 | sort >expected &&
-    test_cmp actual expected
-  '
-  
-  # ipfs dht get <key>
-  test_expect_success 'get with good keys works' '
-    HASH="$(echo "hello world" | ipfsi 2 add -q)" &&
-    ipfsi 2 name publish "/ipfs/$HASH" &&
-    ipfsi 1 dht get "/ipns/$PEERID_2" >get_result
-  '
-
-  test_expect_success 'get with good keys contains the right value' '
-    cat get_result | grep -aq "/ipfs/$HASH"
-  '
-
-  test_expect_success 'put round trips (#3124)' '
-    ipfsi 0 dht put "/ipns/$PEERID_2" get_result | sort >putted &&
-    [ -s putted ] ||
-    test_fsh cat putted
-  '
-  
-  test_expect_success 'put with bad keys fails (issue #5113)' '
-    ipfsi 0 dht put "foo" <<<bar >putted
-    ipfsi 0 dht put "/pk/foo" <<<bar >>putted
-    ipfsi 0 dht put "/ipns/foo" <<<bar >>putted
-    [ ! -s putted ] ||
-    test_fsh cat putted
-  '
-  
-  test_expect_success 'put with bad keys returns error (issue #4611)' '
-    test_must_fail ipfsi 0 dht put "foo" <<<bar &&
-    test_must_fail ipfsi 0 dht put "/pk/foo" <<<bar &&
-    test_must_fail ipfsi 0 dht put "/ipns/foo" <<<bar
-  '
-  
-  test_expect_success 'get with bad keys (issue #4611)' '
-    test_must_fail ipfsi 0 dht get "foo" &&
-    test_must_fail ipfsi 0 dht get "/pk/foo"
-  '
-  
-  test_expect_success "add a ref so we can find providers for it" '
-    echo "some stuff" > afile &&
-    HASH=$(ipfsi 3 add -q afile)
-  '
-  
-  # ipfs dht findprovs <key>
-  test_expect_success 'findprovs' '
-    ipfsi 4 dht findprovs $HASH > provs &&
-    iptb attr get 3 id > expected &&
-    test_cmp provs expected
-  '
-  
-  
-  # ipfs dht query <peerID>
-  #
-  # We test all nodes. 4 nodes should see the same peer ID, one node (the
-  # closest) should see a different one.
-
-  for i in $(test_seq 0 4); do
-    test_expect_success "query from $i" '
-      ipfsi "$i" dht query "$HASH" | head -1 >closest-$i
-    '
-  done
-
-  test_expect_success "collecting results" '
-    cat closest-* | sort | uniq -c | sed -e "s/ *\([0-9]\+\) .*/\1/g" | sort -g > actual &&
-    echo 1 > expected &&
-    echo 4 >> expected
-  '
-
-  test_expect_success "checking results" '
-    test_cmp actual expected
-  '
-
-  test_expect_success 'stop iptb' '
-    iptb stop
-  '
-
-  test_expect_success "dht commands fail when offline" '
-    test_must_fail ipfsi 0 dht findprovs "$HASH" 2>err_findprovs &&
-    test_must_fail ipfsi 0 dht findpeer "$HASH" 2>err_findpeer &&
-    test_must_fail ipfsi 0 dht put "/ipns/$PEERID_2" "get_result" 2>err_put &&
-    test_should_contain "this command must be run in online mode" err_findprovs &&
-    test_should_contain "this command must be run in online mode" err_findpeer &&
-    test_should_contain "this command must be run in online mode" err_put
-  '
-}
-
-test_dht
-test_dht --enable-pubsub-experiment --enable-namesys-pubsub
-
-test_done
diff --git a/test/sharness/t0170-routing-dht.sh b/test/sharness/t0170-routing-dht.sh
index 2ef0a9cd1e2bd066653bb4f99b75cb319171e04d..e6e9940f28ad17c42721591b0d001a81fde2a9b5 100755
--- a/test/sharness/t0170-routing-dht.sh
+++ b/test/sharness/t0170-routing-dht.sh
@@ -24,14 +24,14 @@ test_dht() {
     PEERID_0=$(iptb attr get 0 id) &&
     PEERID_2=$(iptb attr get 2 id)
   '
-  
+
   # ipfs routing findpeer <peerID>
   test_expect_success 'findpeer' '
     ipfsi 1 routing findpeer $PEERID_0 | sort >actual &&
     ipfsi 0 id -f "<addrs>" | cut -d / -f 1-5 | sort >expected &&
     test_cmp actual expected
   '
-  
+
   # ipfs routing get <key>
   test_expect_success 'get with good keys works' '
     HASH="$(echo "hello world" | ipfsi 2 add -q)" &&
@@ -48,7 +48,7 @@ test_dht() {
     [ -s putted ] ||
     test_fsh cat putted
   '
-  
+
   test_expect_success 'put with bad keys fails (issue #5113)' '
     ipfsi 0 routing put "foo" <<<bar >putted
     ipfsi 0 routing put "/pk/foo" <<<bar >>putted
@@ -56,31 +56,37 @@ test_dht() {
     [ ! -s putted ] ||
     test_fsh cat putted
   '
-  
+
   test_expect_success 'put with bad keys returns error (issue #4611)' '
     test_must_fail ipfsi 0 routing put "foo" <<<bar &&
     test_must_fail ipfsi 0 routing put "/pk/foo" <<<bar &&
     test_must_fail ipfsi 0 routing put "/ipns/foo" <<<bar
   '
-  
+
   test_expect_success 'get with bad keys (issue #4611)' '
     test_must_fail ipfsi 0 routing get "foo" &&
     test_must_fail ipfsi 0 routing get "/pk/foo"
   '
-  
+
   test_expect_success "add a ref so we can find providers for it" '
     echo "some stuff" > afile &&
     HASH=$(ipfsi 3 add -q afile)
   '
-  
+
   # ipfs routing findprovs <key>
   test_expect_success 'findprovs' '
     ipfsi 4 routing findprovs $HASH > provs &&
     iptb attr get 3 id > expected &&
     test_cmp provs expected
   '
-  
-  
+
+  # ipfs routing get --enc=json has correct properties
+  test_expect_success 'routing get --enc=json has correct properties' '
+    HASH="$(echo "hello world" | ipfsi 2 add -q)" &&
+    ipfsi 2 name publish "/ipfs/$HASH" &&
+    ipfsi 1 routing get --enc=json "/ipns/$PEERID_2" | jq -e "has(\"Extra\") and has(\"Type\")"
+  '
+
   # ipfs dht query <peerID>
   #
   # We test all nodes. 4 nodes should see the same peer ID, one node (the
@@ -112,7 +118,7 @@ test_dht() {
     test_must_fail ipfsi 0 routing put "/ipns/$PEERID_2" "get_result" 2>err_put &&
     test_should_contain "this command must be run in online mode" err_findprovs &&
     test_should_contain "this command must be run in online mode" err_findpeer &&
-    test_should_contain "this command must be run in online mode" err_put
+    test_should_contain "this action must be run in online mode" err_put
   '
 }
 
diff --git a/test/sharness/t0171-peering.sh b/test/sharness/t0171-peering.sh
deleted file mode 100755
index 207b279803a205f3a03f62797a62f952ca8b8a37..0000000000000000000000000000000000000000
--- a/test/sharness/t0171-peering.sh
+++ /dev/null
@@ -1,127 +0,0 @@
-#!/usr/bin/env bash
-
-test_description="Test peering service"
-
-. lib/test-lib.sh
-
-NUM_NODES=3
-
-test_expect_success 'init iptb' '
-  rm -rf .iptb/ &&
-  iptb testbed create -type localipfs -count $NUM_NODES -init
-'
-
-test_expect_success 'disabling routing' '
-  iptb run -- ipfs config Routing.Type none
-'
-
-for i in $(seq 0 2); do
-  ADDR="$(printf '["/ip4/127.0.0.1/tcp/%s"]' "$(( 3000 + ( RANDOM % 1000 ) ))")"
-  test_expect_success "configuring node $i to listen on $ADDR" '
-    ipfsi "$i" config --json Addresses.Swarm "$ADDR"
-  '
-done
-
-peer_id() {
-    ipfsi "$1" config Identity.PeerID
-}
-
-peer_addrs() {
-    ipfsi "$1" config Addresses.Swarm
-}
-
-peer() {
-  PEER1="$1" &&
-  PEER2="$2" &&
-  PEER_LIST="$(ipfsi "$PEER1" config Peering.Peers || true)" &&
-  { [[ "$PEER_LIST" == "null" ]] || PEER_LIST_INNER="${PEER_LIST:1:-1}"; } &&
-  ADDR_INFO="$(printf '[%s{"ID": "%s", "Addrs": %s}]' \
-             "${PEER_LIST_INNER:+${PEER_LIST_INNER},}" \
-             "$(peer_id "$PEER2")" \
-             "$(peer_addrs "$PEER2")")" &&
-  ipfsi "$PEER1" config --json Peering.Peers "${ADDR_INFO}"
-}
-
-# Peer:
-# - 0 <-> 1
-# - 1 -> 2
-test_expect_success 'configure peering' '
-  peer 0 1 &&
-  peer 1 0 &&
-  peer 1 2
-'
-
-list_peers() {
-    ipfsi "$1" swarm peers | sed 's|.*/p2p/\([^/]*\)$|\1|' | sort -u
-}
-
-check_peers() {
-  sleep 20 # give it some time to settle.
-  test_expect_success 'verifying peering for peer 0' '
-    list_peers 0 > peers_0_actual &&
-    peer_id 1 > peers_0_expected &&
-    test_cmp peers_0_expected peers_0_actual
-  '
-
-  test_expect_success 'verifying peering for peer 1' '
-    list_peers 1 > peers_1_actual &&
-    { peer_id 0 && peer_id 2 ; } | sort -u > peers_1_expected &&
-    test_cmp peers_1_expected peers_1_actual
-  '
-
-  test_expect_success 'verifying peering for peer 2' '
-    list_peers 2 > peers_2_actual &&
-    peer_id 1 > peers_2_expected &&
-    test_cmp peers_2_expected peers_2_actual
-  '
-}
-
-test_expect_success 'startup cluster' '
-  iptb start -wait &&
-  iptb run -- ipfs log level peering debug
-'
-
-check_peers
-
-disconnect() {
-    ipfsi "$1" swarm disconnect "/p2p/$(peer_id "$2")"
-}
-
-# Bidirectional peering shouldn't cause problems (e.g., simultaneous connect
-# issues).
-test_expect_success 'disconnecting 0->1' '
-  disconnect 0 1
-'
-
-check_peers
-
-# 1 should reconnect to 2 when 2 disconnects from 1.
-test_expect_success 'disconnecting 2->1' '
-  disconnect 2 1
-'
-
-check_peers
-
-# 2 isn't peering. This test ensures that 1 will re-peer with 2 when it comes
-# back online.
-test_expect_success 'stopping 2' '
-  iptb stop 2
-'
-
-# Wait to disconnect
-sleep 30
-
-test_expect_success 'starting 2' '
-  iptb start 2
-'
-
-# Wait for backoff
-sleep 30
-
-check_peers
-
-test_expect_success "stop testbed" '
-  iptb stop
-'
-
-test_done
diff --git a/test/sharness/t0400-api-no-gateway.sh b/test/sharness/t0400-api-no-gateway.sh
index 137f99a950ec412b7464850403ee06171a8d669c..d0daeece3da2fd544d832b4616a30a4c44d8ba2b 100755
--- a/test/sharness/t0400-api-no-gateway.sh
+++ b/test/sharness/t0400-api-no-gateway.sh
@@ -10,6 +10,13 @@ test_description="Test API security"
 
 test_init_ipfs
 
+# Import test case
+# See the static fixtures in ./t0400-api-no-gateway/
+test_expect_success "Add the test directory" '
+  ipfs dag import ../t0400-api-no-gateway/fixtures.car
+'
+HASH=QmNYERzV2LfD2kkfahtfv44ocHzEFK1sLBaE7zdcYT2GAZ # a file containing the string "testing"
+
 # by default, we don't let you load arbitrary ipfs objects through the api,
 # because this would open up the api to scripting vulnerabilities.
 # only the webui objects are allowed.
@@ -17,14 +24,12 @@ test_init_ipfs
 
 test_launch_ipfs_daemon
 test_expect_success "Gateway on API unavailable" '
-  HASH=$(echo "testing" | ipfs add -q)
   test_curl_resp_http_code "http://127.0.0.1:$API_PORT/ipfs/$HASH" "HTTP/1.1 404 Not Found"
 '
 test_kill_ipfs_daemon
 
 test_launch_ipfs_daemon --unrestricted-api
 test_expect_success "Gateway on --unrestricted-api API available" '
-  HASH=$(echo "testing" | ipfs add -q)
   test_curl_resp_http_code "http://127.0.0.1:$API_PORT/ipfs/$HASH" "HTTP/1.1 200 OK"
 '
 test_kill_ipfs_daemon
diff --git a/test/sharness/t0400-api-no-gateway/README.md b/test/sharness/t0400-api-no-gateway/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..32222d41b842c020c5c1fe97ac88e9cc7415d4c6
--- /dev/null
+++ b/test/sharness/t0400-api-no-gateway/README.md
@@ -0,0 +1,16 @@
+# Dataset description/sources
+
+- fixtures.car
+  - raw CARv1
+
+generated with:
+
+```sh
+# using ipfs version 0.18.1
+HASH=$(echo "testing" | ipfs add -q)
+ipfs dag export $HASH > fixtures.car
+
+echo HASH=${HASH} # a file containing the string "testing"
+
+# HASH=QmNYERzV2LfD2kkfahtfv44ocHzEFK1sLBaE7zdcYT2GAZ # a file containing the string "testing"
+```
diff --git a/test/sharness/t0400-api-no-gateway/fixtures.car b/test/sharness/t0400-api-no-gateway/fixtures.car
new file mode 100644
index 0000000000000000000000000000000000000000..1e090db6dc1e7d3a07c8523de752e61dc744bd1f
Binary files /dev/null and b/test/sharness/t0400-api-no-gateway/fixtures.car differ
diff --git a/testplans/bitswap/go.mod b/testplans/bitswap/go.mod
index 3ae17384cb4e0084acec59fed814b7e3f35ceb81..79925df147c3c908ddacf5c337795fdb102d0793 100644
--- a/testplans/bitswap/go.mod
+++ b/testplans/bitswap/go.mod
@@ -2,17 +2,16 @@ module github.com/ipfs/go-ipfs/testplans/bitswap
 
 require (
 	github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
-	github.com/ipfs/go-bitswap v0.10.1
-	github.com/ipfs/go-block-format v0.0.3
-	github.com/ipfs/go-cid v0.2.0
-	github.com/ipfs/go-datastore v0.5.1
+	github.com/ipfs/go-cid v0.3.2
+	github.com/ipfs/go-datastore v0.6.0
 	github.com/ipfs/go-ipfs-blockstore v1.2.0
 	github.com/ipfs/go-ipfs-exchange-interface v0.2.0
 	github.com/ipfs/go-ipfs-regression v0.0.1
+	github.com/ipfs/go-libipfs v0.4.0
 	github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db // indirect
-	github.com/libp2p/go-libp2p v0.22.0
+	github.com/libp2p/go-libp2p v0.23.4
 	github.com/libp2p/go-libp2p-kad-dht v0.18.0
-	github.com/multiformats/go-multiaddr v0.6.0
+	github.com/multiformats/go-multiaddr v0.8.0
 	github.com/multiformats/go-multihash v0.2.1
 	github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
 	github.com/smartystreets/assertions v1.0.1 // indirect
diff --git a/testplans/bitswap/go.sum b/testplans/bitswap/go.sum
index c71296c05b1a340d5829181394889c532d722f0d..5cb07e8c0b4b0589b592ad1968869d093d911a7a 100644
--- a/testplans/bitswap/go.sum
+++ b/testplans/bitswap/go.sum
@@ -61,8 +61,6 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
 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/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
-github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
-github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
 github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
 github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
 github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y=
@@ -70,7 +68,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJ
 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
 github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc=
 github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
-github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
 github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
 github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
 github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
@@ -87,7 +84,6 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
 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/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
 github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
 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=
@@ -106,11 +102,14 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
 github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d h1:t5Wuyh53qYyg9eqn4BbnlIT+vmhyww0TatL+zT3uWgI=
 github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
-github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/go-systemd/v22 v22.4.0 h1:y9YHcjnjynCd/DVbg5j9L/33jQM3MxJlbj/zWskzfGU=
+github.com/coreos/go-systemd/v22 v22.4.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0=
 github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis=
 github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -130,8 +129,9 @@ github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlN
 github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE=
 github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
 github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
 github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
@@ -262,6 +262,7 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
 github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f h1:KMlcu9X58lhTA/KrfX8Bi1LQSO4pzoVjTiL3h4Jk+Zk=
 github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
@@ -289,26 +290,27 @@ github.com/influxdata/influxdb1-client v0.0.0-20200515024757-02f0bf5dbca3 h1:k3/
 github.com/influxdata/influxdb1-client v0.0.0-20200515024757-02f0bf5dbca3/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/go-bitswap v0.10.1 h1:XaMmwMR8NgxpzB2hVtZsVLPJPTn2pfAA66GN8gZJTl8=
-github.com/ipfs/go-bitswap v0.10.1/go.mod h1:+fZEvycxviZ7c+5KlKwTzLm0M28g2ukCPqiuLfJk4KA=
 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
-github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc=
 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
+github.com/ipfs/go-block-format v0.1.1 h1:129vSO3zwbsYADcyQWcOYiuCpAqt462SFfqFHdFJhhI=
+github.com/ipfs/go-block-format v0.1.1/go.mod h1:+McEIT+g52p+zz5xGAABGSOKrzmrdX97bc0USBdWPUs=
 github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
 github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
 github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
 github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=
 github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog=
 github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
-github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0=
 github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
+github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
+github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
 github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
 github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
 github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
 github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
 github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
-github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ=
 github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
+github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
+github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
 github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
 github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
@@ -324,7 +326,6 @@ github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtL
 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
 github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
 github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
-github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs=
 github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q=
 github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU=
 github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y=
@@ -333,15 +334,19 @@ github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY
 github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
 github.com/ipfs/go-ipfs-regression v0.0.1 h1:LX3lrYYgiCE9QmL/qlc4Mh0cewdOHRl5pArbeQRllsU=
 github.com/ipfs/go-ipfs-regression v0.0.1/go.mod h1:I9yKzBjbirC5D0ND0DBkiQ5PPSQ2R2YjhcqHPj8L28A=
-github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY=
-github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM=
+github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9OWevc=
+github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo=
 github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
 github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8=
 github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ=
 github.com/ipfs/go-ipld-format v0.3.0 h1:Mwm2oRLzIuUwEPewWAWyMuuBQUsn3awfFEYVb8akMOQ=
 github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM=
-github.com/ipfs/go-ipns v0.2.0 h1:BgmNtQhqOw5XEZ8RAfWEpK4DhqaYiuP6h71MhIp7xXU=
 github.com/ipfs/go-ipns v0.2.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
+github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
+github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
+github.com/ipfs/go-libipfs v0.3.0/go.mod h1:pSUHZ5qPJTAidsxe9bAeHp3KIiw2ODEW2a2kM3v+iXI=
+github.com/ipfs/go-libipfs v0.4.0 h1:TkUxJGjtPnSzAgkw7VjS0/DBay3MPjmTBa4dGdUQCDE=
+github.com/ipfs/go-libipfs v0.4.0/go.mod h1:XsU2cP9jBhDrXoJDe0WxikB8XcVmD3k2MEZvB3dbYu8=
 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
 github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A=
 github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs=
@@ -355,8 +360,8 @@ github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
 github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
 github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
 github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
-github.com/ipfs/go-peertaskqueue v0.7.0 h1:VyO6G4sbzX80K58N60cCaHsSsypbUNs1GjO5seGNsQ0=
-github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
+github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU=
+github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM=
 github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8=
 github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db h1:kFwGn8rXa/Z31ev1OFNQsYeNKNCdifnTPl/NvPy5L38=
 github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8=
@@ -390,12 +395,14 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
 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/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
-github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A=
 github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo=
+github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0=
 github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0=
+github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
 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/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
@@ -408,8 +415,9 @@ github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.3/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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
 github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
 github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
@@ -421,13 +429,12 @@ github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS
 github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
 github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
 github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
-github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw=
 github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4=
+github.com/libp2p/go-libp2p v0.23.4 h1:hWi9XHSOVFR1oDWRk7rigfyA4XNMuYL20INNybP9LP8=
+github.com/libp2p/go-libp2p v0.23.4/go.mod h1:s9DEa5NLR4g+LZS+md5uGU4emjMWFiqkZr6hBTY8UxI=
 github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
 github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw=
 github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI=
-github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=
-github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco=
 github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
 github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
 github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
@@ -446,12 +453,10 @@ github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVd
 github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s=
 github.com/libp2p/go-libp2p-peerstore v0.8.0 h1:bzTG693TA1Ju/zKmUCQzDLSqiJnyRFVwPpuloZ/OZtI=
 github.com/libp2p/go-libp2p-peerstore v0.8.0/go.mod h1:9geHWmNA3YDlQBjL/uPEJD6vpDK12aDNlUNHJ6kio/s=
-github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q=
 github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=
 github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
 github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
 github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
-github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
 github.com/libp2p/go-libp2p-testing v0.11.0/go.mod h1:qG4sF27dfKFoK9KlVzK2y52LQKhp0VEmLjV5aDqr1Hg=
 github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
 github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
@@ -475,19 +480,20 @@ github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6
 github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560=
 github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k=
 github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
-github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q=
 github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4=
+github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ=
+github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
 github.com/libp2p/zeroconf/v2 v2.2.0/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
-github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU=
 github.com/lucas-clemente/quic-go v0.28.1/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0=
+github.com/lucas-clemente/quic-go v0.29.1 h1:Z+WMJ++qMLhvpFkRZA+jl3BTxUjm415YBmWanXB8zP0=
+github.com/lucas-clemente/quic-go v0.29.1/go.mod h1:CTcNfLYJS2UuRNB+zcNlgvkjBhxX6Hm3WUxxAQx2mgE=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/marten-seemann/qpack v0.2.1 h1:jvTsT/HpCn2UZJdP+UUB53FfUUgeOyG5K1ns0OJOGVs=
 github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc=
-github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ=
 github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
-github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ=
 github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s=
 github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM=
 github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
@@ -496,6 +502,8 @@ github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK
 github.com/marten-seemann/qtls-go1-19 v0.1.0/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
+github.com/marten-seemann/webtransport-go v0.1.1 h1:TnyKp3pEXcDooTaNn4s9dYpMJ7kMnTp7k5h+SgYP/mc=
+github.com/marten-seemann/webtransport-go v0.1.1/go.mod h1:kBEh5+RSvOA4troP1vyOVBWK4MIMzDICXVrvCPrYcrM=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
@@ -521,7 +529,6 @@ github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdn
 github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
 github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
-github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
 github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
 github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
 github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
@@ -534,18 +541,16 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
-github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
 github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
 github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
 github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
 github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
 github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
-github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE=
 github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM=
+github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
+github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
 github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
 github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
-github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
-github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
 github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
 github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
 github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
@@ -554,8 +559,10 @@ github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u
 github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
 github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=
 github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM=
-github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg=
 github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM=
+github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs=
+github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU=
+github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs=
 github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
 github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
 github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
@@ -568,10 +575,10 @@ github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPw
 github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI=
 github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
 github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
-github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
 github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues=
+github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE=
+github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
 github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
-github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
 github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
 github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
@@ -591,6 +598,7 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
 github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
 github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
 github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
@@ -634,8 +642,9 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
-github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
 github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
+github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ=
 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=
@@ -663,6 +672,7 @@ github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqn
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
 github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
@@ -700,7 +710,6 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
 github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
-github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
 github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU=
 github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -716,6 +725,7 @@ github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 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=
@@ -723,12 +733,14 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
 github.com/testground/sdk-go v0.2.7 h1:SDLDukPZIaZOeG2gQjCNsh5EB3QL3mOhOM4p0BMpqlc=
 github.com/testground/sdk-go v0.2.7/go.mod h1:Q4dnWsUBH+dZ1u7aEGDBHWGUaLfhitjUq3UJQqxeTmk=
+github.com/thoas/go-funk v0.9.1/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
 github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
@@ -746,6 +758,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -781,8 +794,9 @@ go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
 go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
 go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
 go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
-go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0=
 go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U=
+go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY=
+go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY=
 go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
 golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
 golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -790,12 +804,9 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/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-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -820,6 +831,10 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
+golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
+golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b h1:SCE/18RnFsLrjydh/R/s5EVvHoZprqEQUuoxK8q2Pc4=
+golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -844,6 +859,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
 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.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -892,14 +910,16 @@ golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
 golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 h1:KafLifaRFIuSJ5C+7CyFJOF9haxKNC1CEIDk8GX6X0k=
+golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -986,6 +1006,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1066,6 +1087,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
+golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
 golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1166,6 +1189,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
diff --git a/testplans/bitswap/main.go b/testplans/bitswap/main.go
index 95eb47f031ec5592063a4f1976981cfae600d15b..aa98d4f31aed9c611cc25f059d0fe2ed2165e061 100644
--- a/testplans/bitswap/main.go
+++ b/testplans/bitswap/main.go
@@ -12,9 +12,9 @@ import (
 	"github.com/testground/sdk-go/runtime"
 	"github.com/testground/sdk-go/sync"
 
-	bitswap "github.com/ipfs/go-bitswap"
-	bsnet "github.com/ipfs/go-bitswap/network"
-	block "github.com/ipfs/go-block-format"
+	bitswap "github.com/ipfs/go-libipfs/bitswap"
+	bsnet "github.com/ipfs/go-libipfs/bitswap/network"
+	block "github.com/ipfs/go-libipfs/blocks"
 	"github.com/ipfs/go-cid"
 	datastore "github.com/ipfs/go-datastore"
 	blockstore "github.com/ipfs/go-ipfs-blockstore"
diff --git a/thirdparty/verifbs/verifbs.go b/thirdparty/verifbs/verifbs.go
index 7be5348a82cc3d9c4682a5421dfb574c96e2ba39..ca2f5d839500a579920a1a35a995e9ed51f15fd7 100644
--- a/thirdparty/verifbs/verifbs.go
+++ b/thirdparty/verifbs/verifbs.go
@@ -3,9 +3,9 @@ package verifbs
 import (
 	"context"
 
-	blocks "github.com/ipfs/go-block-format"
 	cid "github.com/ipfs/go-cid"
 	bstore "github.com/ipfs/go-ipfs-blockstore"
+	blocks "github.com/ipfs/go-libipfs/blocks"
 	"github.com/ipfs/go-verifcid"
 )
 
diff --git a/version.go b/version.go
index b03eff4a97773de5f5ae6abbf026917836613d58..18bbf9a2d33e3c9ebbe9e336baf2e44b9ec40976 100644
--- a/version.go
+++ b/version.go
@@ -11,7 +11,7 @@ import (
 var CurrentCommit string
 
 // CurrentVersionNumber is the current application's version literal
-const CurrentVersionNumber = "0.18.1"
+const CurrentVersionNumber = "0.19.0"
 
 const ApiVersion = "/kubo/" + CurrentVersionNumber + "/" //nolint