diff --git a/.bingo/.gitignore b/.bingo/.gitignore
new file mode 100644
index 000000000..9efccf683
--- /dev/null
+++ b/.bingo/.gitignore
@@ -0,0 +1,13 @@
+
+# Ignore everything
+*
+
+# But not these files:
+!.gitignore
+!*.mod
+!*.sum
+!README.md
+!Variables.mk
+!variables.env
+
+*tmp.mod
diff --git a/.bingo/README.md b/.bingo/README.md
new file mode 100644
index 000000000..7a5c2d4f6
--- /dev/null
+++ b/.bingo/README.md
@@ -0,0 +1,14 @@
+# Project Development Dependencies.
+
+This is directory which stores Go modules with pinned buildable package that is used within this repository, managed by https://github.com/bwplotka/bingo.
+
+* Run `bingo get` to install all tools having each own module file in this directory.
+* Run `bingo get <tool>` to install <tool> that have own module file in this directory.
+* For Makefile: Make sure to put `include .bingo/Variables.mk` in your Makefile, then use $(<upper case tool name>) variable where <tool> is the .bingo/<tool>.mod.
+* For shell: Run `source .bingo/variables.env` to source all environment variable for each tool.
+* For go: Import `.bingo/variables.go` to for variable names.
+* See https://github.com/bwplotka/bingo or -h on how to add, remove or change binaries dependencies.
+
+## Requirements
+
+* Go 1.14+
diff --git a/.bingo/Variables.mk b/.bingo/Variables.mk
new file mode 100644
index 000000000..a4753b600
--- /dev/null
+++ b/.bingo/Variables.mk
@@ -0,0 +1,49 @@
+# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.9. DO NOT EDIT.
+# All tools are designed to be build inside $GOBIN.
+BINGO_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+GOPATH ?= $(shell go env GOPATH)
+GOBIN  ?= $(firstword $(subst :, ,${GOPATH}))/bin
+GO     ?= $(shell which go)
+
+# Below generated variables ensure that every time a tool under each variable is invoked, the correct version
+# will be used; reinstalling only if needed.
+# For example for bingo variable:
+#
+# In your main Makefile (for non array binaries):
+#
+#include .bingo/Variables.mk # Assuming -dir was set to .bingo .
+#
+#command: $(BINGO)
+#	@echo "Running bingo"
+#	@$(BINGO) <flags/args..>
+#
+BINGO := $(GOBIN)/bingo-v0.9.0
+$(BINGO): $(BINGO_DIR)/bingo.mod
+	@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
+	@echo "(re)installing $(GOBIN)/bingo-v0.9.0"
+	@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=bingo.mod -o=$(GOBIN)/bingo-v0.9.0 "github.com/bwplotka/bingo"
+
+GINKGO := $(GOBIN)/ginkgo-v2.22.2
+$(GINKGO): $(BINGO_DIR)/ginkgo.mod
+	@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
+	@echo "(re)installing $(GOBIN)/ginkgo-v2.22.2"
+	@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=ginkgo.mod -o=$(GOBIN)/ginkgo-v2.22.2 "github.com/onsi/ginkgo/v2/ginkgo"
+
+GOLANGCI_LINT := $(GOBIN)/golangci-lint-v1.63.4
+$(GOLANGCI_LINT): $(BINGO_DIR)/golangci-lint.mod
+	@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
+	@echo "(re)installing $(GOBIN)/golangci-lint-v1.63.4"
+	@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=golangci-lint.mod -o=$(GOBIN)/golangci-lint-v1.63.4 "github.com/golangci/golangci-lint/cmd/golangci-lint"
+
+GORELEASER := $(GOBIN)/goreleaser-v1.26.2
+$(GORELEASER): $(BINGO_DIR)/goreleaser.mod
+	@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
+	@echo "(re)installing $(GOBIN)/goreleaser-v1.26.2"
+	@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=goreleaser.mod -o=$(GOBIN)/goreleaser-v1.26.2 "github.com/goreleaser/goreleaser"
+
+PROTOC_GEN_GO_GRPC := $(GOBIN)/protoc-gen-go-grpc-v1.3.0
+$(PROTOC_GEN_GO_GRPC): $(BINGO_DIR)/protoc-gen-go-grpc.mod
+	@# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies.
+	@echo "(re)installing $(GOBIN)/protoc-gen-go-grpc-v1.3.0"
+	@cd $(BINGO_DIR) && GOWORK=off $(GO) build -mod=mod -modfile=protoc-gen-go-grpc.mod -o=$(GOBIN)/protoc-gen-go-grpc-v1.3.0 "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
+
diff --git a/.bingo/bingo.mod b/.bingo/bingo.mod
new file mode 100644
index 000000000..e7fa8545f
--- /dev/null
+++ b/.bingo/bingo.mod
@@ -0,0 +1,5 @@
+module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
+
+go 1.22.2
+
+require github.com/bwplotka/bingo v0.9.0
diff --git a/.bingo/bingo.sum b/.bingo/bingo.sum
new file mode 100644
index 000000000..f231dd11b
--- /dev/null
+++ b/.bingo/bingo.sum
@@ -0,0 +1,29 @@
+github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
+github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/bwplotka/bingo v0.9.0 h1:slnsdJYExR4iRalHR6/ZiYnr9vSazOuFGmc2LdX293g=
+github.com/bwplotka/bingo v0.9.0/go.mod h1:GxC/y/xbmOK5P29cn+B3HuOSw0s2gruddT3r+rDizDw=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/efficientgo/core v1.0.0-rc.0 h1:jJoA0N+C4/knWYVZ6GrdHOtDyrg8Y/TR4vFpTaqTsqs=
+github.com/efficientgo/core v1.0.0-rc.0/go.mod h1:kQa0V74HNYMfuJH6jiPiwNdpWXl4xd/K4tzlrcvYDQI=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
+github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
+github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
+golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg=
+mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8=
diff --git a/.bingo/ginkgo.mod b/.bingo/ginkgo.mod
new file mode 100644
index 000000000..c1e0852df
--- /dev/null
+++ b/.bingo/ginkgo.mod
@@ -0,0 +1,5 @@
+module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
+
+go 1.22.2
+
+require github.com/onsi/ginkgo/v2 v2.22.2 // ginkgo
diff --git a/.bingo/ginkgo.sum b/.bingo/ginkgo.sum
new file mode 100644
index 000000000..e2123cdc6
--- /dev/null
+++ b/.bingo/ginkgo.sum
@@ -0,0 +1,106 @@
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+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-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA=
+github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.1.3 h1:e/3Cwtogj0HA+25nMP1jCMDIf8RtRYbGwGGuBIFztkc=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
+github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
+github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
+github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
+golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+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=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/.bingo/go.mod b/.bingo/go.mod
new file mode 100644
index 000000000..610249af0
--- /dev/null
+++ b/.bingo/go.mod
@@ -0,0 +1 @@
+module _ // Fake go.mod auto-created by 'bingo' for go -moddir compatibility with non-Go projects. Commit this file, together with other .mod files.
\ No newline at end of file
diff --git a/.bingo/golangci-lint.mod b/.bingo/golangci-lint.mod
new file mode 100644
index 000000000..8104ff4ba
--- /dev/null
+++ b/.bingo/golangci-lint.mod
@@ -0,0 +1,5 @@
+module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
+
+go 1.22.5
+
+require github.com/golangci/golangci-lint v1.63.4 // cmd/golangci-lint
diff --git a/.bingo/golangci-lint.sum b/.bingo/golangci-lint.sum
new file mode 100644
index 000000000..bcc2ba2df
--- /dev/null
+++ b/.bingo/golangci-lint.sum
@@ -0,0 +1,1071 @@
+4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA=
+4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs=
+4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc=
+4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8=
+github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0=
+github.com/4meepo/tagalign v1.4.1 h1:GYTu2FaPGOGb/xJalcqHeD4il5BiCywyEYZOA55P6J4=
+github.com/4meepo/tagalign v1.4.1/go.mod h1:2H9Yu6sZ67hmuraFgfZkNcg5Py9Ch/Om9l2K/2W1qS4=
+github.com/Abirdcfly/dupword v0.1.1 h1:Bsxe0fIw6OwBtXMIncaTxCLHYO5BB+3mcsR5E8VXloY=
+github.com/Abirdcfly/dupword v0.1.1/go.mod h1:B49AcJdTYYkpd4HjgAcutNGG9HZ2JWwKunH9Y2BA6sM=
+github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE=
+github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw=
+github.com/Antonboom/errname v0.1.13 h1:JHICqsewj/fNckzrfVSe+T33svwQxmjC+1ntDsHOVvM=
+github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns=
+github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA=
+github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
+github.com/Antonboom/nilnil v0.1.9 h1:eKFMejSxPSA9eLSensFmjW2XTgTwJMjZ8hUHtV4s/SQ=
+github.com/Antonboom/nilnil v0.1.9/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ=
+github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs=
+github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0=
+github.com/Antonboom/testifylint v1.4.3 h1:ohMt6AHuHgttaQ1xb6SSnxCeK4/rnK7KKzbvs7DmEck=
+github.com/Antonboom/testifylint v1.4.3/go.mod h1:+8Q9+AOLsz5ZiQiiYujJKs9mNz398+M6UgslP4qgJLA=
+github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk=
+github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
+github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/Crocmagnon/fatcontext v0.5.2 h1:vhSEg8Gqng8awhPju2w7MKHqMlg4/NI+gSDHtR3xgwA=
+github.com/Crocmagnon/fatcontext v0.5.2/go.mod h1:87XhRMaInHP44Q7Tlc7jkgKKB7kZAOPiDkFMdKCC+74=
+github.com/Crocmagnon/fatcontext v0.5.3 h1:zCh/wjc9oyeF+Gmp+V60wetm8ph2tlsxocgg/J0hOps=
+github.com/Crocmagnon/fatcontext v0.5.3/go.mod h1:XoCQYY1J+XTfyv74qLXvNw4xFunr3L1wkopIIKG7wGM=
+github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
+github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
+github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 h1:/fTUt5vmbkAcMBt4YQiuC23cV0kEsN1MVMNqeOW43cU=
+github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0/go.mod h1:ONJg5sxcbsdQQ4pOW8TGdTidT2TMAUy/2Xhr8mrYaao=
+github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
+github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA=
+github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ=
+github.com/alecthomas/go-check-sumtype v0.1.4 h1:WCvlB3l5Vq5dZQTFmodqL2g68uHiSwwlWcT5a2FGK0c=
+github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
+github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU=
+github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alexkohler/nakedret/v2 v2.0.4 h1:yZuKmjqGi0pSmjGpOC016LtPJysIL0WEUiaXW5SUnNg=
+github.com/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU=
+github.com/alexkohler/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU=
+github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU=
+github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
+github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
+github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
+github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
+github.com/alingse/nilnesserr v0.1.1 h1:7cYuJewpy9jFNMEA72Q1+3Nm3zKHzg+Q28D5f2bBFUA=
+github.com/alingse/nilnesserr v0.1.1/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg=
+github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
+github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
+github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
+github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
+github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU=
+github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY=
+github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM=
+github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w=
+github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo=
+github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
+github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
+github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw=
+github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo=
+github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A=
+github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc=
+github.com/breml/bidichk v0.2.7 h1:dAkKQPLl/Qrk7hnP6P+E0xOodrq8Us7+U0o4UBOAlQY=
+github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ=
+github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs=
+github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos=
+github.com/breml/errchkjson v0.3.6 h1:VLhVkqSBH96AvXEyclMR37rZslRrY2kcyq+31HCsVrA=
+github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U=
+github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk=
+github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8=
+github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0=
+github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA=
+github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY=
+github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M=
+github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs=
+github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ=
+github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc=
+github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI=
+github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc=
+github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
+github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
+github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
+github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
+github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
+github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/ckaznocha/intrange v0.2.0 h1:FykcZuJ8BD7oX93YbO1UY9oZtkRbp+1/kJcDjkefYLs=
+github.com/ckaznocha/intrange v0.2.0/go.mod h1:r5I7nUlAAG56xmkOpw4XVr16BXhwYTUdcuRFeevn1oE=
+github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY=
+github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
+github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
+github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=
+github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=
+github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
+github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
+github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
+github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
+github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
+github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
+github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
+github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
+github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
+github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
+github.com/firefart/nonamedreturns v1.0.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA=
+github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw=
+github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
+github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
+github.com/ghostiam/protogetter v0.3.6 h1:R7qEWaSgFCsy20yYHNIJsU9ZOb8TziSRRxuAOTVKeOk=
+github.com/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw=
+github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY=
+github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
+github.com/go-critic/go-critic v0.11.4 h1:O7kGOCx0NDIni4czrkRIXTnit0mkyKOCePh3My6OyEU=
+github.com/go-critic/go-critic v0.11.4/go.mod h1:2QAdo4iuLik5S9YG0rT4wcZ8QxwHYkrr6/2MWAiv/vc=
+github.com/go-critic/go-critic v0.11.5 h1:TkDTOn5v7EEngMxu8KbuFqFR43USaaH8XRJLz1jhVYA=
+github.com/go-critic/go-critic v0.11.5/go.mod h1:wu6U7ny9PiaHaZHcvMDmdysMqvDem162Rh3zWTrqk8M=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
+github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=
+github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s=
+github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw=
+github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
+github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ=
+github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw=
+github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY=
+github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco=
+github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4=
+github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA=
+github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA=
+github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
+github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw=
+github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
+github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
+github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
+github.com/go-viper/mapstructure/v2 v2.1.0 h1:gHnMa2Y/pIxElCH2GlZZ1lZSsn6XMtufpGyP1XxdC/w=
+github.com/go-viper/mapstructure/v2 v2.1.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
+github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
+github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
+github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
+github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY=
+github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
+github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
+github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
+github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU=
+github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s=
+github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME=
+github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE=
+github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9 h1:t5wybL6RtO83VwoMOb7U/Peqe3gGKQlPIC66wXmnkvM=
+github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9/go.mod h1:Ag3L7sh7E28qAp/5xnpMMTuGYqxLZoSaEHZDkZB1RgU=
+github.com/golangci/golangci-lint v1.61.0 h1:VvbOLaRVWmyxCnUIMTbf1kDsaJbTzH20FAMXTAlQGu8=
+github.com/golangci/golangci-lint v1.61.0/go.mod h1:e4lztIrJJgLPhWvFPDkhiMwEFRrWlmFbrZea3FsJyN8=
+github.com/golangci/golangci-lint v1.63.4 h1:bJQFQ3hSfUto597dkL7ipDzOxsGEpiWdLiZ359OWOBI=
+github.com/golangci/golangci-lint v1.63.4/go.mod h1:Hx0B7Lg5/NXbaOHem8+KU+ZUIzMI6zNj/7tFwdnn10I=
+github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
+github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
+github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA=
+github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM=
+github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
+github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc=
+github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs=
+github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=
+github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs=
+github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s=
+github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
+github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
+github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=
+github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
+github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q=
+github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=
+github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70=
+github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak=
+github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
+github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
+github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
+github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo=
+github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw=
+github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
+github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
+github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk=
+github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
+github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
+github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
+github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48=
+github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
+github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk=
+github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
+github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc=
+github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk=
+github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
+github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
+github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
+github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY=
+github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos=
+github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k=
+github.com/kisielk/errcheck v1.7.0 h1:+SbscKmWJ5mOK/bO1zS60F5I9WwZDWOfRsC4RwfwRV0=
+github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
+github.com/kisielk/errcheck v1.8.0 h1:ZX/URYa7ilESY19ik/vBmCn6zdGQLxACwjAcWbHlYlg=
+github.com/kisielk/errcheck v1.8.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kkHAIKE/contextcheck v1.1.5 h1:CdnJh63tcDe53vG+RebdpdXJTc9atMgGqdx8LXxiilg=
+github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs=
+github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I=
+github.com/kunwardeep/paralleltest v1.0.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs=
+github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY=
+github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ=
+github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA=
+github.com/lasiar/canonicalheader v1.1.1 h1:wC+dY9ZfiqiPwAexUApFush/csSPXeIi4QqyxXmng8I=
+github.com/lasiar/canonicalheader v1.1.1/go.mod h1:cXkb3Dlk6XXy+8MVQnF23CYKWlyA7kfQhSw2CcZtZb0=
+github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4=
+github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI=
+github.com/ldez/exptostd v0.3.1 h1:90yWWoAKMFHeovTK8uzBms9Ppp8Du/xQ20DRO26Ymrw=
+github.com/ldez/exptostd v0.3.1/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ=
+github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg=
+github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g=
+github.com/ldez/gomoddirectives v0.6.0 h1:Jyf1ZdTeiIB4dd+2n4qw+g4aI9IJ6JyfOZ8BityWvnA=
+github.com/ldez/gomoddirectives v0.6.0/go.mod h1:TuwOGYoPAoENDWQpe8DMqEm5nIfjrxZXmxX/CExWyZ4=
+github.com/ldez/grignotin v0.7.0 h1:vh0dI32WhHaq6LLPZ38g7WxXuZ1+RzyrJ7iPG9JMa8c=
+github.com/ldez/grignotin v0.7.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk=
+github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo=
+github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4=
+github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk=
+github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I=
+github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA=
+github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ=
+github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
+github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
+github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM=
+github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM=
+github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
+github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
+github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
+github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI=
+github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
+github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
+github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
+github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 h1:gWg6ZQ4JhDfJPqlo2srm/LN17lpybq15AryXIRcWYLE=
+github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
+github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
+github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
+github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M=
+github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
+github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U=
+github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=
+github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg=
+github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
+github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
+github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
+github.com/nunnatsa/ginkgolinter v0.16.2 h1:8iLqHIZvN4fTLDC0Ke9tbSZVcyVHoBs0HIbnVSxfHJk=
+github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ=
+github.com/nunnatsa/ginkgolinter v0.18.4 h1:zmX4KUR+6fk/vhUFt8DOP6KwznekhkmVSzzVJve2vyM=
+github.com/nunnatsa/ginkgolinter v0.18.4/go.mod h1:AMEane4QQ6JwFz5GgjI5xLUM9S/CylO+UyM97fN2iBI=
+github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
+github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
+github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
+github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
+github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
+github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
+github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
+github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
+github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/polyfloyd/go-errorlint v1.6.0 h1:tftWV9DE7txiFzPpztTAwyoRLKNj9gpVm2cg8/OwcYY=
+github.com/polyfloyd/go-errorlint v1.6.0/go.mod h1:HR7u8wuP1kb1NeN1zqTd1ZMlqUKPPHF+Id4vIPvDqVw=
+github.com/polyfloyd/go-errorlint v1.7.0 h1:Zp6lzCK4hpBDj8y8a237YK4EPrMXQWvOe3nGoH4pFrU=
+github.com/polyfloyd/go-errorlint v1.7.0/go.mod h1:dGWKu85mGHnegQ2SWpEybFityCg3j7ZbwsVUxAOk9gY=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
+github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
+github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
+github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
+github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
+github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
+github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo=
+github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI=
+github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE=
+github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
+github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo=
+github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=
+github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU=
+github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
+github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
+github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
+github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI=
+github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
+github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
+github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
+github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
+github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
+github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
+github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=
+github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4=
+github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
+github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
+github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
+github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
+github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI=
+github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
+github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ=
+github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
+github.com/securego/gosec/v2 v2.21.2 h1:deZp5zmYf3TWwU7A7cR2+SolbTpZ3HQiwFqnzQyEl3M=
+github.com/securego/gosec/v2 v2.21.2/go.mod h1:au33kg78rNseF5PwPnTWhuYBFf534bvJRvOrgZ/bFzU=
+github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk=
+github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA=
+github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
+github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
+github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
+github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=
+github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
+github.com/sivchari/tenv v1.10.0 h1:g/hzMA+dBCKqGXgW8AV/1xIWhAvDrx0zFKNR48NFMg0=
+github.com/sivchari/tenv v1.10.0/go.mod h1:tdY24masnVoZFxYrHv/nD6Tc8FbkEtAQEEziXpyMgqY=
+github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY=
+github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw=
+github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00=
+github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo=
+github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM=
+github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c=
+github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
+github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
+github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
+github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
+github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
+github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
+github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
+github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc=
+github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I=
+github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4=
+github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk=
+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/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
+github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
+github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg=
+github.com/tdakkota/asciicheck v0.3.0 h1:LqDGgZdholxZMaJgpM6b0U9CFIjDCbFdUF00bDnBKOQ=
+github.com/tdakkota/asciicheck v0.3.0/go.mod h1:KoJKXuX/Z/lt6XzLo8WMBfQGzak0SrAKZlvRr4tg8Ac=
+github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
+github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
+github.com/tetafro/godot v1.4.17 h1:pGzu+Ye7ZUEFx7LHU0dAKmCOXWsPjl7qA6iMGndsjPs=
+github.com/tetafro/godot v1.4.17/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
+github.com/tetafro/godot v1.4.20 h1:z/p8Ek55UdNvzt4TFn2zx2KscpW4rWqcnUrdmvWJj7E=
+github.com/tetafro/godot v1.4.20/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
+github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M=
+github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
+github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg=
+github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
+github.com/timonwong/loggercheck v0.9.4 h1:HKKhqrjcVj8sxL7K77beXh0adEm6DLjV/QOGeMXEVi4=
+github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg=
+github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg=
+github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
+github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4=
+github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
+github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg=
+github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
+github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
+github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
+github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI=
+github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4=
+github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI=
+github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA=
+github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ=
+github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
+github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g=
+github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
+github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM=
+github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U=
+github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA=
+github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
+github.com/uudashr/iface v1.3.0 h1:zwPch0fs9tdh9BmL5kcgSpvnObV+yHjO4JjVBl8IA10=
+github.com/uudashr/iface v1.3.0/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
+github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
+github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
+github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
+github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
+github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs=
+github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4=
+github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw=
+github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo=
+gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8=
+go-simpler.org/musttag v0.12.2 h1:J7lRc2ysXOq7eM8rwaTYnNrHd5JwjppzB6mScysB2Cs=
+go-simpler.org/musttag v0.12.2/go.mod h1:uN1DVIasMTQKk6XSik7yrJoEysGtR2GRqvWnI9S7TYM=
+go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE=
+go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM=
+go-simpler.org/sloglint v0.7.2 h1:Wc9Em/Zeuu7JYpl+oKoYOsQSy2X560aVueCW/m6IijY=
+go-simpler.org/sloglint v0.7.2/go.mod h1:US+9C80ppl7VsThQclkM7BkCHQAzuz8kHLsW3ppuluo=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
+go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
+go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
+go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
+go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
+go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
+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=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+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-20240904232852-e7e105dedf7e h1:I88y4caeGeuDQxgdoFPUq097j7kNfw6uvuiNxUBfcBk=
+golang.org/x/exp v0.0.0-20240904232852-e7e105dedf7e/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
+golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8=
+golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f h1:WTyX8eCCyfdqiPYkRGm0MqElSfYFH3yR1+rl/mct9sA=
+golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
+golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
+golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
+golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
+golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
+golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
+golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
+golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
+golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
+golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
+golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/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=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
+google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I=
+honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs=
+mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
+mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
+mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
+mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/.bingo/goreleaser.mod b/.bingo/goreleaser.mod
new file mode 100644
index 000000000..f9b0b721b
--- /dev/null
+++ b/.bingo/goreleaser.mod
@@ -0,0 +1,5 @@
+module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
+
+go 1.22.2
+
+require github.com/goreleaser/goreleaser v1.26.2
diff --git a/.bingo/goreleaser.sum b/.bingo/goreleaser.sum
new file mode 100644
index 000000000..0034e5452
--- /dev/null
+++ b/.bingo/goreleaser.sum
@@ -0,0 +1,1769 @@
+bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
+cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
+cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
+cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
+cloud.google.com/go v0.82.0/go.mod h1:vlKccHJGuFBFufnAnuB08dfEH9Y3H7dzDzRECFdC2TA=
+cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
+cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
+cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
+cloud.google.com/go v0.88.0/go.mod h1:dnKwfYbP9hQhefiUvpbcAyoGSHUrOxR20JVElLiUvEY=
+cloud.google.com/go v0.89.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
+cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
+cloud.google.com/go v0.92.2/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
+cloud.google.com/go v0.92.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
+cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
+cloud.google.com/go v0.94.0 h1:QDB2MZHqjTt0hGKnoEWyG/iWykue/lvkLdogLgrg10U=
+cloud.google.com/go v0.94.0/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
+cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
+cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
+cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/firestore v1.5.0/go.mod h1:c4nNYR1qdq7eaZ+jSc5fonrQN2k3M7sWATcYTiakjEo=
+cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc=
+cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
+cloud.google.com/go/kms v0.1.0 h1:VXAb5OzejDcyhFzIDeZ5n5AUdlsFnCyexuascIwWMj0=
+cloud.google.com/go/kms v0.1.0/go.mod h1:8Qp8PCAypHg4FdmlyW1QRAv09BGQ9Uzh7JnmIZxPk+c=
+cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs=
+cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs=
+cloud.google.com/go/monitoring v0.1.0/go.mod h1:Hpm3XfzJv+UTiXzCG5Ffp0wijzHTC7Cv4eR7o3x/fEE=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/pubsub v1.16.0/go.mod h1:6A8EfoWZ/lUvCWStKGwAWauJZSiuV0Mkmu6WilK/TxQ=
+cloud.google.com/go/secretmanager v0.1.0/go.mod h1:3nGKHvnzDUVit7U0S9KAKJ4aOsO1xtwRG+7ey5LK1bM=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.16.1 h1:sMEIc4wxvoY3NXG7Rn9iP7jb/2buJgWR1vNXCR/UPfs=
+cloud.google.com/go/storage v1.16.1/go.mod h1:LaNorbty3ehnU3rEjXSNV/NRgQA0O8Y+uh6bPe5UOk4=
+cloud.google.com/go/storage v1.39.1 h1:MvraqHKhogCOTXTlct/9C3K3+Uy2jBmFYb3/Sp6dVtY=
+cloud.google.com/go/storage v1.39.1/go.mod h1:xK6xZmxZmo+fyP7+DEF6FhNc24/JAe95OLyOHCXFH1o=
+cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g=
+code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
+code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M=
+code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA=
+code.gitea.io/sdk/gitea v0.18.0 h1:+zZrwVmujIrgobt6wVBWCqITz6bn1aBjnCUHmpZrerI=
+code.gitea.io/sdk/gitea v0.18.0/go.mod h1:IG9xZJoltDNeDSW0qiF2Vqx5orMWa7OhVWrjvrd5NpI=
+contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ=
+contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
+dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
+dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
+github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
+github.com/Azure/azure-amqp-common-go/v3 v3.1.0/go.mod h1:PBIGdzcO1teYoufTKMcGibdKaYZv4avS+O6LNIp8bq0=
+github.com/Azure/azure-amqp-common-go/v3 v3.1.1/go.mod h1:YsDaPfaO9Ub2XeSKdIy2DfwuiQlHQCauHJwSqtrkECI=
+github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
+github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
+github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v57.0.0+incompatible h1:isVki3PbIFrwKvKdVP1byxo73/pt+Nn174YxW1k4PNw=
+github.com/Azure/azure-sdk-for-go v57.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
+github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
+github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM=
+github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE=
+github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw=
+github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1 h1:fXPMAmuh0gDuRDey0atC8cXBuKIlqCzCkL8sm1n9Ov0=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.1/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4=
+github.com/Azure/azure-service-bus-go v0.10.16/go.mod h1:MlkLwGGf1ewcx5jZadn0gUEty+tTg0RaElr6bPf+QhI=
+github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM=
+github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck=
+github.com/Azure/go-amqp v0.13.0/go.mod h1:qj+o8xPCz9tMSbQ83Vp8boHahuRDl5mkNHyt1xlxUTs=
+github.com/Azure/go-amqp v0.13.11/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk=
+github.com/Azure/go-amqp v0.13.12/go.mod h1:D5ZrjQqB1dyp1A+G73xeL/kNn7D5qHJIIsNNps7YNmk=
+github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.11.3/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
+github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
+github.com/Azure/go-autorest/autorest v0.11.20 h1:s8H1PbCZSqg/DH7JMlOz6YMig6htWLNPsjDdlLqCx3M=
+github.com/Azure/go-autorest/autorest v0.11.20/go.mod h1:o3tqFY+QR40VOlk+pV4d77mORO64jOXSgEnPQgLK6JY=
+github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
+github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
+github.com/Azure/go-autorest/autorest v0.11.29/go.mod h1:ZtEzC4Jy2JDrZLxvWs8LrBWEBycl1hbT1eknI8MtfAs=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
+github.com/Azure/go-autorest/autorest/adal v0.9.11/go.mod h1:nBKAnTomx8gDtl+3ZCJv2v0KACFHWTB2drffI1B68Pk=
+github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
+github.com/Azure/go-autorest/autorest/adal v0.9.15 h1:X+p2GF0GWyOiSmqohIaEeuNFNDY4I4EOlVuUQvFdWMk=
+github.com/Azure/go-autorest/autorest/adal v0.9.15/go.mod h1:tGMin8I49Yij6AQ+rvV+Xa/zwxYQB5hmsd6DkfAx2+A=
+github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
+github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk=
+github.com/Azure/go-autorest/autorest/adal v0.9.23 h1:Yepx8CvFxwNKpH6ja7RZ+sKX+DWYNldbLiALMC3BTz8=
+github.com/Azure/go-autorest/autorest/adal v0.9.23/go.mod h1:5pcMqFkdPhviJdlEy3kC/v1ZLnQl0MH6XA5YCcMhy4c=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.8 h1:TzPg6B6fTZ0G1zBf3T54aI7p3cAT6u//TOXGPmFMOXg=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.8/go.mod h1:kxyKZTSfKh8OVFWPAgOgQ/frrJgeYQJPyR5fLFmXko4=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 h1:wkAZRgT/pn8HhFyzfe9UnqOjJYqlembgCTi72Bm/xKk=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.12/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.3 h1:DOhB+nXkF7LN0JfBGB5YtCF6QLK8mLe4psaHF7ZQEKM=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.3/go.mod h1:yAQ2b6eP/CmLPnmLvxtT1ALIY3OR1oFcCqVBi8vHiTc=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0=
+github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
+github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
+github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
+github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac=
+github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
+github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/DisgoOrg/disgohook v1.4.4 h1:6xU+nRtyCYX7RyKvRnroJE8JMv+YIrQEMBDGUjBGDlQ=
+github.com/DisgoOrg/disgohook v1.4.4/go.mod h1:l7r9dZgfkA3KiV+ErxqweKaknnskmzZO+SRTNHvJTUU=
+github.com/DisgoOrg/log v1.1.0 h1:a6hLfVSDuTFJc5AKQ8FDYQ5TASnwk3tciUyXThm1CR4=
+github.com/DisgoOrg/log v1.1.0/go.mod h1:Qihgz6fax3JCfuO7vxVavL0LyHS0sUdQ9OmykQ2fiQs=
+github.com/DisgoOrg/restclient v1.2.8 h1:0Kv2g2bNYUvAAeIpJ1oNHorRcj5z6qkO2kOlm4R7cAs=
+github.com/DisgoOrg/restclient v1.2.8/go.mod h1:2pc/htya/5kjxvWNYya98sb8B4mexobxmWvhTiWPt94=
+github.com/GoogleCloudPlatform/cloudsql-proxy v1.24.0/go.mod h1:3tx938GhY4FC+E1KT/jNjDw7Z5qxAEtIiERJ2sXjnII=
+github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
+github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
+github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
+github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
+github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
+github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
+github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
+github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
+github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
+github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
+github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c h1:bNpaLLv2Y4kslsdkdCwAYu8Bak1aGVtxwi8Z/wy4Yuo=
+github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
+github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
+github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
+github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
+github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
+github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
+github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1 h1:6mZ7MG/flSahicBVy4GKlWI+dzoR5rgnm7H8e17TAio=
+github.com/alecthomas/jsonschema v0.0.0-20211209230136-e2b41affa5c1/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
+github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
+github.com/anchore/bubbly v0.0.0-20230518153401-87b6af8ccf22 h1:5NFK6VGgqBUOAX2SYyzFYvNdOiYDxzim8jga386FlZY=
+github.com/anchore/bubbly v0.0.0-20230518153401-87b6af8ccf22/go.mod h1:Kv+Mm9CdtnV8iem48iEPIwy7/N4Wmk0hpxYNH5gTwKQ=
+github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw=
+github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg=
+github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
+github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb/go.mod h1:DmTY2Mfcv38hsHbG78xMiTDdxFtkHpgYNVDPsF2TgHk=
+github.com/anchore/quill v0.4.1 h1:mffDnvnER3ZgPjN5hexc3nr/4Y1dtKdDB6td5K8uInk=
+github.com/anchore/quill v0.4.1/go.mod h1:t6hOPYDohN8wn2SRWQdNkJBkhmK8s3gzuHzzgcEvzQU=
+github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
+github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
+github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
+github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
+github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/atc0005/go-teams-notify/v2 v2.6.1 h1:t22ybzQuaQs4UJe4ceF5VYGsPhs6ir3nZOId/FBy6Go=
+github.com/atc0005/go-teams-notify/v2 v2.6.1/go.mod h1:xo6GejLDHn3tWBA181F8LrllIL0xC1uRsRxq7YNXaaY=
+github.com/atc0005/go-teams-notify/v2 v2.10.0 h1:eQvRIkyESQgBvlUdQ/iPol/lj3QcRyrdEQM3+c/nXhM=
+github.com/atc0005/go-teams-notify/v2 v2.10.0/go.mod h1:SIeE1UfCcVRYMqP5b+r1ZteHyA/2UAjzWF5COnZ8q0w=
+github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+github.com/aws/aws-sdk-go v1.40.34 h1:SBYmodndE2d4AYucuuJnOXk4MD1SFbucoIdpwKVKeSA=
+github.com/aws/aws-sdk-go v1.40.34/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
+github.com/aws/aws-sdk-go v1.53.0 h1:MMo1x1ggPPxDfHMXJnQudTbGXYlD4UigUAud1DJxPVo=
+github.com/aws/aws-sdk-go v1.53.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
+github.com/aws/aws-sdk-go-v2 v1.9.0 h1:+S+dSqQCN3MSU5vJRu1HqHrq00cJn6heIMU7X9hcsoo=
+github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
+github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA=
+github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1 h1:gTK2uhtAPtFcdRRJilZPx8uJLL2J85xK11nKtWL0wfU=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.1/go.mod h1:sxpLb+nZk7tIfCWChfd+h4QwHNUR57d8hA1cleTkjJo=
+github.com/aws/aws-sdk-go-v2/config v1.7.0 h1:J2cZ7qe+3IpqBEXnHUrFrOjoB9BlsXg7j53vxcl5IVg=
+github.com/aws/aws-sdk-go-v2/config v1.7.0/go.mod h1:w9+nMZ7soXCe5nT46Ri354SNhXDQ6v+V5wqDjnZE+GY=
+github.com/aws/aws-sdk-go-v2/config v1.27.13 h1:WbKW8hOzrWoOA/+35S5okqO/2Ap8hkkFUzoW8Hzq24A=
+github.com/aws/aws-sdk-go-v2/config v1.27.13/go.mod h1:XLiyiTMnguytjRER7u5RIkhIqS8Nyz41SwAWb4xEjxs=
+github.com/aws/aws-sdk-go-v2/credentials v1.4.0 h1:kmvesfjY861FzlCU9mvAfe01D9aeXcG2ZuC+k9F2YLM=
+github.com/aws/aws-sdk-go-v2/credentials v1.4.0/go.mod h1:dgGR+Qq7Wjcd4AOAW5Rf5Tnv3+x7ed6kETXyS9WCuAY=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.13 h1:XDCJDzk/u5cN7Aple7D/MiAhx1Rjo/0nueJ0La8mRuE=
+github.com/aws/aws-sdk-go-v2/credentials v1.17.13/go.mod h1:FMNcjQrmuBYvOTZDtOLCIu0esmxjF7RuA/89iSXWzQI=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0 h1:OxTAgH8Y4BXHD6PGCJ8DHx2kaZPCQfSTqmDsdRZFezE=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0/go.mod h1:CpNzHK9VEFUCknu50kkB8z58AH2B5DvPP7ea1LHve/Y=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9 h1:vXY/Hq1XdxHBIYgBUmug/AbMyIe1AKulPYS2/VE1X70=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.16.9/go.mod h1:GyJJTZoHVuENM4TeJEl5Ffs4W9m19u+4wKJcDi/GZ4A=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2 h1:d95cddM3yTm4qffj3P6EnP+TzX1SSkWaQypXSgT/hpA=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2/go.mod h1:BQV0agm+JEhqR+2RT5e1XTFIDcAAV0eW6z2trp+iduw=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3 h1:mDnFOE2sVkyphMWtTH+stv0eW3k0OTx94K63xpxHty4=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.3/go.mod h1:V8MuRVcCRt5h1S+Fwu8KbC7l/gBGo3yBAyUbJM2IJOk=
+github.com/aws/aws-sdk-go-v2/service/ecr v1.28.0 h1:rdPrcOZmqT2F+yzmKEImrx5XUs7Hpf4V9Rp6E8mhsxQ=
+github.com/aws/aws-sdk-go-v2/service/ecr v1.28.0/go.mod h1:if7ybzzjOmDB8pat9FE35AHTY6ZxlYSy3YviSmFZv8c=
+github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.5 h1:452e/nFuqPvwPg+1OD2CG/v29R9MH8egJSJKh2Qduv8=
+github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.5/go.mod h1:8pvvNAklmq+hKmqyvFoMRg0bwg9sdGOvdwximmKiKP0=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5 h1:mbWNpfRUTT6bnacmvOTKXZjR/HycibdWzNpfbrbLDIs=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.5/go.mod h1:FCOPWGjsshkkICJIn9hq9xr6dLKtyaWpuUojiN3W1/8=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0 h1:VNJ5NLBteVXEwE2F1zEXVmyIH58mZ6kIQGJoC7C+vkg=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0/go.mod h1:R1KK+vY8AfalhG1AOu5e35pOD2SdoPKQCFLTvnxiohk=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3 h1:4t+QEX7BsXz98W8W1lNvMAG+NX8qHz2CjLBxQKku40g=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.3/go.mod h1:oFcjjUq5Hm09N9rpxTdeMeLeQcxS7mIkBkL8qUKng+A=
+github.com/aws/aws-sdk-go-v2/service/kms v1.5.0 h1:10e9mzaaYIIePEuxUzW5YJ8LKHNG/NX63evcvS3ux9U=
+github.com/aws/aws-sdk-go-v2/service/kms v1.5.0/go.mod h1:w7JuP9Oq1IKMFQPkNe3V6s9rOssXzOVEMNEqK1L1bao=
+github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU=
+github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4 h1:lW5xUzOPGAMY7HPuNF4FdyBwRc3UJ/e8KsapbesVeNU=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.51.4/go.mod h1:MGTaf3x/+z7ZGugCGvepnx2DS6+caCYYqKhzVoLNYPk=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.6.0/go.mod h1:B+7C5UKdVq1ylkI/A6O8wcurFtaux0R1njePNPtKwoA=
+github.com/aws/aws-sdk-go-v2/service/ssm v1.10.0/go.mod h1:4dXS5YNqI3SNbetQ7X7vfsMlX6ZnboJA2dulBwJx7+g=
+github.com/aws/aws-sdk-go-v2/service/sso v1.4.0 h1:sHXMIKYS6YiLPzmKSvDpPmOpJDHxmAUgbiF49YNVztg=
+github.com/aws/aws-sdk-go-v2/service/sso v1.4.0/go.mod h1:+1fpWnL96DL23aXPpMGbsmKe8jLTEfbjuQoA4WS1VaA=
+github.com/aws/aws-sdk-go-v2/service/sso v1.20.6 h1:o5cTaeunSpfXiLTIBx5xo2enQmiChtu1IBbzXnfU9Hs=
+github.com/aws/aws-sdk-go-v2/service/sso v1.20.6/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.0 h1:Qe0r0lVURDDeBQJ4yP+BOrJkvkiCo/3FH/t+wY11dmw=
+github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.0/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak=
+github.com/aws/aws-sdk-go-v2/service/sts v1.7.0 h1:1at4e5P+lvHNl2nUktdM2/v+rpICg/QSEr9TO/uW9vU=
+github.com/aws/aws-sdk-go-v2/service/sts v1.7.0/go.mod h1:0qcSMCyASQPN2sk/1KQLQ2Fh6yq8wm0HSDAimPhzCoM=
+github.com/aws/aws-sdk-go-v2/service/sts v1.28.7 h1:et3Ta53gotFR4ERLXXHIHl/Uuk1qYpP5uU7cvNql8ns=
+github.com/aws/aws-sdk-go-v2/service/sts v1.28.7/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw=
+github.com/aws/smithy-go v1.8.0 h1:AEwwwXQZtUwP5Mz506FeXXrKBe0jA8gVM+1gEcSRooc=
+github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
+github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
+github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
+github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240514230400-03fa26f5508f h1:Z0kS9pJDQgCg3u2lH6+CdYaFbyQtyukVTiUCG6re0E4=
+github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240514230400-03fa26f5508f/go.mod h1:rAE739ssmE5O5fLuQ2y8uHdmOJaelE5I0Es3SxV0y1A=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
+github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blacktop/go-dwarf v1.0.9 h1:eT/L7gt0gllvvgnRXY0MFKjNB6+jtOY5DTm2ynVX2dY=
+github.com/blacktop/go-dwarf v1.0.9/go.mod h1:4W2FKgSFYcZLDwnR7k+apv5i3nrau4NGl9N6VQ9DSTo=
+github.com/blacktop/go-macho v1.1.162 h1:FjM3XAsJTAOGZ1eppRSX9ZBX3Bk11JMTC1amsZAOA5I=
+github.com/blacktop/go-macho v1.1.162/go.mod h1:f2X4noFBob4G5bWUrzvPBKDVcFWZgDCM7rIn7ygTID0=
+github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
+github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
+github.com/bluesky-social/indigo v0.0.0-20240411170459-440932307e0d h1:xxPhzCOpmOntzVe8S6tqsMdFgaB8B4NXSV54lG4B1qk=
+github.com/bluesky-social/indigo v0.0.0-20240411170459-440932307e0d/go.mod h1:ysMQ0a4RYWjgyvKrl5ME352oHA6QgK900g5sB9XXgPE=
+github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
+github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw=
+github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw=
+github.com/caarlos0/ctrlc v1.2.0 h1:AtbThhmbeYx1WW3WXdWrd94EHKi+0NPRGS4/4pzrjwk=
+github.com/caarlos0/ctrlc v1.2.0/go.mod h1:n3gDlSjsXZ7rbD9/RprIR040b7oaLfNStikPd4gFago=
+github.com/caarlos0/env/v11 v11.0.1 h1:A8dDt9Ub9ybqRSUF3fQc/TA/gTam2bKT4Pit+cwrsPs=
+github.com/caarlos0/env/v11 v11.0.1/go.mod h1:2RC3HQu8BQqtEK3V4iHPxj0jOdWdbPpWJ6pOueeU1xM=
+github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k=
+github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
+github.com/caarlos0/go-reddit/v3 v3.0.1 h1:w8ugvsrHhaE/m4ez0BO/sTBOBWI9WZTjG7VTecHnql4=
+github.com/caarlos0/go-reddit/v3 v3.0.1/go.mod h1:QlwgmG5SAqxMeQvg/A2dD1x9cIZCO56BMnMdjXLoisI=
+github.com/caarlos0/go-shellwords v1.0.12 h1:HWrUnu6lGbWfrDcFiHcZiwOLzHWjjrPVehULaTFgPp8=
+github.com/caarlos0/go-shellwords v1.0.12/go.mod h1:bYeeX1GrTLPl5cAMYEzdm272qdsQAZiaHgeF0KTk1Gw=
+github.com/caarlos0/go-version v0.1.1 h1:1bikKHkGGVIIxqCmufhSSs3hpBScgHGacrvsi8FuIfc=
+github.com/caarlos0/go-version v0.1.1/go.mod h1:Ze5Qx4TsBBi5FyrSKVg1Ibc44KGV/llAaKGp86oTwZ0=
+github.com/caarlos0/log v0.4.4 h1:LnvgBz/ofsJ00AupP/cEfksJSZglb1L69g4Obk/sdAc=
+github.com/caarlos0/log v0.4.4/go.mod h1:+AmCI9Liv5LKXmzFmFI1htuHdTTj/0R3KuoP9DMY7Mo=
+github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk=
+github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc=
+github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8=
+github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM=
+github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc=
+github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
+github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
+github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
+github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/charmbracelet/bubbletea v0.22.1 h1:z66q0LWdJNOWEH9zadiAIXp2GN1AWrwNXU8obVY9X24=
+github.com/charmbracelet/bubbletea v0.22.1/go.mod h1:8/7hVvbPN6ZZPkczLiB8YpLkLJ0n7DMho5Wvfd2X1C0=
+github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
+github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
+github.com/charmbracelet/x/exp/ordered v0.0.0-20231010190216-1cb11efc897d h1:+o+e/8hf7cG0SbAzEAm/usJ8qoZPgFXhudLjop+TM0g=
+github.com/charmbracelet/x/exp/ordered v0.0.0-20231010190216-1cb11efc897d/go.mod h1:aoG4bThKYIOnyB55r202eHqo6TkN7ZXV+cu4Do3eoBQ=
+github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4=
+github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
+github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
+github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
+github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
+github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
+github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k=
+github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM=
+github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
+github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
+github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
+github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
+github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
+github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb h1:7ENzkH+O3juL+yj2undESLTaAeRllHwCs/b8z6aWSfc=
+github.com/dghubble/go-twitter v0.0.0-20211115160449-93a8679adecb/go.mod h1:qhZBgV9e4WyB1JNjHpcXVkUe3knWUwYuAPB1hITdm50=
+github.com/dghubble/oauth1 v0.7.1 h1:JjbOVSVVkms9A4h/sTQy5Jb2nFuAAVb2qVYgenJPyrE=
+github.com/dghubble/oauth1 v0.7.1/go.mod h1:0eEzON0UY/OLACQrmnjgJjmvCGXzjBCsZqL1kWDXtF0=
+github.com/dghubble/oauth1 v0.7.3 h1:EkEM/zMDMp3zOsX2DC/ZQ2vnEX3ELK0/l9kb+vs4ptE=
+github.com/dghubble/oauth1 v0.7.3/go.mod h1:oxTe+az9NSMIucDPDCCtzJGsPhciJV33xocHfcR2sVY=
+github.com/dghubble/sling v1.4.0 h1:/n8MRosVTthvMbwlNZgLx579OGVjUOy3GNEv5BIqAWY=
+github.com/dghubble/sling v1.4.0/go.mod h1:0r40aNsU9EdDUVBNhfCstAtFgutjgJGYbO1oNzkMoM8=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
+github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
+github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
+github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
+github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/cli v25.0.4+incompatible h1:DatRkJ+nrFoYL2HZUzjM5Z5sAmcA5XGp+AW0oEw2+cA=
+github.com/docker/cli v25.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
+github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
+github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
+github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+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.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/elliotchance/orderedmap/v2 v2.2.0 h1:7/2iwO98kYT4XkOjA9mBEIwvi4KpGB4cyHeOFOnj4Vk=
+github.com/elliotchance/orderedmap/v2 v2.2.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q=
+github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
+github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
+github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
+github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
+github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
+github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
+github.com/github/smimesign v0.2.0 h1:Hho4YcX5N1I9XNqhq0fNx0Sts8MhLonHd+HRXVGNjvk=
+github.com/github/smimesign v0.2.0/go.mod h1:iZiiwNT4HbtGRVqCQu7uJPEZCuEE5sfSSttcnePkDl4=
+github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
+github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
+github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
+github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
+github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
+github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
+github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
+github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
+github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
+github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs=
+github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
+github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
+github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
+github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
+github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
+github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
+github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
+github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE=
+github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
+github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco=
+github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs=
+github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ=
+github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc=
+github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
+github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
+github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c=
+github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4=
+github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
+github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58=
+github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
+github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc=
+github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU=
+github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
+github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 h1:wG8n/XJQ07TmjbITcGiUaOtXxdrINDz1b0J1w0SzqDc=
+github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2phvKXWBBdD3K0iGnDBGbzRpISP2zBl8=
+github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
+github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
+github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
+github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o=
+github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
+github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
+github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
+github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
+github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
+github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY=
+github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
+github.com/google/go-github/v43 v43.0.0 h1:y+GL7LIsAIF2NZlJ46ZoC/D1W1ivZasT0lnWHMYPZ+U=
+github.com/google/go-github/v43 v43.0.0/go.mod h1:ZkTvvmCXBvsfPpTHXnH/d2hP9Y0cTbvN9kr5xqyXOIc=
+github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4=
+github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4=
+github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
+github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk=
+github.com/google/go-replayers/httpreplay v1.0.0/go.mod h1:LJhKoTwS5Wy5Ld/peq8dFFG5OfJyHEz7ft+DsTUv25M=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/ko v0.15.4 h1:0blRbIdPmSy6v4LvedGxbI/8krdJYQgbSih3v6Y8V1c=
+github.com/google/ko v0.15.4/go.mod h1:ZkcmfV91Xt6ZzOBHc/cXXGYnqWdNWDVy/gHoUU9sjag=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e h1:6Jn9JtfCn20uycra92LxTkq5yfBKNSFlRJPBk8/Cxhg=
+github.com/google/rpmpack v0.0.0-20220314092521-38642b5e571e/go.mod h1:83rLnx5vhPyN/mDzBYJWtiPf+9xnSVQynTpqZWe7OnY=
+github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a h1:JJBdjSfqSy3mnDT0940ASQFghwcZ4y4cb6ttjAoXqwE=
+github.com/google/rpmpack v0.6.1-0.20240329070804-c2247cbb881a/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI=
+github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
+github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
+github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
+github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
+github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
+github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
+github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
+github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
+github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
+github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso=
+github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
+github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
+github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
+github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/goreleaser/chglog v0.1.2 h1:tdzAb/ILeMnphzI9zQ7Nkq+T8R9qyXli8GydD8plFRY=
+github.com/goreleaser/chglog v0.1.2/go.mod h1:tTZsFuSZK4epDXfjMkxzcGbrIOXprf0JFp47BjIr3B8=
+github.com/goreleaser/chglog v0.6.1 h1:NZKiX8l0FTQPRzBgKST7knvNZmZ04f7PEGkN2wInfhE=
+github.com/goreleaser/chglog v0.6.1/go.mod h1:Bnnfo07jMZkaAb0uRNASMZyOsX6ROW6X1qbXqN3guUo=
+github.com/goreleaser/fileglob v1.3.0 h1:/X6J7U8lbDpQtBvGcwwPS6OpzkNVlVEsFUVRx9+k+7I=
+github.com/goreleaser/fileglob v1.3.0/go.mod h1:Jx6BoXv3mbYkEzwm9THo7xbr5egkAraxkGorbJb4RxU=
+github.com/goreleaser/goreleaser v1.8.3 h1:4vP28LV1VOL+mtEVvejCkN6KD1OU++7YNCh9dojxcO0=
+github.com/goreleaser/goreleaser v1.8.3/go.mod h1:DpiLDZkJQ1bbKW0ipWPJApOp8T4naqqk9nxyldGRy4k=
+github.com/goreleaser/goreleaser v1.26.2 h1:1iY1HaXtRiMTrwy6KE1sNjkRjsjMi+9l0k6WUX8GpWw=
+github.com/goreleaser/goreleaser v1.26.2/go.mod h1:mHi6zr6fuuOh5eHdWWgyo/N8BWED5WEVtb/4GETc9jQ=
+github.com/goreleaser/nfpm/v2 v2.15.1 h1:OdscWscGNR4aBepj2S5p6JUHWFd3CJdTJlSq7UqMMTY=
+github.com/goreleaser/nfpm/v2 v2.15.1/go.mod h1:fpR40o+Wq6aeE5xoSZY3E23r06aLntuYIr2zBCJ1x1o=
+github.com/goreleaser/nfpm/v2 v2.37.1 h1:RUmeEt8OlEVeSzKRrO5Vl5qVWCtUwx4j9uivGuRo5fw=
+github.com/goreleaser/nfpm/v2 v2.37.1/go.mod h1:q8+sZXFqn106/eGw+9V+I8+izFxZ/sJjrhwmEUxXhUg=
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
+github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M=
+github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
+github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
+github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
+github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
+github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
+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=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
+github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
+github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
+github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
+github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
+github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
+github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
+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-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
+github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
+github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
+github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
+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-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ=
+github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
+github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw=
+github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo=
+github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0=
+github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs=
+github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs=
+github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk=
+github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U=
+github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg=
+github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
+github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
+github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
+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/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
+github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
+github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
+github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
+github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
+github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
+github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
+github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
+github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
+github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
+github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
+github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU=
+github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 h1:WGrKdjHtWC67RX96eTkYD2f53NDHhrq/7robWTAfk4s=
+github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491/go.mod h1:o158RFmdEbYyIZmXAbrvmJWesbyxlLKee6X64VPVuOc=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
+github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
+github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
+github.com/mattn/go-isatty v0.0.3/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.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
+github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
+github.com/mattn/go-mastodon v0.0.8 h1:UgKs4SmQ5JeawxMIPP7NQ9xncmOXA+5q6jYk4erR7vk=
+github.com/mattn/go-mastodon v0.0.8/go.mod h1:8YkqetHoAVEktRkK15qeiv/aaIMfJ/Gc89etisPZtHU=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
+github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/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/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
+github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 h1:kMlmsLSbjkikxQJ1IPwaM+7LJ9ltFu/fi8CRzvSnQmA=
+github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
+github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/muesli/coral v1.0.0 h1:odyqkoEg4aJAINOzvnjN4tUsdp+Zleccs7tRIAkkYzU=
+github.com/muesli/coral v1.0.0/go.mod h1:bf91M/dkp7iHQw73HOoR9PekdTJMTD6ihJgWoDitde8=
+github.com/muesli/mango v0.1.0 h1:DZQK45d2gGbql1arsYA4vfg4d7I9Hfx5rX/GCmzsAvI=
+github.com/muesli/mango v0.1.0/go.mod h1:5XFpbC8jY5UUv89YQciiXNlbi+iJgt29VDC5xbzrLL4=
+github.com/muesli/mango-cobra v1.2.0 h1:DQvjzAM0PMZr85Iv9LIMaYISpTOliMEg+uMFtNbYvWg=
+github.com/muesli/mango-cobra v1.2.0/go.mod h1:vMJL54QytZAJhCT13LPVDfkvCUJ5/4jNUKF/8NC2UjA=
+github.com/muesli/mango-coral v1.0.1 h1:W3nGbUC/q5vLscQ6GPzteHZrJI1Msjw5Hns82o0xRkI=
+github.com/muesli/mango-coral v1.0.1/go.mod h1:EPSlYH67AtcxQrxssNw6r/lMFxHTjuDoGfq9Uxxevhg=
+github.com/muesli/mango-pflag v0.1.0 h1:UADqbYgpUyRoBja3g6LUL+3LErjpsOwaC9ywvBWe7Sg=
+github.com/muesli/mango-pflag v0.1.0/go.mod h1:YEQomTxaCUp8PrbhFh10UfbhbQrM/xJ4i2PB8VTLLW0=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
+github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
+github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
+github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
+github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
+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.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
+github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
+github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
+github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
+github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
+github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
+github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
+github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
+github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
+github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pborman/getopt v0.0.0-20180811024354-2b5b3bfb099b/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
+github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
+github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
+github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
+github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
+github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
+github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
+github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
+github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
+github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e h1:7q6NSFZDeGfvvtIRwBrU/aegEYJYmvev0cHAwo17zZQ=
+github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e/go.mod h1:DkpGd78rljTxKAnTDPFqXSGxvETQnJyuSOQwsHycqfs=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbmfHkLguCE9laoZCUzEEpIZXA=
+github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
+github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
+github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sigstore/cosign/v2 v2.2.4 h1:iY4vtEacmu2hkNj1Fh+8EBqBwKs2DHM27/lbNWDFJro=
+github.com/sigstore/cosign/v2 v2.2.4/go.mod h1:JZlRD2uaEjVAvZ1XJ3QkkZJhTqSDVtLaet+C/TMR81Y=
+github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8=
+github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc=
+github.com/sigstore/sigstore v1.8.3 h1:G7LVXqL+ekgYtYdksBks9B38dPoIsbscjQJX/MGWkA4=
+github.com/sigstore/sigstore v1.8.3/go.mod h1:mqbTEariiGA94cn6G3xnDiV6BD8eSLdL/eA7bvJ0fVs=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
+github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/slack-go/slack v0.10.2 h1:KMN/h2sgUninHXvQI8PrR/PHBUuWp2NPvz2Kr66tki4=
+github.com/slack-go/slack v0.10.2/go.mod h1:5FLdBRv7VW/d9EBxx/eEktOptWygbA9K2QK/KW7ds1s=
+github.com/slack-go/slack v0.13.0 h1:7my/pR2ubZJ9912p9FtvALYpbt0cQPAqkRy2jaSI1PQ=
+github.com/slack-go/slack v0.13.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
+github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
+github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.4.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
+github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
+github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
+github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
+github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
+github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
+github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
+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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+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.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
+github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
+github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
+github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
+github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
+github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk=
+github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
+github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
+github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
+github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
+github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
+github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
+github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 h1:jIVmlAFIqV3d+DOxazTR9v+zgj8+VYuQBzPgBZvWBHA=
+github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651/go.mod h1:b26F2tHLqaoRQf8DywqzVaV1MQ9yvjb0OMcNl7Nxu20=
+github.com/wagoodman/go-progress v0.0.0-20220614130704-4b1c25a33c7c h1:gFwUKtkv6QzQsFdIjvPqd0Qdw42DHUEbbUdiUTI1uco=
+github.com/wagoodman/go-progress v0.0.0-20220614130704-4b1c25a33c7c/go.mod h1:jLXFoL31zFaHKAAyZUh+sxiTDFe1L1ZHrcK2T1itVKA=
+github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
+github.com/whyrusleeping/cbor-gen v0.1.1-0.20240311221002-68b9f235c302 h1:MhInbXe4SzcImAKktUvWBCWZgcw6MYf5NfumTj1BhAw=
+github.com/whyrusleeping/cbor-gen v0.1.1-0.20240311221002-68b9f235c302/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so=
+github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
+github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
+github.com/xanzy/go-gitlab v0.63.0 h1:a9fXpKWykUS6dowapFej/2Wjf4aOAEFC1q2ZIcz4IpI=
+github.com/xanzy/go-gitlab v0.63.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
+github.com/xanzy/go-gitlab v0.105.0 h1:3nyLq0ESez0crcaM19o5S//SvezOQguuIHZ3wgX64hM=
+github.com/xanzy/go-gitlab v0.105.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
+github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
+github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
+github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo=
+github.com/xanzy/ssh-agent v0.3.1/go.mod h1:QIE4lCeL7nkC25x+yA3LBIYfwCc1TFziCtG7cBAac6w=
+github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
+github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+gitlab.com/digitalxero/go-conventional-commit v1.0.7 h1:8/dO6WWG+98PMhlZowt/YjuiKhqhGlOCwlIV8SqqGh8=
+gitlab.com/digitalxero/go-conventional-commit v1.0.7/go.mod h1:05Xc2BFsSyC5tKhK0y+P3bs0AwUtNuTp+mTpbCU/DZ0=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
+go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
+go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
+go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
+go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
+go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
+go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
+go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
+go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
+go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
+go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
+go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
+go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
+go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
+go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
+go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
+go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+gocloud.dev v0.24.0 h1:cNtHD07zQQiv02OiwwDyVMuHmR7iQt2RLkzoAgz7wBs=
+gocloud.dev v0.24.0/go.mod h1:uA+als++iBX5ShuG4upQo/3Zoz49iIPlYUWHV5mM8w8=
+gocloud.dev v0.37.0 h1:XF1rN6R0qZI/9DYjN16Uy0durAmSlf58DHOcb28GPro=
+gocloud.dev v0.37.0/go.mod h1:7/O4kqdInCNsc6LqgmuFnS0GRew4XNNYWpA44yQnwco=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/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-20190325154230-a5d413f7728c/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-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
+golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+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=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+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-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8=
+golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
+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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
+golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210825183410-e898025ed96a/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 h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
+golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
+golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201109165425-215b40eba54c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210223095934-7937bea0104d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
+golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
+golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
+golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
+golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
+golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
+google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
+google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I=
+google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
+google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
+google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
+google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
+google.golang.org/api v0.52.0/go.mod h1:Him/adpjt0sxtkWViy0b6xyKW/SD71CwdJ7HqJo7SrU=
+google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
+google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.56.0 h1:08F9XVYTLOGeSQb3xI9C0gXMuQanhdGed0cWFhDozbI=
+google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
+google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk=
+google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
+google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210517163617-5e0236093d7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
+google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
+google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
+google.golang.org/genproto v0.0.0-20210721163202-f1cecdd8b78a/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
+google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
+google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210825212027-de86158e7fda/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8=
+google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s=
+google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U=
+google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 h1:oqta3O3AnlWbmIE3bFnWbu4bRxZjfbWCp0cKSuZh01E=
+google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
+google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
+google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
+gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
+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/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs=
+gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
+gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
+gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
+lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
+nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
+nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+sigs.k8s.io/kind v0.23.0 h1:8fyDGWbWTeCcCTwA04v4Nfr45KKxbSPH1WO9K+jVrBg=
+sigs.k8s.io/kind v0.23.0/go.mod h1:ZQ1iZuJLh3T+O8fzhdi3VWcFTzsdXtNv2ppsHc8JQ7s=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
+software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k=
+software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI=
diff --git a/.bingo/protoc-gen-go-grpc.mod b/.bingo/protoc-gen-go-grpc.mod
new file mode 100644
index 000000000..51b100833
--- /dev/null
+++ b/.bingo/protoc-gen-go-grpc.mod
@@ -0,0 +1,5 @@
+module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
+
+go 1.22.2
+
+require google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0
diff --git a/.bingo/protoc-gen-go-grpc.sum b/.bingo/protoc-gen-go-grpc.sum
new file mode 100644
index 000000000..1f112872e
--- /dev/null
+++ b/.bingo/protoc-gen-go-grpc.sum
@@ -0,0 +1,12 @@
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
+google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
diff --git a/.bingo/variables.env b/.bingo/variables.env
new file mode 100644
index 000000000..4f607b50d
--- /dev/null
+++ b/.bingo/variables.env
@@ -0,0 +1,20 @@
+# Auto generated binary variables helper managed by https://github.com/bwplotka/bingo v0.9. DO NOT EDIT.
+# All tools are designed to be build inside $GOBIN.
+# Those variables will work only until 'bingo get' was invoked, or if tools were installed via Makefile's Variables.mk.
+GOBIN=${GOBIN:=$(go env GOBIN)}
+
+if [ -z "$GOBIN" ]; then
+	GOBIN="$(go env GOPATH)/bin"
+fi
+
+
+BINGO="${GOBIN}/bingo-v0.9.0"
+
+GINKGO="${GOBIN}/ginkgo-v2.22.2"
+
+GOLANGCI_LINT="${GOBIN}/golangci-lint-v1.63.4"
+
+GORELEASER="${GOBIN}/goreleaser-v1.26.2"
+
+PROTOC_GEN_GO_GRPC="${GOBIN}/protoc-gen-go-grpc-v1.3.0"
+
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..025457d21
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,22 @@
+version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "daily"
+  - package-ecosystem: "gomod"
+    directory: "/"
+    schedule:
+      interval: "daily"
+    groups:
+      k8s-dependencies:
+        patterns:
+          - "k8s.io/*"
+          - "sigs.k8s.io/*"
+      golang-x-deps:
+        patterns:
+          - "golang.org/x/*"
+  - package-exosystem: "docker"
+    directory: "/"
+    schedule:
+      interval: "daily"
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index c6328b451..1bd35d01d 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -12,8 +12,8 @@ jobs:
   build:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-go@v2
+      - uses: actions/checkout@v4
+      - uses: actions/setup-go@v5
         with:
-          go-version: '~1.16'
+          go-version-file: "go.mod"
       - run: make build
diff --git a/.github/workflows/codecov.sh b/.github/workflows/codecov.sh
deleted file mode 100755
index 914a56277..000000000
--- a/.github/workflows/codecov.sh
+++ /dev/null
@@ -1,1884 +0,0 @@
-#!/usr/bin/env bash
-
-# Apache License Version 2.0, January 2004
-# https://github.com/codecov/codecov-bash/blob/master/LICENSE
-
-set -e +o pipefail
-
-VERSION="1.0.1"
-
-codecov_flags=( )
-url="https://codecov.io"
-env="$CODECOV_ENV"
-service=""
-token=""
-search_in=""
-# shellcheck disable=SC2153
-flags="$CODECOV_FLAGS"
-exit_with=0
-curlargs=""
-curlawsargs=""
-dump="0"
-clean="0"
-curl_s="-s"
-name="$CODECOV_NAME"
-include_cov=""
-exclude_cov=""
-ddp="$HOME/Library/Developer/Xcode/DerivedData"
-xp=""
-files=""
-save_to=""
-direct_file_upload=""
-cacert="$CODECOV_CA_BUNDLE"
-gcov_ignore="-not -path './bower_components/**' -not -path './node_modules/**' -not -path './vendor/**'"
-gcov_include=""
-
-ft_gcov="1"
-ft_coveragepy="1"
-ft_fix="1"
-ft_search="1"
-ft_s3="1"
-ft_network="1"
-ft_xcodellvm="1"
-ft_xcodeplist="0"
-ft_gcovout="1"
-ft_html="0"
-ft_yaml="0"
-
-_git_root=$(git rev-parse --show-toplevel 2>/dev/null || hg root 2>/dev/null || echo "$PWD")
-git_root="$_git_root"
-remote_addr=""
-if [ "$git_root" = "$PWD" ];
-then
-  git_root="."
-fi
-
-branch_o=""
-build_o=""
-commit_o=""
-pr_o=""
-prefix_o=""
-network_filter_o=""
-search_in_o=""
-slug_o=""
-tag_o=""
-url_o=""
-git_ls_files_recurse_submodules_o=""
-package="bash"
-
-commit="$VCS_COMMIT_ID"
-branch="$VCS_BRANCH_NAME"
-pr="$VCS_PULL_REQUEST"
-slug="$VCS_SLUG"
-tag="$VCS_TAG"
-build_url="$CI_BUILD_URL"
-build="$CI_BUILD_ID"
-job="$CI_JOB_ID"
-
-beta_xcode_partials=""
-
-proj_root="$git_root"
-gcov_exe="gcov"
-gcov_arg=""
-
-b="\033[0;36m"
-g="\033[0;32m"
-r="\033[0;31m"
-e="\033[0;90m"
-y="\033[0;33m"
-x="\033[0m"
-
-show_help() {
-cat << EOF
-
-                Codecov Bash $VERSION
-
-          Global report uploading tool for Codecov
-       Documentation at https://docs.codecov.io/docs
-    Contribute at https://github.com/codecov/codecov-bash
-
-
-    -h          Display this help and exit
-    -f FILE     Target file(s) to upload
-
-                 -f "path/to/file"     only upload this file
-                                       skips searching unless provided patterns below
-
-                 -f '!*.bar'           ignore all files at pattern *.bar
-                 -f '*.foo'            include all files at pattern *.foo
-                 Must use single quotes.
-                 This is non-exclusive, use -s "*.foo" to match specific paths.
-
-    -s DIR       Directory to search for coverage reports.
-                 Already searches project root and artifact folders.
-    -t TOKEN     Set the private repository token
-                 (option) set environment variable CODECOV_TOKEN=:uuid
-
-                 -t @/path/to/token_file
-                 -t uuid
-
-    -n NAME      Custom defined name of the upload. Visible in Codecov UI
-
-    -e ENV       Specify environment variables to be included with this build
-                 Also accepting environment variables: CODECOV_ENV=VAR,VAR2
-
-                 -e VAR,VAR2
-
-    -k prefix    Prefix filepaths to help resolve path fixing
-
-    -i prefix    Only include files in the network with a certain prefix. Useful for upload-specific path fixing
-
-    -X feature   Toggle functionalities
-
-                 -X gcov          Disable gcov
-                 -X coveragepy    Disable python coverage
-                 -X fix           Disable report fixing
-                 -X search        Disable searching for reports
-                 -X xcode         Disable xcode processing
-                 -X network       Disable uploading the file network
-                 -X gcovout       Disable gcov output
-                 -X html          Enable coverage for HTML files
-                 -X recursesubs   Enable recurse submodules in git projects when searching for source files
-                 -X yaml          Enable coverage for YAML files
-
-    -N           The commit SHA of the parent for which you are uploading coverage. If not present,
-                 the parent will be determined using the API of your repository provider.
-                 When using the repository provider's API, the parent is determined via finding
-                 the closest ancestor to the commit.
-
-    -R root dir  Used when not in git/hg project to identify project root directory
-    -F flag      Flag the upload to group coverage metrics
-
-                 -F unittests        This upload is only unittests
-                 -F integration      This upload is only integration tests
-                 -F ui,chrome        This upload is Chrome - UI tests
-
-    -c           Move discovered coverage reports to the trash
-    -z FILE      Upload specified file directly to Codecov and bypass all report generation.
-                 This is inteded to be used only with a pre-formatted Codecov report and is not
-                 expected to work under any other circumstances.
-    -Z           Exit with 1 if not successful. Default will Exit with 0
-
-    -- xcode --
-    -D           Custom Derived Data Path for Coverage.profdata and gcov processing
-                 Default '~/Library/Developer/Xcode/DerivedData'
-    -J           Specify packages to build coverage. Uploader will only build these packages.
-                 This can significantly reduces time to build coverage reports.
-
-                 -J 'MyAppName'      Will match "MyAppName" and "MyAppNameTests"
-                 -J '^ExampleApp$'   Will match only "ExampleApp" not "ExampleAppTests"
-
-    -- gcov --
-    -g GLOB      Paths to ignore during gcov gathering
-    -G GLOB      Paths to include during gcov gathering
-    -p dir       Project root directory
-                 Also used when preparing gcov
-    -x gcovexe   gcov executable to run. Defaults to 'gcov'
-    -a gcovargs  extra arguments to pass to gcov
-
-    -- Override CI Environment Variables --
-       These variables are automatically detected by popular CI providers
-
-    -B branch    Specify the branch name
-    -C sha       Specify the commit sha
-    -P pr        Specify the pull request number
-    -b build     Specify the build number
-    -T tag       Specify the git tag
-
-    -- Enterprise --
-    -u URL       Set the target url for Enterprise customers
-                 Not required when retrieving the bash uploader from your CCE
-                 (option) Set environment variable CODECOV_URL=https://my-hosted-codecov.com
-    -r SLUG      owner/repo slug used instead of the private repo token in Enterprise
-                 (option) set environment variable CODECOV_SLUG=:owner/:repo
-                 (option) set in your codecov.yml "codecov.slug"
-    -S PATH      File path to your cacert.pem file used to verify ssl with Codecov Enterprise (optional)
-                 (option) Set environment variable: CODECOV_CA_BUNDLE="/path/to/ca.pem"
-    -U curlargs  Extra curl arguments to communicate with Codecov. e.g., -U "--proxy http://http-proxy"
-    -A curlargs  Extra curl arguments to communicate with AWS.
-
-    -- Debugging --
-    -d           Don't upload, but dump upload file to stdout
-    -q PATH      Write upload file to path
-    -K           Remove color from the output
-    -v           Verbose mode
-
-EOF
-}
-
-
-say() {
-  echo -e "$1"
-}
-
-
-urlencode() {
-  echo "$1" | curl -Gso /dev/null -w "%{url_effective}" --data-urlencode @- "" | cut -c 3- | sed -e 's/%0A//'
-}
-
-swiftcov() {
-  _dir=$(dirname "$1" | sed 's/\(Build\).*/\1/g')
-  for _type in app framework xctest
-  do
-    find "$_dir" -name "*.$_type" | while read -r f
-    do
-      _proj=${f##*/}
-      _proj=${_proj%."$_type"}
-      if [ "$2" = "" ] || [ "$(echo "$_proj" | grep -i "$2")" != "" ];
-      then
-        say "    $g+$x Building reports for $_proj $_type"
-        dest=$([ -f "$f/$_proj" ] && echo "$f/$_proj" || echo "$f/Contents/MacOS/$_proj")
-        # shellcheck disable=SC2001
-        _proj_name=$(echo "$_proj" | sed -e 's/[[:space:]]//g')
-        # shellcheck disable=SC2086
-        xcrun llvm-cov show $beta_xcode_partials -instr-profile "$1" "$dest" > "$_proj_name.$_type.coverage.txt" \
-         || say "    ${r}x>${x} llvm-cov failed to produce results for $dest"
-      fi
-    done
-  done
-}
-
-
-# Credits to: https://gist.github.com/pkuczynski/8665367
-parse_yaml() {
-   local prefix=$2
-   local s='[[:space:]]*' w='[a-zA-Z0-9_]*'
-   local fs
-   fs=$(echo @|tr @ '\034')
-   sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-        -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$1" |
-   awk -F"$fs" '{
-      indent = length($1)/2;
-      vname[indent] = $2;
-      for (i in vname) {if (i > indent) {delete vname[i]}}
-      if (length($3) > 0) {
-         vn=""; if (indent > 0) {vn=(vn)(vname[0])("_")}
-         printf("%s%s%s=\"%s\"\n", "'"$prefix"'",vn, $2, $3);
-      }
-   }'
-}
-
-if [ $# != 0 ];
-then
-  while getopts "a:A:b:B:cC:dD:e:f:F:g:G:hi:J:k:Kn:p:P:Q:q:r:R:s:S:t:T:u:U:vx:X:Zz:N:-" o
-  do
-    codecov_flags+=( "$o" )
-    case "$o" in
-      "-")
-        echo -e "${r}Long options are not supported${x}"
-        exit 2
-        ;;
-      "?")
-        ;;
-      "N")
-        parent=$OPTARG
-        ;;
-      "a")
-        gcov_arg=$OPTARG
-        ;;
-      "A")
-        curlawsargs="$OPTARG"
-        ;;
-      "b")
-        build_o="$OPTARG"
-        ;;
-      "B")
-        branch_o="$OPTARG"
-        ;;
-      "c")
-        clean="1"
-        ;;
-      "C")
-        commit_o="$OPTARG"
-        ;;
-      "d")
-        dump="1"
-        ;;
-      "D")
-        ddp="$OPTARG"
-        ;;
-      "e")
-        env="$env,$OPTARG"
-        ;;
-      "f")
-        if [ "${OPTARG::1}" = "!" ];
-        then
-          exclude_cov="$exclude_cov -not -path '${OPTARG:1}'"
-
-        elif [[ "$OPTARG" = *"*"* ]];
-        then
-          include_cov="$include_cov -or -path '$OPTARG'"
-
-        else
-          ft_search=0
-          if [ "$files" = "" ];
-          then
-            files="$OPTARG"
-          else
-            files="$files
-$OPTARG"
-          fi
-        fi
-        ;;
-      "F")
-        if [ "$flags" = "" ];
-        then
-          flags="$OPTARG"
-        else
-          flags="$flags,$OPTARG"
-        fi
-        ;;
-      "g")
-        gcov_ignore="$gcov_ignore -not -path '$OPTARG'"
-        ;;
-      "G")
-        gcov_include="$gcov_include -path '$OPTARG'"
-        ;;
-      "h")
-        show_help
-        exit 0;
-        ;;
-      "i")
-        network_filter_o="$OPTARG"
-        ;;
-      "J")
-        ft_xcodellvm="1"
-        ft_xcodeplist="0"
-        if [ "$xp" = "" ];
-        then
-          xp="$OPTARG"
-        else
-          xp="$xp\|$OPTARG"
-        fi
-        ;;
-      "k")
-        prefix_o=$(echo "$OPTARG" | sed -e 's:^/*::' -e 's:/*$::')
-        ;;
-      "K")
-        b=""
-        g=""
-        r=""
-        e=""
-        x=""
-        ;;
-      "n")
-        name="$OPTARG"
-        ;;
-      "p")
-        proj_root="$OPTARG"
-        ;;
-      "P")
-        pr_o="$OPTARG"
-        ;;
-      "Q")
-        # this is only meant for Codecov packages to overwrite
-        package="$OPTARG"
-        ;;
-      "q")
-        save_to="$OPTARG"
-        ;;
-      "r")
-        slug_o="$OPTARG"
-        ;;
-      "R")
-        git_root="$OPTARG"
-        ;;
-      "s")
-        if [ "$search_in_o" = "" ];
-        then
-          search_in_o="$OPTARG"
-        else
-          search_in_o="$search_in_o $OPTARG"
-        fi
-        ;;
-      "S")
-        # shellcheck disable=SC2089
-        cacert="--cacert \"$OPTARG\""
-        ;;
-      "t")
-        if [ "${OPTARG::1}" = "@" ];
-        then
-          token=$(< "${OPTARG:1}" tr -d ' \n')
-        else
-          token="$OPTARG"
-        fi
-        ;;
-      "T")
-        tag_o="$OPTARG"
-        ;;
-      "u")
-        url_o=$(echo "$OPTARG" | sed -e 's/\/$//')
-        ;;
-      "U")
-        curlargs="$OPTARG"
-        ;;
-      "v")
-        set -x
-        curl_s=""
-        ;;
-      "x")
-        gcov_exe=$OPTARG
-        ;;
-      "X")
-        if [ "$OPTARG" = "gcov" ];
-        then
-          ft_gcov="0"
-        elif [ "$OPTARG" = "coveragepy" ] || [ "$OPTARG" = "py" ];
-        then
-          ft_coveragepy="0"
-        elif [ "$OPTARG" = "gcovout" ];
-        then
-          ft_gcovout="0"
-        elif [ "$OPTARG" = "xcodellvm" ];
-        then
-          ft_xcodellvm="1"
-          ft_xcodeplist="0"
-        elif [ "$OPTARG" = "fix" ] || [ "$OPTARG" = "fixes" ];
-        then
-          ft_fix="0"
-        elif [ "$OPTARG" = "xcode" ];
-        then
-          ft_xcodellvm="0"
-          ft_xcodeplist="0"
-        elif [ "$OPTARG" = "search" ];
-        then
-          ft_search="0"
-        elif [ "$OPTARG" = "xcodepartials" ];
-        then
-          beta_xcode_partials="-use-color"
-        elif [ "$OPTARG" = "network" ];
-        then
-          ft_network="0"
-        elif [ "$OPTARG" = "s3" ];
-        then
-          ft_s3="0"
-        elif [ "$OPTARG" = "html" ];
-        then
-          ft_html="1"
-        elif [ "$OPTARG" = "recursesubs" ];
-        then
-          git_ls_files_recurse_submodules_o="--recurse-submodules"
-        elif [ "$OPTARG" = "yaml" ];
-        then
-          ft_yaml="1"
-        fi
-        ;;
-      "Z")
-        exit_with=1
-        ;;
-      "z")
-        direct_file_upload="$OPTARG"
-        ft_gcov="0"
-        ft_coveragepy="0"
-        ft_fix="0"
-        ft_search="0"
-        ft_network="0"
-        ft_xcodellvm="0"
-        ft_gcovout="0"
-        include_cov=""
-        ;;
-      *)
-        echo -e "${r}Unexpected flag not supported${x}"
-        ;;
-    esac
-  done
-fi
-
-say "
-  _____          _
- / ____|        | |
-| |     ___   __| | ___  ___ _____   __
-| |    / _ \\ / _\` |/ _ \\/ __/ _ \\ \\ / /
-| |___| (_) | (_| |  __/ (_| (_) \\ V /
- \\_____\\___/ \\__,_|\\___|\\___\\___/ \\_/
-                              Bash-$VERSION
-
-"
-
-# check for installed tools
-# git/hg
-if [ "$direct_file_upload" = "" ];
-then
-  if [ -x "$(command -v git)" ];
-  then
-    say "$b==>$x $(git --version) found"
-  else
-    say "$y==>$x git not installed, testing for mercurial"
-    if [ -x "$(command -v hg)" ];
-    then
-      say "$b==>$x $(hg --version) found"
-    else
-      say "$r==>$x git nor mercurial are installed. Uploader may fail or have unintended consequences"
-    fi
-  fi
-fi
-# curl
-if [ -x "$(command -v curl)" ];
-then
-  say "$b==>$x $(curl --version)"
-else
-  say "$r==>$x curl not installed. Exiting."
-  exit ${exit_with};
-fi
-
-search_in="$proj_root"
-
-#shellcheck disable=SC2154
-if [ "$JENKINS_URL" != "" ];
-then
-  say "$e==>$x Jenkins CI detected."
-  # https://wiki.jenkins-ci.org/display/JENKINS/Building+a+software+project
-  # https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin#GitHubpullrequestbuilderplugin-EnvironmentVariables
-  service="jenkins"
-
-  # shellcheck disable=SC2154
-  if [ "$ghprbSourceBranch" != "" ];
-  then
-     branch="$ghprbSourceBranch"
-  elif [ "$GIT_BRANCH" != "" ];
-  then
-     branch="$GIT_BRANCH"
-  elif [ "$BRANCH_NAME" != "" ];
-  then
-    branch="$BRANCH_NAME"
-  fi
-
-  # shellcheck disable=SC2154
-  if [ "$ghprbActualCommit" != "" ];
-  then
-    commit="$ghprbActualCommit"
-  elif [ "$GIT_COMMIT" != "" ];
-  then
-    commit="$GIT_COMMIT"
-  fi
-
-  # shellcheck disable=SC2154
-  if [ "$ghprbPullId" != "" ];
-  then
-    pr="$ghprbPullId"
-  elif [ "$CHANGE_ID" != "" ];
-  then
-    pr="$CHANGE_ID"
-  fi
-
-  build="$BUILD_NUMBER"
-  # shellcheck disable=SC2153
-  build_url=$(urlencode "$BUILD_URL")
-
-elif [ "$CI" = "true" ] && [ "$TRAVIS" = "true" ] && [ "$SHIPPABLE" != "true" ];
-then
-  say "$e==>$x Travis CI detected."
-  # https://docs.travis-ci.com/user/environment-variables/
-  service="travis"
-  commit="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
-  build="$TRAVIS_JOB_NUMBER"
-  pr="$TRAVIS_PULL_REQUEST"
-  job="$TRAVIS_JOB_ID"
-  slug="$TRAVIS_REPO_SLUG"
-  env="$env,TRAVIS_OS_NAME"
-  tag="$TRAVIS_TAG"
-  if [ "$TRAVIS_BRANCH" != "$TRAVIS_TAG" ];
-  then
-    branch="${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
-  fi
-
-  language=$(compgen -A variable | grep "^TRAVIS_.*_VERSION$" | head -1)
-  if [ "$language" != "" ];
-  then
-    env="$env,${!language}"
-  fi
-
-elif [ "$CODEBUILD_CI" = "true" ];
-then
-  say "$e==>$x AWS Codebuild detected."
-  # https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
-  service="codebuild"
-  commit="$CODEBUILD_RESOLVED_SOURCE_VERSION"
-  build="$CODEBUILD_BUILD_ID"
-  branch="$(echo "$CODEBUILD_WEBHOOK_HEAD_REF" | sed 's/^refs\/heads\///')"
-  if [ "${CODEBUILD_SOURCE_VERSION/pr}" = "$CODEBUILD_SOURCE_VERSION" ] ; then
-    pr="false"
-  else
-    pr="$(echo "$CODEBUILD_SOURCE_VERSION" | sed 's/^pr\///')"
-  fi
-  job="$CODEBUILD_BUILD_ID"
-  slug="$(echo "$CODEBUILD_SOURCE_REPO_URL" | sed 's/^.*:\/\/[^\/]*\///' | sed 's/\.git$//')"
-
-elif [ "$CI" = "true" ] && [ "$CI_NAME" = "codeship" ];
-then
-  say "$e==>$x Codeship CI detected."
-  # https://www.codeship.io/documentation/continuous-integration/set-environment-variables/
-  service="codeship"
-  branch="$CI_BRANCH"
-  build="$CI_BUILD_NUMBER"
-  build_url=$(urlencode "$CI_BUILD_URL")
-  commit="$CI_COMMIT_ID"
-
-elif [ -n "$CF_BUILD_URL" ] && [ -n "$CF_BUILD_ID" ];
-then
-  say "$e==>$x Codefresh CI detected."
-  # https://docs.codefresh.io/v1.0/docs/variables
-  service="codefresh"
-  branch="$CF_BRANCH"
-  build="$CF_BUILD_ID"
-  build_url=$(urlencode "$CF_BUILD_URL")
-  commit="$CF_REVISION"
-
-elif [ "$TEAMCITY_VERSION" != "" ];
-then
-  say "$e==>$x TeamCity CI detected."
-  # https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters
-  # https://confluence.jetbrains.com/plugins/servlet/mobile#content/view/74847298
-  if [ "$TEAMCITY_BUILD_BRANCH" = '' ];
-  then
-    echo "    Teamcity does not automatically make build parameters available as environment variables."
-    echo "    Add the following environment parameters to the build configuration"
-    echo "    env.TEAMCITY_BUILD_BRANCH = %teamcity.build.branch%"
-    echo "    env.TEAMCITY_BUILD_ID = %teamcity.build.id%"
-    echo "    env.TEAMCITY_BUILD_URL = %teamcity.serverUrl%/viewLog.html?buildId=%teamcity.build.id%"
-    echo "    env.TEAMCITY_BUILD_COMMIT = %system.build.vcs.number%"
-    echo "    env.TEAMCITY_BUILD_REPOSITORY = %vcsroot.<YOUR TEAMCITY VCS NAME>.url%"
-  fi
-  service="teamcity"
-  branch="$TEAMCITY_BUILD_BRANCH"
-  build="$TEAMCITY_BUILD_ID"
-  build_url=$(urlencode "$TEAMCITY_BUILD_URL")
-  if [ "$TEAMCITY_BUILD_COMMIT" != "" ];
-  then
-    commit="$TEAMCITY_BUILD_COMMIT"
-  else
-    commit="$BUILD_VCS_NUMBER"
-  fi
-  remote_addr="$TEAMCITY_BUILD_REPOSITORY"
-
-elif [ "$CI" = "true" ] && [ "$CIRCLECI" = "true" ];
-then
-  say "$e==>$x Circle CI detected."
-  # https://circleci.com/docs/environment-variables
-  service="circleci"
-  branch="$CIRCLE_BRANCH"
-  build="$CIRCLE_BUILD_NUM"
-  job="$CIRCLE_NODE_INDEX"
-  if [ "$CIRCLE_PROJECT_REPONAME" != "" ];
-  then
-    slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
-  else
-    # git@github.com:owner/repo.git
-    slug="${CIRCLE_REPOSITORY_URL##*:}"
-    # owner/repo.git
-    slug="${slug%%.git}"
-  fi
-  pr="${CIRCLE_PULL_REQUEST##*/}"
-  commit="$CIRCLE_SHA1"
-  search_in="$search_in $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS"
-
-elif [ "$BUDDYBUILD_BRANCH" != "" ];
-then
-  say "$e==>$x buddybuild detected"
-  # http://docs.buddybuild.com/v6/docs/custom-prebuild-and-postbuild-steps
-  service="buddybuild"
-  branch="$BUDDYBUILD_BRANCH"
-  build="$BUDDYBUILD_BUILD_NUMBER"
-  build_url="https://dashboard.buddybuild.com/public/apps/$BUDDYBUILD_APP_ID/build/$BUDDYBUILD_BUILD_ID"
-  # BUDDYBUILD_TRIGGERED_BY
-  if [ "$ddp" = "$HOME/Library/Developer/Xcode/DerivedData" ];
-  then
-    ddp="/private/tmp/sandbox/${BUDDYBUILD_APP_ID}/bbtest"
-  fi
-
-elif [ "${bamboo_planRepository_revision}" != "" ];
-then
-  say "$e==>$x Bamboo detected"
-  # https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html#Bamboovariables-Build-specificvariables
-  service="bamboo"
-  commit="${bamboo_planRepository_revision}"
-  # shellcheck disable=SC2154
-  branch="${bamboo_planRepository_branch}"
-  # shellcheck disable=SC2154
-  build="${bamboo_buildNumber}"
-  # shellcheck disable=SC2154
-  build_url="${bamboo_buildResultsUrl}"
-  # shellcheck disable=SC2154
-  remote_addr="${bamboo_planRepository_repositoryUrl}"
-
-elif [ "$CI" = "true" ] && [ "$BITRISE_IO" = "true" ];
-then
-  # http://devcenter.bitrise.io/faq/available-environment-variables/
-  say "$e==>$x Bitrise CI detected."
-  service="bitrise"
-  branch="$BITRISE_GIT_BRANCH"
-  build="$BITRISE_BUILD_NUMBER"
-  build_url=$(urlencode "$BITRISE_BUILD_URL")
-  pr="$BITRISE_PULL_REQUEST"
-  if [ "$GIT_CLONE_COMMIT_HASH" != "" ];
-  then
-    commit="$GIT_CLONE_COMMIT_HASH"
-  fi
-
-elif [ "$CI" = "true" ] && [ "$SEMAPHORE" = "true" ];
-then
-  say "$e==>$x Semaphore CI detected."
-# https://docs.semaphoreci.com/ci-cd-environment/environment-variables/#semaphore-related
-  service="semaphore"
-  branch="$SEMAPHORE_GIT_BRANCH"
-  build="$SEMAPHORE_WORKFLOW_NUMBER"
-  job="$SEMAPHORE_JOB_ID"
-  pr="$PULL_REQUEST_NUMBER"
-  slug="$SEMAPHORE_REPO_SLUG"
-  commit="$REVISION"
-  env="$env,SEMAPHORE_TRIGGER_SOURCE"
-
-elif [ "$CI" = "true" ] && [ "$BUILDKITE" = "true" ];
-then
-  say "$e==>$x Buildkite CI detected."
-  # https://buildkite.com/docs/guides/environment-variables
-  service="buildkite"
-  branch="$BUILDKITE_BRANCH"
-  build="$BUILDKITE_BUILD_NUMBER"
-  job="$BUILDKITE_JOB_ID"
-  build_url=$(urlencode "$BUILDKITE_BUILD_URL")
-  slug="$BUILDKITE_PROJECT_SLUG"
-  commit="$BUILDKITE_COMMIT"
-  if [[ "$BUILDKITE_PULL_REQUEST" != "false" ]]; then
-    pr="$BUILDKITE_PULL_REQUEST"
-  fi
-  tag="$BUILDKITE_TAG"
-
-elif [ "$CI" = "drone" ] || [ "$DRONE" = "true" ];
-then
-  say "$e==>$x Drone CI detected."
-  # http://docs.drone.io/env.html
-  # drone commits are not full shas
-  service="drone.io"
-  branch="$DRONE_BRANCH"
-  build="$DRONE_BUILD_NUMBER"
-  build_url=$(urlencode "${DRONE_BUILD_LINK}")
-  pr="$DRONE_PULL_REQUEST"
-  job="$DRONE_JOB_NUMBER"
-  tag="$DRONE_TAG"
-
-elif [ "$CI" = "true" ] && [ "$HEROKU_TEST_RUN_BRANCH" != "" ];
-then
-  say "$e==>$x Heroku CI detected."
-  # https://devcenter.heroku.com/articles/heroku-ci#environment-variables
-  service="heroku"
-  branch="$HEROKU_TEST_RUN_BRANCH"
-  build="$HEROKU_TEST_RUN_ID"
-  commit="$HEROKU_TEST_RUN_COMMIT_VERSION"
-
-elif [[ "$CI" = "true" || "$CI" = "True" ]] && [[ "$APPVEYOR" = "true" || "$APPVEYOR" = "True" ]];
-then
-  say "$e==>$x Appveyor CI detected."
-  # http://www.appveyor.com/docs/environment-variables
-  service="appveyor"
-  branch="$APPVEYOR_REPO_BRANCH"
-  build=$(urlencode "$APPVEYOR_JOB_ID")
-  pr="$APPVEYOR_PULL_REQUEST_NUMBER"
-  job="$APPVEYOR_ACCOUNT_NAME%2F$APPVEYOR_PROJECT_SLUG%2F$APPVEYOR_BUILD_VERSION"
-  slug="$APPVEYOR_REPO_NAME"
-  commit="$APPVEYOR_REPO_COMMIT"
-  build_url=$(urlencode "${APPVEYOR_URL}/project/${APPVEYOR_REPO_NAME}/builds/$APPVEYOR_BUILD_ID/job/${APPVEYOR_JOB_ID}")
-
-elif [ "$CI" = "true" ] && [ "$WERCKER_GIT_BRANCH" != "" ];
-then
-  say "$e==>$x Wercker CI detected."
-  # http://devcenter.wercker.com/articles/steps/variables.html
-  service="wercker"
-  branch="$WERCKER_GIT_BRANCH"
-  build="$WERCKER_MAIN_PIPELINE_STARTED"
-  slug="$WERCKER_GIT_OWNER/$WERCKER_GIT_REPOSITORY"
-  commit="$WERCKER_GIT_COMMIT"
-
-elif [ "$CI" = "true" ] && [ "$MAGNUM" = "true" ];
-then
-  say "$e==>$x Magnum CI detected."
-  # https://magnum-ci.com/docs/environment
-  service="magnum"
-  branch="$CI_BRANCH"
-  build="$CI_BUILD_NUMBER"
-  commit="$CI_COMMIT"
-
-elif [ "$SHIPPABLE" = "true" ];
-then
-  say "$e==>$x Shippable CI detected."
-  # http://docs.shippable.com/ci_configure/
-  service="shippable"
-  # shellcheck disable=SC2153
-  branch=$([ "$HEAD_BRANCH" != "" ] && echo "$HEAD_BRANCH" || echo "$BRANCH")
-  build="$BUILD_NUMBER"
-  build_url=$(urlencode "$BUILD_URL")
-  pr="$PULL_REQUEST"
-  slug="$REPO_FULL_NAME"
-  # shellcheck disable=SC2153
-  commit="$COMMIT"
-
-elif [ "$TDDIUM" = "true" ];
-then
-  say "Solano CI detected."
-  # http://docs.solanolabs.com/Setup/tddium-set-environment-variables/
-  service="solano"
-  commit="$TDDIUM_CURRENT_COMMIT"
-  branch="$TDDIUM_CURRENT_BRANCH"
-  build="$TDDIUM_TID"
-  pr="$TDDIUM_PR_ID"
-
-elif [ "$GREENHOUSE" = "true" ];
-then
-  say "$e==>$x Greenhouse CI detected."
-  # http://docs.greenhouseci.com/docs/environment-variables-files
-  service="greenhouse"
-  branch="$GREENHOUSE_BRANCH"
-  build="$GREENHOUSE_BUILD_NUMBER"
-  build_url=$(urlencode "$GREENHOUSE_BUILD_URL")
-  pr="$GREENHOUSE_PULL_REQUEST"
-  commit="$GREENHOUSE_COMMIT"
-  search_in="$search_in $GREENHOUSE_EXPORT_DIR"
-
-elif [ "$GITLAB_CI" != "" ];
-then
-  say "$e==>$x GitLab CI detected."
-  # http://doc.gitlab.com/ce/ci/variables/README.html
-  service="gitlab"
-  branch="${CI_BUILD_REF_NAME:-$CI_COMMIT_REF_NAME}"
-  build="${CI_BUILD_ID:-$CI_JOB_ID}"
-  remote_addr="${CI_BUILD_REPO:-$CI_REPOSITORY_URL}"
-  commit="${CI_BUILD_REF:-$CI_COMMIT_SHA}"
-  slug="${CI_PROJECT_PATH}"
-
-elif [ "$GITHUB_ACTIONS" != "" ];
-then
-  say "$e==>$x GitHub Actions detected."
-  say "    Env vars used:"
-  say "      -> GITHUB_ACTIONS:    ${GITHUB_ACTIONS}"
-  say "      -> GITHUB_HEAD_REF:   ${GITHUB_HEAD_REF}"
-  say "      -> GITHUB_REF:        ${GITHUB_REF}"
-  say "      -> GITHUB_REPOSITORY: ${GITHUB_REPOSITORY}"
-  say "      -> GITHUB_RUN_ID:     ${GITHUB_RUN_ID}"
-  say "      -> GITHUB_SHA:        ${GITHUB_SHA}"
-  say "      -> GITHUB_WORKFLOW:   ${GITHUB_WORKFLOW}"
-
-  # https://github.com/features/actions
-  service="github-actions"
-
-  # https://help.github.com/en/articles/virtual-environments-for-github-actions#environment-variables
-  branch="${GITHUB_REF#refs/heads/}"
-  if [  "$GITHUB_HEAD_REF" != "" ];
-  then
-    # PR refs are in the format: refs/pull/7/merge
-    pr="${GITHUB_REF#refs/pull/}"
-    pr="${pr%/merge}"
-    branch="${GITHUB_HEAD_REF}"
-  fi
-  commit="${GITHUB_SHA}"
-  slug="${GITHUB_REPOSITORY}"
-  build="${GITHUB_RUN_ID}"
-  build_url=$(urlencode "http://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}")
-  job="$(urlencode "${GITHUB_WORKFLOW}")"
-
-  # actions/checkout runs in detached HEAD
-  mc=
-  if [ -n "$pr" ] && [ "$pr" != false ] && [ "$commit_o" == "" ];
-  then
-    mc=$(git show --no-patch --format="%P" 2>/dev/null || echo "")
-
-    if [[ "$mc" =~ ^[a-z0-9]{40}[[:space:]][a-z0-9]{40}$ ]];
-    then
-      mc=$(echo "$mc" | cut -d' ' -f2)
-      say "    Fixing merge commit SHA $commit -> $mc"
-      commit=$mc
-    elif [[ "$mc" = "" ]];
-    then
-      say "$r->  Issue detecting commit SHA. Please run actions/checkout with fetch-depth > 1 or set to 0$x"
-    fi
-  fi
-
-elif [ "$SYSTEM_TEAMFOUNDATIONSERVERURI" != "" ];
-then
-  say "$e==>$x Azure Pipelines detected."
-  # https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=vsts
-  # https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&viewFallbackFrom=vsts&tabs=yaml
-  service="azure_pipelines"
-  commit="$BUILD_SOURCEVERSION"
-  build="$BUILD_BUILDNUMBER"
-  if [  -z "$SYSTEM_PULLREQUEST_PULLREQUESTNUMBER" ];
-  then
-    pr="$SYSTEM_PULLREQUEST_PULLREQUESTID"
-  else
-    pr="$SYSTEM_PULLREQUEST_PULLREQUESTNUMBER"
-  fi
-  project="${SYSTEM_TEAMPROJECT}"
-  server_uri="${SYSTEM_TEAMFOUNDATIONSERVERURI}"
-  job="${BUILD_BUILDID}"
-  branch="${BUILD_SOURCEBRANCH#"refs/heads/"}"
-  build_url=$(urlencode "${SYSTEM_TEAMFOUNDATIONSERVERURI}${SYSTEM_TEAMPROJECT}/_build/results?buildId=${BUILD_BUILDID}")
-
-  # azure/pipelines runs in detached HEAD
-  mc=
-  if [ -n "$pr" ] && [ "$pr" != false ];
-  then
-    mc=$(git show --no-patch --format="%P" 2>/dev/null || echo "")
-
-    if [[ "$mc" =~ ^[a-z0-9]{40}[[:space:]][a-z0-9]{40}$ ]];
-    then
-      mc=$(echo "$mc" | cut -d' ' -f2)
-      say "    Fixing merge commit SHA $commit -> $mc"
-      commit=$mc
-    fi
-  fi
-
-elif [ "$CI" = "true" ] && [ "$BITBUCKET_BUILD_NUMBER" != "" ];
-then
-  say "$e==>$x Bitbucket detected."
-  # https://confluence.atlassian.com/bitbucket/variables-in-pipelines-794502608.html
-  service="bitbucket"
-  branch="$BITBUCKET_BRANCH"
-  build="$BITBUCKET_BUILD_NUMBER"
-  slug="$BITBUCKET_REPO_OWNER/$BITBUCKET_REPO_SLUG"
-  job="$BITBUCKET_BUILD_NUMBER"
-  pr="$BITBUCKET_PR_ID"
-  commit="$BITBUCKET_COMMIT"
-  # See https://jira.atlassian.com/browse/BCLOUD-19393
-  if [ "${#commit}" = 12 ];
-  then
-    commit=$(git rev-parse "$BITBUCKET_COMMIT")
-  fi
-
-elif [ "$CI" = "true" ] && [ "$BUDDY" = "true" ];
-then
-  say "$e==>$x Buddy CI detected."
-  # https://buddy.works/docs/pipelines/environment-variables
-  service="buddy"
-  branch="$BUDDY_EXECUTION_BRANCH"
-  build="$BUDDY_EXECUTION_ID"
-  build_url=$(urlencode "$BUDDY_EXECUTION_URL")
-  commit="$BUDDY_EXECUTION_REVISION"
-  pr="$BUDDY_EXECUTION_PULL_REQUEST_NO"
-  tag="$BUDDY_EXECUTION_TAG"
-  slug="$BUDDY_REPO_SLUG"
-
-elif [ "$CIRRUS_CI" != "" ];
-then
-  say "$e==>$x Cirrus CI detected."
-  # https://cirrus-ci.org/guide/writing-tasks/#environment-variables
-  service="cirrus-ci"
-  slug="$CIRRUS_REPO_FULL_NAME"
-  branch="$CIRRUS_BRANCH"
-  pr="$CIRRUS_PR"
-  commit="$CIRRUS_CHANGE_IN_REPO"
-  build="$CIRRUS_BUILD_ID"
-  build_url=$(urlencode "https://cirrus-ci.com/task/$CIRRUS_TASK_ID")
-  job="$CIRRUS_TASK_NAME"
-
-elif [ "$DOCKER_REPO" != "" ];
-then
-  say "$e==>$x Docker detected."
-  # https://docs.docker.com/docker-cloud/builds/advanced/
-  service="docker"
-  branch="$SOURCE_BRANCH"
-  commit="$SOURCE_COMMIT"
-  slug="$DOCKER_REPO"
-  tag="$CACHE_TAG"
-  env="$env,IMAGE_NAME"
-
-else
-  say "${r}x>${x} No CI provider detected."
-  say "    Testing inside Docker? ${b}http://docs.codecov.io/docs/testing-with-docker${x}"
-  say "    Testing with Tox? ${b}https://docs.codecov.io/docs/python#section-testing-with-tox${x}"
-
-fi
-
-say "    ${e}project root:${x} $git_root"
-
-# find branch, commit, repo from git command
-if [ "$GIT_BRANCH" != "" ];
-then
-  branch="$GIT_BRANCH"
-
-elif [ "$branch" = "" ];
-then
-  branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || hg branch 2>/dev/null || echo "")
-  if [ "$branch" = "HEAD" ];
-  then
-    branch=""
-  fi
-fi
-
-if [ "$commit_o" = "" ];
-then
-  if [ "$GIT_COMMIT" != "" ];
-  then
-    commit="$GIT_COMMIT"
-  elif [ "$commit" = "" ];
-  then
-    commit=$(git log -1 --format="%H" 2>/dev/null || hg id -i --debug 2>/dev/null | tr -d '+' || echo "")
-  fi
-else
-  commit="$commit_o"
-fi
-
-if [ "$CODECOV_TOKEN" != "" ] && [ "$token" = "" ];
-then
-  say "${e}-->${x} token set from env"
-  token="$CODECOV_TOKEN"
-fi
-
-if [ "$CODECOV_URL" != "" ] && [ "$url_o" = "" ];
-then
-  say "${e}-->${x} url set from env"
-  url_o=$(echo "$CODECOV_URL" | sed -e 's/\/$//')
-fi
-
-if [ "$CODECOV_SLUG" != "" ];
-then
-  say "${e}-->${x} slug set from env"
-  slug_o="$CODECOV_SLUG"
-
-elif [ "$slug" = "" ];
-then
-  if [ "$remote_addr" = "" ];
-  then
-    remote_addr=$(git config --get remote.origin.url || hg paths default || echo '')
-  fi
-  if [ "$remote_addr" != "" ];
-  then
-    if echo "$remote_addr" | grep -q "//"; then
-      # https
-      slug=$(echo "$remote_addr" | cut -d / -f 4,5 | sed -e 's/\.git$//')
-    else
-      # ssh
-      slug=$(echo "$remote_addr" | cut -d : -f 2 | sed -e 's/\.git$//')
-    fi
-  fi
-  if [ "$slug" = "/" ];
-  then
-    slug=""
-  fi
-fi
-
-yaml=$(cd "$git_root" && \
-          git ls-files "*codecov.yml" "*codecov.yaml" 2>/dev/null \
-       || hg locate "*codecov.yml" "*codecov.yaml" 2>/dev/null \
-       || cd "$proj_root" && find . -maxdepth 1 -type f -name '*codecov.y*ml' 2>/dev/null \
-       || echo '')
-yaml=$(echo "$yaml" | head -1)
-
-if [ "$yaml" != "" ];
-then
-  say "    ${e}Yaml found at:${x} $yaml"
-  if [[ "$yaml" != /* ]]; then
-    # relative path for yaml file given, assume relative to the repo root
-    yaml="$git_root/$yaml"
-  fi
-  config=$(parse_yaml "$yaml" || echo '')
-
-  # TODO validate the yaml here
-
-  if [ "$(echo "$config" | grep 'codecov_token="')" != "" ] && [ "$token" = "" ];
-  then
-    say "${e}-->${x} token set from yaml"
-    token="$(echo "$config" | grep 'codecov_token="' | sed -e 's/codecov_token="//' | sed -e 's/"\.*//')"
-  fi
-
-  if [ "$(echo "$config" | grep 'codecov_url="')" != "" ] && [ "$url_o" = "" ];
-  then
-    say "${e}-->${x} url set from yaml"
-    url_o="$(echo "$config" | grep 'codecov_url="' | sed -e 's/codecov_url="//' | sed -e 's/"\.*//')"
-  fi
-
-  if [ "$(echo "$config" | grep 'codecov_slug="')" != "" ] && [ "$slug_o" = "" ];
-  then
-    say "${e}-->${x} slug set from yaml"
-    slug_o="$(echo "$config" | grep 'codecov_slug="' | sed -e 's/codecov_slug="//' | sed -e 's/"\.*//')"
-  fi
-else
-  say "    ${g}Yaml not found, that's ok! Learn more at${x} ${b}http://docs.codecov.io/docs/codecov-yaml${x}"
-fi
-
-if [ "$branch_o" != "" ];
-then
-  branch=$(urlencode "$branch_o")
-else
-  branch=$(urlencode "$branch")
-fi
-
-if [ "$slug_o" = "" ];
-then
-  urlencoded_slug=$(urlencode "$slug")
-else
-  urlencoded_slug=$(urlencode "$slug_o")
-fi
-
-query="branch=$branch\
-       &commit=$commit\
-       &build=$([ "$build_o" = "" ] && echo "$build" || echo "$build_o")\
-       &build_url=$build_url\
-       &name=$(urlencode "$name")\
-       &tag=$([ "$tag_o" = "" ] && echo "$tag" || echo "$tag_o")\
-       &slug=$urlencoded_slug\
-       &service=$service\
-       &flags=$flags\
-       &pr=$([ "$pr_o" = "" ] && echo "${pr##\#}" || echo "${pr_o##\#}")\
-       &job=$job\
-       &cmd_args=$(IFS=,; echo "${codecov_flags[*]}")"
-
-if [ -n "$project" ] && [ -n "$server_uri" ];
-then
-  query=$(echo "$query&project=$project&server_uri=$server_uri" | tr -d ' ')
-fi
-
-if [ "$parent" != "" ];
-then
-  query=$(echo "parent=$parent&$query" | tr -d ' ')
-fi
-
-if [ "$ft_search" = "1" ];
-then
-  # detect bower comoponents location
-  bower_components="bower_components"
-  bower_rc=$(cd "$git_root" && cat .bowerrc 2>/dev/null || echo "")
-  if [ "$bower_rc" != "" ];
-  then
-    bower_components=$(echo "$bower_rc" | tr -d '\n' | grep '"directory"' | cut -d'"' -f4 | sed -e 's/\/$//')
-    if [ "$bower_components" = "" ];
-    then
-      bower_components="bower_components"
-    fi
-  fi
-
-  # Swift Coverage
-  if [ "$ft_xcodellvm" = "1" ] && [ -d "$ddp" ];
-  then
-    say "${e}==>${x} Processing Xcode reports via llvm-cov"
-    say "    DerivedData folder: $ddp"
-    profdata_files=$(find "$ddp" -name '*.profdata' 2>/dev/null || echo '')
-    if [ "$profdata_files" != "" ];
-    then
-      # xcode via profdata
-      if [ "$xp" = "" ];
-      then
-        # xp=$(xcodebuild -showBuildSettings 2>/dev/null | grep -i "^\s*PRODUCT_NAME" | sed -e 's/.*= \(.*\)/\1/')
-        # say " ${e}->${x} Speed up Xcode processing by adding ${e}-J '$xp'${x}"
-        say "    ${g}hint${x} Speed up Swift processing by using use ${g}-J 'AppName'${x} (regexp accepted)"
-        say "    ${g}hint${x} This will remove Pods/ from your report. Also ${b}https://docs.codecov.io/docs/ignoring-paths${x}"
-      fi
-      while read -r profdata;
-      do
-        if [ "$profdata" != "" ];
-        then
-          swiftcov "$profdata" "$xp"
-        fi
-      done <<< "$profdata_files"
-    else
-      say "    ${e}->${x} No Swift coverage found"
-    fi
-
-    # Obj-C Gcov Coverage
-    if [ "$ft_gcov" = "1" ];
-    then
-      say "    ${e}->${x} Running $gcov_exe for Obj-C"
-      if [ "$ft_gcovout" = "0" ];
-      then
-        # suppress gcov output
-        bash -c "find $ddp -type f -name '*.gcda' $gcov_include $gcov_ignore -exec $gcov_exe -p $gcov_arg {} +" >/dev/null 2>&1 || true
-      else
-        bash -c "find $ddp -type f -name '*.gcda' $gcov_include $gcov_ignore -exec $gcov_exe -p $gcov_arg {} +" || true
-      fi
-    fi
-  fi
-
-  if [ "$ft_xcodeplist" = "1" ] && [ -d "$ddp" ];
-  then
-    say "${e}==>${x} Processing Xcode plists"
-    plists_files=$(find "$ddp" -name '*.xccoverage' 2>/dev/null || echo '')
-    if [ "$plists_files" != "" ];
-    then
-      while read -r plist;
-      do
-        if [ "$plist" != "" ];
-        then
-          say "    ${g}Found${x} plist file at $plist"
-          plutil -convert xml1 -o "$(basename "$plist").plist" -- "$plist"
-        fi
-      done <<< "$plists_files"
-    fi
-  fi
-
-  # Gcov Coverage
-  if [ "$ft_gcov" = "1" ];
-  then
-    say "${e}==>${x} Running $gcov_exe in $proj_root ${e}(disable via -X gcov)${x}"
-    if [ "$ft_gcovout" = "0" ];
-    then
-      # suppress gcov output
-      bash -c "find $proj_root -type f -name '*.gcno' $gcov_include $gcov_ignore -exec $gcov_exe -pb $gcov_arg {} +" >/dev/null 2>&1 || true
-    else
-      bash -c "find $proj_root -type f -name '*.gcno' $gcov_include $gcov_ignore -exec $gcov_exe -pb $gcov_arg {} +" || true
-    fi
-  else
-    say "${e}==>${x} gcov disabled"
-  fi
-
-  # Python Coverage
-  if [ "$ft_coveragepy" = "1" ];
-  then
-    if [ ! -f coverage.xml ];
-    then
-      if command -v coverage >/dev/null 2>&1;
-      then
-        say "${e}==>${x} Python coveragepy exists ${e}disable via -X coveragepy${x}"
-
-        dotcoverage=$(find "$git_root" -name '.coverage' -or -name '.coverage.*' | head -1 || echo '')
-        if [ "$dotcoverage" != "" ];
-        then
-          cd "$(dirname "$dotcoverage")"
-          if [ ! -f .coverage ];
-          then
-            say "    ${e}->${x} Running coverage combine"
-            coverage combine -a
-          fi
-          say "    ${e}->${x} Running coverage xml"
-          if [ "$(coverage xml -i)" != "No data to report." ];
-          then
-            files="$files
-$PWD/coverage.xml"
-          else
-            say "    ${r}No data to report.${x}"
-          fi
-          cd "$proj_root"
-        else
-          say "    ${r}No .coverage file found.${x}"
-        fi
-      else
-        say "${e}==>${x} Python coveragepy not found"
-      fi
-    fi
-  else
-    say "${e}==>${x} Python coveragepy disabled"
-  fi
-
-  if [ "$search_in_o" != "" ];
-  then
-    # location override
-    search_in="$search_in_o"
-  fi
-
-  say "$e==>$x Searching for coverage reports in:"
-  for _path in $search_in
-  do
-    say "    ${g}+${x} $_path"
-  done
-
-  patterns="find $search_in \( \
-                        -name vendor \
-                        -or -name '$bower_components' \
-                        -or -name '.egg-info*' \
-                        -or -name 'conftest_*.c.gcov' \
-                        -or -name .env \
-                        -or -name .envs \
-                        -or -name .git \
-                        -or -name .hg \
-                        -or -name .tox \
-                        -or -name .venv \
-                        -or -name .venvs \
-                        -or -name .virtualenv \
-                        -or -name .virtualenvs \
-                        -or -name .yarn-cache \
-                        -or -name __pycache__ \
-                        -or -name env \
-                        -or -name envs \
-                        -or -name htmlcov \
-                        -or -name js/generated/coverage \
-                        -or -name node_modules \
-                        -or -name venv \
-                        -or -name venvs \
-                        -or -name virtualenv \
-                        -or -name virtualenvs \
-                    \) -prune -or \
-                    -type f \( -name '*coverage*.*' \
-                     -or -name '*.clover' \
-                     -or -name '*.codecov.*' \
-                     -or -name '*.gcov' \
-                     -or -name '*.lcov' \
-                     -or -name '*.lst' \
-                     -or -name 'clover.xml' \
-                     -or -name 'cobertura.xml' \
-                     -or -name 'codecov.*' \
-                     -or -name 'cover.out' \
-                     -or -name 'codecov-result.json' \
-                     -or -name 'coverage-final.json' \
-                     -or -name 'excoveralls.json' \
-                     -or -name 'gcov.info' \
-                     -or -name 'jacoco*.xml' \
-                     -or -name '*Jacoco*.xml' \
-                     -or -name 'lcov.dat' \
-                     -or -name 'lcov.info' \
-                     -or -name 'luacov.report.out' \
-                     -or -name 'naxsi.info' \
-                     -or -name 'nosetests.xml' \
-                     -or -name 'report.xml' \
-                     $include_cov \) \
-                    $exclude_cov \
-                    -not -name '*.am' \
-                    -not -name '*.bash' \
-                    -not -name '*.bat' \
-                    -not -name '*.bw' \
-                    -not -name '*.cfg' \
-                    -not -name '*.class' \
-                    -not -name '*.cmake' \
-                    -not -name '*.cmake' \
-                    -not -name '*.conf' \
-                    -not -name '*.coverage' \
-                    -not -name '*.cp' \
-                    -not -name '*.cpp' \
-                    -not -name '*.crt' \
-                    -not -name '*.css' \
-                    -not -name '*.csv' \
-                    -not -name '*.csv' \
-                    -not -name '*.data' \
-                    -not -name '*.db' \
-                    -not -name '*.dox' \
-                    -not -name '*.ec' \
-                    -not -name '*.ec' \
-                    -not -name '*.egg' \
-                    -not -name '*.el' \
-                    -not -name '*.env' \
-                    -not -name '*.erb' \
-                    -not -name '*.exe' \
-                    -not -name '*.ftl' \
-                    -not -name '*.gif' \
-                    -not -name '*.gradle' \
-                    -not -name '*.gz' \
-                    -not -name '*.h' \
-                    -not -name '*.html' \
-                    -not -name '*.in' \
-                    -not -name '*.jade' \
-                    -not -name '*.jar*' \
-                    -not -name '*.jpeg' \
-                    -not -name '*.jpg' \
-                    -not -name '*.js' \
-                    -not -name '*.less' \
-                    -not -name '*.log' \
-                    -not -name '*.m4' \
-                    -not -name '*.mak*' \
-                    -not -name '*.md' \
-                    -not -name '*.o' \
-                    -not -name '*.p12' \
-                    -not -name '*.pem' \
-                    -not -name '*.png' \
-                    -not -name '*.pom*' \
-                    -not -name '*.profdata' \
-                    -not -name '*.proto' \
-                    -not -name '*.ps1' \
-                    -not -name '*.pth' \
-                    -not -name '*.py' \
-                    -not -name '*.pyc' \
-                    -not -name '*.pyo' \
-                    -not -name '*.rb' \
-                    -not -name '*.rsp' \
-                    -not -name '*.rst' \
-                    -not -name '*.ru' \
-                    -not -name '*.sbt' \
-                    -not -name '*.scss' \
-                    -not -name '*.scss' \
-                    -not -name '*.serialized' \
-                    -not -name '*.sh' \
-                    -not -name '*.snapshot' \
-                    -not -name '*.sql' \
-                    -not -name '*.svg' \
-                    -not -name '*.tar.tz' \
-                    -not -name '*.template' \
-                    -not -name '*.whl' \
-                    -not -name '*.xcconfig' \
-                    -not -name '*.xcoverage.*' \
-                    -not -name '*/classycle/report.xml' \
-                    -not -name '*codecov.yml' \
-                    -not -name '*~' \
-                    -not -name '.*coveragerc' \
-                    -not -name '.coverage*' \
-                    -not -name 'coverage-summary.json' \
-                    -not -name 'createdFiles.lst' \
-                    -not -name 'fullLocaleNames.lst' \
-                    -not -name 'include.lst' \
-                    -not -name 'inputFiles.lst' \
-                    -not -name 'phpunit-code-coverage.xml' \
-                    -not -name 'phpunit-coverage.xml' \
-                    -not -name 'remapInstanbul.coverage*.json' \
-                    -not -name 'scoverage.measurements.*' \
-                    -not -name 'test_*_coverage.txt' \
-                    -not -name 'testrunner-coverage*' \
-                    -print 2>/dev/null"
-  files=$(eval "$patterns" || echo '')
-
-elif [ "$include_cov" != "" ];
-then
-  files=$(eval "find $search_in -type f \( ${include_cov:5} \)$exclude_cov 2>/dev/null" || echo '')
-elif [ "$direct_file_upload" != "" ];
-then
-  files=$direct_file_upload
-fi
-
-num_of_files=$(echo "$files" | wc -l | tr -d ' ')
-if [ "$num_of_files" != '' ] && [ "$files" != '' ];
-then
-  say "    ${e}->${x} Found $num_of_files reports"
-fi
-
-# no files found
-if [ "$files" = "" ];
-then
-  say "${r}-->${x} No coverage report found."
-  say "    Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}"
-  exit ${exit_with};
-fi
-
-if [ "$ft_network" == "1" ];
-then
-  say "${e}==>${x} Detecting git/mercurial file structure"
-  network=$(cd "$git_root" && git ls-files $git_ls_files_recurse_submodules_o 2>/dev/null || hg locate 2>/dev/null || echo "")
-  if [ "$network" = "" ];
-  then
-    network=$(find "$git_root" \( \
-                   -name virtualenv \
-                   -name .virtualenv \
-                   -name virtualenvs \
-                   -name .virtualenvs \
-                   -name '*.png' \
-                   -name '*.gif' \
-                   -name '*.jpg' \
-                   -name '*.jpeg' \
-                   -name '*.md' \
-                   -name .env \
-                   -name .envs \
-                   -name env \
-                   -name envs \
-                   -name .venv \
-                   -name .venvs \
-                   -name venv \
-                   -name venvs \
-                   -name .git \
-                   -name .egg-info \
-                   -name shunit2-2.1.6 \
-                   -name vendor \
-                   -name __pycache__ \
-                   -name node_modules \
-                   -path "*/$bower_components/*" \
-                   -path '*/target/delombok/*' \
-                   -path '*/build/lib/*' \
-                   -path '*/js/generated/coverage/*' \
-                    \) -prune -or \
-                    -type f -print 2>/dev/null || echo '')
-  fi
-
-  if [ "$network_filter_o" != "" ];
-  then
-      network=$(echo "$network" | grep -e "$network_filter_o/*")
-  fi
-  if [ "$prefix_o" != "" ];
-  then
-      network=$(echo "$network" | awk "{print \"$prefix_o/\"\$0}")
-  fi
-fi
-
-upload_file=$(mktemp /tmp/codecov.XXXXXX)
-adjustments_file=$(mktemp /tmp/codecov.adjustments.XXXXXX)
-
-cleanup() {
-    rm -f "$upload_file" "$adjustments_file" "$upload_file.gz"
-}
-
-trap cleanup INT ABRT TERM
-
-
-if [ "$env" != "" ];
-then
-  inc_env=""
-  say "${e}==>${x} Appending build variables"
-  for varname in $(echo "$env" | tr ',' ' ')
-  do
-    if [ "$varname" != "" ];
-    then
-      say "    ${g}+${x} $varname"
-      inc_env="${inc_env}${varname}=$(eval echo "\$${varname}")
-"
-    fi
-  done
-  echo "$inc_env<<<<<< ENV" >> "$upload_file"
-fi
-
-# Append git file list
-# write discovered yaml location
-if [ "$direct_file_upload" = "" ];
-then
-  echo "$yaml" >> "$upload_file"
-fi
-
-if [ "$ft_network" == "1" ];
-then
-  i="woff|eot|otf"  # fonts
-  i="$i|gif|png|jpg|jpeg|psd"  # images
-  i="$i|ptt|pptx|numbers|pages|md|txt|xlsx|docx|doc|pdf|csv"  # docs
-  i="$i|.gitignore"  # supporting docs
-
-  if [ "$ft_html" != "1" ];
-  then
-    i="$i|html"
-  fi
-
-  if [ "$ft_yaml" != "1" ];
-  then
-    i="$i|yml|yaml"
-  fi
-
-  echo "$network" | grep -vwE "($i)$" >> "$upload_file"
-fi
-echo "<<<<<< network" >> "$upload_file"
-
-if [ "$direct_file_upload" = "" ];
-then
-  fr=0
-  say "${e}==>${x} Reading reports"
-  while IFS='' read -r file;
-  do
-    # read the coverage file
-    if [ "$(echo "$file" | tr -d ' ')" != '' ];
-    then
-      if [ -f "$file" ];
-      then
-        report_len=$(wc -c < "$file")
-        if [ "$report_len" -ne 0 ];
-        then
-          say "    ${g}+${x} $file ${e}bytes=$(echo "$report_len" | tr -d ' ')${x}"
-          # append to to upload
-          _filename=$(basename "$file")
-          if [ "${_filename##*.}" = 'gcov' ];
-          then
-            {
-              echo "# path=$(echo "$file.reduced" | sed "s|^$git_root/||")";
-              # get file name
-              head -1 "$file";
-            } >> "$upload_file"
-            # 1. remove source code
-            # 2. remove ending bracket lines
-            # 3. remove whitespace
-            # 4. remove contextual lines
-            # 5. remove function names
-            awk -F': *' '{print $1":"$2":"}' "$file" \
-              | sed '\/: *} *$/d' \
-              | sed 's/^ *//' \
-              | sed '/^-/d' \
-              | sed 's/^function.*/func/' >> "$upload_file"
-          else
-            {
-              echo "# path=${file//^$git_root/||}";
-              cat "$file";
-            } >> "$upload_file"
-          fi
-          echo "<<<<<< EOF" >> "$upload_file"
-          fr=1
-          if [ "$clean" = "1" ];
-          then
-            rm "$file"
-          fi
-        else
-          say "    ${r}-${x} Skipping empty file $file"
-        fi
-      else
-        say "    ${r}-${x} file not found at $file"
-      fi
-    fi
-  done <<< "$(echo -e "$files")"
-
-  if [ "$fr" = "0" ];
-  then
-    say "${r}-->${x} No coverage data found."
-    say "    Please visit ${b}http://docs.codecov.io/docs/supported-languages${x}"
-    say "    search for your projects language to learn how to collect reports."
-    exit ${exit_with};
-  fi
-else
-  cp "$direct_file_upload" "$upload_file"
-  if [ "$clean" = "1" ];
-  then
-    rm "$direct_file_upload"
-  fi
-fi
-
-if [ "$ft_fix" = "1" ];
-then
-  say "${e}==>${x} Appending adjustments"
-  say "    ${b}https://docs.codecov.io/docs/fixing-reports${x}"
-
-  empty_line='^[[:space:]]*$'
-  # //
-  syntax_comment='^[[:space:]]*//.*'
-  # /* or */
-  syntax_comment_block='^[[:space:]]*(\/\*|\*\/)[[:space:]]*$'
-  # { or }
-  syntax_bracket='^[[:space:]]*[\{\}][[:space:]]*(//.*)?$'
-  # [ or ]
-  syntax_list='^[[:space:]]*[][][[:space:]]*(//.*)?$'
-  # func ... {
-  syntax_go_func='^[[:space:]]*[func].*[\{][[:space:]]*$'
-
-  # shellcheck disable=SC2089
-  skip_dirs="-not -path '*/$bower_components/*' \
-             -not -path '*/node_modules/*'"
-
-  cut_and_join() {
-    awk 'BEGIN { FS=":" }
-         $3 ~ /\/\*/ || $3 ~ /\*\// { print $0 ; next }
-         $1!=key { if (key!="") print out ; key=$1 ; out=$1":"$2 ; next }
-         { out=out","$2 }
-         END { print out }' 2>/dev/null
-  }
-
-  if echo "$network" | grep -m1 '.kt$' 1>/dev/null;
-  then
-    # skip brackets and comments
-    cd "$git_root" && \
-      find . -type f \
-             -name '*.kt' \
-             -exec \
-      grep -nIHE -e "$syntax_bracket" \
-                 -e "$syntax_comment_block" {} \; \
-      | cut_and_join \
-      >> "$adjustments_file" \
-      || echo ''
-
-    # last line in file
-    cd "$git_root" && \
-      find . -type f \
-             -name '*.kt' -exec \
-      wc -l {} \; \
-      | while read -r l; do echo "EOF: $l"; done \
-      2>/dev/null \
-      >> "$adjustments_file" \
-      || echo ''
-  fi
-
-  if echo "$network" | grep -m1 '.go$' 1>/dev/null;
-  then
-    # skip empty lines, comments, and brackets
-    cd "$git_root" && \
-      find . -type f \
-             -not -path '*/vendor/*' \
-             -not -path '*/caches/*' \
-             -name '*.go' \
-             -exec \
-      grep -nIHE \
-           -e "$empty_line" \
-           -e "$syntax_comment" \
-           -e "$syntax_comment_block" \
-           -e "$syntax_bracket" \
-           -e "$syntax_go_func" \
-           {} \; \
-      | cut_and_join \
-      >> "$adjustments_file" \
-      || echo ''
-  fi
-
-  if echo "$network" | grep -m1 '.dart$' 1>/dev/null;
-  then
-    # skip brackets
-    cd "$git_root" && \
-      find . -type f \
-             -name '*.dart' \
-             -exec \
-      grep -nIHE \
-           -e "$syntax_bracket" \
-           {} \; \
-      | cut_and_join \
-      >> "$adjustments_file" \
-      || echo ''
-  fi
-
-  if echo "$network" | grep -m1 '.php$' 1>/dev/null;
-  then
-    # skip empty lines, comments, and brackets
-    cd "$git_root" && \
-      find . -type f \
-             -not -path "*/vendor/*" \
-             -name '*.php' \
-             -exec \
-      grep -nIHE \
-           -e "$syntax_list" \
-           -e "$syntax_bracket" \
-           -e '^[[:space:]]*\);[[:space:]]*(//.*)?$' \
-           {} \; \
-      | cut_and_join \
-      >> "$adjustments_file" \
-      || echo ''
-  fi
-
-  if echo "$network" | grep -m1 '\(.c\.cpp\|.cxx\|.h\|.hpp\|.m\|.swift\|.vala\)$' 1>/dev/null;
-  then
-    # skip brackets
-    # shellcheck disable=SC2086,SC2090
-    cd "$git_root" && \
-      find . -type f \
-             $skip_dirs \
-         \( \
-           -name '*.c' \
-           -or -name '*.cpp' \
-           -or -name '*.cxx' \
-           -or -name '*.h' \
-           -or -name '*.hpp' \
-           -or -name '*.m' \
-           -or -name '*.swift' \
-           -or -name '*.vala' \
-         \) -exec \
-      grep -nIHE \
-           -e "$empty_line" \
-           -e "$syntax_bracket" \
-           -e '// LCOV_EXCL' \
-           {} \; \
-      | cut_and_join \
-      >> "$adjustments_file" \
-      || echo ''
-
-    # skip brackets
-    # shellcheck disable=SC2086,SC2090
-    cd "$git_root" && \
-      find . -type f \
-             $skip_dirs \
-         \( \
-           -name '*.c' \
-           -or -name '*.cpp' \
-           -or -name '*.cxx' \
-           -or -name '*.h' \
-           -or -name '*.hpp' \
-           -or -name '*.m' \
-           -or -name '*.swift' \
-           -or -name '*.vala' \
-         \) -exec \
-      grep -nIH '// LCOV_EXCL' \
-           {} \; \
-      >> "$adjustments_file" \
-      || echo ''
-
-  fi
-
-  found=$(< "$adjustments_file" tr -d ' ')
-
-  if [ "$found" != "" ];
-  then
-    say "    ${g}+${x} Found adjustments"
-    {
-      echo "# path=fixes";
-      cat "$adjustments_file";
-      echo "<<<<<< EOF";
-    } >> "$upload_file"
-    rm -rf "$adjustments_file"
-  else
-    say "    ${e}->${x} No adjustments found"
-  fi
-fi
-
-if [ "$url_o" != "" ];
-then
-  url="$url_o"
-fi
-
-if [ "$dump" != "0" ];
-then
-  # trim whitespace from query
-  say "    ${e}->${x} Dumping upload file (no upload)"
-  echo "$url/upload/v4?$(echo "package=$package-$VERSION&token=$token&$query" | tr -d ' ')"
-  cat "$upload_file"
-else
-  if [ "$save_to" != "" ];
-  then
-    say "${e}==>${x} Copying upload file to ${save_to}"
-    mkdir -p "$(dirname "$save_to")"
-    cp "$upload_file" "$save_to"
-  fi
-
-  say "${e}==>${x} Gzipping contents"
-  gzip -nf9 "$upload_file"
-  say "        $(du -h "$upload_file.gz")"
-
-  query=$(echo "${query}" | tr -d ' ')
-  say "${e}==>${x} Uploading reports"
-  say "    ${e}url:${x} $url"
-  say "    ${e}query:${x} $query"
-
-  # Full query without token (to display on terminal output)
-  queryNoToken=$(echo "package=$package-$VERSION&token=secret&$query" | tr -d ' ')
-  # now add token to query
-  query=$(echo "package=$package-$VERSION&token=$token&$query" | tr -d ' ')
-
-  if [ "$ft_s3" = "1" ];
-  then
-    say "${e}->${x}  Pinging Codecov"
-    say "$url/upload/v4?$queryNoToken"
-    # shellcheck disable=SC2086,2090
-    res=$(curl $curl_s -X POST $cacert \
-          --retry 5 --retry-delay 2 --connect-timeout 2 \
-          -H 'X-Reduced-Redundancy: false' \
-          -H 'X-Content-Type: application/x-gzip' \
-          -H 'Content-Length: 0' \
-          --write-out "\n%{response_code}\n" \
-          $curlargs \
-          "$url/upload/v4?$query" || true)
-    # a good reply is "https://codecov.io" + "\n" + "https://storage.googleapis.com/codecov/..."
-    s3target=$(echo "$res" | sed -n 2p)
-    status=$(tail -n1 <<< "$res")
-
-    if [ "$status" = "200" ] && [ "$s3target" != "" ];
-    then
-      say "${e}->${x}  Uploading to"
-      say "${s3target}"
-
-      # shellcheck disable=SC2086
-      s3=$(curl -fiX PUT \
-          --data-binary @"$upload_file.gz" \
-          -H 'Content-Type: application/x-gzip' \
-          -H 'Content-Encoding: gzip' \
-          $curlawsargs \
-          "$s3target" || true)
-
-      if [ "$s3" != "" ];
-      then
-        say "    ${g}->${x} Reports have been successfully queued for processing at ${b}$(echo "$res" | sed -n 1p)${x}"
-        exit 0
-      else
-        say "    ${r}X>${x} Failed to upload"
-      fi
-    elif [ "$status" = "400" ];
-    then
-        # 400 Error
-        say "${r}${res}${x}"
-        exit ${exit_with}
-    else
-        say "${r}${res}${x}"
-    fi
-  fi
-
-  say "${e}==>${x} Uploading to Codecov"
-
-  # shellcheck disable=SC2086,2090
-  res=$(curl -X POST $cacert \
-        --data-binary @"$upload_file.gz" \
-        --retry 5 --retry-delay 2 --connect-timeout 2 \
-        -H 'Content-Type: text/plain' \
-        -H 'Content-Encoding: gzip' \
-        -H 'X-Content-Encoding: gzip' \
-        -H 'Accept: text/plain' \
-        $curlargs \
-        "$url/upload/v2?$query&attempt=$i" || echo 'HTTP 500')
-  # HTTP 200
-  # http://....
-  status=$(echo "$res" | head -1 | cut -d' ' -f2)
-  if [ "$status" = "" ] || [ "$status" = "200" ];
-  then
-    say "    Reports have been successfully queued for processing at ${b}$(echo "$res" | head -2 | tail -1)${x}"
-    exit 0
-  else
-    say "    ${g}${res}${x}"
-    exit ${exit_with}
-  fi
-
-  say "    ${r}X> Failed to upload coverage reports${x}"
-fi
-
-exit ${exit_with}
diff --git a/.github/workflows/go-apidiff.yaml b/.github/workflows/go-apidiff.yaml
index 37a64fe0d..0b0c93942 100644
--- a/.github/workflows/go-apidiff.yaml
+++ b/.github/workflows/go-apidiff.yaml
@@ -8,20 +8,21 @@ on:
     paths:
       - '**'
       - '!doc/**'
+  merge_group:
 
 jobs:
   go-apidiff:
     if: github.event_name == 'pull_request'
     runs-on: ubuntu-latest
     steps:
-    - name: Set up Go
-      uses: actions/setup-go@v2
-      with:
-        go-version: '~1.16'
-      id: go
     - name: Check out code into the Go module directory
-      uses: actions/checkout@v2
+      uses: actions/checkout@v4
       with:
         fetch-depth: 0
+    - name: Set up Go
+      uses: actions/setup-go@v5
+      with:
+        go-version-file: 'go.mod'
+      id: go
     - name: Run go-apidiff
-      uses: joelanford/go-apidiff@master
+      uses: joelanford/go-apidiff@main
diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml
index 1267e452c..30bb9d313 100644
--- a/.github/workflows/goreleaser.yaml
+++ b/.github/workflows/goreleaser.yaml
@@ -6,43 +6,109 @@ on:
     tags:
       - 'v[0-9]+.[0-9]+.[0-9]+'
   pull_request: {}
+  merge_group:
 defaults:
   run:
     shell: bash
 jobs:
-  goreleaser:
+  release:
+    needs:
+      - build-windows
+      - build-darwin
+      - build-linux
+
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v4
+      - uses: actions/download-artifact@v4
+
+      - run: |
+         for dist in dist-*; do
+           tar -C "${dist}" -xf "${dist}/${dist}.tar"
+         done
+
+      - name: Create assets
+        run: |
+          set -xe
+          mkdir -p assets
+          cat dist-*/dist/checksums.txt > assets/checksums.txt
+          for asset in dist-*/dist/*_*/*; do
+            base=$(basename "${asset}")
+            variant=$(basename $(dirname "${asset}") | cut -d_ -f1)
+            cp "${asset}" "assets/${variant}-${base}"
+          done
+          find assets -ls
+          cat assets/checksums.txt
+
+      - name: Upload Release Assets
+        if: github.ref_type == 'tag'
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+        run: gh release create "${{ github.ref_name }}" --generate-notes ./assets/*
+
+  build-windows:
+    runs-on: windows-latest
+    steps:
+      - uses: actions/checkout@v4
         with:
-          # GoReleaser requires fetch-depth: 0 for
-          # changelog generation to work correctly.
+          # GoReleaser requires fetch-depth: 0 to correctly
+          # run git describe
           fetch-depth: 0
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+      - name: "Run GoReleaser"
+        run: make release
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          RELEASE_ARGS: release --skip=validate --clean -f release/goreleaser.windows.yaml ${{ github.event_name == 'pull_request' && '--snapshot' || '' }}
 
-      - uses: actions/setup-go@v2
+      - run: tar -cvf dist-windows.tar dist
+      - uses: actions/upload-artifact@v4
         with:
-          go-version: '~1.16'
+          name: dist-windows
+          path: dist-windows.tar
 
-      - name: "Install linux cross-compilers"
-        run: |
-          sudo apt-get update
-          sudo apt-get install -y gcc-aarch64-linux-gnu gcc-s390x-linux-gnu gcc-powerpc64le-linux-gnu gcc-mingw-w64-x86-64
+  build-darwin:
+    runs-on: macos-latest
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          # GoReleaser requires fetch-depth: 0 to correctly
+          # run git describe
+          fetch-depth: 0
 
-      - name: "Install yq"
-        run: |
-          sudo wget https://github.com/mikefarah/yq/releases/download/v4.10.0/yq_linux_amd64 -O /usr/local/bin/yq
-          sudo chmod +x /usr/local/bin/yq
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+      - name: "Run GoReleaser"
+        run: make release
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          RELEASE_ARGS: release --rm-dist -f release/goreleaser.darwin.yaml --skip=validate ${{ github.event_name == 'pull_request' && '--snapshot' || '' }}
 
-      - name: "Disable image pushes for pull requests"
-        if: github.event_name == 'pull_request'
-        run: |
-          yq eval '.dockers[].skip_push=true' -i .goreleaser.yaml
-          yq eval '.docker_manifests[].skip_push=true' -i .goreleaser.yaml
+      - run: gtar -cvf dist-darwin.tar dist
+      - uses: actions/upload-artifact@v4
+        with:
+          name: dist-darwin
+          path: dist-darwin.tar
 
-      - name: "Disable the Github release upload for non-tag builds"
-        if: startsWith(github.ref, 'refs/tags') != true
+  build-linux:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          # GoReleaser requires fetch-depth: 0 to correctly
+          # run git describe
+          fetch-depth: 0
+
+      - uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+      - name: "Install linux cross-compilers"
         run: |
-          yq eval '.release.disable=true' -i .goreleaser.yaml
+          sudo apt-get update
+          sudo apt-get install -y gcc-aarch64-linux-gnu gcc-s390x-linux-gnu gcc-powerpc64le-linux-gnu
 
       - name: "Set the image tag"
         run: |
@@ -61,17 +127,23 @@ jobs:
 
       - name: "Login to Quay"
         if: github.event_name != 'pull_request'
-        uses: docker/login-action@v1
+        uses: docker/login-action@v3
         with:
           username: ${{ secrets.QUAY_USERNAME }}
           password: ${{ secrets.QUAY_PASSWORD }}
           registry: quay.io
 
       - name: Set up QEMU
-        uses: docker/setup-qemu-action@v1
+        uses: docker/setup-qemu-action@v3
 
       - name: "Run GoReleaser"
         run: make release
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          RELEASE_ARGS: release --rm-dist ${{ !startsWith(github.ref, 'refs/tags') && '--skip-validate' || '' }}
+          RELEASE_ARGS: release --rm-dist -f release/goreleaser.linux.yaml --skip=validate ${{ github.event_name == 'pull_request' && '--snapshot' || '' }}
+
+      - run: tar -cvf dist-linux.tar dist
+      - uses: actions/upload-artifact@v4
+        with:
+          name: dist-linux
+          path: dist-linux.tar
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
deleted file mode 100644
index 6d05f2f7d..000000000
--- a/.github/workflows/release.yaml
+++ /dev/null
@@ -1,48 +0,0 @@
-name: release
-on:
-  push:
-    tags:
-      - 'v[0-9]+.[0-9]+.[0-9]+'
-defaults:
-  run:
-    shell: bash
-jobs:
-  create:
-    runs-on: ubuntu-latest
-    outputs:
-      upload_url: ${{ steps.release.outputs.upload_url }}
-    steps:
-      - uses: actions/create-release@v1
-        id: release
-        env:
-          GITHUB_TOKEN: ${{ github.token }}
-        with:
-          draft: true
-          tag_name: ${{ github.ref }}
-          release_name: ${{ github.ref }}
-  assets:
-    needs: create
-    strategy:
-      matrix:
-        os:
-          - ubuntu-latest
-          - macos-latest
-          - windows-latest
-    runs-on: ${{ matrix.os }}
-    steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-go@v2
-        with:
-          go-version: '~1.16'
-      - run: |
-          echo "asset_path=bin/opm" >> $GITHUB_ENV
-          echo "asset_name=$(go env GOOS)-$(go env GOARCH)-opm$(go env GOEXE)" >> $GITHUB_ENV
-      - run: make ${{ env.asset_path }}
-      - uses: actions/upload-release-asset@v1
-        env:
-          GITHUB_TOKEN: ${{ github.token }}
-        with:
-          upload_url: ${{ needs.create.outputs.upload_url }}
-          asset_path: ${{ env.asset_path }}
-          asset_name: ${{ env.asset_name }}
-          asset_content_type: application/octet-stream
diff --git a/.github/workflows/retest.yaml b/.github/workflows/retest.yaml
deleted file mode 100644
index 5886e8946..000000000
--- a/.github/workflows/retest.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-on:
-  issue_comment:
-    types: [created]
-
-jobs:
-  rerun_pr_tests:
-    name: rerun_pr_tests
-    if: ${{ github.event.issue.pull_request }}
-    runs-on: ubuntu-20.04
-    steps:
-    - uses: estroz/rerun-actions@main
-      with:
-        repo_token: ${{ secrets.GITHUB_TOKEN }}
-        comment_id: ${{ github.event.comment.id }}
diff --git a/.github/workflows/sanity.yaml b/.github/workflows/sanity.yaml
index 39c61419f..68d8b6d36 100644
--- a/.github/workflows/sanity.yaml
+++ b/.github/workflows/sanity.yaml
@@ -8,16 +8,17 @@ on:
     paths:
       - '**'
       - '!doc/**'
+  merge_group:
 
 jobs:
   sanity:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-go@v2
+      - uses: actions/checkout@v4
+      - uses: actions/setup-go@v5
         with:
-          go-version: '~1.16'
+          go-version-file: "go.mod"
       - name: Install goimports
         run: go install golang.org/x/tools/cmd/goimports@latest
-      - name: Run sanity checks
-        run: make vendor && make lint && git diff --exit-code
+      - name: Run verify checks
+        run: make verify
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 189089586..a353509cf 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -7,21 +7,20 @@ on:
     paths:
       - '**'
       - '!doc/**'
+  merge_group:
+
 jobs:
   e2e:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-go@v2
+      - uses: actions/checkout@v4
+      - uses: actions/setup-go@v5
         with:
-          go-version: '~1.16'
+          go-version-file: 'go.mod'
       - name: Install podman
         run: |
-          . /etc/os-release
-          echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
-          curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
           sudo apt-get update
-          sudo apt-get -y install conntrack podman
+          sudo apt-get -y install podman
           podman version
       - name: Create kind cluster and setup local docker registry
         run: |
diff --git a/.github/workflows/unit.yaml b/.github/workflows/unit.yaml
index 0f97ca0d6..26634c6a2 100644
--- a/.github/workflows/unit.yaml
+++ b/.github/workflows/unit.yaml
@@ -8,15 +8,20 @@ on:
     paths:
       - '**'
       - '!doc/**'
+  merge_group:
 
 jobs:
   unit:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-go@v2
+      - uses: actions/checkout@v4
+      - uses: actions/setup-go@v5
         with:
-          go-version: '~1.16'
+          go-version-file: "go.mod"
       - run: make unit
       - run: sed -i'' "s:^github.com/$GITHUB_REPOSITORY/::" coverage.out
-      - run: .github/workflows/codecov.sh -Z -f coverage.out
+      - uses: codecov/codecov-action@v5
+        with:
+          disable_search: true
+          files: coverage.out
+          token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.gitignore b/.gitignore
index fe176ef93..e36468cc8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -179,7 +179,6 @@ tags
 *.userprefs
 
 # Build results
-[Dd]ebug/
 [Dd]ebugPublic/
 x64/
 x86/
@@ -470,3 +469,10 @@ test/e2e/index_tmp*
 
 # don't check in the certs directory
 certs/*
+
+# ignore temp artifacts of building images
+pkg/lib/indexer/index.Dockerfile*
+
+# ignore vendor since we don't commit it
+vendor/*
+
diff --git a/.golangci.yaml b/.golangci.yaml
new file mode 100644
index 000000000..0bc5d1097
--- /dev/null
+++ b/.golangci.yaml
@@ -0,0 +1,83 @@
+########
+# NOTE
+#
+#  This file is duplicated in the following repos:
+#    - operator-framework/kubectl-operator
+#    - operator-framework/catalogd
+#    - operator-framework/operator-controller
+#    - operator-framework/operator-registry
+#
+#  If you are making a change, please make it in ALL
+#  of the above repositories!
+#
+#  TODO: Find a way to have a shared golangci config.
+########
+
+run:
+  # Default timeout is 1m, up to give more room
+  timeout: 4m
+
+linters:
+  enable:
+  - asciicheck
+  - bodyclose
+  - errorlint
+  - gci
+  - gofmt
+  - govet
+  - gosec
+  - importas
+  - misspell
+  - nestif
+  - nonamedreturns
+  - prealloc
+  - stylecheck
+  - testifylint
+  - tparallel
+  - unconvert
+  - unparam
+  - unused
+  - whitespace
+
+linters-settings:
+  gci:
+    sections:
+      - standard
+      - dot
+      - default
+      - prefix(github.com/operator-framework)
+      - localmodule
+    custom-order: true
+
+  errorlint:
+    errorf: false
+
+  importas:
+    alias:
+    - pkg: k8s.io/apimachinery/pkg/apis/meta/v1
+      alias: metav1
+    - pkg: k8s.io/apimachinery/pkg/api/errors
+      alias: apierrors
+    - pkg: k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1
+      alias: apiextensionsv1
+    - pkg: k8s.io/apimachinery/pkg/util/runtime
+      alias: utilruntime
+    - pkg: "^k8s\\.io/api/([^/]+)/(v[^/]+)$"
+      alias: $1$2
+    - pkg: sigs.k8s.io/controller-runtime
+      alias: ctrl
+    - pkg: github.com/blang/semver/v4
+      alias: bsemver
+
+issues:
+  # exclusion rules, mostly to avoid functionally complete areas and reduce unit test noise
+  exclude-rules:
+    - path: _test\.go
+      linters:
+        - unused
+        - govet
+
+
+output:
+  formats:
+    - format: tab
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
deleted file mode 100644
index 8049d451c..000000000
--- a/.goreleaser.yaml
+++ /dev/null
@@ -1,174 +0,0 @@
-builds:
-  - id: linux-amd64
-    main: ./cmd/opm
-    binary: opm
-    goos:
-      - linux
-    goarch:
-      - amd64
-    env:
-      - CC=gcc
-      - CGO_ENABLED=1
-    mod_timestamp: "{{ .CommitTimestamp }}"
-    flags: &build-flags
-      - -tags=json1,netgo,osusergo
-    asmflags: &build-asmflags
-      - all=-trimpath={{ .Env.PWD }}
-    gcflags: &build-gcflags
-      - all=-trimpath={{ .Env.PWD }}
-    ldflags: &build-ldflags
-      - -s -w
-      - -extldflags=-static
-      - -X {{ .Env.PKG }}/cmd/opm/version.gitCommit={{ .Env.GIT_COMMIT }}
-      - -X {{ .Env.PKG }}/cmd/opm/version.opmVersion={{ .Env.OPM_VERSION }}
-      - -X {{ .Env.PKG }}/cmd/opm/version.buildDate={{ .Env.BUILD_DATE }}
-  - id: linux-arm64
-    main: ./cmd/opm
-    binary: opm
-    goos:
-      - linux
-    goarch:
-      - arm64
-    env:
-      - CC=aarch64-linux-gnu-gcc
-      - CGO_ENABLED=1
-    mod_timestamp: "{{ .CommitTimestamp }}"
-    flags: *build-flags
-    asmflags: *build-asmflags
-    gcflags: *build-gcflags
-    ldflags: *build-ldflags
-  - id: linux-ppc64le
-    main: ./cmd/opm
-    binary: opm
-    goos:
-      - linux
-    goarch:
-      - ppc64le
-    env:
-      - CC=powerpc64le-linux-gnu-gcc
-      - CGO_ENABLED=1
-    mod_timestamp: "{{ .CommitTimestamp }}"
-    flags: *build-flags
-    asmflags: *build-asmflags
-    gcflags: *build-gcflags
-    ldflags: *build-ldflags
-  - id: linux-s390x
-    main: ./cmd/opm
-    binary: opm
-    goos:
-      - linux
-    goarch:
-      - s390x
-    env:
-      - CC=s390x-linux-gnu-gcc
-      - CGO_ENABLED=1
-    mod_timestamp: "{{ .CommitTimestamp }}"
-    flags: *build-flags
-    asmflags: *build-asmflags
-    gcflags: *build-gcflags
-    ldflags: *build-ldflags
-  - id: windows-amd64
-    main: ./cmd/opm
-    binary: opm
-    goos:
-      - windows
-    goarch:
-      - amd64
-    env:
-      - CC=x86_64-w64-mingw32-gcc-posix
-      - CGO_ENABLED=1
-    mod_timestamp: "{{ .CommitTimestamp }}"
-    flags: *build-flags
-    asmflags: *build-asmflags
-    gcflags: *build-gcflags
-    ldflags: *build-ldflags
-archives:
-  - id: opm
-    builds:
-      - linux-amd64
-      - linux-arm64
-      - linux-ppc64le
-      - linux-s390x
-      - windows-amd64
-    name_template: "{{ .Binary }}_{{ .Env.OPM_VERSION }}_{{ .Os }}_{{ .Arch }}"
-    format: binary
-dockers:
-  - image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-amd64"
-    ids: ["linux-amd64"]
-    goos: linux
-    goarch: amd64
-    dockerfile: release/goreleaser.opm.Dockerfile
-    extra_files: ["nsswitch.conf"]
-    use: buildx
-    build_flag_templates:
-      - --platform=linux/amd64
-  - image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-arm64"
-    ids: ["linux-arm64"]
-    goos: linux
-    goarch: arm64
-    dockerfile: release/goreleaser.opm.Dockerfile
-    extra_files: ["nsswitch.conf"]
-    use: buildx
-    build_flag_templates:
-      - --platform=linux/arm64
-  - image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-ppc64le"
-    ids: ["linux-ppc64le"]
-    goos: linux
-    goarch: ppc64le
-    dockerfile: release/goreleaser.opm.Dockerfile
-    extra_files: ["nsswitch.conf"]
-    use: buildx
-    build_flag_templates:
-      - --platform=linux/ppc64le
-  - image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-s390x"
-    ids: ["linux-s390x"]
-    goos: linux
-    goarch: s390x
-    dockerfile: release/goreleaser.opm.Dockerfile
-    extra_files: ["nsswitch.conf"]
-    use: buildx
-    build_flag_templates:
-      - --platform=linux/s390x
-docker_manifests:
-  # IMAGE_TAG is either set by the Makefile or the goreleaser action workflow,
-  # This image is intended to be tagged/pushed on all trunk (master, release branch) commits and tags.
-  - name_template: "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}"
-    image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-amd64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-arm64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-ppc64le"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-s390x"
-  # Release image builds will be skipped if *_IMAGE_OR_EMPTY variables are empty.
-  # https://github.com/goreleaser/goreleaser/blob/9ed3c0c/internal/pipe/docker/manifest.go#L105
-  - name_template: "{{ .Env.MAJ_MIN_IMAGE_OR_EMPTY }}"
-    image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-amd64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-arm64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-ppc64le"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-s390x"
-  - name_template: "{{ .Env.MAJ_IMAGE_OR_EMPTY }}"
-    image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-amd64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-arm64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-ppc64le"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-s390x"
-  - name_template: "{{ .Env.LATEST_IMAGE_OR_EMPTY }}"
-    image_templates:
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-amd64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-arm64"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-ppc64le"
-      - "{{ .Env.OPM_IMAGE_REPO }}:{{ .Env.IMAGE_TAG }}-s390x"
-checksum:
-  name_template: 'checksums.txt'
-snapshot:
-  name_template: "{{ .Env.OPM_VERSION }}"
-release:
-  name_template: "{{ .Env.OPM_VERSION }}"
-  draft: true
-  ## Disable release steps, since a separate GitHub Action job
-  ## handles binary builds and release uploads
-  disable: true
diff --git a/DCO b/DCO
new file mode 100644
index 000000000..8201f9921
--- /dev/null
+++ b/DCO
@@ -0,0 +1,37 @@
+Developer Certificate of Origin
+Version 1.1
+
+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
+1 Letterman Drive
+Suite D4700
+San Francisco, CA, 94129
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+
+Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 02a32b433..000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,37 +0,0 @@
-FROM registry.ci.openshift.org/ocp/builder:rhel-8-golang-1.16-openshift-4.8 AS builder
-
-ENV GOPATH /go
-ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
-
-WORKDIR /src
-
-COPY . .
-RUN make build cross
-
-# copy and build vendored grpc_health_probe
-RUN CGO_ENABLED=0 go build -mod=vendor -tags netgo -ldflags "-w" ./vendor/github.com/grpc-ecosystem/grpc-health-probe/...
-
-FROM registry.ci.openshift.org/ocp/4.8:base
-
-COPY --from=builder /src/bin/* /bin/registry/
-COPY --from=builder /src/grpc-health-probe /bin/grpc_health_probe
-
-RUN ln -s /bin/registry/* /bin
-
-RUN mkdir /registry
-RUN chgrp -R 0 /registry && \
-    chmod -R g+rwx /registry
-WORKDIR /registry
-
-# This image doesn't need to run as root user
-USER 1001
-
-EXPOSE 50051
-
-ENTRYPOINT ["/bin/registry-server"]
-CMD ["--database", "/bundles.db"]
-
-LABEL io.k8s.display-name="OpenShift Operator Registry" \
-      io.k8s.description="This is a component of OpenShift Operator Lifecycle Manager and is the base for operator catalog API containers." \
-      maintainer="Odin Team <aos-odin@redhat.com>" \
-      summary="Operator Registry runs in a Kubernetes or OpenShift cluster to provide operator catalog data to Operator Lifecycle Manager."
diff --git a/Makefile b/Makefile
index 41c1674e5..c2992c598 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,27 @@
 SHELL = /bin/bash
-GO := GOFLAGS="-mod=vendor" go
+GO := go
 CMDS := $(addprefix bin/, $(shell ls ./cmd | grep -v opm))
 OPM := $(addprefix bin/, opm)
 SPECIFIC_UNIT_TEST := $(if $(TEST),-run $(TEST),)
+SPECIFIC_SKIP_UNIT_TEST := $(if $(SKIP),-skip $(SKIP),)
 extra_env := $(GOENV)
 export PKG := github.com/operator-framework/operator-registry
 export GIT_COMMIT := $(or $(SOURCE_GIT_COMMIT),$(shell git rev-parse --short HEAD))
 export OPM_VERSION := $(or $(SOURCE_GIT_TAG),$(shell git describe --always --tags HEAD))
 export BUILD_DATE := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
 
+.DEFAULT_GOAL := all
+
+# bingo manages consistent tooling versions for things like kind, kustomize, etc.
+include .bingo/Variables.mk
+
+# protoc is not a go binary, so we need a custom recipe for it.
+PROTOC := ./tools/bin/protoc
+PROTOC_VERSION := 27.0
+.PHONY: $(PROTOC)
+$(PROTOC):
+	./scripts/ensure-protoc.sh $(PROTOC_VERSION)
+
 # define characters
 null  :=
 space := $(null) #
@@ -60,7 +73,16 @@ static: build
 
 .PHONY: unit
 unit:
-	$(GO) test -coverprofile=coverage.out $(SPECIFIC_UNIT_TEST) $(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/...
+	$(GO) test -coverprofile=coverage.out $(SPECIFIC_UNIT_TEST) $(SPECIFIC_SKIP_UNIT_TEST) $(TAGS) $(TEST_RACE) -count=1 ./pkg/... ./alpha/...
+
+.PHONY: tidy
+tidy:
+	go mod tidy
+	go mod verify
+
+.PHONY: verify
+verify: tidy codegen lint
+	git diff --exit-code
 
 .PHONY: sanity-check
 sanity-check:
@@ -74,37 +96,32 @@ sanity-check:
 	docker run --rm -it -v "$(shell pwd)"/pkg/lib/indexer/testdata/:/database sanity-container \
 		./bin/opm registry serve --database /database/bundles.db --timeout-seconds 1
 
-.PHONY: image
-image:
-	docker build .
 
 .PHONY: image-upstream
 image-upstream:
 	docker build -f upstream-example.Dockerfile .
 
-.PHONY: vendor
-vendor:
-	$(GO) mod tidy
-	$(GO) mod vendor
-	$(GO) mod verify
-
 .PHONY: lint
-lint:
-	find . -name '*.go' -not -path "./vendor/*" | xargs goimports -w
+#lint:
+#	find . -type f -name '*.go' ! -name '*.pb.go' -print0 | xargs -0 goimports -w
+lint: $(GOLANGCI_LINT)
+	$(GOLANGCI_LINT) run $(GOLANGCI_LINT_ARGS)
+
+.PHONY: fix-lint
+fix-lint: $(GOLANGCI_LINT)
+	$(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_ARGS)
+
+.PHONY: bingo-upgrade
+bingo-upgrade: $(BINGO) #EXHELP Upgrade tools
+	@for pkg in $$($(BINGO) list | awk '{ print $$3 }' | tail -n +3 | sed 's/@.*//'); do \
+		echo -e "Upgrading \033[35m$$pkg\033[0m to latest..."; \
+		$(BINGO) get "$$pkg@latest"; \
+	done
 
 .PHONY: codegen
-codegen:
-	protoc -I pkg/api/ --go_out=pkg/api pkg/api/*.proto
-	protoc -I pkg/api/ --go-grpc_out=pkg/api pkg/api/*.proto
-	protoc -I pkg/api/grpc_health_v1 --go_out=pkg/api/grpc_health_v1 pkg/api/grpc_health_v1/*.proto
-	protoc -I pkg/api/grpc_health_v1 --go-grpc_out=pkg/api/grpc_health_v1 pkg/api/grpc_health_v1/*.proto
-
-.PHONY: container-codegen
-container-codegen:
-	docker build -t operator-registry:codegen -f codegen.Dockerfile .
-	docker run --name temp-codegen operator-registry:codegen /bin/true
-	docker cp temp-codegen:/codegen/pkg/api/. ./pkg/api
-	docker rm temp-codegen
+codegen: $(PROTOC) $(PROTOC_GEN_GO_GRPC)
+	$(PROTOC) --plugin=protoc-gen-go=$(PROTOC_GEN_GO_GRPC) -I pkg/api/ --go_out=pkg/api pkg/api/*.proto
+	$(PROTOC) --plugin=protoc-gen-go-grpc=$(PROTOC_GEN_GO_GRPC) -I pkg/api/ --go-grpc_out=pkg/api pkg/api/*.proto
 
 .PHONY: generate-fakes
 generate-fakes:
@@ -115,15 +132,14 @@ clean:
 	@rm -rf ./bin
 
 .PHONY: e2e
-e2e:
-	$(GO) run github.com/onsi/ginkgo/ginkgo --v --randomizeAllSpecs --randomizeSuites --race $(if $(TEST),-focus '$(TEST)') $(TAGS) ./test/e2e -- $(if $(SKIPTLS),-skip-tls true)
-
+e2e: $(GINKGO)
+	$(GINKGO) --v --randomize-all --progress --trace --randomize-suites --race $(if $(TEST),-focus '$(TEST)') $(TAGS) ./test/e2e -- $(if $(SKIPTLS),-skip-tls-verify true) $(if $(USEHTTP),-use-http true)
 
 .PHONY: release
 export OPM_IMAGE_REPO ?= quay.io/operator-framework/opm
 export IMAGE_TAG ?= $(OPM_VERSION)
-export MAJ_MIN_IMAGE_OR_EMPTY ?= $(call tagged-or-empty,$(shell echo $(OPM_VERSION) | grep -Eo 'v[0-9]+\.[0-9]+'))
-export MAJ_IMAGE_OR_EMPTY ?= $(call tagged-or-empty,$(shell echo $(OPM_VERSION) | grep -Eo 'v[0-9]+'))
+export MAJ_MIN_IMAGE_OR_EMPTY := $(call tagged-or-empty,$(shell echo $(OPM_VERSION) | grep -Eo 'v[0-9]+\.[0-9]+'))
+export MAJ_IMAGE_OR_EMPTY := $(call tagged-or-empty,$(shell echo $(OPM_VERSION) | grep -Eo 'v[0-9]+'))
 # LATEST_TAG is the latest semver tag in HEAD. Used to deduce whether
 # OPM_VERSION is the new latest tag, or a prior minor/patch tag, below.
 # NOTE: this can only be relied upon if full git history is present.
@@ -133,13 +149,31 @@ LATEST_TAG := $(shell git tag -l | tr - \~ | sort -V | tr \~ - | tail -n1)
 # is not a prerelase tag and == LATEST_TAG, otherwise the empty string.
 # An empty string causes goreleaser to skip building the manifest image for latest,
 # which we do not want when cutting a non-latest release (old minor/patch tag).
-export LATEST_IMAGE_OR_EMPTY ?= $(shell \
+export LATEST_IMAGE_OR_EMPTY := $(shell \
 	echo $(OPM_VERSION) | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$$' \
 	&& [ "$(shell echo -e "$(OPM_VERSION)\n$(LATEST_TAG)" | sort -rV | head -n1)" == "$(OPM_VERSION)" ] \
 	&& echo "$(OPM_IMAGE_REPO):latest" || echo "")
-release: RELEASE_ARGS ?= release --rm-dist --snapshot
+RELEASE_GOOS := $(shell go env GOOS)
+RELEASE_ARGS ?= release --clean --snapshot -f release/goreleaser.$(RELEASE_GOOS).yaml
+
+# Note: bingo does not yet support windows (https://github.com/bwplotka/bingo/issues/26)
+# so GOOS=windows gets its own way to install goreleaser
+ifeq ($(RELEASE_GOOS), windows)
+GORELEASER := $(shell pwd)/bin/goreleaser
+release: windows-goreleaser-install
+else
+release: $(GORELEASER)
+endif
 release:
-	./scripts/fetch goreleaser 0.177.0 && ./bin/goreleaser $(RELEASE_ARGS)
+	$(GORELEASER) $(RELEASE_ARGS)
+
+.PHONY: windows-goreleaser-install
+windows-goreleaser-install:
+	# manually install goreleaser from the bingo directory in the same way bingo (currently) installs it.
+	# This is done to ensure the same version of goreleaser is used across all platforms
+	mkdir -p $(dir $(GORELEASER))
+	@echo "(re)installing $(GORELEASER)"
+	GOWORK=off $(GO) build -mod=mod -modfile=.bingo/goreleaser.mod -o=$(GORELEASER) "github.com/goreleaser/goreleaser"
 
 # tagged-or-empty returns $(OPM_IMAGE_REPO):$(1) when HEAD is assigned a non-prerelease semver tag,
 # otherwise the empty string. An empty string causes goreleaser to skip building
@@ -151,3 +185,4 @@ $(shell \
 	&& git describe --tags --exact-match HEAD >/dev/null 2>&1 \
 	&& echo "$(OPM_IMAGE_REPO):$(1)" || echo "" )
 endef
+
diff --git a/OWNERS b/OWNERS
index 492072e22..67ce7f24c 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,27 +1,32 @@
 # approval == this is a good idea /approve
 approvers:
-  - ecordell
-  - njhale
+  - awgreene
   - dinhxuanvu
-  - kevinrizza
-  - benluddy
+  - grokspawn
   - joelanford
+  - kevinrizza
+  - njhale
+  - oceanc80
+  - perdasilva
 # review == this code is good /lgtm
 reviewers:
-  - ecordell
-  - njhale
-  - dinhxuanvu
-  - kevinrizza
-  - gallettilance
   - anik120
-  - exdx
+  - ankitathomas
   - awgreene
   - benluddy
-  - hasbro17
-  - ankitathomas
-  - estroz
-  - joelanford
+  - dinhxuanvu
+  - everettraven
+  - exdx
+  - gallettilance
+  - grokspawn
   - jmrodri
-  - timflannagan
+  - joelanford
+  - kevinrizza
+  - njhale
+  - oceanc80
+  - perdasilva
+  - rashmigottipati
+  - theishshah
+  - varshaprasad96
 # Bugzilla component
 component: "OLM"
diff --git a/README.md b/README.md
index 5cea5f90f..8e1ea563c 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,13 @@
 
 Operator Registry runs in a Kubernetes or OpenShift cluster to provide operator catalog data to [Operator Lifecycle Manager](https://github.com/operator-framework/operator-lifecycle-manager).
 
+# Certificate of Origin
+
+By contributing to this project you agree to the Developer Certificate of
+Origin (DCO). This document was created by the Linux Kernel community and is a
+simple statement that you, as a contributor, have the legal right to make the
+contribution. See the [DCO](DCO) file for details.
+
 # Overview
 
 This project provides the following binaries:
@@ -256,11 +263,11 @@ grpcurl -plaintext -d '{"pkgName":"etcd","channelName":"alpha"}' localhost:50051
 ```json
 {
   "csvName": "etcdoperator.v0.9.2",
-  "csvJson": "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"iVBORw0KGgoAAAANSUhEUgAAAOEAAADZCAYAAADWmle6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAEKlJREFUeNrsndt1GzkShmEev4sTgeiHfRYdgVqbgOgITEVgOgLTEQydwIiKwFQCayoCU6+7DyYjsBiBFyVVz7RkXvqCSxXw/+f04XjGQ6IL+FBVuL769euXgZ7r39f/G9iP0X+u/jWDNZzZdGI/Ftama1jjuV4BwmcNpbAf1Fgu+V/9YRvNAyzT2a59+/GT/3hnn5m16wKWedJrmOCxkYztx9Q+py/+E0GJxtJdReWfz+mxNt+QzS2Mc0AI+HbBBwj9QViKbH5t64DsP2fvmGXUkWU4WgO+Uve2YQzBUGd7r+zH2ZG/tiUQc4QxKwgbwFfVGwwmdLL5wH78aPC/ZBem9jJpCAX3xtcNASSNgJLzUPSQyjB1zQNl8IQJ9MIU4lx2+Jo72ysXYKl1HSzN02BMa/vbZ5xyNJIshJzwf3L0dQhJw4Sih/SFw9Tk8sVeghVPoefaIYCkMZCKbrcP9lnZuk0uPUjGE/KE8JQry7W2tgfuC3vXgvNV+qSQbyFtAtyWk7zWiYevvuUQ9QEQCvJ+5mmu6dTjz1zFHLFj8Eb87MtxaZh/IQFIHom+9vgTWwZxAQjT9X4vtbEVPojwjiV471s00mhAckpwGuCn1HtFtRDaSh6y9zsL+LNBvCG/24ThcxHObdlWc1v+VQJe8LcO0jwtuF8BwnAAUgP9M8JPU2Me+Oh12auPGT6fHuTePE3bLDy+x9pTLnhMn+07TQGh//Bz1iI0c6kvtqInjvPZcYR3KsPVmUsPYt9nFig9SCY8VQNhpPBzn952bbgcsk2EvM89wzh3UEffBbyPqvBUBYQ8ODGPFOLsa7RF096WJ69L+E4EmnpjWu5o4ChlKaRTKT39RMMaVPEQRsz/nIWlDN80chjdJlSd1l0pJCAMVZsniobQVuxceMM9OFoaMd9zqZtjMEYYDW38Drb8Y0DYPLShxn0pvIFuOSxd7YCPet9zk452wsh54FJoeN05hcgSQoG5RR0Qh9Q4E4VvL4wcZq8UACgaRFEQKgSwWrkr5WFnGxiHSutqJGlXjBgIOayhwYBTA0ER0oisIVSUV0AAMT0IASCUO4hRIQSAEECMCCEPwqyQA0JCQBzEGjWNAqHiUVAoXUWbvggOIQCEAOJzxTjoaQ4AIaE64/aZridUsBYUgkhB15oGg1DBIl8IqirYwV6hPSGBSFteMCUBSVXwfYixBmamRubeMyjzMJQBDDowE3OesDD+zwqFoDqiEwXoXJpljB+PvWJGy75BKF1FPxhKygJuqUdYQGlLxNEXkrYyjQ0GbaAwEnUIlLRNvVjQDYUAsJB0HKLE4y0AIpQNgCIhBIhQTgCKhZBBpAN/v6LtQI50JfUgYOnnjmLUFHKhjxbAmdTCaTiBm3ovLPqG2urWAij6im0Nd9aTN9ygLUEt9LgSRnohxUPIKxlGaE+/6Y7znFf0yX+GnkvFFWmarkab2o9PmTeq8sbd2a7DaysXz7i64VeznN4jCQhN9gdDbRiuWrfrsq0mHIrlaq+hlotCtd3Um9u0BYWY8y5D67wccJoZjFca7iUs9VqZcfsZwTd1sbWGG+OcYaTnPAP7rTQVVlM4Sg3oGvB1tmNh0t/HKXZ1jFoIMwCQjtqbhNxUmkGYqgZEDZP11HN/S3gAYRozf0l8C5kKEKUvW0t1IfeWG/5MwgheZTT1E0AEhDkAePQO+Ig2H3DncAkQM4cwUQCD530dU4B5Yvmi2LlDqXfWrxMCcMth51RToRMNUXFnfc2KJ0+Ryl0VNOUwlhh6NoxK5gnViTgQpUG4SqSyt5z3zRJpuKmt3Q1614QaCBPaN6je+2XiFcWAKOXcUfIYKRyL/1lb7pe5VxSxxjQ6hImshqGRt5GWZVKO6q2wHwujfwDtIvaIdexj8Cm8+a68EqMfox6x/voMouZF4dHnEGNeCDMwT6vdNfekH1MafMk4PI06YtqLVGl95aEM9Z5vAeCTOA++YLtoVJRrsqNCaJ6WRmkdYaNec5BT/lcTRMqrhmwfjbpkj55+OKp8IEbU/JLgPJE6Wa3TTe9sHS+ShVD5QIyqIxMEwKh12olC6mHIed5ewEop80CNlfIOADYOT2nd6ZXCop+Ebqchc0JqxKcKASxChycJgUh1rnHA5ow9eTrhqNI7JWiAYYwBGGdpyNLoGw0Pkh96h1BpHihyywtATDM/7Hk2fN9EnH8BgKJCU4ooBkbXFMZJiPbrOyecGl3zgQDQL4hk10IZiOe+5w99Q/gBAEIJgPhJM4QAEEoFREAIAAEiIASAkD8Qt4AQAEIAERAGFlX4CACKAXGVM4ivMwWwCLFAlyeoaa70QePKm5Dlp+/n+ye/5dYgva6YsUaVeMa+tzNFeJtWwc+udbJ0Fg399kLielQJ5Ze61c2+7ytA6EZetiPxZC6tj22yJCv6jUwOyj/zcbqAxOMyAKEbfeHtNa7DtYXptjsk2kJxR+eIeim/tHNofUKYy8DMrQcAKWz6brpvzyIAlpwPhQ49l6b7skJf5Z+YTOYQc4FwLDxvoTDwaygQK+U/kVr+ytSFBG01Q3gnJJR4cNiAhx4HDub8/b5DULXlj6SVZghFiE+LdvE9vo/o8Lp1RmH5hzm0T6wdbZ6n+D6i44zDRc3ln6CpAEJfXiRU45oqLz8gFAThWsh7ughrRibc0QynHgZpNJa/ENJ+loCwu/qOGnFIjYR/n7TfgycULhcQhu6VC+HfF+L3BoAQ4WiZTw1M+FPCnA2gKC6/FAhXgDC+ojQGh3NuWsvfF1L/D5ohlCKtl1j2ldu9a/nPAKFwN56Bst10zCG0CPleXN/zXPgHQZXaZaBgrbzyY5V/mUA+6F0hwtGN9rwu5DVZPuwWqfxdFz1LWbJ2lwKEa+0Qsm4Dl3fp+Pu0lV97PgwIPfSsS+UQhj5Oo+vvFULazRIQyvGEcxPuNLCth2MvFsrKn8UOilAQShkh7TTczYNMoS6OdP47msrPi82lXKGWhCdMZYS0bFy+vcnGAjP1CIfvgbKNA9glecEH9RD6Ol4wRuWyN/G9MHnksS6o/GPf5XcwNSUlHzQhDuAKtWJmkwKElU7lylP5rgIcsquh/FI8YZCDpkJBuE4FQm7Icw8N+SrUGaQKyi8FwiDt1ve5o+Vu7qYHy/psgK8cvh+FTYuO77bhEC7GuaPiys/L1X4IgXDL+e3M5+ovLxBy5VLuIebw1oqcHoPfoaMJUsHays878r8KbDc3xtPx/84gZPBG/JwaufrsY/SRG/OY3//8QMNdsvdZCFtbW6f8pFuf5bflILAlX7O+4fdfugKyFYS8T2zAsXthdG0VurPGKwI06oF5vkBgHWkNp6ry29+lsPZMU3vijnXFNmoclr+6+Ou/FIb8yb30sS8YGjmTqCLyQsi5N/6ZwKs0Yenj68pfPjF6N782Dp2FzV9CTyoSeY8mLK16qGxIkLI8oa1n8tz9juP40DlK0epxYEbojbq+9QfurBeVIlCO9D2396bxiV4lkYQ3hOAFw2pbhqMGISkkQOMcQ9EqhDmGZZdo92JC0YHRNTfoSg+5e0IT+opqCKHoIU+4ztQIgBD1EFNrQAgIpYSil9lDmPHqkROPt+JC6AgPquSuumJmg0YARVCuneDfvPVeJokZ6pIXDkNxQtGzTF9/BQjRG0tQznfb74RwCQghpALBtIQnfK4zhxdyQvVCUeknMIT3hLyY+T5jo0yABqKPQNpUNw/09tGZod5jgCaYFxyYvJcNPkv9eof+I3pnCFEHIETjSM8L9tHZHYCQT9PaZGycU6yg8S4akDnJ+P03L0+t23XGzCLzRgII/Wqa+fv/xlfvmKvMUOcOrlCDdoei1MGdZm6G5VEIfRzzjd4aQs69n699Rx7ewhvCGzr2gmTPs8zNsJOrXt24FbkhhOjCfT4ICA/rPbyhUy94Dks0gJCX1NzCZui9YUd3oei+c257TalFbgg19ILHrlrL2gvWgXAL26EX76gZTNASQnad8Ibwhl284NhgXpB0c+jKhWO3Ms1hP9ihJYB9eMF6qd1BCPk0qA1s+LimFIu7m4nsdQIzPK4VbQ8hYvrnuSH2G9b2ggP78QmWqBdF9Vx8SSY6QYdUW7BTA1schZATyhvY8lHvcRbNUS9YGFy2U+qmzh2YPVc0I7yAOFyHfRpyUwtCSzOdPXMHmz7qDIM0e0V2wZTEk+6Ym6N63eBLp/b5Bts+2cKCSJ/LuoZO3ANSiE5hKAZjnvNSS4931jcw9jpwT0feV/qSJ1pVtCyfHKDkvK8Ejx7pUxGh2xFNSwx8QTi2H9ceC0/nni64MS/5N5dG39pDqvRV+WgGk71c9VFXF9b+xYvOw/d61iv7m3MvEHryhvecwC52jSSx4VIIgwnMNT/UsTxIgpPt3K/ARj15CptwL3Zd/ceDSATj2DGQjbxgWwhdeMMte7zpy5On9vymRm/YxBYljGVjKWF9VJf7I1+sex3wY8w/V1QPTborW/72gkdsRDaZMJBdbdHIC7aCkAu9atlLbtnrzerMnyToDaGwelOnk3/hHSem/ZK7e/t7jeeR20LYBgqa8J80gS8jbwi5F02Uj1u2NYJxap8PLkJfLxA2hIJyvnHX/AfeEPLpBfe0uSFHbnXaea3Qd5d6HcpYZ8L6M7lnFwMQ3MNg+RxUR1+6AshtbsVgfXTEg1sIGax9UND2p7f270wdG3eK9gXVGHdw2k5sOyZv+Nbs39Z308XR9DqWb2J+PwKDhuKHPobfuXf7gnYGHdCs7bhDDadD4entDug7LWNsnRNW4mYqwJ9dk+GGSTPBiA2j0G8RWNM5upZtcG4/3vMfP7KnbK2egx6CCnDPhRn7NgD3cghLIad5WcM2SO38iqHvvMOosyeMpQ5zlVCaaj06GVs9xUbHdiKoqrHWgquFEFMWUEWfXUxJAML23hAHFOctmjZQffKD2pywkhtSGHKNtpitLroscAeE7kCkSsC60vxEl6yMtL9EL5HKGCMszU5bk8gdkklAyEn5FO0yK419rIxBOIqwFMooDE0tHEVYijAUECIshRCGIhxFWIowFJ5QkEYIS5PTJrUwNGlPyN6QQPyKtpuM1E/K5+YJDV/MiA3AaehzqgAm7QnZG9IGYKo8bHnSK7VblLL3hOwNHziPuEGOqE5brrdR6i+atCfckyeWD47HkAkepRGLY/e8A8J0gCwYSNypF08bBm+e6zVz2UL4AshhBUjML/rXLefqC82bcQFhGC9JDwZ1uuu+At0S5gCETYHsV4DUeD9fDN2Zfy5OXaW2zAwQygCzBLJ8cvaW5OXKC1FxfTggFAHmoAJnSiOw2wps9KwRWgJCLaEswaj5NqkLwAYIU4BxqTSXbHXpJdRMPZgAOiAMqABCNGYIEEJutEK5IUAIwYMDQgiCACEEAcJs1Vda7gGqDhCmoiEghAAhBAHCrKXVo2C1DCBMRlp37uMIEECoX7xrX3P5C9QiINSuIcoPAUI0YkAICLNWgfJDh4T9hH7zqYH9+JHAq7zBqWjwhPAicTVCVQJCNF50JghHocahKK0X/ZnQKyEkhSdUpzG8OgQI42qC94EQjsYLRSmH+pbgq73L6bYkeEJ4DYTYmeg1TOBFc/usTTp3V9DdEuXJ2xDCUbXhaXk0/kAYmBvuMB4qkC35E5e5AMKkwSQgyxufyuPy6fMMgAFCSI73LFXU/N8AmEL9X4ABACNSKMHAgb34AAAAAElFTkSuQmCC\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}",
+  "csvJson": "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"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\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}",
   "object": [
     "{\"apiVersion\":\"apiextensions.k8s.io/v1beta1\",\"kind\":\"CustomResourceDefinition\",\"metadata\":{\"name\":\"etcdbackups.etcd.database.coreos.com\"},\"spec\":{\"group\":\"etcd.database.coreos.com\",\"names\":{\"kind\":\"EtcdBackup\",\"listKind\":\"EtcdBackupList\",\"plural\":\"etcdbackups\",\"singular\":\"etcdbackup\"},\"scope\":\"Namespaced\",\"version\":\"v1beta2\"}}",
     "{\"apiVersion\":\"apiextensions.k8s.io/v1beta1\",\"kind\":\"CustomResourceDefinition\",\"metadata\":{\"name\":\"etcdclusters.etcd.database.coreos.com\"},\"spec\":{\"group\":\"etcd.database.coreos.com\",\"names\":{\"kind\":\"EtcdCluster\",\"listKind\":\"EtcdClusterList\",\"plural\":\"etcdclusters\",\"shortNames\":[\"etcdclus\",\"etcd\"],\"singular\":\"etcdcluster\"},\"scope\":\"Namespaced\",\"version\":\"v1beta2\"}}",
-    "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"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\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}",
+    "{\"apiVersion\":\"operators.coreos.com/v1alpha1\",\"kind\":\"ClusterServiceVersion\",\"metadata\":{\"annotations\":{\"alm-examples\":\"[{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdCluster\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example\\\",\\\"namespace\\\":\\\"default\\\"},\\\"spec\\\":{\\\"size\\\":3,\\\"version\\\":\\\"3.2.13\\\"}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdRestore\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"spec\\\":{\\\"etcdCluster\\\":{\\\"name\\\":\\\"example-etcd-cluster\\\"},\\\"backupStorageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}},{\\\"apiVersion\\\":\\\"etcd.database.coreos.com/v1beta2\\\",\\\"kind\\\":\\\"EtcdBackup\\\",\\\"metadata\\\":{\\\"name\\\":\\\"example-etcd-cluster-backup\\\"},\\\"spec\\\":{\\\"etcdEndpoints\\\":[\\\"\\u003cetcd-cluster-endpoints\\u003e\\\"],\\\"storageType\\\":\\\"S3\\\",\\\"s3\\\":{\\\"path\\\":\\\"\\u003cfull-s3-path\\u003e\\\",\\\"awsSecret\\\":\\\"\\u003caws-secret\\u003e\\\"}}}]\",\"tectonic-visibility\":\"ocs\"},\"name\":\"etcdoperator.v0.9.2\",\"namespace\":\"placeholder\"},\"spec\":{\"customresourcedefinitions\":{\"owned\":[{\"description\":\"Represents a cluster of etcd nodes.\",\"displayName\":\"etcd Cluster\",\"kind\":\"EtcdCluster\",\"name\":\"etcdclusters.etcd.database.coreos.com\",\"resources\":[{\"kind\":\"Service\",\"version\":\"v1\"},{\"kind\":\"Pod\",\"version\":\"v1\"}],\"specDescriptors\":[{\"description\":\"The desired number of member Pods for the etcd cluster.\",\"displayName\":\"Size\",\"path\":\"size\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podCount\"]},{\"description\":\"Limits describes the minimum/maximum amount of compute resources required/allowed\",\"displayName\":\"Resource Requirements\",\"path\":\"pod.resources\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:resourceRequirements\"]}],\"statusDescriptors\":[{\"description\":\"The status of each of the member Pods for the etcd cluster.\",\"displayName\":\"Member Status\",\"path\":\"members\",\"x-descriptors\":[\"urn:alm:descriptor:com.tectonic.ui:podStatuses\"]},{\"description\":\"The service at which the running etcd cluster can be accessed.\",\"displayName\":\"Service\",\"path\":\"serviceName\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Service\"]},{\"description\":\"The current size of the etcd cluster.\",\"displayName\":\"Cluster Size\",\"path\":\"size\"},{\"description\":\"The current version of the etcd cluster.\",\"displayName\":\"Current Version\",\"path\":\"currentVersion\"},{\"description\":\"The target version of the etcd cluster, after upgrading.\",\"displayName\":\"Target Version\",\"path\":\"targetVersion\"},{\"description\":\"The current status of the etcd cluster.\",\"displayName\":\"Status\",\"path\":\"phase\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase\"]},{\"description\":\"Explanation for the current status of the cluster.\",\"displayName\":\"Status Details\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to backup an etcd cluster.\",\"displayName\":\"etcd Backup\",\"kind\":\"EtcdBackup\",\"name\":\"etcdbackups.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"Specifies the endpoints of an etcd cluster.\",\"displayName\":\"etcd Endpoint(s)\",\"path\":\"etcdEndpoints\",\"x-descriptors\":[\"urn:alm:descriptor:etcd:endpoint\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the backup was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any backup related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"},{\"description\":\"Represents the intent to restore an etcd cluster from a backup.\",\"displayName\":\"etcd Restore\",\"kind\":\"EtcdRestore\",\"name\":\"etcdrestores.etcd.database.coreos.com\",\"specDescriptors\":[{\"description\":\"References the EtcdCluster which should be restored,\",\"displayName\":\"etcd Cluster\",\"path\":\"etcdCluster.name\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:EtcdCluster\",\"urn:alm:descriptor:text\"]},{\"description\":\"The full AWS S3 path where the backup is saved.\",\"displayName\":\"S3 Path\",\"path\":\"s3.path\",\"x-descriptors\":[\"urn:alm:descriptor:aws:s3:path\"]},{\"description\":\"The name of the secret object that stores the AWS credential and config files.\",\"displayName\":\"AWS Secret\",\"path\":\"s3.awsSecret\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes:Secret\"]}],\"statusDescriptors\":[{\"description\":\"Indicates if the restore was successful.\",\"displayName\":\"Succeeded\",\"path\":\"succeeded\",\"x-descriptors\":[\"urn:alm:descriptor:text\"]},{\"description\":\"Indicates the reason for any restore related failures.\",\"displayName\":\"Reason\",\"path\":\"reason\",\"x-descriptors\":[\"urn:alm:descriptor:io.kubernetes.phase:reason\"]}],\"version\":\"v1beta2\"}]},\"description\":\"etcd is a distributed key value store that provides a reliable way to store data across a cluster of machines. It’s open-source and available on GitHub. etcd gracefully handles leader elections during network partitions and will tolerate machine failure, including the leader. Your applications can read and write data into etcd.\\nA simple use-case is to store database connection details or feature flags within etcd as key value pairs. These values can be watched, allowing your app to reconfigure itself when they change. Advanced uses take advantage of the consistency guarantees to implement database leader elections or do distributed locking across a cluster of workers.\\n\\n_The etcd Open Cloud Service is Public Alpha. The goal before Beta is to fully implement backup features._\\n\\n### Reading and writing to etcd\\n\\nCommunicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service.\\n\\n[Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)\\n\\n### Supported Features\\n\\n\\n**High availability**\\n\\n\\nMultiple instances of etcd are networked together and secured. Individual failures or networking issues are transparently handled to keep your cluster up and running.\\n\\n\\n**Automated updates**\\n\\n\\nRolling out a new etcd version works like all Kubernetes rolling updates. Simply declare the desired version, and the etcd service starts a safe rolling update to the new version automatically.\\n\\n\\n**Backups included**\\n\\n\\nComing soon, the ability to schedule backups to happen on or off cluster.\\n\",\"displayName\":\"etcd\",\"icon\":[{\"base64data\":\"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\",\"mediatype\":\"image/png\"}],\"install\":{\"spec\":{\"deployments\":[{\"name\":\"etcd-operator\",\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"name\":\"etcd-operator-alm-owned\"}},\"template\":{\"metadata\":{\"labels\":{\"name\":\"etcd-operator-alm-owned\"},\"name\":\"etcd-operator-alm-owned\"},\"spec\":{\"containers\":[{\"command\":[\"etcd-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-operator\"},{\"command\":[\"etcd-backup-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-backup-operator\"},{\"command\":[\"etcd-restore-operator\",\"--create-crd=false\"],\"env\":[{\"name\":\"MY_POD_NAMESPACE\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.namespace\"}}},{\"name\":\"MY_POD_NAME\",\"valueFrom\":{\"fieldRef\":{\"fieldPath\":\"metadata.name\"}}}],\"image\":\"quay.io/coreos/etcd-operator@sha256:c0301e4686c3ed4206e370b42de5a3bd2229b9fb4906cf85f3f30650424abec2\",\"name\":\"etcd-restore-operator\"}],\"serviceAccountName\":\"etcd-operator\"}}}}],\"permissions\":[{\"rules\":[{\"apiGroups\":[\"etcd.database.coreos.com\"],\"resources\":[\"etcdclusters\",\"etcdbackups\",\"etcdrestores\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"pods\",\"services\",\"endpoints\",\"persistentvolumeclaims\",\"events\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"apps\"],\"resources\":[\"deployments\"],\"verbs\":[\"*\"]},{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\"]}],\"serviceAccountName\":\"etcd-operator\"}]},\"strategy\":\"deployment\"},\"keywords\":[\"etcd\",\"key value\",\"database\",\"coreos\",\"open source\"],\"labels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"},\"links\":[{\"name\":\"Blog\",\"url\":\"https://coreos.com/etcd\"},{\"name\":\"Documentation\",\"url\":\"https://coreos.com/operators/etcd/docs/latest/\"},{\"name\":\"etcd Operator Source Code\",\"url\":\"https://github.com/coreos/etcd-operator\"}],\"maintainers\":[{\"email\":\"support@coreos.com\",\"name\":\"CoreOS, Inc\"}],\"maturity\":\"alpha\",\"provider\":{\"name\":\"CoreOS, Inc\"},\"replaces\":\"etcdoperator.v0.9.0\",\"selector\":{\"matchLabels\":{\"alm-owner-etcd\":\"etcdoperator\",\"operated-by\":\"etcdoperator\"}},\"version\":\"0.9.2\"}}",
     "{\"apiVersion\":\"apiextensions.k8s.io/v1beta1\",\"kind\":\"CustomResourceDefinition\",\"metadata\":{\"name\":\"etcdrestores.etcd.database.coreos.com\"},\"spec\":{\"group\":\"etcd.database.coreos.com\",\"names\":{\"kind\":\"EtcdRestore\",\"listKind\":\"EtcdRestoreList\",\"plural\":\"etcdrestores\",\"singular\":\"etcdrestore\"},\"scope\":\"Namespaced\",\"version\":\"v1beta2\"}}"
   ]
 }
diff --git a/alpha/action/diff.go b/alpha/action/diff.go
deleted file mode 100644
index 7912cf8a7..000000000
--- a/alpha/action/diff.go
+++ /dev/null
@@ -1,180 +0,0 @@
-package action
-
-import (
-	"context"
-	"errors"
-	"fmt"
-	"io"
-
-	"github.com/blang/semver/v4"
-	"github.com/sirupsen/logrus"
-	utilerrors "k8s.io/apimachinery/pkg/util/errors"
-	"k8s.io/apimachinery/pkg/util/yaml"
-
-	"github.com/operator-framework/operator-registry/alpha/declcfg"
-	"github.com/operator-framework/operator-registry/alpha/model"
-	"github.com/operator-framework/operator-registry/pkg/image"
-)
-
-type Diff struct {
-	Registry image.Registry
-
-	OldRefs []string
-	NewRefs []string
-	// SkipDependencies directs Run() to not include dependencies
-	// of bundles included in the diff if true.
-	SkipDependencies bool
-
-	IncludeConfig DiffIncludeConfig
-	// IncludeAdditively catalog objects specified in IncludeConfig.
-	IncludeAdditively bool
-
-	Logger *logrus.Entry
-}
-
-func (a Diff) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) {
-	if err := a.validate(); err != nil {
-		return nil, err
-	}
-
-	// Disallow bundle refs.
-	mask := RefDCDir | RefDCImage | RefSqliteFile | RefSqliteImage
-
-	// Heads-only mode does not require an old ref, so there may be nothing to render.
-	var oldModel model.Model
-	if len(a.OldRefs) != 0 {
-		oldRender := Render{Refs: a.OldRefs, Registry: a.Registry, AllowedRefMask: mask}
-		oldCfg, err := oldRender.Run(ctx)
-		if err != nil {
-			if errors.Is(err, ErrNotAllowed) {
-				return nil, fmt.Errorf("%w (diff does not permit direct bundle references)", err)
-			}
-			return nil, fmt.Errorf("error rendering old refs: %v", err)
-		}
-		oldModel, err = declcfg.ConvertToModel(*oldCfg)
-		if err != nil {
-			return nil, fmt.Errorf("error converting old declarative config to model: %v", err)
-		}
-	}
-
-	newRender := Render{Refs: a.NewRefs, Registry: a.Registry, AllowedRefMask: mask}
-	newCfg, err := newRender.Run(ctx)
-	if err != nil {
-		if errors.Is(err, ErrNotAllowed) {
-			return nil, fmt.Errorf("%w (diff does not permit direct bundle references)", err)
-		}
-		return nil, fmt.Errorf("error rendering new refs: %v", err)
-	}
-	newModel, err := declcfg.ConvertToModel(*newCfg)
-	if err != nil {
-		return nil, fmt.Errorf("error converting new declarative config to model: %v", err)
-	}
-
-	g := &declcfg.DiffGenerator{
-		Logger:            a.Logger,
-		SkipDependencies:  a.SkipDependencies,
-		Includer:          convertIncludeConfigToIncluder(a.IncludeConfig),
-		IncludeAdditively: a.IncludeAdditively,
-	}
-	diffModel, err := g.Run(oldModel, newModel)
-	if err != nil {
-		return nil, fmt.Errorf("error generating diff: %v", err)
-	}
-
-	cfg := declcfg.ConvertFromModel(diffModel)
-	return &cfg, nil
-}
-
-func (p Diff) validate() error {
-	if len(p.NewRefs) == 0 {
-		return fmt.Errorf("no new refs to diff")
-	}
-	return nil
-}
-
-// DiffIncludeConfig configures Diff.Run() to include a set of packages,
-// channels, and/or bundles/versions in the output DeclarativeConfig.
-// These override other diff mechanisms. For example, if running in
-// heads-only mode but package "foo" channel "stable" is specified,
-// the entire "stable" channel (all channel bundles) is added to the output.
-type DiffIncludeConfig struct {
-	// Packages to include.
-	Packages []DiffIncludePackage `json:"packages" yaml:"packages"`
-}
-
-// DiffIncludePackage contains a name (required) and channels and/or versions
-// (optional) to include in the diff. The full package is only included if no channels
-// or versions are specified.
-type DiffIncludePackage struct {
-	// Name of package.
-	Name string `json:"name" yaml:"name"`
-	// Channels to include.
-	Channels []DiffIncludeChannel `json:"channels,omitempty" yaml:"channels,omitempty"`
-	// Versions to include. All channels containing these versions
-	// are parsed for an upgrade graph.
-	Versions []semver.Version `json:"versions,omitempty" yaml:"versions,omitempty"`
-	// Bundles are bundle names to include. All channels containing these bundles
-	// are parsed for an upgrade graph.
-	// Set this field only if the named bundle has no semantic version metadata.
-	Bundles []string `json:"bundles,omitempty" yaml:"bundles,omitempty"`
-}
-
-// DiffIncludeChannel contains a name (required) and versions (optional)
-// to include in the diff. The full channel is only included if no versions are specified.
-type DiffIncludeChannel struct {
-	// Name of channel.
-	Name string `json:"name" yaml:"name"`
-	// Versions to include.
-	Versions []semver.Version `json:"versions,omitempty" yaml:"versions,omitempty"`
-	// Bundles are bundle names to include.
-	// Set this field only if the named bundle has no semantic version metadata.
-	Bundles []string `json:"bundles,omitempty" yaml:"bundles,omitempty"`
-}
-
-// LoadDiffIncludeConfig loads a (YAML or JSON) DiffIncludeConfig from r.
-func LoadDiffIncludeConfig(r io.Reader) (c DiffIncludeConfig, err error) {
-	dec := yaml.NewYAMLOrJSONDecoder(r, 8)
-	if err := dec.Decode(&c); err != nil {
-		return DiffIncludeConfig{}, err
-	}
-
-	if len(c.Packages) == 0 {
-		return c, fmt.Errorf("must specify at least one package in include config")
-	}
-
-	var errs []error
-	for pkgI, pkg := range c.Packages {
-		if pkg.Name == "" {
-			errs = append(errs, fmt.Errorf("package at index %v requires a name", pkgI))
-			continue
-		}
-		for chI, ch := range pkg.Channels {
-			if ch.Name == "" {
-				errs = append(errs, fmt.Errorf("package %s: channel at index %v requires a name", pkg.Name, chI))
-				continue
-			}
-		}
-	}
-	return c, utilerrors.NewAggregate(errs)
-}
-
-func convertIncludeConfigToIncluder(c DiffIncludeConfig) (includer declcfg.DiffIncluder) {
-	includer.Packages = make([]declcfg.DiffIncludePackage, len(c.Packages))
-	for pkgI, cpkg := range c.Packages {
-		pkg := &includer.Packages[pkgI]
-		pkg.Name = cpkg.Name
-		pkg.AllChannels.Versions = cpkg.Versions
-		pkg.AllChannels.Bundles = cpkg.Bundles
-
-		if len(cpkg.Channels) != 0 {
-			pkg.Channels = make([]declcfg.DiffIncludeChannel, len(cpkg.Channels))
-			for chI, cch := range cpkg.Channels {
-				ch := &pkg.Channels[chI]
-				ch.Name = cch.Name
-				ch.Versions = cch.Versions
-				ch.Bundles = cch.Bundles
-			}
-		}
-	}
-	return includer
-}
diff --git a/alpha/action/diff_test.go b/alpha/action/diff_test.go
deleted file mode 100644
index e00c81e22..000000000
--- a/alpha/action/diff_test.go
+++ /dev/null
@@ -1,422 +0,0 @@
-package action
-
-import (
-	"bytes"
-	"context"
-	"embed"
-	"errors"
-	"io/fs"
-	"path"
-	"path/filepath"
-	"strings"
-	"testing"
-
-	"github.com/blang/semver/v4"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-
-	"github.com/operator-framework/operator-registry/alpha/declcfg"
-	"github.com/operator-framework/operator-registry/pkg/containertools"
-	"github.com/operator-framework/operator-registry/pkg/image"
-	"github.com/operator-framework/operator-registry/pkg/lib/bundle"
-)
-
-func TestDiff(t *testing.T) {
-	type spec struct {
-		name        string
-		diff        Diff
-		expectedCfg *declcfg.DeclarativeConfig
-		assertion   require.ErrorAssertionFunc
-	}
-
-	registry, err := newDiffRegistry()
-	require.NoError(t, err)
-
-	specs := []spec{
-		{
-			name: "Success/Latest",
-			diff: Diff{
-				Registry: registry,
-				OldRefs:  []string{filepath.Join("testdata", "index-declcfgs", "old")},
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-latest")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Success/HeadsOnly",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-headsonly")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Success/IncludePackage",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-				IncludeConfig: DiffIncludeConfig{
-					Packages: []DiffIncludePackage{{Name: "baz"}},
-				},
-				IncludeAdditively: true,
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-include-pkg")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Success/IncludeChannel",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-				IncludeConfig: DiffIncludeConfig{
-					Packages: []DiffIncludePackage{
-						{
-							Name:     "baz",
-							Channels: []DiffIncludeChannel{{Name: "stable"}},
-						},
-					},
-				},
-				IncludeAdditively: true,
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-include-channel")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Success/IncludeVersion",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-				IncludeConfig: DiffIncludeConfig{
-					Packages: []DiffIncludePackage{
-						{
-							Name:     "baz",
-							Versions: []semver.Version{semver.MustParse("1.0.0")},
-						},
-					},
-				},
-				IncludeAdditively: true,
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-include-channel")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Success/IncludeBundle",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-				IncludeConfig: DiffIncludeConfig{
-					Packages: []DiffIncludePackage{
-						{
-							Name:    "baz",
-							Bundles: []string{"baz.v1.0.0"},
-						},
-					},
-				},
-				IncludeAdditively: true,
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-include-channel")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Success/IncludeSameVersionAndBundle",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-				IncludeConfig: DiffIncludeConfig{
-					Packages: []DiffIncludePackage{
-						{
-							Name:     "baz",
-							Versions: []semver.Version{semver.MustParse("1.0.0")},
-							Bundles:  []string{"baz.v1.0.0"},
-						},
-					},
-				},
-				IncludeAdditively: true,
-			},
-			expectedCfg: loadDirFS(t, indicesDir, filepath.Join("testdata", "index-declcfgs", "exp-include-channel")),
-			assertion:   require.NoError,
-		},
-		{
-			name: "Fail/NewBundleImage",
-			diff: Diff{
-				Registry: registry,
-				NewRefs:  []string{"test.registry/foo-operator/foo-bundle:v0.1.0"},
-			},
-			assertion: func(t require.TestingT, err error, _ ...interface{}) {
-				if !assert.Error(t, err) {
-					require.Fail(t, "expected an error")
-				}
-				if !errors.Is(err, ErrNotAllowed) {
-					require.Fail(t, "err is not ErrNotAllowed", err)
-				}
-			},
-		},
-		{
-			name: "Fail/OldBundleImage",
-			diff: Diff{
-				Registry: registry,
-				OldRefs:  []string{"test.registry/foo-operator/foo-bundle:v0.1.0"},
-				NewRefs:  []string{filepath.Join("testdata", "index-declcfgs", "latest")},
-			},
-			assertion: func(t require.TestingT, err error, _ ...interface{}) {
-				if !assert.Error(t, err) {
-					require.Fail(t, "expected an error")
-				}
-				if !errors.Is(err, ErrNotAllowed) {
-					require.Fail(t, "err is not ErrNotAllowed", err)
-				}
-			},
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			actualCfg, actualErr := s.diff.Run(context.Background())
-			s.assertion(t, actualErr)
-			require.Equal(t, s.expectedCfg, actualCfg)
-		})
-	}
-}
-
-func TestLoadDiffIncludeConfig(t *testing.T) {
-	type spec struct {
-		name             string
-		input            string
-		expectedCfg      DiffIncludeConfig
-		expectedIncluder declcfg.DiffIncluder
-		assertion        require.ErrorAssertionFunc
-	}
-
-	specs := []spec{
-		{
-			name: "Success/Basic",
-			input: `
-packages:
-- name: foo
-`,
-			expectedCfg: DiffIncludeConfig{
-				Packages: []DiffIncludePackage{{Name: "foo"}},
-			},
-			expectedIncluder: declcfg.DiffIncluder{
-				Packages: []declcfg.DiffIncludePackage{{Name: "foo"}},
-			},
-			assertion: require.NoError,
-		},
-		{
-			name: "Success/MultiPackage",
-			input: `
-packages:
-- name: foo
-  channels:
-  - name: stable
-    bundles:
-    - foo.v0.3.0
-    versions:
-    - 0.1.0
-    - 0.2.0
-  versions:
-  - 1.0.0
-- name: bar
-  channels:
-  - name: stable
-    versions:
-    - 0.1.0
-  versions:
-  - 1.0.0
-  bundles:
-  - bar.v1.2.0
-`,
-			expectedCfg: DiffIncludeConfig{
-				Packages: []DiffIncludePackage{
-					{
-						Name: "foo",
-						Channels: []DiffIncludeChannel{
-							{
-								Name:     "stable",
-								Versions: []semver.Version{semver.MustParse("0.1.0"), semver.MustParse("0.2.0")},
-								Bundles:  []string{"foo.v0.3.0"},
-							},
-						},
-						Versions: []semver.Version{semver.MustParse("1.0.0")},
-					},
-					{
-						Name: "bar",
-						Channels: []DiffIncludeChannel{
-							{Name: "stable", Versions: []semver.Version{
-								semver.MustParse("0.1.0"),
-							}},
-						},
-						Versions: []semver.Version{semver.MustParse("1.0.0")},
-						Bundles:  []string{"bar.v1.2.0"},
-					},
-				},
-			},
-			expectedIncluder: declcfg.DiffIncluder{
-				Packages: []declcfg.DiffIncludePackage{
-					{
-						Name: "foo",
-						Channels: []declcfg.DiffIncludeChannel{
-							{
-								Name:     "stable",
-								Versions: []semver.Version{semver.MustParse("0.1.0"), semver.MustParse("0.2.0")},
-								Bundles:  []string{"foo.v0.3.0"},
-							},
-						},
-						AllChannels: declcfg.DiffIncludeChannel{
-							Versions: []semver.Version{semver.MustParse("1.0.0")},
-						},
-					},
-					{
-						Name: "bar",
-						Channels: []declcfg.DiffIncludeChannel{
-							{Name: "stable", Versions: []semver.Version{
-								semver.MustParse("0.1.0"),
-							}},
-						},
-						AllChannels: declcfg.DiffIncludeChannel{
-							Versions: []semver.Version{semver.MustParse("1.0.0")},
-							Bundles:  []string{"bar.v1.2.0"},
-						},
-					},
-				},
-			},
-			assertion: require.NoError,
-		},
-		{
-			name:      "Fail/Empty",
-			input:     ``,
-			assertion: require.Error,
-		},
-		{
-			name: "Fail/NoPackageName",
-			input: `
-packages:
-- channels:
-  - name: stable
-    versions:
-    - 0.1.0
-`,
-			assertion: require.Error,
-		},
-		{
-			name: "Fail/NoChannelName",
-			input: `
-packages:
-- name: foo
-  channels:
-  - versions:
-    - 0.1.0
-`,
-			assertion: require.Error,
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			actualCfg, err := LoadDiffIncludeConfig(bytes.NewBufferString(s.input))
-			s.assertion(t, err)
-			if err == nil {
-				require.Equal(t, s.expectedCfg, actualCfg)
-				require.Equal(t, s.expectedIncluder, convertIncludeConfigToIncluder(actualCfg))
-			}
-		})
-	}
-}
-
-var (
-	//go:embed testdata/foo-bundle-v0.1.0/manifests/*
-	//go:embed testdata/foo-bundle-v0.1.0/metadata/*
-	fooBundlev010 embed.FS
-	//go:embed testdata/foo-bundle-v0.2.0/manifests/*
-	//go:embed testdata/foo-bundle-v0.2.0/metadata/*
-	fooBundlev020 embed.FS
-	//go:embed testdata/foo-bundle-v0.3.0/manifests/*
-	//go:embed testdata/foo-bundle-v0.3.0/metadata/*
-	fooBundlev030 embed.FS
-	//go:embed testdata/foo-bundle-v0.3.1/manifests/*
-	//go:embed testdata/foo-bundle-v0.3.1/metadata/*
-	fooBundlev031 embed.FS
-	//go:embed testdata/bar-bundle-v0.1.0/manifests/*
-	//go:embed testdata/bar-bundle-v0.1.0/metadata/*
-	barBundlev010 embed.FS
-	//go:embed testdata/bar-bundle-v0.2.0/manifests/*
-	//go:embed testdata/bar-bundle-v0.2.0/metadata/*
-	barBundlev020 embed.FS
-	//go:embed testdata/bar-bundle-v1.0.0/manifests/*
-	//go:embed testdata/bar-bundle-v1.0.0/metadata/*
-	barBundlev100 embed.FS
-	//go:embed testdata/baz-bundle-v1.0.0/manifests/*
-	//go:embed testdata/baz-bundle-v1.0.0/metadata/*
-	bazBundlev100 embed.FS
-	//go:embed testdata/baz-bundle-v1.0.1/manifests/*
-	//go:embed testdata/baz-bundle-v1.0.1/metadata/*
-	bazBundlev101 embed.FS
-	//go:embed testdata/baz-bundle-v1.1.0/manifests/*
-	//go:embed testdata/baz-bundle-v1.1.0/metadata/*
-	bazBundlev110 embed.FS
-)
-
-var bundleToFS = map[string]embed.FS{
-	"test.registry/foo-operator/foo-bundle:v0.1.0": fooBundlev010,
-	"test.registry/foo-operator/foo-bundle:v0.2.0": fooBundlev020,
-	"test.registry/foo-operator/foo-bundle:v0.3.0": fooBundlev030,
-	"test.registry/foo-operator/foo-bundle:v0.3.1": fooBundlev031,
-	"test.registry/bar-operator/bar-bundle:v0.1.0": barBundlev010,
-	"test.registry/bar-operator/bar-bundle:v0.2.0": barBundlev020,
-	"test.registry/bar-operator/bar-bundle:v1.0.0": barBundlev100,
-	"test.registry/baz-operator/baz-bundle:v1.0.0": bazBundlev100,
-	"test.registry/baz-operator/baz-bundle:v1.0.1": bazBundlev101,
-	"test.registry/baz-operator/baz-bundle:v1.1.0": bazBundlev110,
-}
-
-//go:embed testdata/index-declcfgs
-var indicesDir embed.FS
-
-func newDiffRegistry() (image.Registry, error) {
-	subDeclcfgImage, err := fs.Sub(indicesDir, "testdata/index-declcfgs")
-	if err != nil {
-		return nil, err
-	}
-	reg := &image.MockRegistry{
-		RemoteImages: map[image.Reference]*image.MockImage{
-			image.SimpleReference("test.registry/catalog/index-declcfg:latest"): {
-				Labels: map[string]string{containertools.ConfigsLocationLabel: "/latest/index.yaml"},
-				FS:     subDeclcfgImage,
-			},
-			image.SimpleReference("test.registry/catalog/index-declcfg:old"): {
-				Labels: map[string]string{containertools.ConfigsLocationLabel: "/old/index.yaml"},
-				FS:     subDeclcfgImage,
-			},
-		},
-	}
-
-	for name, bfs := range bundleToFS {
-		base := filepath.Base(name)
-		pkg := base[:strings.Index(base, ":")]
-		base = strings.ReplaceAll(base, ":", "-")
-		subImage, err := fs.Sub(bfs, path.Join("testdata", base))
-		if err != nil {
-			return nil, err
-		}
-		reg.RemoteImages[image.SimpleReference(name)] = &image.MockImage{
-			Labels: map[string]string{bundle.PackageLabel: pkg},
-			FS:     subImage,
-		}
-	}
-
-	return reg, nil
-}
-
-func loadDirFS(t *testing.T, parent fs.FS, dir string) *declcfg.DeclarativeConfig {
-	sub, err := fs.Sub(parent, dir)
-	if err != nil {
-		t.Fatal(err)
-	}
-	cfg, err := declcfg.LoadFS(sub)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return cfg
-}
diff --git a/alpha/action/generate_dockerfile.go b/alpha/action/generate_dockerfile.go
index ef2a6d871..fc3a8ff1e 100644
--- a/alpha/action/generate_dockerfile.go
+++ b/alpha/action/generate_dockerfile.go
@@ -9,10 +9,11 @@ import (
 )
 
 type GenerateDockerfile struct {
-	BaseImage   string
-	IndexDir    string
-	ExtraLabels map[string]string
-	Writer      io.Writer
+	BaseImage    string
+	BuilderImage string
+	IndexDir     string
+	ExtraLabels  map[string]string
+	Writer       io.Writer
 }
 
 func (i GenerateDockerfile) Run() error {
@@ -39,18 +40,36 @@ func (i GenerateDockerfile) validate() error {
 	return nil
 }
 
-const dockerfileTmpl = `# The base image is expected to contain
-# /bin/opm (with a serve subcommand) and /bin/grpc_health_probe
+const dockerfileTmpl = `# The builder image is expected to contain
+# /bin/opm (with serve subcommand)
+FROM {{.BuilderImage}} as builder
+
+# Copy FBC root into image at /configs and pre-populate serve cache
+ADD {{.IndexDir}} /configs
+RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"]
+
 FROM {{.BaseImage}}
 
+{{- if ne .BaseImage "scratch" }}
+# The base image is expected to contain
+# /bin/opm (with serve subcommand) and /bin/grpc_health_probe
+
 # Configure the entrypoint and command
 ENTRYPOINT ["/bin/opm"]
-CMD ["serve", "/configs"]
+CMD ["serve", "/configs", "--cache-dir=/tmp/cache"]
+{{- else }}
+# OLMv0 CatalogSources that use binary-less images must set:
+# spec:
+#   grpcPodConfig:
+#     extractContent:
+#       catalogDir: /configs
+#       cacheDir: /tmp/cache
+{{- end }}
 
-# Copy declarative config root into image at /configs
-ADD {{.IndexDir}} /configs
+COPY --from=builder /configs /configs
+COPY --from=builder /tmp/cache /tmp/cache
 
-# Set DC-specific label for the location of the DC root directory
+# Set FBC-specific label for the location of the FBC root directory
 # in the image
 LABEL ` + containertools.ConfigsLocationLabel + `=/configs
 {{- if .ExtraLabels }}
diff --git a/alpha/action/generate_dockerfile_test.go b/alpha/action/generate_dockerfile_test.go
index 6e0a79543..0f94aa345 100644
--- a/alpha/action/generate_dockerfile_test.go
+++ b/alpha/action/generate_dockerfile_test.go
@@ -41,21 +41,30 @@ func TestGenerateDockerfile(t *testing.T) {
 		{
 			name: "Success/WithoutExtraLabels",
 			gen: GenerateDockerfile{
-				BaseImage: "foo",
-				IndexDir:  "bar",
+				BuilderImage: "foo",
+				BaseImage:    "foo",
+				IndexDir:     "bar",
 			},
-			expectedDockerfile: `# The base image is expected to contain
-# /bin/opm (with a serve subcommand) and /bin/grpc_health_probe
+			expectedDockerfile: `# The builder image is expected to contain
+# /bin/opm (with serve subcommand)
+FROM foo as builder
+
+# Copy FBC root into image at /configs and pre-populate serve cache
+ADD bar /configs
+RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"]
+
 FROM foo
+# The base image is expected to contain
+# /bin/opm (with serve subcommand) and /bin/grpc_health_probe
 
 # Configure the entrypoint and command
 ENTRYPOINT ["/bin/opm"]
-CMD ["serve", "/configs"]
+CMD ["serve", "/configs", "--cache-dir=/tmp/cache"]
 
-# Copy declarative config root into image at /configs
-ADD bar /configs
+COPY --from=builder /configs /configs
+COPY --from=builder /tmp/cache /tmp/cache
 
-# Set DC-specific label for the location of the DC root directory
+# Set FBC-specific label for the location of the FBC root directory
 # in the image
 LABEL operators.operatorframework.io.index.configs.v1=/configs
 `,
@@ -63,25 +72,129 @@ LABEL operators.operatorframework.io.index.configs.v1=/configs
 		{
 			name: "Success/WithExtraLabels",
 			gen: GenerateDockerfile{
-				BaseImage: "foo",
-				IndexDir:  "bar",
+				BuilderImage: "foo",
+				BaseImage:    "foo",
+				IndexDir:     "bar",
 				ExtraLabels: map[string]string{
 					"key1": "value1",
 					"key2": "value2",
 				},
 			},
-			expectedDockerfile: `# The base image is expected to contain
-# /bin/opm (with a serve subcommand) and /bin/grpc_health_probe
+			expectedDockerfile: `# The builder image is expected to contain
+# /bin/opm (with serve subcommand)
+FROM foo as builder
+
+# Copy FBC root into image at /configs and pre-populate serve cache
+ADD bar /configs
+RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"]
+
 FROM foo
+# The base image is expected to contain
+# /bin/opm (with serve subcommand) and /bin/grpc_health_probe
 
 # Configure the entrypoint and command
 ENTRYPOINT ["/bin/opm"]
-CMD ["serve", "/configs"]
+CMD ["serve", "/configs", "--cache-dir=/tmp/cache"]
+
+COPY --from=builder /configs /configs
+COPY --from=builder /tmp/cache /tmp/cache
+
+# Set FBC-specific label for the location of the FBC root directory
+# in the image
+LABEL operators.operatorframework.io.index.configs.v1=/configs
+
+# Set other custom labels
+LABEL "key1"="value1"
+LABEL "key2"="value2"
+`,
+		},
 
-# Copy declarative config root into image at /configs
+		{
+			name: "Scratch/Fail/EmptyBaseImage",
+			gen: GenerateDockerfile{
+				BuilderImage: "foo",
+				IndexDir:     "bar",
+				ExtraLabels: map[string]string{
+					"key1": "value1",
+					"key2": "value2",
+				},
+			},
+			expectedErr: "base image is unset",
+		},
+		{
+			name: "Scratch/Fail/EmptyFromDir",
+			gen: GenerateDockerfile{
+				BuilderImage: "foo",
+				BaseImage:    "scratch",
+				ExtraLabels: map[string]string{
+					"key1": "value1",
+					"key2": "value2",
+				},
+			},
+			expectedErr: "index directory is unset",
+		},
+		{
+			name: "Scratch/Success/WithoutExtraLabels",
+			gen: GenerateDockerfile{
+				BuilderImage: "foo",
+				BaseImage:    "scratch",
+				IndexDir:     "bar",
+			},
+			expectedDockerfile: `# The builder image is expected to contain
+# /bin/opm (with serve subcommand)
+FROM foo as builder
+
+# Copy FBC root into image at /configs and pre-populate serve cache
 ADD bar /configs
+RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"]
+
+FROM scratch
+# OLMv0 CatalogSources that use binary-less images must set:
+# spec:
+#   grpcPodConfig:
+#     extractContent:
+#       catalogDir: /configs
+#       cacheDir: /tmp/cache
+
+COPY --from=builder /configs /configs
+COPY --from=builder /tmp/cache /tmp/cache
+
+# Set FBC-specific label for the location of the FBC root directory
+# in the image
+LABEL operators.operatorframework.io.index.configs.v1=/configs
+`,
+		},
+		{
+			name: "Scratch/Success/WithExtraLabels",
+			gen: GenerateDockerfile{
+				BuilderImage: "foo",
+				BaseImage:    "scratch",
+				IndexDir:     "bar",
+				ExtraLabels: map[string]string{
+					"key1": "value1",
+					"key2": "value2",
+				},
+			},
+			expectedDockerfile: `# The builder image is expected to contain
+# /bin/opm (with serve subcommand)
+FROM foo as builder
+
+# Copy FBC root into image at /configs and pre-populate serve cache
+ADD bar /configs
+RUN ["/bin/opm", "serve", "/configs", "--cache-dir=/tmp/cache", "--cache-only"]
+
+FROM scratch
+# OLMv0 CatalogSources that use binary-less images must set:
+# spec:
+#   grpcPodConfig:
+#     extractContent:
+#       catalogDir: /configs
+#       cacheDir: /tmp/cache
+
+COPY --from=builder /configs /configs
+COPY --from=builder /tmp/cache /tmp/cache
 
-# Set DC-specific label for the location of the DC root directory
+# Set FBC-specific label for the location of the FBC root directory
 # in the image
 LABEL operators.operatorframework.io.index.configs.v1=/configs
 
diff --git a/alpha/action/init.go b/alpha/action/init.go
index 910b882cd..242d8f818 100644
--- a/alpha/action/init.go
+++ b/alpha/action/init.go
@@ -3,7 +3,6 @@ package action
 import (
 	"fmt"
 	"io"
-	"io/ioutil"
 
 	"github.com/h2non/filetype"
 
@@ -25,7 +24,7 @@ func (i Init) Run() (*declcfg.Package, error) {
 		DefaultChannel: i.DefaultChannel,
 	}
 	if i.DescriptionReader != nil {
-		descriptionData, err := ioutil.ReadAll(i.DescriptionReader)
+		descriptionData, err := io.ReadAll(i.DescriptionReader)
 		if err != nil {
 			return nil, fmt.Errorf("read description: %v", err)
 		}
@@ -33,7 +32,7 @@ func (i Init) Run() (*declcfg.Package, error) {
 	}
 
 	if i.IconReader != nil {
-		iconData, err := ioutil.ReadAll(i.IconReader)
+		iconData, err := io.ReadAll(i.IconReader)
 		if err != nil {
 			return nil, fmt.Errorf("read icon: %v", err)
 		}
diff --git a/alpha/action/list.go b/alpha/action/list.go
index 4c67dc628..80c014d1d 100644
--- a/alpha/action/list.go
+++ b/alpha/action/list.go
@@ -14,14 +14,16 @@ import (
 
 	"github.com/operator-framework/operator-registry/alpha/declcfg"
 	"github.com/operator-framework/operator-registry/alpha/model"
+	"github.com/operator-framework/operator-registry/pkg/image"
 )
 
 type ListPackages struct {
 	IndexReference string
+	Registry       image.Registry
 }
 
 func (l *ListPackages) Run(ctx context.Context) (*ListPackagesResult, error) {
-	m, err := indexRefToModel(ctx, l.IndexReference)
+	m, err := indexRefToModel(ctx, l.IndexReference, l.Registry)
 	if err != nil {
 		return nil, err
 	}
@@ -72,10 +74,11 @@ func getDisplayName(pkg model.Package) string {
 type ListChannels struct {
 	IndexReference string
 	PackageName    string
+	Registry       image.Registry
 }
 
 func (l *ListChannels) Run(ctx context.Context) (*ListChannelsResult, error) {
-	m, err := indexRefToModel(ctx, l.IndexReference)
+	m, err := indexRefToModel(ctx, l.IndexReference, l.Registry)
 	if err != nil {
 		return nil, err
 	}
@@ -128,10 +131,11 @@ func (r *ListChannelsResult) WriteColumns(w io.Writer) error {
 type ListBundles struct {
 	IndexReference string
 	PackageName    string
+	Registry       image.Registry
 }
 
 func (l *ListBundles) Run(ctx context.Context) (*ListBundlesResult, error) {
-	m, err := indexRefToModel(ctx, l.IndexReference)
+	m, err := indexRefToModel(ctx, l.IndexReference, l.Registry)
 	if err != nil {
 		return nil, err
 	}
@@ -179,10 +183,11 @@ func (r *ListBundlesResult) WriteColumns(w io.Writer) error {
 	return tw.Flush()
 }
 
-func indexRefToModel(ctx context.Context, ref string) (model.Model, error) {
+func indexRefToModel(ctx context.Context, ref string, reg image.Registry) (model.Model, error) {
 	render := Render{
 		Refs:           []string{ref},
 		AllowedRefMask: RefDCImage | RefDCDir | RefSqliteImage | RefSqliteFile,
+		Registry:       reg,
 	}
 	cfg, err := render.Run(ctx)
 	if err != nil {
diff --git a/alpha/action/list_test.go b/alpha/action/list_test.go
index 87f53886e..090439d44 100644
--- a/alpha/action/list_test.go
+++ b/alpha/action/list_test.go
@@ -28,7 +28,7 @@ foo   Foo Operator  beta
 		{
 			name:        "Error/UnknownIndex",
 			list:        ListPackages{IndexReference: "unknown-index"},
-			expectedErr: `render reference "unknown-index": error resolving name : object required`,
+			expectedErr: `render reference "unknown-index": failed to pull image "unknown-index": repository name must be canonical`,
 		},
 	}
 	for _, s := range specs {
@@ -79,7 +79,7 @@ foo      stable   foo.v0.2.0
 		{
 			name:        "Error/UnknownIndex",
 			list:        ListChannels{IndexReference: "unknown-index"},
-			expectedErr: `render reference "unknown-index": error resolving name : object required`,
+			expectedErr: `render reference "unknown-index": failed to pull image "unknown-index": repository name must be canonical`,
 		},
 		{
 			name:        "Error/UnknownPackage",
@@ -138,7 +138,7 @@ foo      stable   foo.v0.2.0  foo.v0.1.0  foo.v0.1.1,foo.v0.1.2  <0.2.0      tes
 		{
 			name:        "Error/UnknownIndex",
 			list:        ListBundles{IndexReference: "unknown-index"},
-			expectedErr: `render reference "unknown-index": error resolving name : object required`,
+			expectedErr: `render reference "unknown-index": failed to pull image "unknown-index": repository name must be canonical`,
 		},
 		{
 			name:        "Error/UnknownPackage",
diff --git a/alpha/action/migrate.go b/alpha/action/migrate.go
index 8cca8b897..8122d1648 100644
--- a/alpha/action/migrate.go
+++ b/alpha/action/migrate.go
@@ -1,14 +1,11 @@
 package action
 
 import (
-	"bytes"
 	"context"
 	"fmt"
-	"io"
-	"io/ioutil"
 	"os"
-	"path/filepath"
 
+	"github.com/operator-framework/operator-registry/alpha/action/migrations"
 	"github.com/operator-framework/operator-registry/alpha/declcfg"
 	"github.com/operator-framework/operator-registry/pkg/image"
 )
@@ -16,16 +13,15 @@ import (
 type Migrate struct {
 	CatalogRef string
 	OutputDir  string
+	Migrations *migrations.Migrations
 
-	WriteFunc WriteFunc
+	WriteFunc declcfg.WriteFunc
 	FileExt   string
 	Registry  image.Registry
 }
 
-type WriteFunc func(config declcfg.DeclarativeConfig, w io.Writer) error
-
 func (m Migrate) Run(ctx context.Context) error {
-	entries, err := ioutil.ReadDir(m.OutputDir)
+	entries, err := os.ReadDir(m.OutputDir)
 	if err != nil && !os.IsNotExist(err) {
 		return err
 	}
@@ -34,14 +30,11 @@ func (m Migrate) Run(ctx context.Context) error {
 	}
 
 	r := Render{
-		Refs: []string{m.CatalogRef},
-
-		// Only allow sqlite images and files to be migrated. Other types cannot
-		// always be migrated cleanly because they may contain file references.
-		// Rendered sqlite databases never contain file references.
-		AllowedRefMask: RefSqliteImage | RefSqliteFile,
+		Refs:       []string{m.CatalogRef},
+		Migrations: m.Migrations,
 
-		skipSqliteDeprecationLog: true,
+		// Only allow catalogs to be migrated.
+		AllowedRefMask: RefSqliteImage | RefSqliteFile | RefDCImage | RefDCDir,
 	}
 	if m.Registry != nil {
 		r.Registry = m.Registry
@@ -52,48 +45,5 @@ func (m Migrate) Run(ctx context.Context) error {
 		return fmt.Errorf("render catalog image: %w", err)
 	}
 
-	return writeToFS(*cfg, m.OutputDir, m.WriteFunc, m.FileExt)
-}
-
-func writeToFS(cfg declcfg.DeclarativeConfig, rootDir string, writeFunc WriteFunc, fileExt string) error {
-	channelsByPackage := map[string][]declcfg.Channel{}
-	for _, c := range cfg.Channels {
-		channelsByPackage[c.Package] = append(channelsByPackage[c.Package], c)
-	}
-	bundlesByPackage := map[string][]declcfg.Bundle{}
-	for _, b := range cfg.Bundles {
-		bundlesByPackage[b.Package] = append(bundlesByPackage[b.Package], b)
-	}
-
-	if err := os.MkdirAll(rootDir, 0777); err != nil {
-		return err
-	}
-
-	for _, p := range cfg.Packages {
-		fcfg := declcfg.DeclarativeConfig{
-			Packages: []declcfg.Package{p},
-			Channels: channelsByPackage[p.Name],
-			Bundles:  bundlesByPackage[p.Name],
-		}
-		pkgDir := filepath.Join(rootDir, p.Name)
-		if err := os.MkdirAll(pkgDir, 0777); err != nil {
-			return err
-		}
-		filename := filepath.Join(pkgDir, fmt.Sprintf("catalog%s", fileExt))
-		if err := writeFile(fcfg, filename, writeFunc); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func writeFile(cfg declcfg.DeclarativeConfig, filename string, writeFunc WriteFunc) error {
-	buf := &bytes.Buffer{}
-	if err := writeFunc(cfg, buf); err != nil {
-		return fmt.Errorf("write to buffer for %q: %v", filename, err)
-	}
-	if err := ioutil.WriteFile(filename, buf.Bytes(), 0666); err != nil {
-		return fmt.Errorf("write file %q: %v", filename, err)
-	}
-	return nil
+	return declcfg.WriteFS(*cfg, m.OutputDir, m.WriteFunc, m.FileExt)
 }
diff --git a/alpha/action/migrate_test.go b/alpha/action/migrate_test.go
index 1296cf80d..a0b5d2771 100644
--- a/alpha/action/migrate_test.go
+++ b/alpha/action/migrate_test.go
@@ -2,7 +2,6 @@ package action_test
 
 import (
 	"context"
-	"fmt"
 	"io/fs"
 	"os"
 	"path/filepath"
@@ -32,12 +31,12 @@ func TestMigrate(t *testing.T) {
 		image.SimpleReference("test.registry/bar-operator/bar-bundle:v0.2.0"): "testdata/bar-bundle-v0.2.0",
 	}
 
-	tmpDir := t.TempDir()
-	dbFile := filepath.Join(tmpDir, "index.db")
+	sqliteDBDir := t.TempDir()
+	dbFile := filepath.Join(sqliteDBDir, "index.db")
 	err := generateSqliteFile(dbFile, sqliteBundles)
 	require.NoError(t, err)
 
-	reg, err := newMigrateRegistry(sqliteBundles)
+	reg, err := newMigrateRegistry(t, sqliteBundles)
 	require.NoError(t, err)
 
 	specs := []spec{
@@ -45,81 +44,105 @@ func TestMigrate(t *testing.T) {
 			name: "SqliteImage/Success",
 			migrate: action.Migrate{
 				CatalogRef: "test.registry/migrate/catalog:sqlite",
-				OutputDir:  filepath.Join(tmpDir, "sqlite-image"),
 				WriteFunc:  declcfg.WriteYAML,
 				FileExt:    ".yaml",
 				Registry:   reg,
 			},
 			expectedFiles: map[string]string{
-				"foo/catalog.yaml": migrateFooCatalog(),
-				"bar/catalog.yaml": migrateBarCatalog(),
+				"foo/catalog.yaml": migrateFooCatalogSqlite(),
+				"bar/catalog.yaml": migrateBarCatalogSqlite(),
 			},
 		},
 		{
 			name: "SqliteFile/Success",
 			migrate: action.Migrate{
 				CatalogRef: dbFile,
-				OutputDir:  filepath.Join(tmpDir, "sqlite-file"),
 				WriteFunc:  declcfg.WriteYAML,
 				FileExt:    ".yaml",
 				Registry:   reg,
 			},
 			expectedFiles: map[string]string{
-				"foo/catalog.yaml": migrateFooCatalog(),
-				"bar/catalog.yaml": migrateBarCatalog(),
+				"foo/catalog.yaml": migrateFooCatalogSqlite(),
+				"bar/catalog.yaml": migrateBarCatalogSqlite(),
 			},
 		},
 		{
-			name: "DeclcfgImage/Failure",
+			name: "DeclcfgImage/Success",
 			migrate: action.Migrate{
 				CatalogRef: "test.registry/foo-operator/foo-index-declcfg:v0.2.0",
-				OutputDir:  filepath.Join(tmpDir, "declcfg-image"),
 				WriteFunc:  declcfg.WriteYAML,
 				FileExt:    ".yaml",
 				Registry:   reg,
 			},
-			expectErr: action.ErrNotAllowed,
+			expectedFiles: map[string]string{
+				"foo/catalog.yaml": migrateFooCatalogFBC(),
+			},
 		},
 		{
-			name: "DeclcfgDir/Failure",
+			name: "DeclcfgDir/Success",
 			migrate: action.Migrate{
 				CatalogRef: "testdata/foo-index-v0.2.0-declcfg",
-				OutputDir:  filepath.Join(tmpDir, "declcfg-dir"),
 				WriteFunc:  declcfg.WriteYAML,
 				FileExt:    ".yaml",
 				Registry:   reg,
 			},
-			expectErr: action.ErrNotAllowed,
+			expectedFiles: map[string]string{
+				"foo/catalog.yaml": migrateFooCatalogFBC(),
+			},
 		},
 		{
 			name: "BundleImage/Failure",
 			migrate: action.Migrate{
 				CatalogRef: "test.registry/foo-operator/foo-bundle:v0.1.0",
-				OutputDir:  filepath.Join(tmpDir, "bundle-image"),
 				WriteFunc:  declcfg.WriteYAML,
 				FileExt:    ".yaml",
 				Registry:   reg,
 			},
 			expectErr: action.ErrNotAllowed,
 		},
+		{
+			name: "SqliteImage/Success/NoMigrations",
+			migrate: action.Migrate{
+				CatalogRef: "test.registry/migrate/catalog:sqlite",
+				WriteFunc:  declcfg.WriteYAML,
+				FileExt:    ".yaml",
+				Registry:   reg,
+				Migrations: nil,
+			},
+			expectedFiles: map[string]string{
+				"foo/catalog.yaml": migrateFooCatalogSqlite(),
+				"bar/catalog.yaml": migrateBarCatalogSqlite(),
+			},
+		},
 	}
 	for _, s := range specs {
 		t.Run(s.name, func(t *testing.T) {
+			s.migrate.OutputDir = t.TempDir()
+
 			err := s.migrate.Run(context.Background())
 			require.ErrorIs(t, err, s.expectErr)
-			for file, expectedData := range s.expectedFiles {
-				path := filepath.Join(s.migrate.OutputDir, file)
-				actualData, err := os.ReadFile(path)
+			if s.expectErr != nil {
+				return
+			}
+			actualFS := os.DirFS(s.migrate.OutputDir)
+			require.NoError(t, fs.WalkDir(actualFS, ".", func(path string, d fs.DirEntry, err error) error {
+				require.NoError(t, err)
+				if d.IsDir() {
+					return nil
+				}
+				actualData, err := fs.ReadFile(actualFS, path)
 				require.NoError(t, err)
-				fmt.Println(string(actualData))
+				expectedData, ok := s.expectedFiles[path]
+				require.True(t, ok, "output directory contained unexpected file %q", path)
 				require.Equal(t, expectedData, string(actualData))
-			}
+				return nil
+			}))
 		})
 	}
 }
 
-func newMigrateRegistry(imageMap map[image.Reference]string) (image.Registry, error) {
-	subSqliteImage, err := generateSqliteFS(imageMap)
+func newMigrateRegistry(t *testing.T, imageMap map[image.Reference]string) (image.Registry, error) {
+	subSqliteImage, err := generateSqliteFS(t, imageMap)
 	if err != nil {
 		return nil, err
 	}
@@ -158,7 +181,7 @@ func newMigrateRegistry(imageMap map[image.Reference]string) (image.Registry, er
 	return reg, nil
 }
 
-func migrateFooCatalog() string {
+func migrateFooCatalogSqlite() string {
 	return `---
 defaultChannel: beta
 name: foo
@@ -214,10 +237,10 @@ properties:
     versionRange: <0.1.0
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0=
+    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19
+    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0=
 relatedImages:
 - image: test.registry/foo-operator/foo-bundle:v0.1.0
   name: ""
@@ -249,10 +272,10 @@ properties:
     versionRange: <0.1.0
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwiaW5zdGFsbCI6eyJzcGVjIjp7ImRlcGxveW1lbnRzIjpbeyJuYW1lIjoiZm9vLW9wZXJhdG9yIiwic3BlYyI6eyJ0ZW1wbGF0ZSI6eyJzcGVjIjp7ImNvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQ6djAuMi4wIn1dfX19fSx7Im5hbWUiOiJmb28tb3BlcmF0b3ItMiIsInNwZWMiOnsidGVtcGxhdGUiOnsic3BlYyI6eyJjb250YWluZXJzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvby0yOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQtMjp2MC4yLjAifV19fX19XX0sInN0cmF0ZWd5IjoiZGVwbG95bWVudCJ9LCJyZWxhdGVkSW1hZ2VzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvbzp2MC4yLjAiLCJuYW1lIjoib3BlcmF0b3IifSx7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLW90aGVyOnYwLjIuMCIsIm5hbWUiOiJvdGhlciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19
+    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19
+    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwiaW5zdGFsbCI6eyJzcGVjIjp7ImRlcGxveW1lbnRzIjpbeyJuYW1lIjoiZm9vLW9wZXJhdG9yIiwic3BlYyI6eyJ0ZW1wbGF0ZSI6eyJzcGVjIjp7ImNvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQ6djAuMi4wIn1dfX19fSx7Im5hbWUiOiJmb28tb3BlcmF0b3ItMiIsInNwZWMiOnsidGVtcGxhdGUiOnsic3BlYyI6eyJjb250YWluZXJzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvby0yOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQtMjp2MC4yLjAifV19fX19XX0sInN0cmF0ZWd5IjoiZGVwbG95bWVudCJ9LCJyZWxhdGVkSW1hZ2VzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvbzp2MC4yLjAiLCJuYW1lIjoib3BlcmF0b3IifSx7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLW90aGVyOnYwLjIuMCIsIm5hbWUiOiJvdGhlciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19
 relatedImages:
 - image: test.registry/foo-operator/foo-2:v0.2.0
   name: ""
@@ -270,7 +293,7 @@ schema: olm.bundle
 `
 }
 
-func migrateBarCatalog() string {
+func migrateBarCatalogSqlite() string {
 	return `---
 defaultChannel: alpha
 name: bar
@@ -301,10 +324,10 @@ properties:
     version: 0.1.0
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0=
+    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19
+    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhci52MC4xLjAifSwic3BlYyI6eyJjdXN0b21yZXNvdXJjZWRlZmluaXRpb25zIjp7Im93bmVkIjpbeyJncm91cCI6InRlc3QuYmFyIiwia2luZCI6IkJhciIsIm5hbWUiOiJiYXJzLnRlc3QuYmFyIiwidmVyc2lvbiI6InYxYWxwaGExIn1dfSwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Jhci1vcGVyYXRvci9iYXI6djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0=
 relatedImages:
 - image: test.registry/bar-operator/bar-bundle:v0.1.0
   name: ""
@@ -327,10 +350,10 @@ properties:
     version: 0.2.0
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0=
+    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19
 - type: olm.bundle.object
   value:
-    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImJhcnMudGVzdC5iYXIifSwic3BlYyI6eyJncm91cCI6InRlc3QuYmFyIiwibmFtZXMiOnsia2luZCI6IkJhciIsInBsdXJhbCI6ImJhcnMifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MWFscGhhMSJ9XX19
+    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJiYXIudjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmJhciIsImtpbmQiOiJCYXIiLCJuYW1lIjoiYmFycy50ZXN0LmJhciIsInZlcnNpb24iOiJ2MWFscGhhMSJ9XX0sInJlbGF0ZWRJbWFnZXMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9iYXItb3BlcmF0b3IvYmFyOnYwLjIuMCIsIm5hbWUiOiJvcGVyYXRvciJ9XSwic2tpcHMiOlsiYmFyLnYwLjEuMCJdLCJ2ZXJzaW9uIjoiMC4yLjAifX0=
 relatedImages:
 - image: test.registry/bar-operator/bar-bundle:v0.2.0
   name: ""
@@ -339,3 +362,123 @@ relatedImages:
 schema: olm.bundle
 `
 }
+
+func migrateFooCatalogFBC() string {
+	return `---
+defaultChannel: beta
+name: foo
+properties:
+- type: owner
+  value:
+    group: abc.com
+    name: admin
+schema: olm.package
+---
+entries:
+- name: foo.v0.1.0
+  skipRange: <0.1.0
+- name: foo.v0.2.0
+  replaces: foo.v0.1.0
+  skipRange: <0.2.0
+  skips:
+  - foo.v0.1.1
+  - foo.v0.1.2
+name: beta
+package: foo
+properties:
+- type: user
+  value:
+    group: xyz.com
+    name: account
+schema: olm.channel
+---
+entries:
+- name: foo.v0.2.0
+  replaces: foo.v0.1.0
+  skipRange: <0.2.0
+  skips:
+  - foo.v0.1.1
+  - foo.v0.1.2
+name: stable
+package: foo
+schema: olm.channel
+---
+image: test.registry/foo-operator/foo-bundle:v0.1.0
+name: foo.v0.1.0
+package: foo
+properties:
+- type: olm.gvk
+  value:
+    group: test.foo
+    kind: Foo
+    version: v1
+- type: olm.gvk.required
+  value:
+    group: test.bar
+    kind: Bar
+    version: v1alpha1
+- type: olm.package
+  value:
+    packageName: foo
+    version: 0.1.0
+- type: olm.package.required
+  value:
+    packageName: bar
+    versionRange: <0.1.0
+- type: olm.bundle.object
+  value:
+    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMS4wIn0sIm5hbWUiOiJmb28udjAuMS4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwicmVsYXRlZEltYWdlcyI6W3siaW1hZ2UiOiJ0ZXN0LnJlZ2lzdHJ5L2Zvby1vcGVyYXRvci9mb286djAuMS4wIiwibmFtZSI6Im9wZXJhdG9yIn1dLCJ2ZXJzaW9uIjoiMC4xLjAifX0=
+- type: olm.bundle.object
+  value:
+    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19
+relatedImages:
+- image: test.registry/foo-operator/foo-bundle:v0.1.0
+  name: ""
+- image: test.registry/foo-operator/foo:v0.1.0
+  name: operator
+schema: olm.bundle
+---
+image: test.registry/foo-operator/foo-bundle:v0.2.0
+name: foo.v0.2.0
+package: foo
+properties:
+- type: olm.gvk
+  value:
+    group: test.foo
+    kind: Foo
+    version: v1
+- type: olm.gvk.required
+  value:
+    group: test.bar
+    kind: Bar
+    version: v1alpha1
+- type: olm.package
+  value:
+    packageName: foo
+    version: 0.2.0
+- type: olm.package.required
+  value:
+    packageName: bar
+    versionRange: <0.1.0
+- type: olm.bundle.object
+  value:
+    data: eyJhcGlWZXJzaW9uIjoib3BlcmF0b3JzLmNvcmVvcy5jb20vdjFhbHBoYTEiLCJraW5kIjoiQ2x1c3RlclNlcnZpY2VWZXJzaW9uIiwibWV0YWRhdGEiOnsiYW5ub3RhdGlvbnMiOnsib2xtLnNraXBSYW5nZSI6Ilx1MDAzYzAuMi4wIn0sIm5hbWUiOiJmb28udjAuMi4wIn0sInNwZWMiOnsiY3VzdG9tcmVzb3VyY2VkZWZpbml0aW9ucyI6eyJvd25lZCI6W3siZ3JvdXAiOiJ0ZXN0LmZvbyIsImtpbmQiOiJGb28iLCJuYW1lIjoiZm9vcy50ZXN0LmZvbyIsInZlcnNpb24iOiJ2MSJ9XX0sImRpc3BsYXlOYW1lIjoiRm9vIE9wZXJhdG9yIiwiaW5zdGFsbCI6eyJzcGVjIjp7ImRlcGxveW1lbnRzIjpbeyJuYW1lIjoiZm9vLW9wZXJhdG9yIiwic3BlYyI6eyJ0ZW1wbGF0ZSI6eyJzcGVjIjp7ImNvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQ6djAuMi4wIn1dfX19fSx7Im5hbWUiOiJmb28tb3BlcmF0b3ItMiIsInNwZWMiOnsidGVtcGxhdGUiOnsic3BlYyI6eyJjb250YWluZXJzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvby0yOnYwLjIuMCJ9XSwiaW5pdENvbnRhaW5lcnMiOlt7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLWluaXQtMjp2MC4yLjAifV19fX19XX0sInN0cmF0ZWd5IjoiZGVwbG95bWVudCJ9LCJyZWxhdGVkSW1hZ2VzIjpbeyJpbWFnZSI6InRlc3QucmVnaXN0cnkvZm9vLW9wZXJhdG9yL2Zvbzp2MC4yLjAiLCJuYW1lIjoib3BlcmF0b3IifSx7ImltYWdlIjoidGVzdC5yZWdpc3RyeS9mb28tb3BlcmF0b3IvZm9vLW90aGVyOnYwLjIuMCIsIm5hbWUiOiJvdGhlciJ9XSwicmVwbGFjZXMiOiJmb28udjAuMS4wIiwic2tpcHMiOlsiZm9vLnYwLjEuMSIsImZvby52MC4xLjIiXSwidmVyc2lvbiI6IjAuMi4wIn19
+- type: olm.bundle.object
+  value:
+    data: eyJhcGlWZXJzaW9uIjoiYXBpZXh0ZW5zaW9ucy5rOHMuaW8vdjEiLCJraW5kIjoiQ3VzdG9tUmVzb3VyY2VEZWZpbml0aW9uIiwibWV0YWRhdGEiOnsibmFtZSI6ImZvb3MudGVzdC5mb28ifSwic3BlYyI6eyJncm91cCI6InRlc3QuZm9vIiwibmFtZXMiOnsia2luZCI6IkZvbyIsInBsdXJhbCI6ImZvb3MifSwidmVyc2lvbnMiOlt7Im5hbWUiOiJ2MSJ9XX19
+relatedImages:
+- image: test.registry/foo-operator/foo-2:v0.2.0
+  name: ""
+- image: test.registry/foo-operator/foo-bundle:v0.2.0
+  name: ""
+- image: test.registry/foo-operator/foo-init-2:v0.2.0
+  name: ""
+- image: test.registry/foo-operator/foo-init:v0.2.0
+  name: ""
+- image: test.registry/foo-operator/foo-other:v0.2.0
+  name: other
+- image: test.registry/foo-operator/foo:v0.2.0
+  name: operator
+schema: olm.bundle
+`
+}
diff --git a/alpha/action/migrations/000_bundle_object_to_csv_metadata.go b/alpha/action/migrations/000_bundle_object_to_csv_metadata.go
new file mode 100644
index 000000000..d5c6896ea
--- /dev/null
+++ b/alpha/action/migrations/000_bundle_object_to_csv_metadata.go
@@ -0,0 +1,47 @@
+package migrations
+
+import (
+	"encoding/json"
+
+	"github.com/operator-framework/api/pkg/operators/v1alpha1"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/property"
+)
+
+func bundleObjectToCSVMetadata(cfg *declcfg.DeclarativeConfig) error {
+	convertBundleObjectToCSVMetadata := func(b *declcfg.Bundle) error {
+		if b.Image == "" || b.CsvJSON == "" {
+			return nil
+		}
+
+		var csv v1alpha1.ClusterServiceVersion
+		if err := json.Unmarshal([]byte(b.CsvJSON), &csv); err != nil {
+			return err
+		}
+
+		props := b.Properties[:0]
+		for _, p := range b.Properties {
+			switch p.Type {
+			case property.TypeBundleObject:
+				// Get rid of the bundle objects
+			case property.TypeCSVMetadata:
+				// If this bundle already has a CSV metadata
+				// property, we won't mutate the bundle at all.
+				return nil
+			default:
+				// Keep all of the other properties
+				props = append(props, p)
+			}
+		}
+		b.Properties = append(props, property.MustBuildCSVMetadata(csv))
+		return nil
+	}
+
+	for bi := range cfg.Bundles {
+		if err := convertBundleObjectToCSVMetadata(&cfg.Bundles[bi]); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/alpha/action/migrations/migrations.go b/alpha/action/migrations/migrations.go
new file mode 100644
index 000000000..22ff86b74
--- /dev/null
+++ b/alpha/action/migrations/migrations.go
@@ -0,0 +1,104 @@
+package migrations
+
+import (
+	"fmt"
+	"slices"
+	"strings"
+	"text/tabwriter"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+)
+
+type MigrationToken string
+
+const (
+	invalidMigration string = ""
+	NoMigrations     string = "none"
+	AllMigrations    string = "all"
+)
+
+type Migration interface {
+	Token() MigrationToken
+	Help() string
+	Migrate(*declcfg.DeclarativeConfig) error
+}
+
+func newMigration(token string, help string, fn func(config *declcfg.DeclarativeConfig) error) Migration {
+	return &simpleMigration{token: MigrationToken(token), help: help, fn: fn}
+}
+
+type simpleMigration struct {
+	token MigrationToken
+	help  string
+	fn    func(*declcfg.DeclarativeConfig) error
+}
+
+func (s simpleMigration) Token() MigrationToken {
+	return s.token
+}
+
+func (s simpleMigration) Migrate(config *declcfg.DeclarativeConfig) error {
+	return s.fn(config)
+}
+
+func (s simpleMigration) Help() string {
+	return s.help
+}
+
+type Migrations struct {
+	Migrations []Migration
+}
+
+// allMigrations represents the migration catalog
+// the order of these migrations is important
+var allMigrations = []Migration{
+	newMigration(NoMigrations, "do nothing", func(_ *declcfg.DeclarativeConfig) error { return nil }),
+	newMigration("bundle-object-to-csv-metadata", `migrates bundles' "olm.bundle.object" to "olm.csv.metadata"`, bundleObjectToCSVMetadata),
+}
+
+func NewMigrations(name string) (*Migrations, error) {
+	if name == AllMigrations {
+		return &Migrations{Migrations: slices.Clone(allMigrations)}, nil
+	}
+
+	migrations := slices.Clone(allMigrations)
+
+	found := false
+	keep := migrations[:0]
+	for _, migration := range migrations {
+		keep = append(keep, migration)
+		if migration.Token() == MigrationToken(name) {
+			found = true
+			break
+		}
+	}
+	if !found {
+		return nil, fmt.Errorf("unknown migration level %q", name)
+	}
+	return &Migrations{Migrations: keep}, nil
+}
+
+func HelpText() string {
+	var help strings.Builder
+	help.WriteString("\nThe migrator will run all migrations up to and including the selected level.\n\n")
+	help.WriteString("Available migrators:\n")
+	if len(allMigrations) == 0 {
+		help.WriteString("   (no migrations available in this version)\n")
+	}
+
+	tabber := tabwriter.NewWriter(&help, 0, 0, 1, ' ', 0)
+	for _, migration := range allMigrations {
+		fmt.Fprintf(tabber, "  - %s\t: %s\n", migration.Token(), migration.Help())
+	}
+	tabber.Flush()
+	return help.String()
+}
+
+func (m *Migrations) Migrate(config *declcfg.DeclarativeConfig) error {
+	for _, migration := range m.Migrations {
+		if err := migration.Migrate(config); err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/alpha/action/migrations/migrations_test.go b/alpha/action/migrations/migrations_test.go
new file mode 100644
index 000000000..d3b1ad074
--- /dev/null
+++ b/alpha/action/migrations/migrations_test.go
@@ -0,0 +1,141 @@
+package migrations
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/stretchr/testify/require"
+
+	"github.com/operator-framework/api/pkg/operators/v1alpha1"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/property"
+)
+
+func TestMigrations(t *testing.T) {
+	noneMigration, err := NewMigrations(NoMigrations)
+	require.NoError(t, err)
+	csvMigration, err := NewMigrations("bundle-object-to-csv-metadata")
+	require.NoError(t, err)
+	allMigrations, err := NewMigrations(AllMigrations)
+	require.NoError(t, err)
+
+	migrationPhaseEvaluators := map[MigrationToken]func(*declcfg.DeclarativeConfig) error{
+		MigrationToken(NoMigrations): func(d *declcfg.DeclarativeConfig) error {
+			if diff := cmp.Diff(*d, unmigratedCatalogFBC()); diff != "" {
+				return fmt.Errorf("'none' migrator is not expected to change the config\n%s", diff)
+			}
+			return nil
+		},
+		MigrationToken("bundle-object-to-csv-metadata"): func(d *declcfg.DeclarativeConfig) error {
+			if diff := cmp.Diff(*d, csvMetadataCatalogFBC()); diff != "" {
+				return fmt.Errorf("unexpected result of migration\n%s", diff)
+			}
+			return nil
+		},
+	}
+
+	tests := []struct {
+		name      string
+		migrators *Migrations
+	}{
+		{
+			name:      "NoMigrations",
+			migrators: noneMigration,
+		},
+		{
+			name:      "BundleObjectToCSVMetadata",
+			migrators: csvMigration,
+		},
+		{
+			name:      "MigrationSequence",
+			migrators: allMigrations,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			var config = unmigratedCatalogFBC()
+
+			for _, m := range test.migrators.Migrations {
+				err := m.Migrate(&config)
+				require.NoError(t, err)
+				err = migrationPhaseEvaluators[m.Token()](&config)
+				require.NoError(t, err)
+			}
+		})
+	}
+}
+
+func mustBuildCSVMetadata(r io.Reader) property.Property {
+	var csv v1alpha1.ClusterServiceVersion
+	if err := json.NewDecoder(r).Decode(&csv); err != nil {
+		panic(err)
+	}
+	return property.MustBuildCSVMetadata(csv)
+}
+
+var fooRawCsv = []byte(`{"apiVersion": "operators.coreos.com/v1alpha1", "kind": "ClusterServiceVersion", "metadata": {"name": "foo.v0.1.0"}, "spec": {"displayName": "Foo Operator", "customresourcedefinitions": {"owned": [{"group": "test.foo", "version": "v1", "kind": "Foo", "name": "foos.test.foo"}]}, "version": "0.1.0", "relatedImages": [{"name": "operator", "image": "test.registry/foo-operator/foo:v0.1.0"}]}}`)
+
+var fooRawCrd = []byte(`---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: foos.test.foo
+spec:
+  group: test.foo
+  names:
+    kind: Foo
+    plural: foos
+  versions:
+    - name: v1`,
+)
+
+func unmigratedCatalogFBC() declcfg.DeclarativeConfig {
+	return declcfg.DeclarativeConfig{
+		Bundles: []declcfg.Bundle{
+			{
+				Schema:  "olm.bundle",
+				Name:    "foo.v0.1.0",
+				Package: "foo",
+				Image:   "quay.io/openshift-community-operators/foo:v0.1.0",
+				Properties: []property.Property{
+					property.MustBuildGVK("test.foo", "v1", "Foo"),
+					property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+					property.MustBuildPackage("foo", "0.1.0"),
+					property.MustBuildPackageRequired("bar", "<0.1.0"),
+					property.MustBuildBundleObject(fooRawCrd),
+					property.MustBuildBundleObject(fooRawCsv),
+				},
+				Objects: []string{string(fooRawCsv), string(fooRawCrd)},
+				CsvJSON: string(fooRawCsv),
+			},
+		},
+	}
+}
+
+func csvMetadataCatalogFBC() declcfg.DeclarativeConfig {
+	return declcfg.DeclarativeConfig{
+		Bundles: []declcfg.Bundle{
+			{
+				Schema:  "olm.bundle",
+				Name:    "foo.v0.1.0",
+				Package: "foo",
+				Image:   "quay.io/openshift-community-operators/foo:v0.1.0",
+				Properties: []property.Property{
+					property.MustBuildGVK("test.foo", "v1", "Foo"),
+					property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+					property.MustBuildPackage("foo", "0.1.0"),
+					property.MustBuildPackageRequired("bar", "<0.1.0"),
+					mustBuildCSVMetadata(bytes.NewReader(fooRawCsv)),
+				},
+				Objects: []string{string(fooRawCsv), string(fooRawCrd)},
+				CsvJSON: string(fooRawCsv),
+			},
+		},
+	}
+}
diff --git a/alpha/action/render.go b/alpha/action/render.go
index 3f38390a0..ad7a066b4 100644
--- a/alpha/action/render.go
+++ b/alpha/action/render.go
@@ -6,24 +6,25 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sort"
 	"strings"
 	"sync"
+	"text/template"
 
 	"github.com/h2non/filetype"
 	"github.com/h2non/filetype/matchers"
-	"github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/util/sets"
 
+	"github.com/operator-framework/operator-registry/alpha/action/migrations"
 	"github.com/operator-framework/operator-registry/alpha/declcfg"
 	"github.com/operator-framework/operator-registry/alpha/property"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/image"
 	"github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
 	"github.com/operator-framework/operator-registry/pkg/lib/bundle"
+	"github.com/operator-framework/operator-registry/pkg/lib/log"
 	"github.com/operator-framework/operator-registry/pkg/registry"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
 )
@@ -38,6 +39,7 @@ const (
 	RefSqliteFile
 	RefDCImage
 	RefDCDir
+	RefBundleDir
 
 	RefAll = 0
 )
@@ -49,19 +51,15 @@ func (r RefType) Allowed(refType RefType) bool {
 var ErrNotAllowed = errors.New("not allowed")
 
 type Render struct {
-	Refs           []string
-	Registry       image.Registry
-	AllowedRefMask RefType
+	Refs             []string
+	Registry         image.Registry
+	AllowedRefMask   RefType
+	ImageRefTemplate *template.Template
+	Migrations       *migrations.Migrations
 
 	skipSqliteDeprecationLog bool
 }
 
-func nullLogger() *logrus.Entry {
-	logger := logrus.New()
-	logger.SetOutput(ioutil.Discard)
-	return logrus.NewEntry(logger)
-}
-
 func (r Render) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) {
 	if r.skipSqliteDeprecationLog {
 		// exhaust once with a no-op function.
@@ -72,17 +70,20 @@ func (r Render) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) {
 		if err != nil {
 			return nil, fmt.Errorf("create registry: %v", err)
 		}
-		defer reg.Destroy()
+		defer func() {
+			_ = reg.Destroy()
+		}()
 		r.Registry = reg
 	}
 
+	// nolint:prealloc
 	var cfgs []declcfg.DeclarativeConfig
 	for _, ref := range r.Refs {
 		cfg, err := r.renderReference(ctx, ref)
 		if err != nil {
 			return nil, fmt.Errorf("render reference %q: %w", ref, err)
 		}
-		renderBundleObjects(cfg)
+		moveBundleObjectsToEndOfPropertySlices(cfg)
 
 		for _, b := range cfg.Bundles {
 			sort.Slice(b.RelatedImages, func(i, j int) bool {
@@ -90,6 +91,10 @@ func (r Render) Run(ctx context.Context) (*declcfg.DeclarativeConfig, error) {
 			})
 		}
 
+		if err := r.migrate(cfg); err != nil {
+			return nil, fmt.Errorf("migrate: %v", err)
+		}
+
 		cfgs = append(cfgs, *cfg)
 	}
 
@@ -108,7 +113,7 @@ func (r Render) createRegistry() (*containerdregistry.Registry, error) {
 		// The containerd registry impl is somewhat verbose, even on the happy path,
 		// so discard all logger logs. Any important failures will be returned from
 		// registry methods and eventually logged as fatal errors.
-		containerdregistry.WithLog(nullLogger()),
+		containerdregistry.WithLog(log.Null()),
 	)
 	if err != nil {
 		return nil, err
@@ -117,51 +122,77 @@ func (r Render) createRegistry() (*containerdregistry.Registry, error) {
 }
 
 func (r Render) renderReference(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) {
-	if stat, serr := os.Stat(ref); serr == nil {
-		if stat.IsDir() {
-			if !r.AllowedRefMask.Allowed(RefDCDir) {
-				return nil, fmt.Errorf("cannot render declarative config directory: %w", ErrNotAllowed)
-			}
-			return declcfg.LoadFS(os.DirFS(ref))
-		} else {
-			// The only supported file type is an sqlite DB file,
-			// since declarative configs will be in a directory.
-			if err := checkDBFile(ref); err != nil {
-				return nil, err
-			}
-			if !r.AllowedRefMask.Allowed(RefSqliteFile) {
-				return nil, fmt.Errorf("cannot render sqlite file: %w", ErrNotAllowed)
+	stat, err := os.Stat(ref)
+	if err != nil {
+		return r.imageToDeclcfg(ctx, ref)
+	}
+	// nolint:nestif
+	if stat.IsDir() {
+		dirEntries, err := os.ReadDir(ref)
+		if err != nil {
+			return nil, err
+		}
+		if isBundle(dirEntries) {
+			// Looks like a bundle directory
+			if !r.AllowedRefMask.Allowed(RefBundleDir) {
+				return nil, fmt.Errorf("cannot render bundle directory %q: %w", ref, ErrNotAllowed)
 			}
-			return sqliteToDeclcfg(ctx, ref)
+			return r.renderBundleDirectory(ref)
 		}
+
+		// Otherwise, assume it is a declarative config root directory.
+		if !r.AllowedRefMask.Allowed(RefDCDir) {
+			return nil, fmt.Errorf("cannot render declarative config directory: %w", ErrNotAllowed)
+		}
+		return declcfg.LoadFS(ctx, os.DirFS(ref))
 	}
-	return r.imageToDeclcfg(ctx, ref)
+	// The only supported file type is an sqlite DB file,
+	// since declarative configs will be in a directory.
+	if err := checkDBFile(ref); err != nil {
+		return nil, err
+	}
+	if !r.AllowedRefMask.Allowed(RefSqliteFile) {
+		return nil, fmt.Errorf("cannot render sqlite file: %w", ErrNotAllowed)
+	}
+
+	db, err := sqlite.Open(ref)
+	if err != nil {
+		return nil, err
+	}
+	defer db.Close()
+	return sqliteToDeclcfg(ctx, db)
 }
 
 func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.DeclarativeConfig, error) {
 	ref := image.SimpleReference(imageRef)
 	if err := r.Registry.Pull(ctx, ref); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to pull image %q: %v", ref, err)
 	}
 	labels, err := r.Registry.Labels(ctx, ref)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to get labels for image %q: %v", ref, err)
 	}
-	tmpDir, err := ioutil.TempDir("", "render-unpack-")
+	tmpDir, err := os.MkdirTemp("", "render-unpack-")
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("create tempdir: %v", err)
 	}
 	defer os.RemoveAll(tmpDir)
 	if err := r.Registry.Unpack(ctx, ref, tmpDir); err != nil {
-		return nil, err
+		return nil, fmt.Errorf("failed to unpack image %q: %v", ref, err)
 	}
 
 	var cfg *declcfg.DeclarativeConfig
+	// nolint:nestif
 	if dbFile, ok := labels[containertools.DbLocationLabel]; ok {
 		if !r.AllowedRefMask.Allowed(RefSqliteImage) {
 			return nil, fmt.Errorf("cannot render sqlite image: %w", ErrNotAllowed)
 		}
-		cfg, err = sqliteToDeclcfg(ctx, filepath.Join(tmpDir, dbFile))
+		db, err := sqlite.Open(filepath.Join(tmpDir, dbFile))
+		if err != nil {
+			return nil, err
+		}
+		defer db.Close()
+		cfg, err = sqliteToDeclcfg(ctx, db)
 		if err != nil {
 			return nil, err
 		}
@@ -169,7 +200,7 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D
 		if !r.AllowedRefMask.Allowed(RefDCImage) {
 			return nil, fmt.Errorf("cannot render declarative config image: %w", ErrNotAllowed)
 		}
-		cfg, err = declcfg.LoadFS(os.DirFS(filepath.Join(tmpDir, configsDir)))
+		cfg, err = declcfg.LoadFS(ctx, os.DirFS(filepath.Join(tmpDir, configsDir)))
 		if err != nil {
 			return nil, err
 		}
@@ -182,10 +213,11 @@ func (r Render) imageToDeclcfg(ctx context.Context, imageRef string) (*declcfg.D
 			return nil, err
 		}
 
-		cfg, err = bundleToDeclcfg(img.Bundle)
+		bundle, err := bundleToDeclcfg(img.Bundle)
 		if err != nil {
 			return nil, err
 		}
+		cfg = &declcfg.DeclarativeConfig{Bundles: []declcfg.Bundle{*bundle}}
 	} else {
 		labelKeys := sets.StringKeySet(labels)
 		labelVals := []string{}
@@ -213,17 +245,11 @@ func checkDBFile(ref string) error {
 	return nil
 }
 
-func sqliteToDeclcfg(ctx context.Context, dbFile string) (*declcfg.DeclarativeConfig, error) {
+func sqliteToDeclcfg(ctx context.Context, db *sql.DB) (*declcfg.DeclarativeConfig, error) {
 	logDeprecationMessage.Do(func() {
 		sqlite.LogSqliteDeprecation()
 	})
 
-	db, err := sqlite.Open(dbFile)
-	if err != nil {
-		return nil, err
-	}
-	defer db.Close()
-
 	migrator, err := sqlite.NewSQLLiteMigrator(db)
 	if err != nil {
 		return nil, err
@@ -258,6 +284,7 @@ func populateDBRelatedImages(ctx context.Context, cfg *declcfg.DeclarativeConfig
 	}
 	defer rows.Close()
 
+	// nolint:staticcheck
 	images := map[string]sets.String{}
 	for rows.Next() {
 		var (
@@ -295,7 +322,7 @@ func populateDBRelatedImages(ctx context.Context, cfg *declcfg.DeclarativeConfig
 	return nil
 }
 
-func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error) {
+func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.Bundle, error) {
 	objs, props, err := registry.ObjectsAndPropertiesFromBundle(bundle)
 	if err != nil {
 		return nil, fmt.Errorf("get properties for bundle %q: %v", bundle.Name, err)
@@ -304,17 +331,18 @@ func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error
 	if err != nil {
 		return nil, fmt.Errorf("get related images for bundle %q: %v", bundle.Name, err)
 	}
-	var csvJson []byte
+
+	var csvJSON []byte
 	for _, obj := range bundle.Objects {
 		if obj.GetKind() == "ClusterServiceVersion" {
-			csvJson, err = json.Marshal(obj)
+			csvJSON, err = json.Marshal(obj)
 			if err != nil {
 				return nil, fmt.Errorf("marshal CSV JSON for bundle %q: %v", bundle.Name, err)
 			}
 		}
 	}
 
-	dBundle := declcfg.Bundle{
+	return &declcfg.Bundle{
 		Schema:        "olm.bundle",
 		Name:          bundle.Name,
 		Package:       bundle.Package,
@@ -322,10 +350,8 @@ func bundleToDeclcfg(bundle *registry.Bundle) (*declcfg.DeclarativeConfig, error
 		Properties:    props,
 		RelatedImages: relatedImages,
 		Objects:       objs,
-		CsvJSON:       string(csvJson),
-	}
-
-	return &declcfg.DeclarativeConfig{Bundles: []declcfg.Bundle{dBundle}}, nil
+		CsvJSON:       string(csvJSON),
+	}, nil
 }
 
 func getRelatedImages(b *registry.Bundle) ([]declcfg.RelatedImage, error) {
@@ -354,7 +380,7 @@ func getRelatedImages(b *registry.Bundle) ([]declcfg.RelatedImage, error) {
 		allImages = allImages.Insert(ri.Image)
 	}
 
-	if !allImages.Has(b.BundleImage) {
+	if b.BundleImage != "" && !allImages.Has(b.BundleImage) {
 		relatedImages = append(relatedImages, declcfg.RelatedImage{
 			Image: b.BundleImage,
 		})
@@ -376,29 +402,105 @@ func getRelatedImages(b *registry.Bundle) ([]declcfg.RelatedImage, error) {
 	return relatedImages, nil
 }
 
-func renderBundleObjects(cfg *declcfg.DeclarativeConfig) {
+func moveBundleObjectsToEndOfPropertySlices(cfg *declcfg.DeclarativeConfig) {
 	for bi, b := range cfg.Bundles {
-		props := b.Properties[:0]
+		var (
+			others []property.Property
+			objs   []property.Property
+		)
 		for _, p := range b.Properties {
-			if p.Type != property.TypeBundleObject {
-				props = append(props, p)
+			switch p.Type {
+			case property.TypeBundleObject, property.TypeCSVMetadata:
+				objs = append(objs, p)
+			default:
+				others = append(others, p)
 			}
 		}
+		cfg.Bundles[bi].Properties = append(others, objs...)
+	}
+}
 
-		for _, obj := range b.Objects {
-			props = append(props, property.MustBuildBundleObjectData([]byte(obj)))
-		}
-		cfg.Bundles[bi].Properties = props
+func (r Render) migrate(cfg *declcfg.DeclarativeConfig) error {
+	// If there are no migrations, do nothing.
+	if r.Migrations == nil {
+		return nil
 	}
+	return r.Migrations.Migrate(cfg)
 }
 
 func combineConfigs(cfgs []declcfg.DeclarativeConfig) *declcfg.DeclarativeConfig {
 	out := &declcfg.DeclarativeConfig{}
 	for _, in := range cfgs {
-		out.Packages = append(out.Packages, in.Packages...)
-		out.Channels = append(out.Channels, in.Channels...)
-		out.Bundles = append(out.Bundles, in.Bundles...)
-		out.Others = append(out.Others, in.Others...)
+		out.Merge(&in)
 	}
 	return out
 }
+
+func isBundle(entries []os.DirEntry) bool {
+	foundManifests := false
+	foundMetadata := false
+	for _, e := range entries {
+		if e.IsDir() {
+			switch e.Name() {
+			case "manifests":
+				foundManifests = true
+			case "metadata":
+				foundMetadata = true
+			}
+		}
+		if foundMetadata && foundManifests {
+			return true
+		}
+	}
+	return false
+}
+
+type imageReferenceTemplateData struct {
+	Package string
+	Name    string
+	Version string
+}
+
+func (r *Render) renderBundleDirectory(ref string) (*declcfg.DeclarativeConfig, error) {
+	img, err := registry.NewImageInput(image.SimpleReference(""), ref)
+	if err != nil {
+		return nil, err
+	}
+	if err := r.templateBundleImageRef(img.Bundle); err != nil {
+		return nil, fmt.Errorf("failed templating image reference from bundle for %q: %v", ref, err)
+	}
+	fbcBundle, err := bundleToDeclcfg(img.Bundle)
+	if err != nil {
+		return nil, err
+	}
+	return &declcfg.DeclarativeConfig{Bundles: []declcfg.Bundle{*fbcBundle}}, nil
+}
+
+func (r *Render) templateBundleImageRef(bundle *registry.Bundle) error {
+	if r.ImageRefTemplate == nil {
+		return nil
+	}
+
+	var pkgProp property.Package
+	for _, p := range bundle.Properties {
+		if p.Type != property.TypePackage {
+			continue
+		}
+		if err := json.Unmarshal(p.Value, &pkgProp); err != nil {
+			return err
+		}
+		break
+	}
+
+	var buf strings.Builder
+	tmplInput := imageReferenceTemplateData{
+		Package: bundle.Package,
+		Name:    bundle.Name,
+		Version: pkgProp.Version,
+	}
+	if err := r.ImageRefTemplate.Execute(&buf, tmplInput); err != nil {
+		return err
+	}
+	bundle.BundleImage = buf.String()
+	return nil
+}
diff --git a/alpha/action/render_test.go b/alpha/action/render_test.go
index b355233ec..72fdd8a4e 100644
--- a/alpha/action/render_test.go
+++ b/alpha/action/render_test.go
@@ -3,18 +3,20 @@ package action_test
 import (
 	"context"
 	"embed"
-	"errors"
+	"encoding/json"
+	"fmt"
 	"io/fs"
 	"os"
 	"path/filepath"
 	"testing"
 	"testing/fstest"
+	"text/template"
 
-	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"k8s.io/apimachinery/pkg/util/yaml"
 
 	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/alpha/action/migrations"
 	"github.com/operator-framework/operator-registry/alpha/declcfg"
 	"github.com/operator-framework/operator-registry/alpha/property"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
@@ -24,6 +26,22 @@ import (
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
 )
 
+type fauxMigration struct {
+	token   string
+	help    string
+	migrate func(*declcfg.DeclarativeConfig) error
+}
+
+func (m fauxMigration) Token() migrations.MigrationToken {
+	return migrations.MigrationToken(m.token)
+}
+func (m fauxMigration) Help() string {
+	return m.help
+}
+func (m fauxMigration) Migrate(config *declcfg.DeclarativeConfig) error {
+	return m.migrate(config)
+}
+
 func TestRender(t *testing.T) {
 	type spec struct {
 		name      string
@@ -32,7 +50,7 @@ func TestRender(t *testing.T) {
 		assertion require.ErrorAssertionFunc
 	}
 
-	reg, err := newRegistry()
+	reg, err := newRegistry(t)
 	require.NoError(t, err)
 	foov1csv, err := bundleImageV1.ReadFile("testdata/foo-bundle-v0.1.0/manifests/foo.v0.1.0.csv.yaml")
 	require.NoError(t, err)
@@ -66,13 +84,491 @@ func TestRender(t *testing.T) {
 		image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0",
 		image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0",
 	}
-	assert.NoError(t, generateSqliteFile(dbFile, imageMap))
+	require.NoError(t, generateSqliteFile(dbFile, imageMap))
+	testMigrations := migrations.Migrations{
+		Migrations: []migrations.Migration{
+			fauxMigration{"faux-migration", "my help text", func(d *declcfg.DeclarativeConfig) error {
+				for i := range d.Bundles {
+					d.Bundles[i].Name = fmt.Sprintf("%s-MIGRATED", d.Bundles[i].Name)
+				}
+				return nil
+			}},
+		},
+	}
 
 	specs := []spec{
 		{
-			name: "Success/SqliteIndexImage",
+			name: "Success/SqliteIndexImage",
+			render: action.Render{
+				Refs:     []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"},
+				Registry: reg,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Packages: []declcfg.Package{
+					{
+						Schema:         "olm.package",
+						Name:           "foo",
+						DefaultChannel: "beta",
+					},
+				},
+				Channels: []declcfg.Channel{
+					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+				},
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.1.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.1.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.1.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.1.0",
+							},
+						},
+						CsvJSON: string(foov1csv),
+						Objects: []string{string(foov1csv), string(foov1crd)},
+					},
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+						CsvJSON: string(foov2csv),
+						Objects: []string{string(foov2csv), string(foov2crd)},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/SqliteIndexImageWithMigration",
+			render: action.Render{
+				Refs:       []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"},
+				Registry:   reg,
+				Migrations: &testMigrations,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Packages: []declcfg.Package{
+					{
+						Schema:         "olm.package",
+						Name:           "foo",
+						DefaultChannel: "beta",
+					},
+				},
+				Channels: []declcfg.Channel{
+					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+				},
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.1.0-MIGRATED",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.1.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.1.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.1.0",
+							},
+						},
+						CsvJSON: string(foov1csv),
+						Objects: []string{string(foov1csv), string(foov1crd)},
+					},
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0-MIGRATED",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+						CsvJSON: string(foov2csv),
+						Objects: []string{string(foov2csv), string(foov2crd)},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/SqliteFile",
+			render: action.Render{
+				Refs:     []string{dbFile},
+				Registry: reg,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Packages: []declcfg.Package{
+					{
+						Schema:         "olm.package",
+						Name:           "foo",
+						DefaultChannel: "beta",
+					},
+				},
+				Channels: []declcfg.Channel{
+					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+				},
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.1.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.1.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.1.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.1.0",
+							},
+						},
+						CsvJSON: string(foov1csv),
+						Objects: []string{string(foov1csv), string(foov1crd)},
+					},
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+						CsvJSON: string(foov2csv),
+						Objects: []string{string(foov2csv), string(foov2crd)},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/SqliteFileMigration",
+			render: action.Render{
+				Refs:       []string{dbFile},
+				Registry:   reg,
+				Migrations: &testMigrations,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Packages: []declcfg.Package{
+					{
+						Schema:         "olm.package",
+						Name:           "foo",
+						DefaultChannel: "beta",
+					},
+				},
+				Channels: []declcfg.Channel{
+					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+				},
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.1.0-MIGRATED",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.1.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.1.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.1.0",
+							},
+						},
+						CsvJSON: string(foov1csv),
+						Objects: []string{string(foov1csv), string(foov1crd)},
+					},
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0-MIGRATED",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+						CsvJSON: string(foov2csv),
+						Objects: []string{string(foov2csv), string(foov2crd)},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/DeclcfgIndexImage",
+			render: action.Render{
+				Refs:     []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"},
+				Registry: reg,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Packages: []declcfg.Package{
+					{
+						Schema:         "olm.package",
+						Name:           "foo",
+						DefaultChannel: "beta",
+						Properties: []property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					},
+				},
+				Channels: []declcfg.Channel{
+					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					},
+						Properties: []property.Property{
+							{Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")},
+						},
+					},
+					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
+						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
+					}},
+				},
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.1.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.1.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov1csv),
+							property.MustBuildBundleObject(foov1crd),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.1.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.1.0",
+							},
+						},
+						CsvJSON: string(foov1csv),
+						Objects: []string{string(foov1csv), string(foov1crd)},
+					},
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2csv),
+							property.MustBuildBundleObject(foov2crd),
+						},
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+						CsvJSON: string(foov2csv),
+						Objects: []string{string(foov2csv), string(foov2crd)},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/DeclcfgDirectory",
 			render: action.Render{
-				Refs:     []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"},
+				Refs:     []string{"testdata/foo-index-v0.2.0-declcfg"},
 				Registry: reg,
 			},
 			expectCfg: &declcfg.DeclarativeConfig{
@@ -81,15 +577,21 @@ func TestRender(t *testing.T) {
 						Schema:         "olm.package",
 						Name:           "foo",
 						DefaultChannel: "beta",
+						Properties: []property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
 					},
 				},
 				Channels: []declcfg.Channel{
 					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
 						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
 						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
-					}},
+					},
+						Properties: []property.Property{
+							{Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")},
+						},
+					},
 					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
-						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
 						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
 					}},
 				},
@@ -104,8 +606,8 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.1.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov1csv),
-							property.MustBuildBundleObjectData(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+							property.MustBuildBundleObject(foov1crd),
 						},
 						RelatedImages: []declcfg.RelatedImage{
 							{
@@ -129,8 +631,8 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov2csv),
-							property.MustBuildBundleObjectData(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+							property.MustBuildBundleObject(foov2crd),
 						},
 						RelatedImages: []declcfg.RelatedImage{
 							{
@@ -162,10 +664,11 @@ func TestRender(t *testing.T) {
 			assertion: require.NoError,
 		},
 		{
-			name: "Success/SqliteFile",
+			name: "Success/DeclcfgImageMigrate",
 			render: action.Render{
-				Refs:     []string{dbFile},
-				Registry: reg,
+				Refs:       []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"},
+				Registry:   reg,
+				Migrations: &testMigrations,
 			},
 			expectCfg: &declcfg.DeclarativeConfig{
 				Packages: []declcfg.Package{
@@ -173,22 +676,28 @@ func TestRender(t *testing.T) {
 						Schema:         "olm.package",
 						Name:           "foo",
 						DefaultChannel: "beta",
+						Properties: []property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
 					},
 				},
 				Channels: []declcfg.Channel{
 					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
 						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
 						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
-					}},
+					},
+						Properties: []property.Property{
+							{Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")},
+						},
+					},
 					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
-						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
 						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
 					}},
 				},
 				Bundles: []declcfg.Bundle{
 					{
 						Schema:  "olm.bundle",
-						Name:    "foo.v0.1.0",
+						Name:    "foo.v0.1.0-MIGRATED",
 						Package: "foo",
 						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
 						Properties: []property.Property{
@@ -196,8 +705,8 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.1.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov1csv),
-							property.MustBuildBundleObjectData(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+							property.MustBuildBundleObject(foov1crd),
 						},
 						RelatedImages: []declcfg.RelatedImage{
 							{
@@ -213,7 +722,7 @@ func TestRender(t *testing.T) {
 					},
 					{
 						Schema:  "olm.bundle",
-						Name:    "foo.v0.2.0",
+						Name:    "foo.v0.2.0-MIGRATED",
 						Package: "foo",
 						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
 						Properties: []property.Property{
@@ -221,8 +730,8 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov2csv),
-							property.MustBuildBundleObjectData(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+							property.MustBuildBundleObject(foov2crd),
 						},
 						RelatedImages: []declcfg.RelatedImage{
 							{
@@ -254,10 +763,11 @@ func TestRender(t *testing.T) {
 			assertion: require.NoError,
 		},
 		{
-			name: "Success/DeclcfgIndexImage",
+			name: "Success/DeclcfgDirectoryMigrate",
 			render: action.Render{
-				Refs:     []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"},
-				Registry: reg,
+				Refs:       []string{"testdata/foo-index-v0.2.0-declcfg"},
+				Registry:   reg,
+				Migrations: &testMigrations,
 			},
 			expectCfg: &declcfg.DeclarativeConfig{
 				Packages: []declcfg.Package{
@@ -265,13 +775,20 @@ func TestRender(t *testing.T) {
 						Schema:         "olm.package",
 						Name:           "foo",
 						DefaultChannel: "beta",
+						Properties: []property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
 					},
 				},
 				Channels: []declcfg.Channel{
 					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
 						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
 						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
-					}},
+					},
+						Properties: []property.Property{
+							{Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")},
+						},
+					},
 					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
 						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
 					}},
@@ -279,7 +796,7 @@ func TestRender(t *testing.T) {
 				Bundles: []declcfg.Bundle{
 					{
 						Schema:  "olm.bundle",
-						Name:    "foo.v0.1.0",
+						Name:    "foo.v0.1.0-MIGRATED",
 						Package: "foo",
 						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
 						Properties: []property.Property{
@@ -287,8 +804,8 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.1.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov1csv),
-							property.MustBuildBundleObjectData(foov1crd),
+							property.MustBuildBundleObject(foov1csv),
+							property.MustBuildBundleObject(foov1crd),
 						},
 						RelatedImages: []declcfg.RelatedImage{
 							{
@@ -304,7 +821,7 @@ func TestRender(t *testing.T) {
 					},
 					{
 						Schema:  "olm.bundle",
-						Name:    "foo.v0.2.0",
+						Name:    "foo.v0.2.0-MIGRATED",
 						Package: "foo",
 						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
 						Properties: []property.Property{
@@ -312,8 +829,8 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov2csv),
-							property.MustBuildBundleObjectData(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+							property.MustBuildBundleObject(foov2crd),
 						},
 						RelatedImages: []declcfg.RelatedImage{
 							{
@@ -345,57 +862,67 @@ func TestRender(t *testing.T) {
 			assertion: require.NoError,
 		},
 		{
-			name: "Success/DeclcfgDirectory",
+			name: "Success/BundleImage",
 			render: action.Render{
-				Refs:     []string{"testdata/foo-index-v0.2.0-declcfg"},
+				Refs:     []string{"test.registry/foo-operator/foo-bundle:v0.2.0"},
 				Registry: reg,
 			},
 			expectCfg: &declcfg.DeclarativeConfig{
-				Packages: []declcfg.Package{
-					{
-						Schema:         "olm.package",
-						Name:           "foo",
-						DefaultChannel: "beta",
-					},
-				},
-				Channels: []declcfg.Channel{
-					{Schema: "olm.channel", Package: "foo", Name: "beta", Entries: []declcfg.ChannelEntry{
-						{Name: "foo.v0.1.0", SkipRange: "<0.1.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
-					}},
-					{Schema: "olm.channel", Package: "foo", Name: "stable", Entries: []declcfg.ChannelEntry{
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0", SkipRange: "<0.2.0", Skips: []string{"foo.v0.1.1", "foo.v0.1.2"}},
-					}},
-				},
 				Bundles: []declcfg.Bundle{
 					{
 						Schema:  "olm.bundle",
-						Name:    "foo.v0.1.0",
+						Name:    "foo.v0.2.0",
 						Package: "foo",
-						Image:   "test.registry/foo-operator/foo-bundle:v0.1.0",
+						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
 						Properties: []property.Property{
 							property.MustBuildGVK("test.foo", "v1", "Foo"),
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
-							property.MustBuildPackage("foo", "0.1.0"),
+							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov1csv),
-							property.MustBuildBundleObjectData(foov1crd),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
 						},
+						Objects: []string{string(foov2csv), string(foov2crd)},
+						CsvJSON: string(foov2csv),
 						RelatedImages: []declcfg.RelatedImage{
 							{
-								Image: "test.registry/foo-operator/foo-bundle:v0.1.0",
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
 							},
 							{
 								Name:  "operator",
-								Image: "test.registry/foo-operator/foo:v0.1.0",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
 							},
 						},
-						CsvJSON: string(foov1csv),
-						Objects: []string{string(foov1csv), string(foov1crd)},
 					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/BundleImageMigration",
+			render: action.Render{
+				Refs:       []string{"test.registry/foo-operator/foo-bundle:v0.2.0"},
+				Registry:   reg,
+				Migrations: &testMigrations,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Bundles: []declcfg.Bundle{
 					{
 						Schema:  "olm.bundle",
-						Name:    "foo.v0.2.0",
+						Name:    "foo.v0.2.0-MIGRATED",
 						Package: "foo",
 						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
 						Properties: []property.Property{
@@ -403,9 +930,11 @@ func TestRender(t *testing.T) {
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov2csv),
-							property.MustBuildBundleObjectData(foov2crd),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
 						},
+						Objects: []string{string(foov2csv), string(foov2crd)},
+						CsvJSON: string(foov2csv),
 						RelatedImages: []declcfg.RelatedImage{
 							{
 								Image: "test.registry/foo-operator/foo-2:v0.2.0",
@@ -428,17 +957,15 @@ func TestRender(t *testing.T) {
 								Image: "test.registry/foo-operator/foo:v0.2.0",
 							},
 						},
-						CsvJSON: string(foov2csv),
-						Objects: []string{string(foov2csv), string(foov2crd)},
 					},
 				},
 			},
 			assertion: require.NoError,
 		},
 		{
-			name: "Success/BundleImage",
+			name: "Success/BundleImageWithNoCSVRelatedImages",
 			render: action.Render{
-				Refs:     []string{"test.registry/foo-operator/foo-bundle:v0.2.0"},
+				Refs:     []string{"test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0"},
 				Registry: reg,
 			},
 			expectCfg: &declcfg.DeclarativeConfig{
@@ -447,14 +974,106 @@ func TestRender(t *testing.T) {
 						Schema:  "olm.bundle",
 						Name:    "foo.v0.2.0",
 						Package: "foo",
-						Image:   "test.registry/foo-operator/foo-bundle:v0.2.0",
+						Image:   "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crdNoRelatedImages),
+							property.MustBuildBundleObject(foov2csvNoRelatedImages),
+						},
+						Objects: []string{string(foov2csvNoRelatedImages), string(foov2crdNoRelatedImages)},
+						CsvJSON: string(foov2csvNoRelatedImages),
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/BundleImageWithNoCSVRelatedImagesMigration",
+			render: action.Render{
+				Refs:       []string{"test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0"},
+				Registry:   reg,
+				Migrations: &testMigrations,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0-MIGRATED",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csvNoRelatedImages),
+						},
+						Objects: []string{string(foov2csvNoRelatedImages), string(foov2crdNoRelatedImages)},
+						CsvJSON: string(foov2csvNoRelatedImages),
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/BundleDirectoryWithImageRefTemplate",
+			render: action.Render{
+				Refs:             []string{"testdata/foo-bundle-v0.2.0"},
+				ImageRefTemplate: template.Must(template.New("imageRef").Parse("test.registry/{{.Package}}-operator/{{.Package}}:v{{.Version}}")),
+				Registry:         reg,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo:v0.2.0",
 						Properties: []property.Property{
 							property.MustBuildGVK("test.foo", "v1", "Foo"),
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov2csv),
-							property.MustBuildBundleObjectData(foov2crd),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
 						},
 						Objects: []string{string(foov2csv), string(foov2crd)},
 						CsvJSON: string(foov2csv),
@@ -463,7 +1082,53 @@ func TestRender(t *testing.T) {
 								Image: "test.registry/foo-operator/foo-2:v0.2.0",
 							},
 							{
-								Image: "test.registry/foo-operator/foo-bundle:v0.2.0",
+								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
+							},
+							{
+								Image: "test.registry/foo-operator/foo-init:v0.2.0",
+							},
+							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
+								Image: "test.registry/foo-operator/foo:v0.2.0",
+							},
+						},
+					},
+				},
+			},
+			assertion: require.NoError,
+		},
+		{
+			name: "Success/BundleDirectoryWithImageRefTemplateMigration",
+			render: action.Render{
+				Refs:             []string{"testdata/foo-bundle-v0.2.0"},
+				ImageRefTemplate: template.Must(template.New("imageRef").Parse("test.registry/{{.Package}}-operator/{{.Package}}:v{{.Version}}")),
+				Registry:         reg,
+				Migrations:       &testMigrations,
+			},
+			expectCfg: &declcfg.DeclarativeConfig{
+				Bundles: []declcfg.Bundle{
+					{
+						Schema:  "olm.bundle",
+						Name:    "foo.v0.2.0-MIGRATED",
+						Package: "foo",
+						Image:   "test.registry/foo-operator/foo:v0.2.0",
+						Properties: []property.Property{
+							property.MustBuildGVK("test.foo", "v1", "Foo"),
+							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
+							property.MustBuildPackage("foo", "0.2.0"),
+							property.MustBuildPackageRequired("bar", "<0.1.0"),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
+						},
+						Objects: []string{string(foov2csv), string(foov2crd)},
+						CsvJSON: string(foov2csv),
+						RelatedImages: []declcfg.RelatedImage{
+							{
+								Image: "test.registry/foo-operator/foo-2:v0.2.0",
 							},
 							{
 								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
@@ -486,9 +1151,9 @@ func TestRender(t *testing.T) {
 			assertion: require.NoError,
 		},
 		{
-			name: "Success/BundleImageWithNoCSVRelatedImages",
+			name: "Success/BundleDirectory",
 			render: action.Render{
-				Refs:     []string{"test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0"},
+				Refs:     []string{"testdata/foo-bundle-v0.2.0"},
 				Registry: reg,
 			},
 			expectCfg: &declcfg.DeclarativeConfig{
@@ -497,24 +1162,20 @@ func TestRender(t *testing.T) {
 						Schema:  "olm.bundle",
 						Name:    "foo.v0.2.0",
 						Package: "foo",
-						Image:   "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0",
 						Properties: []property.Property{
 							property.MustBuildGVK("test.foo", "v1", "Foo"),
 							property.MustBuildGVKRequired("test.bar", "v1alpha1", "Bar"),
 							property.MustBuildPackage("foo", "0.2.0"),
 							property.MustBuildPackageRequired("bar", "<0.1.0"),
-							property.MustBuildBundleObjectData(foov2csvNoRelatedImages),
-							property.MustBuildBundleObjectData(foov2crdNoRelatedImages),
+							property.MustBuildBundleObject(foov2crd),
+							property.MustBuildBundleObject(foov2csv),
 						},
-						Objects: []string{string(foov2csvNoRelatedImages), string(foov2crdNoRelatedImages)},
-						CsvJSON: string(foov2csvNoRelatedImages),
+						Objects: []string{string(foov2csv), string(foov2crd)},
+						CsvJSON: string(foov2csv),
 						RelatedImages: []declcfg.RelatedImage{
 							{
 								Image: "test.registry/foo-operator/foo-2:v0.2.0",
 							},
-							{
-								Image: "test.registry/foo-operator/foo-bundle-no-csv-related-images:v0.2.0",
-							},
 							{
 								Image: "test.registry/foo-operator/foo-init-2:v0.2.0",
 							},
@@ -522,6 +1183,11 @@ func TestRender(t *testing.T) {
 								Image: "test.registry/foo-operator/foo-init:v0.2.0",
 							},
 							{
+								Name:  "other",
+								Image: "test.registry/foo-operator/foo-other:v0.2.0",
+							},
+							{
+								Name:  "operator",
 								Image: "test.registry/foo-operator/foo:v0.2.0",
 							},
 						},
@@ -536,7 +1202,17 @@ func TestRender(t *testing.T) {
 		t.Run(s.name, func(t *testing.T) {
 			actualCfg, actualErr := s.render.Run(context.Background())
 			s.assertion(t, actualErr)
-			require.Equal(t, s.expectCfg, actualCfg)
+			require.Equal(t, len(s.expectCfg.Packages), len(actualCfg.Packages))
+			require.Equal(t, s.expectCfg.Packages, actualCfg.Packages)
+			require.Equal(t, len(s.expectCfg.Channels), len(actualCfg.Channels))
+			require.Equal(t, s.expectCfg.Channels, actualCfg.Channels)
+			require.Equal(t, len(s.expectCfg.Bundles), len(actualCfg.Bundles))
+			for i := range s.expectCfg.Bundles {
+				actual, expected := actualCfg.Bundles[i], s.expectCfg.Bundles[i]
+				require.Equal(t, expected, actual, "bundle %d", i)
+			}
+			require.Equal(t, len(s.expectCfg.Others), len(actualCfg.Others))
+			require.Equal(t, s.expectCfg.Others, actualCfg.Others)
 		})
 	}
 }
@@ -548,7 +1224,7 @@ func TestAllowRefMask(t *testing.T) {
 		expectErr error
 	}
 
-	reg, err := newRegistry()
+	reg, err := newRegistry(t)
 	require.NoError(t, err)
 
 	dir := t.TempDir()
@@ -557,7 +1233,7 @@ func TestAllowRefMask(t *testing.T) {
 		image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0",
 		image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0",
 	}
-	assert.NoError(t, generateSqliteFile(dbFile, imageMap))
+	require.NoError(t, generateSqliteFile(dbFile, imageMap))
 
 	specs := []spec{
 		{
@@ -574,7 +1250,7 @@ func TestAllowRefMask(t *testing.T) {
 			render: action.Render{
 				Refs:           []string{"test.registry/foo-operator/foo-index-sqlite:v0.2.0"},
 				Registry:       reg,
-				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteFile | action.RefBundleImage,
+				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteFile | action.RefBundleImage | action.RefBundleDir,
 			},
 			expectErr: action.ErrNotAllowed,
 		},
@@ -592,7 +1268,7 @@ func TestAllowRefMask(t *testing.T) {
 			render: action.Render{
 				Refs:           []string{dbFile},
 				Registry:       reg,
-				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefBundleImage,
+				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefBundleImage | action.RefBundleDir,
 			},
 			expectErr: action.ErrNotAllowed,
 		},
@@ -610,7 +1286,7 @@ func TestAllowRefMask(t *testing.T) {
 			render: action.Render{
 				Refs:           []string{"test.registry/foo-operator/foo-index-declcfg:v0.2.0"},
 				Registry:       reg,
-				AllowedRefMask: action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage,
+				AllowedRefMask: action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage | action.RefBundleDir,
 			},
 			expectErr: action.ErrNotAllowed,
 		},
@@ -628,7 +1304,7 @@ func TestAllowRefMask(t *testing.T) {
 			render: action.Render{
 				Refs:           []string{"testdata/foo-index-v0.2.0-declcfg"},
 				Registry:       reg,
-				AllowedRefMask: action.RefDCImage | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage,
+				AllowedRefMask: action.RefDCImage | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage | action.RefBundleDir,
 			},
 			expectErr: action.ErrNotAllowed,
 		},
@@ -646,7 +1322,25 @@ func TestAllowRefMask(t *testing.T) {
 			render: action.Render{
 				Refs:           []string{"test.registry/foo-operator/foo-bundle:v0.2.0"},
 				Registry:       reg,
-				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile,
+				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleDir,
+			},
+			expectErr: action.ErrNotAllowed,
+		},
+		{
+			name: "BundleDir/Allowed",
+			render: action.Render{
+				Refs:           []string{"testdata/foo-bundle-v0.2.0"},
+				Registry:       reg,
+				AllowedRefMask: action.RefBundleDir,
+			},
+			expectErr: nil,
+		},
+		{
+			name: "BundleDir/NotAllowed",
+			render: action.Render{
+				Refs:           []string{"testdata/foo-bundle-v0.2.0"},
+				Registry:       reg,
+				AllowedRefMask: action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile | action.RefBundleImage,
 			},
 			expectErr: action.ErrNotAllowed,
 		},
@@ -659,6 +1353,7 @@ func TestAllowRefMask(t *testing.T) {
 					"test.registry/foo-operator/foo-index-declcfg:v0.2.0",
 					"testdata/foo-index-v0.2.0-declcfg",
 					"test.registry/foo-operator/foo-bundle:v0.2.0",
+					"testdata/foo-bundle-v0.2.0",
 				},
 				Registry: reg,
 			},
@@ -668,18 +1363,17 @@ func TestAllowRefMask(t *testing.T) {
 	for _, s := range specs {
 		t.Run(s.name, func(t *testing.T) {
 			_, err := s.render.Run(context.Background())
-			require.True(t, errors.Is(err, s.expectErr), "expected error %#v to be %#v", err, s.expectErr)
+			require.ErrorIs(t, err, s.expectErr, "expected error %#v to be %#v", err, s.expectErr)
 		})
 	}
 }
 
 func TestAllowRefMaskAllowed(t *testing.T) {
 	type spec struct {
-		name   string
-		mask   action.RefType
-		pass   []action.RefType
-		fail   []action.RefType
-		expect bool
+		name string
+		mask action.RefType
+		pass []action.RefType
+		fail []action.RefType
 	}
 
 	specs := []spec{
@@ -692,6 +1386,7 @@ func TestAllowRefMaskAllowed(t *testing.T) {
 				action.RefSqliteImage,
 				action.RefSqliteFile,
 				action.RefBundleImage,
+				action.RefBundleDir,
 			},
 			fail: []action.RefType{},
 		},
@@ -751,13 +1446,13 @@ var bundleImageV2NoCSVRelatedImages embed.FS
 //go:embed testdata/foo-index-v0.2.0-declcfg/foo/*
 var declcfgImage embed.FS
 
-func newRegistry() (image.Registry, error) {
+func newRegistry(t *testing.T) (image.Registry, error) {
 	imageMap := map[image.Reference]string{
 		image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.1.0"): "testdata/foo-bundle-v0.1.0",
 		image.SimpleReference("test.registry/foo-operator/foo-bundle:v0.2.0"): "testdata/foo-bundle-v0.2.0",
 	}
 
-	subSqliteImage, err := generateSqliteFS(imageMap)
+	subSqliteImage, err := generateSqliteFS(t, imageMap)
 	if err != nil {
 		return nil, err
 	}
@@ -813,12 +1508,8 @@ func newRegistry() (image.Registry, error) {
 	}, nil
 }
 
-func generateSqliteFS(imageMap map[image.Reference]string) (fs.FS, error) {
-	dir, err := os.MkdirTemp("", "opm-render-test-")
-	if err != nil {
-		return nil, err
-	}
-	defer os.RemoveAll(dir)
+func generateSqliteFS(t *testing.T, imageMap map[image.Reference]string) (fs.FS, error) {
+	dir := t.TempDir()
 
 	dbFile := filepath.Join(dir, "index.db")
 	if err := generateSqliteFile(dbFile, imageMap); err != nil {
diff --git a/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml b/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml
index 7a126ee50..933b108d2 100644
--- a/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml
+++ b/alpha/action/testdata/foo-index-v0.2.0-declcfg/foo/index.yaml
@@ -2,6 +2,11 @@
 schema: olm.package
 name: foo
 defaultChannel: beta
+properties:
+  - type: owner
+    value:
+      group: abc.com
+      name: admin
 ---
 schema: olm.channel
 package: foo
@@ -15,6 +20,11 @@ entries:
     skips:
       - foo.v0.1.1
       - foo.v0.1.2
+properties:
+  - type: user
+    value:
+      group: xyz.com
+      name: account
 ---
 schema: olm.channel
 package: foo
diff --git a/alpha/declcfg/declcfg.go b/alpha/declcfg/declcfg.go
index 688d5982a..9e4f752ee 100644
--- a/alpha/declcfg/declcfg.go
+++ b/alpha/declcfg/declcfg.go
@@ -1,30 +1,41 @@
 package declcfg
 
 import (
+	"bytes"
 	"encoding/json"
+	"errors"
+	"fmt"
+
+	"golang.org/x/text/cases"
+	utilerrors "k8s.io/apimachinery/pkg/util/errors"
+	"k8s.io/apimachinery/pkg/util/sets"
 
 	"github.com/operator-framework/operator-registry/alpha/property"
+	prettyunmarshaler "github.com/operator-framework/operator-registry/pkg/prettyunmarshaler"
 )
 
 const (
-	schemaPackage = "olm.package"
-	schemaChannel = "olm.channel"
-	schemaBundle  = "olm.bundle"
+	SchemaPackage     = "olm.package"
+	SchemaChannel     = "olm.channel"
+	SchemaBundle      = "olm.bundle"
+	SchemaDeprecation = "olm.deprecations"
 )
 
 type DeclarativeConfig struct {
-	Packages []Package
-	Channels []Channel
-	Bundles  []Bundle
-	Others   []Meta
+	Packages     []Package
+	Channels     []Channel
+	Bundles      []Bundle
+	Deprecations []Deprecation
+	Others       []Meta
 }
 
 type Package struct {
-	Schema         string `json:"schema"`
-	Name           string `json:"name"`
-	DefaultChannel string `json:"defaultChannel"`
-	Icon           *Icon  `json:"icon,omitempty"`
-	Description    string `json:"description,omitempty"`
+	Schema         string              `json:"schema"`
+	Name           string              `json:"name"`
+	DefaultChannel string              `json:"defaultChannel"`
+	Icon           *Icon               `json:"icon,omitempty"`
+	Description    string              `json:"description,omitempty"`
+	Properties     []property.Property `json:"properties,omitempty" hash:"set"`
 }
 
 type Icon struct {
@@ -33,10 +44,11 @@ type Icon struct {
 }
 
 type Channel struct {
-	Schema  string         `json:"schema"`
-	Name    string         `json:"name"`
-	Package string         `json:"package"`
-	Entries []ChannelEntry `json:"entries"`
+	Schema     string              `json:"schema"`
+	Name       string              `json:"name"`
+	Package    string              `json:"package"`
+	Entries    []ChannelEntry      `json:"entries"`
+	Properties []property.Property `json:"properties,omitempty" hash:"set"`
 }
 
 type ChannelEntry struct {
@@ -50,15 +62,15 @@ type ChannelEntry struct {
 // Top-level fields are the source of truth, i.e. not CSV values.
 //
 // Notes:
-// - Any field slice type field or type containing a slice somewhere
-//   where two types/fields are equal if their contents are equal regardless
-//   of order must have a `hash:"set"` field tag for bundle comparison.
-// - Any fields that have a `json:"-"` tag must be included in the equality
-//   evaluation in bundlesEqual().
+//   - Any field slice type field or type containing a slice somewhere
+//     where two types/fields are equal if their contents are equal regardless
+//     of order must have a `hash:"set"` field tag for bundle comparison.
+//   - Any fields that have a `json:"-"` tag must be included in the equality
+//     evaluation in bundlesEqual().
 type Bundle struct {
 	Schema        string              `json:"schema"`
-	Name          string              `json:"name"`
-	Package       string              `json:"package"`
+	Name          string              `json:"name,omitempty"`
+	Package       string              `json:"package,omitempty"`
 	Image         string              `json:"image"`
 	Properties    []property.Property `json:"properties,omitempty" hash:"set"`
 	RelatedImages []RelatedImage      `json:"relatedImages,omitempty" hash:"set"`
@@ -79,9 +91,26 @@ type RelatedImage struct {
 	Image string `json:"image"`
 }
 
+type Deprecation struct {
+	Schema  string             `json:"schema"`
+	Package string             `json:"package"`
+	Entries []DeprecationEntry `json:"entries"`
+}
+
+type DeprecationEntry struct {
+	Reference PackageScopedReference `json:"reference"`
+	Message   string                 `json:"message"`
+}
+
+type PackageScopedReference struct {
+	Schema string `json:"schema"`
+	Name   string `json:"name,omitempty"`
+}
+
 type Meta struct {
 	Schema  string
 	Package string
+	Name    string
 
 	Blob json.RawMessage
 }
@@ -91,17 +120,89 @@ func (m Meta) MarshalJSON() ([]byte, error) {
 }
 
 func (m *Meta) UnmarshalJSON(blob []byte) error {
-	type tmp struct {
-		Schema     string              `json:"schema"`
-		Package    string              `json:"package,omitempty"`
-		Properties []property.Property `json:"properties,omitempty"`
+	blobMap := map[string]interface{}{}
+	if err := json.Unmarshal(blob, &blobMap); err != nil {
+		// TODO: unfortunately, there are libraries between here and the original caller
+		//   that eat our error type and return a generic error, such that we lose the
+		//   ability to errors.As to get this error on the other side. For now, just return
+		//   a string error that includes the pretty printed message.
+		return errors.New(prettyunmarshaler.NewJSONUnmarshalError(blob, err).Pretty())
 	}
-	var t tmp
-	if err := json.Unmarshal(blob, &t); err != nil {
+
+	// TODO: this function ensures we do not break backwards compatibility with
+	//    the documented examples of FBC templates, which use upper camel case
+	//    for JSON field names. We need to decide if we want to continue supporting
+	//    case insensitive JSON field names, or if we want to enforce a specific
+	//    case-sensitive key value for each field.
+	if err := extractUniqueMetaKeys(blobMap, m); err != nil {
+		return err
+	}
+
+	buf := bytes.Buffer{}
+	enc := json.NewEncoder(&buf)
+	enc.SetEscapeHTML(false)
+	if err := enc.Encode(blobMap); err != nil {
 		return err
 	}
-	m.Schema = t.Schema
-	m.Package = t.Package
-	m.Blob = blob
+	m.Blob = buf.Bytes()
 	return nil
 }
+
+// extractUniqueMetaKeys enables a case-insensitive key lookup for the schema, package, and name
+// fields of the Meta struct. If the blobMap contains duplicate keys (that is, keys have the same folded value),
+// an error is returned.
+func extractUniqueMetaKeys(blobMap map[string]any, m *Meta) error {
+	keySets := map[string]sets.Set[string]{}
+	folder := cases.Fold()
+	for key := range blobMap {
+		foldKey := folder.String(key)
+		if _, ok := keySets[foldKey]; !ok {
+			keySets[foldKey] = sets.New[string]()
+		}
+		keySets[foldKey].Insert(key)
+	}
+
+	dupErrs := []error{}
+	for foldedKey, keys := range keySets {
+		if len(keys) != 1 {
+			dupErrs = append(dupErrs, fmt.Errorf("duplicate keys for key %q: %v", foldedKey, sets.List(keys)))
+		}
+	}
+	if len(dupErrs) > 0 {
+		return utilerrors.NewAggregate(dupErrs)
+	}
+
+	metaMap := map[string]*string{
+		folder.String("schema"):  &m.Schema,
+		folder.String("package"): &m.Package,
+		folder.String("name"):    &m.Name,
+	}
+
+	for foldedKey, ptr := range metaMap {
+		// if the folded key doesn't exist in the key set derived from the blobMap, that means
+		// the key doesn't exist in the blobMap, so we can skip it
+		if _, ok := keySets[foldedKey]; !ok {
+			continue
+		}
+
+		// reset key to the unfolded key, which we know is the one that appears in the blobMap
+		key := keySets[foldedKey].UnsortedList()[0]
+		if _, ok := blobMap[key]; !ok {
+			continue
+		}
+		v, ok := blobMap[key].(string)
+		if !ok {
+			return fmt.Errorf("expected value for key %q to be a string, got %t: %v", key, blobMap[key], blobMap[key])
+		}
+		*ptr = v
+	}
+	return nil
+}
+
+func (destination *DeclarativeConfig) Merge(src *DeclarativeConfig) {
+	destination.Packages = append(destination.Packages, src.Packages...)
+	destination.Channels = append(destination.Channels, src.Channels...)
+	destination.Bundles = append(destination.Bundles, src.Bundles...)
+	destination.Others = append(destination.Others, src.Others...)
+	destination.Deprecations = append(destination.Deprecations, src.Deprecations...)
+}
diff --git a/alpha/declcfg/declcfg_to_model.go b/alpha/declcfg/declcfg_to_model.go
index 55d775179..342cab403 100644
--- a/alpha/declcfg/declcfg_to_model.go
+++ b/alpha/declcfg/declcfg_to_model.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/blang/semver/v4"
 	"k8s.io/apimachinery/pkg/util/sets"
+	"k8s.io/apimachinery/pkg/util/validation"
 
 	"github.com/operator-framework/operator-registry/alpha/model"
 	"github.com/operator-framework/operator-registry/alpha/property"
@@ -22,6 +23,10 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 			return nil, fmt.Errorf("duplicate package %q", p.Name)
 		}
 
+		if errs := validation.IsDNS1123Label(p.Name); len(errs) > 0 {
+			return nil, fmt.Errorf("invalid package name %q: %v", p.Name, errs)
+		}
+
 		mpkg := &model.Package{
 			Name:        p.Name,
 			Description: p.Description,
@@ -37,7 +42,7 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 		mpkgs[p.Name] = mpkg
 	}
 
-	channelDefinedEntries := map[string]sets.String{}
+	channelDefinedEntries := map[string]sets.Set[string]{}
 	for _, c := range cfg.Channels {
 		mpkg, ok := mpkgs[c.Package]
 		if !ok {
@@ -56,9 +61,13 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 			Package: mpkg,
 			Name:    c.Name,
 			Bundles: map[string]*model.Bundle{},
+			// NOTICE: The field Properties of the type Channel is for internal use only.
+			//   DO NOT use it for any public-facing functionalities.
+			//   This API is in alpha stage and it is subject to change.
+			Properties: c.Properties,
 		}
 
-		cde := sets.NewString()
+		cde := sets.Set[string]{}
 		for _, entry := range c.Entries {
 			if _, ok := mch.Bundles[entry.Name]; ok {
 				return nil, fmt.Errorf("invalid package %q, channel %q: duplicate entry %q", c.Package, c.Name, entry.Name)
@@ -85,7 +94,7 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 
 	// packageBundles tracks the set of bundle names for each package
 	// and is used to detect duplicate bundles.
-	packageBundles := map[string]sets.String{}
+	packageBundles := map[string]sets.Set[string]{}
 
 	for _, b := range cfg.Bundles {
 		if b.Package == "" {
@@ -98,7 +107,7 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 
 		bundles, ok := packageBundles[b.Package]
 		if !ok {
-			bundles = sets.NewString()
+			bundles = sets.Set[string]{}
 		}
 		if bundles.Has(b.Name) {
 			return nil, fmt.Errorf("package %q has duplicate bundle %q", b.Package, b.Name)
@@ -147,7 +156,7 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 
 	for pkg, entries := range channelDefinedEntries {
 		if entries.Len() > 0 {
-			return nil, fmt.Errorf("no olm.bundle blobs found in package %q for olm.channel entries %s", pkg, entries.List())
+			return nil, fmt.Errorf("no olm.bundle blobs found in package %q for olm.channel entries %s", pkg, sets.List[string](entries))
 		}
 	}
 
@@ -164,6 +173,70 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 		}
 	}
 
+	// deprecationsByPackage tracks the set of package names
+	// and is used to detect duplicate packages.
+	deprecationsByPackage := sets.New[string]()
+
+	for i, deprecation := range cfg.Deprecations {
+		// no need to validate schema, since it could not be unmarshaled if missing/invalid
+
+		if deprecation.Package == "" {
+			return nil, fmt.Errorf("package name must be set for deprecation item %v", i)
+		}
+
+		// must refer to package in this catalog
+		mpkg, ok := mpkgs[deprecation.Package]
+		if !ok {
+			return nil, fmt.Errorf("cannot apply deprecations to an unknown package %q", deprecation.Package)
+		}
+
+		// must be unique per package
+		if deprecationsByPackage.Has(deprecation.Package) {
+			return nil, fmt.Errorf("expected a maximum of one deprecation per package: %q", deprecation.Package)
+		}
+		deprecationsByPackage.Insert(deprecation.Package)
+
+		references := sets.New[PackageScopedReference]()
+
+		for j, entry := range deprecation.Entries {
+			if entry.Reference.Schema == "" {
+				return nil, fmt.Errorf("schema must be set for deprecation entry [%v] for package %q", deprecation.Package, j)
+			}
+
+			if references.Has(entry.Reference) {
+				return nil, fmt.Errorf("duplicate deprecation entry %#v for package %q", entry.Reference, deprecation.Package)
+			}
+			references.Insert(entry.Reference)
+
+			switch entry.Reference.Schema {
+			case SchemaBundle:
+				if !packageBundles[deprecation.Package].Has(entry.Reference.Name) {
+					return nil, fmt.Errorf("cannot deprecate bundle %q for package %q: bundle not found", entry.Reference.Name, deprecation.Package)
+				}
+				for _, mch := range mpkg.Channels {
+					if mb, ok := mch.Bundles[entry.Reference.Name]; ok {
+						mb.Deprecation = &model.Deprecation{Message: entry.Message}
+					}
+				}
+			case SchemaChannel:
+				ch, ok := mpkg.Channels[entry.Reference.Name]
+				if !ok {
+					return nil, fmt.Errorf("cannot deprecate channel %q for package %q: channel not found", entry.Reference.Name, deprecation.Package)
+				}
+				ch.Deprecation = &model.Deprecation{Message: entry.Message}
+
+			case SchemaPackage:
+				if entry.Reference.Name != "" {
+					return nil, fmt.Errorf("package name must be empty for deprecated package %q (specified %q)", deprecation.Package, entry.Reference.Name)
+				}
+				mpkg.Deprecation = &model.Deprecation{Message: entry.Message}
+
+			default:
+				return nil, fmt.Errorf("cannot deprecate object %#v referenced by entry %v for package %q: object schema unknown", entry.Reference, j, deprecation.Package)
+			}
+		}
+	}
+
 	if err := mpkgs.Validate(); err != nil {
 		return nil, err
 	}
@@ -172,6 +245,7 @@ func ConvertToModel(cfg DeclarativeConfig) (model.Model, error) {
 }
 
 func relatedImagesToModelRelatedImages(in []RelatedImage) []model.RelatedImage {
+	// nolint:prealloc
 	var out []model.RelatedImage
 	for _, p := range in {
 		out = append(out, model.RelatedImage{
diff --git a/alpha/declcfg/declcfg_to_model_test.go b/alpha/declcfg/declcfg_to_model_test.go
index 34c7bc020..de8639c1b 100644
--- a/alpha/declcfg/declcfg_to_model_test.go
+++ b/alpha/declcfg/declcfg_to_model_test.go
@@ -4,9 +4,11 @@ import (
 	"encoding/json"
 	"testing"
 
+	"github.com/blang/semver/v4"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
+	"github.com/operator-framework/operator-registry/alpha/model"
 	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
@@ -215,6 +217,17 @@ func TestConvertToModel(t *testing.T) {
 				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
 			},
 		},
+		{
+			name:      "Error/PackageBreaksRFC1123",
+			assertion: hasError(`invalid package name "foo.bar": [must not contain dots]`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					newTestPackage("foo.bar", "alpha", svgSmallCircle),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+			},
+		},
 		{
 			name:      "Error/DuplicateChannel",
 			assertion: hasError(`package "foo" has duplicate channel "alpha"`),
@@ -248,6 +261,187 @@ func TestConvertToModel(t *testing.T) {
 				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
 			},
 		},
+		{
+			name:      "Success/ValidModelWithChannelProperties",
+			assertion: require.NoError,
+			cfg: DeclarativeConfig{
+				Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)},
+				Channels: []Channel{
+					addChannelProperties(
+						newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"}),
+						[]property.Property{
+							{Type: "user", Value: json.RawMessage("{\"group\":\"xyz.com\",\"name\":\"account\"}")},
+						},
+					),
+				},
+				Bundles: []Bundle{newTestBundle("foo", "0.1.0")},
+			},
+		},
+		{
+			name:      "Success/ValidModelWithPackageProperties",
+			assertion: require.NoError,
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+			},
+		},
+		{
+			name:      "Error/Deprecation/UnspecifiedPackage",
+			assertion: hasError(`package name must be set for deprecation item 0`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+				Deprecations: []Deprecation{
+					{Schema: SchemaDeprecation},
+				},
+			},
+		},
+		{
+			name:      "Error/Deprecation/OutOfBoundsBundle",
+			assertion: hasError(`cannot deprecate bundle "foo.v2.0.0" for package "foo": bundle not found`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+				Deprecations: []Deprecation{
+					{
+						Schema:  SchemaDeprecation,
+						Package: "foo",
+						Entries: []DeprecationEntry{
+							{Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v2.0.0"}, Message: "foo.v2.0.0 doesn't exist in the first place"},
+						},
+					},
+				},
+			},
+		},
+		{
+			name:      "Error/Deprecation/OutOfBoundsPackage",
+			assertion: hasError(`cannot apply deprecations to an unknown package "nyarl"`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+				Deprecations: []Deprecation{
+					{
+						Schema:  SchemaDeprecation,
+						Package: "nyarl",
+					},
+				},
+			},
+		},
+		{
+			name:      "Error/Deprecation/MultiplePerPackage",
+			assertion: hasError(`expected a maximum of one deprecation per package: "foo"`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+				Deprecations: []Deprecation{
+					{
+						Schema:  SchemaDeprecation,
+						Package: "foo",
+						Entries: []DeprecationEntry{
+							{Reference: PackageScopedReference{Schema: SchemaChannel, Name: "alpha"}, Message: "no more alpha channel"},
+						},
+					},
+					{
+						Schema:  SchemaDeprecation,
+						Package: "foo",
+						Entries: []DeprecationEntry{
+							{Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v0.1.0"}, Message: "foo.v0.1.0 is dead.  do another thing"},
+						},
+					},
+				},
+			},
+		},
+		{
+			name:      "Error/Deprecation/BadRefSchema",
+			assertion: hasError(`cannot deprecate object declcfg.PackageScopedReference{Schema:"badschema", Name:"foo.v2.0.0"} referenced by entry 0 for package "foo": object schema unknown`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+				Deprecations: []Deprecation{
+					{
+						Schema:  SchemaDeprecation,
+						Package: "foo",
+						Entries: []DeprecationEntry{
+							{Reference: PackageScopedReference{Schema: "badschema", Name: "foo.v2.0.0"}, Message: "foo.v2.0.0 doesn't exist in the first place"},
+						},
+					},
+				},
+			},
+		},
+		{
+			name:      "Error/Deprecation/DuplicateRef",
+			assertion: hasError(`duplicate deprecation entry declcfg.PackageScopedReference{Schema:"olm.bundle", Name:"foo.v0.1.0"} for package "foo"`),
+			cfg: DeclarativeConfig{
+				Packages: []Package{
+					addPackageProperties(
+						newTestPackage("foo", "alpha", svgSmallCircle),
+						[]property.Property{
+							{Type: "owner", Value: json.RawMessage("{\"group\":\"abc.com\",\"name\":\"admin\"}")},
+						},
+					),
+				},
+				Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+				Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+				Deprecations: []Deprecation{
+					{
+						Schema:  SchemaDeprecation,
+						Package: "foo",
+						Entries: []DeprecationEntry{
+							{Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v0.1.0"}, Message: "foo.v0.1.0 is bad"},
+							{Reference: PackageScopedReference{Schema: SchemaBundle, Name: "foo.v0.1.0"}, Message: "foo.v0.1.0 is bad"},
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for _, s := range specs {
@@ -258,8 +452,42 @@ func TestConvertToModel(t *testing.T) {
 	}
 }
 
+func TestConvertToModelBundle(t *testing.T) {
+	cfg := DeclarativeConfig{
+		Packages: []Package{newTestPackage("foo", "alpha", svgSmallCircle)},
+		Channels: []Channel{newTestChannel("foo", "alpha", ChannelEntry{Name: "foo.v0.1.0"})},
+		Bundles:  []Bundle{newTestBundle("foo", "0.1.0")},
+	}
+	m, err := ConvertToModel(cfg)
+	require.NoError(t, err)
+
+	pkg, ok := m["foo"]
+	require.True(t, ok, "expected package 'foo' to be present")
+	ch, ok := pkg.Channels["alpha"]
+	require.True(t, ok, "expected channel 'alpha' to be present")
+	b, ok := ch.Bundles["foo.v0.1.0"]
+	require.True(t, ok, "expected bundle 'foo.v0.1.0' to be present")
+
+	assert.Equal(t, pkg, b.Package)
+	assert.Equal(t, ch, b.Channel)
+	assert.Equal(t, "foo.v0.1.0", b.Name)
+	assert.Equal(t, "foo-bundle:v0.1.0", b.Image)
+	assert.Equal(t, "", b.Replaces)
+	assert.Nil(t, b.Skips)
+	assert.Equal(t, "", b.SkipRange)
+	assert.Len(t, b.Properties, 3)
+	assert.Equal(t, []model.RelatedImage{{Name: "bundle", Image: "foo-bundle:v0.1.0"}}, b.RelatedImages)
+	assert.Nil(t, b.Deprecation)
+	assert.Len(t, b.Objects, 2)
+	assert.NotEmpty(t, b.CsvJSON)
+	assert.NotNil(t, b.PropertiesP)
+	assert.Len(t, b.PropertiesP.BundleObjects, 2)
+	assert.Len(t, b.PropertiesP.Packages, 1)
+	assert.Equal(t, semver.MustParse("0.1.0"), b.Version)
+}
+
 func TestConvertToModelRoundtrip(t *testing.T) {
-	expected := buildValidDeclarativeConfig(true)
+	expected := buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: false}) // TODO: turn on deprecation when we have model-->declcfg conversion
 
 	m, err := ConvertToModel(expected)
 	require.NoError(t, err)
@@ -270,7 +498,7 @@ func TestConvertToModelRoundtrip(t *testing.T) {
 
 	assert.Equal(t, expected.Packages, actual.Packages)
 	assert.Equal(t, expected.Bundles, actual.Bundles)
-	assert.Len(t, actual.Others, 0, "expected unrecognized schemas not to make the roundtrip")
+	assert.Empty(t, actual.Others, "expected unrecognized schemas not to make the roundtrip")
 }
 
 func hasError(expectedError string) require.ErrorAssertionFunc {
diff --git a/alpha/declcfg/diff.go b/alpha/declcfg/diff.go
deleted file mode 100644
index 077ddc165..000000000
--- a/alpha/declcfg/diff.go
+++ /dev/null
@@ -1,530 +0,0 @@
-package declcfg
-
-import (
-	"fmt"
-	"reflect"
-	"sort"
-	"sync"
-
-	"github.com/blang/semver/v4"
-	"github.com/mitchellh/hashstructure/v2"
-	"github.com/sirupsen/logrus"
-
-	"github.com/operator-framework/operator-registry/alpha/model"
-	"github.com/operator-framework/operator-registry/alpha/property"
-)
-
-// DiffGenerator configures how diffs are created via Run().
-type DiffGenerator struct {
-	Logger *logrus.Entry
-
-	// SkipDependencies directs Run() to not include dependencies
-	// of bundles included in the diff if true.
-	SkipDependencies bool
-	// Includer for adding catalog objects to Run() output.
-	Includer DiffIncluder
-	// IncludeAdditively catalog objects specified in Includer in headsOnly mode.
-	IncludeAdditively bool
-
-	initOnce sync.Once
-}
-
-func (g *DiffGenerator) init() {
-	g.initOnce.Do(func() {
-		if g.Logger == nil {
-			g.Logger = &logrus.Entry{}
-		}
-		if g.Includer.Logger == nil {
-			g.Includer.Logger = g.Logger
-		}
-	})
-}
-
-// Run returns a Model containing a subset of catalog objects in newModel:
-// - If g.Includer contains objects:
-//   - If g.IncludeAdditively is false, a diff will be generated only on those objects,
-//     depending on the mode.
-//   - If g.IncludeAdditionally is true, the diff will contain included objects,
-//     plus those added by the mode.
-// - If in heads-only mode (oldModel == nil), then the heads of channels are added to the output.
-// - If in latest mode, a diff between old and new Models is added to the output.
-// - Dependencies are added in all modes if g.SkipDependencies is false.
-func (g *DiffGenerator) Run(oldModel, newModel model.Model) (model.Model, error) {
-	g.init()
-
-	// TODO(estroz): loading both oldModel and newModel into memory may
-	// exceed process/hardware limits. Instead, store models on-disk then
-	// load by package.
-
-	outputModel := model.Model{}
-
-	// Prunes old objects from outputModel if they exist.
-	latestPruneFromOutput := func() error {
-
-		for _, outputPkg := range outputModel {
-			oldPkg, oldHasPkg := oldModel[outputPkg.Name]
-			if !oldHasPkg {
-				// outputPkg was already copied to outputModel above.
-				continue
-			}
-			if err := pruneOldFromNewPackage(oldPkg, outputPkg); err != nil {
-				return err
-			}
-			if len(outputPkg.Channels) == 0 {
-				// Remove empty packages.
-				delete(outputModel, outputPkg.Name)
-			}
-		}
-
-		return nil
-	}
-
-	headsOnlyMode := len(oldModel) == 0
-	latestMode := !headsOnlyMode
-	isInclude := len(g.Includer.Packages) != 0
-
-	switch {
-	case !g.IncludeAdditively && isInclude: // Only diff between included objects.
-
-		// Add included packages/channels/bundles from newModel to outputModel.
-		if err := g.Includer.Run(newModel, outputModel); err != nil {
-			return nil, err
-		}
-
-		if latestMode {
-			if err := latestPruneFromOutput(); err != nil {
-				return nil, err
-			}
-		}
-
-	case isInclude: // Add included objects to outputModel.
-
-		// Add included packages/channels/bundles from newModel to outputModel.
-		if err := g.Includer.Run(newModel, outputModel); err != nil {
-			return nil, err
-		}
-
-		fallthrough
-	default:
-
-		if headsOnlyMode { // Net-new diff of heads only.
-
-			// Make shallow copies of packages and channels that are only
-			// filled with channel heads.
-			for _, newPkg := range newModel {
-				// This package may have been created in the include step.
-				outputPkg, pkgIncluded := outputModel[newPkg.Name]
-				if !pkgIncluded {
-					outputPkg = copyPackageNoChannels(newPkg)
-					outputModel[outputPkg.Name] = outputPkg
-				}
-				for _, newCh := range newPkg.Channels {
-					if _, chIncluded := outputPkg.Channels[newCh.Name]; chIncluded {
-						// Head (and other bundles) were added in the include step.
-						continue
-					}
-					outputCh := copyChannelNoBundles(newCh, outputPkg)
-					outputPkg.Channels[outputCh.Name] = outputCh
-					head, err := newCh.Head()
-					if err != nil {
-						return nil, err
-					}
-					outputBundle := copyBundle(head, outputCh, outputPkg)
-					outputModel.AddBundle(*outputBundle)
-				}
-			}
-
-		} else { // Diff between old and new Model.
-
-			// Copy newModel to create an output model by deletion,
-			// which is more succinct than by addition.
-			for _, newPkg := range newModel {
-				if _, pkgIncluded := outputModel[newPkg.Name]; pkgIncluded {
-					// The user has specified the state they want this package to have in the diff
-					// via an inclusion entry, so the package created above should not be changed.
-					continue
-				}
-				outputModel[newPkg.Name] = copyPackage(newPkg)
-			}
-
-			if err := latestPruneFromOutput(); err != nil {
-				return nil, err
-			}
-
-		}
-
-	}
-
-	if !g.SkipDependencies {
-		// Add dependencies to outputModel not already present in oldModel.
-		if err := addAllDependencies(newModel, oldModel, outputModel); err != nil {
-			return nil, err
-		}
-	}
-
-	// Default channel may not have been copied, so set it to the new default channel here.
-	for _, outputPkg := range outputModel {
-		newPkg := newModel[outputPkg.Name]
-		var outputHasDefault bool
-		outputPkg.DefaultChannel, outputHasDefault = outputPkg.Channels[newPkg.DefaultChannel.Name]
-		if !outputHasDefault {
-			// Create a name-only channel since oldModel contains the channel already.
-			outputPkg.DefaultChannel = copyChannelNoBundles(newPkg.DefaultChannel, outputPkg)
-		}
-	}
-
-	return outputModel, nil
-}
-
-// pruneOldFromNewPackage prune any bundles and channels from newPkg that
-// are in oldPkg, but not those that differ in any way.
-func pruneOldFromNewPackage(oldPkg, newPkg *model.Package) error {
-	for _, newCh := range newPkg.Channels {
-		oldCh, oldHasCh := oldPkg.Channels[newCh.Name]
-		if !oldHasCh {
-			// newCh is assumed to have been copied to outputModel by the caller.
-			continue
-		}
-
-		for _, newBundle := range newCh.Bundles {
-			oldBundle, oldHasBundle := oldCh.Bundles[newBundle.Name]
-			if !oldHasBundle {
-				// newBundle is copied to outputModel by the caller if it is a channel head.
-				continue
-			}
-			equal, err := bundlesEqual(oldBundle, newBundle)
-			if err != nil {
-				return err
-			}
-			if equal {
-				delete(newCh.Bundles, newBundle.Name)
-			}
-		}
-		if len(newCh.Bundles) == 0 {
-			// Remove empty channels.
-			delete(newPkg.Channels, newCh.Name)
-		}
-	}
-
-	return nil
-}
-
-// bundlesEqual computes then compares the hashes of b1 and b2 for equality.
-func bundlesEqual(b1, b2 *model.Bundle) (bool, error) {
-	// Use a declarative config bundle type to avoid infinite recursion.
-	dcBundle1 := convertFromModelBundle(b1)
-	dcBundle2 := convertFromModelBundle(b2)
-
-	hash1, err := hashstructure.Hash(dcBundle1, hashstructure.FormatV2, nil)
-	if err != nil {
-		return false, err
-	}
-	hash2, err := hashstructure.Hash(dcBundle2, hashstructure.FormatV2, nil)
-	if err != nil {
-		return false, err
-	}
-	// CsvJSON and Objects are ignored by Hash, so they must be compared separately.
-	return hash1 == hash2 && b1.CsvJSON == b2.CsvJSON && reflect.DeepEqual(b1.Objects, b2.Objects), nil
-}
-
-func addAllDependencies(newModel, oldModel, outputModel model.Model) error {
-	// Get every oldModel's bundle's dependencies, and their dependencies, etc. by BFS.
-	providingBundlesByPackage := map[string][]*model.Bundle{}
-	for curr := getBundles(outputModel); len(curr) != 0; {
-		reqGVKs, reqPkgs, err := findDependencies(curr)
-		if err != nil {
-			return err
-		}
-		// Break early so the entire source model is not iterated through unnecessarily.
-		if len(reqGVKs) == 0 && len(reqPkgs) == 0 {
-			break
-		}
-		curr = nil
-		// Get bundles that provide dependencies from newModel, which should have
-		// the latest bundles of each dependency package.
-		for _, pkg := range newModel {
-			providingBundles := getBundlesThatProvide(pkg, reqGVKs, reqPkgs)
-			curr = append(curr, providingBundles...)
-
-			oldPkg, oldHasPkg := oldModel[pkg.Name]
-			for _, b := range providingBundles {
-				// If the bundle is not in oldModel, add it to the set.
-				// outputModel is checked below.
-				add := true
-				if oldHasPkg {
-					if oldCh, oldHasCh := oldPkg.Channels[b.Channel.Name]; oldHasCh {
-						_, oldHasBundle := oldCh.Bundles[b.Name]
-						add = !oldHasBundle
-					}
-				}
-				if add {
-					providingBundlesByPackage[b.Package.Name] = append(providingBundlesByPackage[b.Package.Name], b)
-				}
-			}
-		}
-	}
-
-	// Add the diff between an oldModel dependency package and its new counterpart
-	// or the entire package if oldModel does not have it.
-	for pkgName, bundles := range providingBundlesByPackage {
-		newPkg := newModel[pkgName]
-		heads := make(map[string]*model.Bundle, len(newPkg.Channels))
-		for _, ch := range newPkg.Channels {
-			var err error
-			if heads[ch.Name], err = ch.Head(); err != nil {
-				return err
-			}
-		}
-
-		// Sort by version then channel so bundles lower in the full graph are more likely
-		// to be included in previous loops.
-		sort.Slice(bundles, func(i, j int) bool {
-			if bundles[i].Channel.Name == bundles[j].Channel.Name {
-				return bundles[i].Version.LT(bundles[j].Version)
-			}
-			return bundles[i].Channel.Name < bundles[j].Channel.Name
-		})
-
-		for _, b := range bundles {
-			newCh := b.Channel
-
-			// Continue if b was added in a previous loop iteration.
-			// Otherwise create a new package/channel for b if they do not exist.
-			var (
-				outputPkg *model.Package
-				outputCh  *model.Channel
-
-				outHasPkg, outHasCh bool
-			)
-			if outputPkg, outHasPkg = outputModel[b.Package.Name]; outHasPkg {
-				if outputCh, outHasCh = outputPkg.Channels[b.Channel.Name]; outHasCh {
-					if _, outputHasBundle := outputCh.Bundles[b.Name]; outputHasBundle {
-						continue
-					}
-				}
-			} else {
-				outputPkg = copyPackageNoChannels(newPkg)
-				outputModel[outputPkg.Name] = outputPkg
-			}
-			if !outHasCh {
-				outputCh = copyChannelNoBundles(newCh, outputPkg)
-				outputPkg.Channels[outputCh.Name] = outputCh
-			}
-
-			head := heads[newCh.Name]
-			graph := makeUpgradeGraph(newCh)
-			intersectingBundles, intersectionFound := findIntersectingBundles(newCh, b, head, graph)
-			if !intersectionFound {
-				// This should never happen, since b and head are from the same model.
-				return fmt.Errorf("channel %s: head %q not reachable from bundle %q", newCh.Name, head.Name, b.Name)
-			}
-			for _, ib := range intersectingBundles {
-				if _, outHasBundle := outputCh.Bundles[ib.Name]; !outHasBundle {
-					outputCh.Bundles[ib.Name] = copyBundle(ib, outputCh, outputPkg)
-				}
-			}
-		}
-	}
-
-	return nil
-}
-
-// getBundles collects all bundles specified by m. Since each bundle
-// references its package, their uniqueness property holds in a flat list.
-func getBundles(m model.Model) (bundles []*model.Bundle) {
-	for _, pkg := range m {
-		for _, ch := range pkg.Channels {
-			for _, b := range ch.Bundles {
-				bundles = append(bundles, b)
-			}
-		}
-	}
-	return bundles
-}
-
-// findDependencies finds all GVK and package dependencies and indexes them
-// by the apropriate key for lookups.
-func findDependencies(bundles []*model.Bundle) (map[property.GVK]struct{}, map[string][]semver.Range, error) {
-	// Find all dependencies of bundles in the output model.
-	reqGVKs := map[property.GVK]struct{}{}
-	reqPkgs := map[string][]semver.Range{}
-	for _, b := range bundles {
-
-		for _, gvkReq := range b.PropertiesP.GVKsRequired {
-			gvk := property.GVK{
-				Group:   gvkReq.Group,
-				Version: gvkReq.Version,
-				Kind:    gvkReq.Kind,
-			}
-			reqGVKs[gvk] = struct{}{}
-		}
-
-		for _, pkgReq := range b.PropertiesP.PackagesRequired {
-			var inRange semver.Range
-			if pkgReq.VersionRange != "" {
-				var err error
-				if inRange, err = semver.ParseRange(pkgReq.VersionRange); err != nil {
-					// Should never happen since model has been validated.
-					return nil, nil, err
-				}
-			} else {
-				// Any bundle in this package will satisfy a range-less package requirement.
-				inRange = func(semver.Version) bool { return true }
-			}
-			reqPkgs[pkgReq.PackageName] = append(reqPkgs[pkgReq.PackageName], inRange)
-		}
-	}
-
-	return reqGVKs, reqPkgs, nil
-}
-
-// getBundlesThatProvide returns the latest-version bundles in pkg that provide
-// a GVK or version in reqGVKs or reqPkgs, respectively.
-func getBundlesThatProvide(pkg *model.Package, reqGVKs map[property.GVK]struct{}, reqPkgs map[string][]semver.Range) (providingBundles []*model.Bundle) {
-	// Pre-allocate the amount of space needed for all ranges
-	// specified by requiring bundles.
-	var bundlesByRange [][]*model.Bundle
-	ranges, isPkgRequired := reqPkgs[pkg.Name]
-	if isPkgRequired {
-		bundlesByRange = make([][]*model.Bundle, len(ranges))
-	}
-	// Collect package bundles that provide a GVK or are in a range.
-	bundlesProvidingGVK := make(map[property.GVK][]*model.Bundle)
-	for _, ch := range pkg.Channels {
-		for _, b := range ch.Bundles {
-			for _, gvk := range b.PropertiesP.GVKs {
-				if _, hasGVK := reqGVKs[gvk]; hasGVK {
-					bundlesProvidingGVK[gvk] = append(bundlesProvidingGVK[gvk], b)
-				}
-			}
-			for i, inRange := range ranges {
-				if inRange(b.Version) {
-					bundlesByRange[i] = append(bundlesByRange[i], b)
-				}
-			}
-		}
-	}
-
-	// Sort bundles providing a GVK by version and use the latest version.
-	latestBundles := make(map[string]*model.Bundle)
-	for gvk, bundles := range bundlesProvidingGVK {
-		sort.Slice(bundles, func(i, j int) bool {
-			return bundles[i].Version.LT(bundles[j].Version)
-		})
-		lb := bundles[len(bundles)-1]
-		latestBundles[lb.Version.String()] = lb
-		delete(reqGVKs, gvk)
-	}
-
-	// Sort bundles in a range by version and use the latest version.
-	unsatisfiedRanges := []semver.Range{}
-	for i, bundlesInRange := range bundlesByRange {
-		if len(bundlesInRange) == 0 {
-			unsatisfiedRanges = append(unsatisfiedRanges, ranges[i])
-			continue
-		}
-		sort.Slice(bundlesInRange, func(i, j int) bool {
-			return bundlesInRange[i].Version.LT(bundlesInRange[j].Version)
-		})
-		lb := bundlesInRange[len(bundlesInRange)-1]
-		latestBundles[lb.Version.String()] = lb
-	}
-	if isPkgRequired && len(unsatisfiedRanges) == 0 {
-		delete(reqPkgs, pkg.Name)
-	}
-	// TODO(estroz): handle missed ranges with logs.
-
-	// Return deduplicated bundles that provide GVKs/versions.
-	for _, b := range latestBundles {
-		providingBundles = append(providingBundles, b)
-	}
-	return providingBundles
-}
-
-func convertFromModelBundle(b *model.Bundle) Bundle {
-	return Bundle{
-		Schema:        schemaBundle,
-		Name:          b.Name,
-		Package:       b.Package.Name,
-		Image:         b.Image,
-		RelatedImages: modelRelatedImagesToRelatedImages(b.RelatedImages),
-		CsvJSON:       b.CsvJSON,
-		Objects:       b.Objects,
-		Properties:    b.Properties,
-	}
-}
-
-func copyPackageNoChannels(in *model.Package) *model.Package {
-	cp := &model.Package{
-		Name:        in.Name,
-		Description: in.Description,
-		Channels:    make(map[string]*model.Channel, len(in.Channels)),
-	}
-	if in.Icon != nil {
-		cp.Icon = &model.Icon{
-			Data:      make([]byte, len(in.Icon.Data)),
-			MediaType: in.Icon.MediaType,
-		}
-		copy(cp.Icon.Data, in.Icon.Data)
-	}
-	return cp
-}
-
-func copyPackage(in *model.Package) *model.Package {
-	cp := copyPackageNoChannels(in)
-	for _, ch := range in.Channels {
-		cp.Channels[ch.Name] = copyChannel(ch, cp)
-	}
-	return cp
-}
-
-func copyChannelNoBundles(in *model.Channel, pkg *model.Package) *model.Channel {
-	cp := &model.Channel{
-		Name:    in.Name,
-		Package: pkg,
-		Bundles: make(map[string]*model.Bundle, len(in.Bundles)),
-	}
-	return cp
-}
-
-func copyChannel(in *model.Channel, pkg *model.Package) *model.Channel {
-	cp := copyChannelNoBundles(in, pkg)
-	for _, b := range in.Bundles {
-		cp.Bundles[b.Name] = copyBundle(b, cp, pkg)
-	}
-	return cp
-}
-
-func copyBundle(in *model.Bundle, ch *model.Channel, pkg *model.Package) *model.Bundle {
-	cp := &model.Bundle{
-		Name:      in.Name,
-		Channel:   ch,
-		Package:   pkg,
-		Image:     in.Image,
-		Replaces:  in.Replaces,
-		Version:   semver.MustParse(in.Version.String()),
-		CsvJSON:   in.CsvJSON,
-		SkipRange: in.SkipRange,
-	}
-	if in.PropertiesP != nil {
-		cp.PropertiesP = new(property.Properties)
-		*cp.PropertiesP = *in.PropertiesP
-	}
-	if len(in.Skips) != 0 {
-		cp.Skips = make([]string, len(in.Skips))
-		copy(cp.Skips, in.Skips)
-	}
-	if len(in.Properties) != 0 {
-		cp.Properties = make([]property.Property, len(in.Properties))
-		copy(cp.Properties, in.Properties)
-	}
-	if len(in.RelatedImages) != 0 {
-		cp.RelatedImages = make([]model.RelatedImage, len(in.RelatedImages))
-		copy(cp.RelatedImages, in.RelatedImages)
-	}
-	if len(in.Objects) != 0 {
-		cp.Objects = make([]string, len(in.Objects))
-		copy(cp.Objects, in.Objects)
-	}
-	return cp
-}
diff --git a/alpha/declcfg/diff_include.go b/alpha/declcfg/diff_include.go
deleted file mode 100644
index 06e9a64a6..000000000
--- a/alpha/declcfg/diff_include.go
+++ /dev/null
@@ -1,288 +0,0 @@
-package declcfg
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/blang/semver/v4"
-	"github.com/sirupsen/logrus"
-	utilerrors "k8s.io/apimachinery/pkg/util/errors"
-
-	"github.com/operator-framework/operator-registry/alpha/model"
-)
-
-// DiffIncluder knows how to add packages, channels, and bundles
-// from a source to a destination model.Model.
-type DiffIncluder struct {
-	// Packages to add.
-	Packages []DiffIncludePackage
-	Logger   *logrus.Entry
-}
-
-// DiffIncludePackage specifies a package, and optionally channels
-// or a set of bundles from all channels (wrapped by a DiffIncludeChannel),
-// to include.
-type DiffIncludePackage struct {
-	// Name of package.
-	Name string
-	// Channels in package.
-	Channels []DiffIncludeChannel
-	// AllChannels contains bundle versions in package.
-	// Upgrade graphs from all channels in the named package containing a version
-	// from this field are included.
-	AllChannels DiffIncludeChannel
-}
-
-// DiffIncludeChannel specifies a channel, and optionally bundles and bundle versions to include.
-type DiffIncludeChannel struct {
-	// Name of channel.
-	Name string
-	// Versions of bundles.
-	Versions []semver.Version
-	// Bundles are bundle names to include.
-	// Set this field only if the named bundle has no semantic version metadata.
-	Bundles []string
-}
-
-// Run adds all packages and channels in DiffIncluder with matching names
-// directly, and all versions plus their upgrade graphs to channel heads,
-// from newModel to outputModel.
-func (i DiffIncluder) Run(newModel, outputModel model.Model) error {
-	var includeErrs []error
-	for _, ipkg := range i.Packages {
-		pkgLog := i.Logger.WithField("package", ipkg.Name)
-		includeErrs = append(includeErrs, ipkg.includeNewInOutputModel(newModel, outputModel, pkgLog)...)
-	}
-	if len(includeErrs) != 0 {
-		return fmt.Errorf("error including items:\n%v", utilerrors.NewAggregate(includeErrs))
-	}
-	return nil
-}
-
-// includeNewInOutputModel adds all packages, channels, and versions (bundles)
-// specified by ipkg that exist in newModel to outputModel. Any package, channel,
-// or version in ipkg not satisfied by newModel is an error.
-func (ipkg DiffIncludePackage) includeNewInOutputModel(newModel, outputModel model.Model, logger *logrus.Entry) (ierrs []error) {
-
-	newPkg, newHasPkg := newModel[ipkg.Name]
-	if !newHasPkg {
-		ierrs = append(ierrs, fmt.Errorf("[package=%q] package does not exist in new model", ipkg.Name))
-		return ierrs
-	}
-	pkgLog := logger.WithField("package", newPkg.Name)
-
-	// No channels or versions were specified, meaning "include the full package".
-	if len(ipkg.Channels) == 0 && len(ipkg.AllChannels.Versions) == 0 && len(ipkg.AllChannels.Bundles) == 0 {
-		outputModel[ipkg.Name] = newPkg
-		return nil
-	}
-
-	outputPkg := copyPackageNoChannels(newPkg)
-	outputModel[outputPkg.Name] = outputPkg
-
-	// Add all channels to ipkg.Channels if bundles or versions were specified to include across all channels.
-	// skipMissingBundleForChannels's value for a channel will be true IFF at least one version is specified,
-	// since some other channel may contain that version.
-	skipMissingBundleForChannels := map[string]bool{}
-	if len(ipkg.AllChannels.Versions) != 0 || len(ipkg.AllChannels.Bundles) != 0 {
-		for newChName := range newPkg.Channels {
-			ipkg.Channels = append(ipkg.Channels, DiffIncludeChannel{
-				Name:     newChName,
-				Versions: ipkg.AllChannels.Versions,
-				Bundles:  ipkg.AllChannels.Bundles,
-			})
-			skipMissingBundleForChannels[newChName] = true
-		}
-	}
-
-	for _, ich := range ipkg.Channels {
-		newCh, pkgHasCh := newPkg.Channels[ich.Name]
-		if !pkgHasCh {
-			ierrs = append(ierrs, fmt.Errorf("[package=%q channel=%q] channel does not exist in new model", newPkg.Name, ich.Name))
-			continue
-		}
-		chLog := pkgLog.WithField("channel", newCh.Name)
-
-		bundles, err := getBundlesForVersions(newCh, ich.Versions, ich.Bundles, chLog, skipMissingBundleForChannels[newCh.Name])
-		if err != nil {
-			ierrs = append(ierrs, fmt.Errorf("[package=%q channel=%q] %v", newPkg.Name, newCh.Name, err))
-			continue
-		}
-		outputCh := copyChannelNoBundles(newCh, outputPkg)
-		outputPkg.Channels[outputCh.Name] = outputCh
-		for _, b := range bundles {
-			tb := copyBundle(b, outputCh, outputPkg)
-			outputCh.Bundles[tb.Name] = tb
-		}
-	}
-
-	return ierrs
-}
-
-// getBundlesForVersions returns all bundles matching a version in vers
-// and their upgrade graph(s) to ch.Head().
-// If skipMissingBundles is true, bundle names and versions not satisfied by bundles in ch
-// will not result in errors.
-func getBundlesForVersions(ch *model.Channel, vers []semver.Version, names []string, logger *logrus.Entry, skipMissingBundles bool) (bundles []*model.Bundle, err error) {
-
-	// Short circuit when no versions were specified, meaning "include the whole channel".
-	if len(vers) == 0 {
-		for _, b := range ch.Bundles {
-			bundles = append(bundles, b)
-		}
-		return bundles, nil
-	}
-
-	// Add every bundle with a specified bundle name or directly satisfying a bundle version to bundles.
-	versionsToInclude := make(map[string]struct{}, len(vers))
-	for _, ver := range vers {
-		versionsToInclude[ver.String()] = struct{}{}
-	}
-	namesToInclude := make(map[string]struct{}, len(vers))
-	for _, name := range names {
-		namesToInclude[name] = struct{}{}
-	}
-	for _, b := range ch.Bundles {
-		_, includeVersionedBundle := versionsToInclude[b.Version.String()]
-		_, includeNamedBundle := namesToInclude[b.Name]
-		if includeVersionedBundle || includeNamedBundle {
-			bundles = append(bundles, b)
-		}
-	}
-
-	// Some version was not satisfied by this channel.
-	if len(bundles) != len(versionsToInclude)+len(namesToInclude) && !skipMissingBundles {
-		for _, b := range bundles {
-			delete(versionsToInclude, b.Version.String())
-			delete(namesToInclude, b.Name)
-		}
-		var verStrs, nameStrs []string
-		for verStr := range versionsToInclude {
-			verStrs = append(verStrs, verStr)
-		}
-		for nameStr := range namesToInclude {
-			nameStrs = append(nameStrs, nameStr)
-		}
-		sb := strings.Builder{}
-		if len(verStrs) != 0 {
-			sb.WriteString(fmt.Sprintf("versions=%+q ", verStrs))
-		}
-		if len(nameStrs) != 0 {
-			sb.WriteString(fmt.Sprintf("names=%+q", nameStrs))
-		}
-		return nil, fmt.Errorf("bundles do not exist in channel: %s", strings.TrimSpace(sb.String()))
-	}
-
-	// Fill in the upgrade graph between each bundle and head.
-	// Regardless of semver order, this step needs to be performed
-	// for each included bundle because there might be leaf nodes
-	// in the upgrade graph for a particular version not captured
-	// by any other fill due to skips not being honored here.
-	head, err := ch.Head()
-	if err != nil {
-		return nil, err
-	}
-	graph := makeUpgradeGraph(ch)
-	bundleSet := map[string]*model.Bundle{}
-	for _, ib := range bundles {
-		if _, addedBundle := bundleSet[ib.Name]; addedBundle {
-			// A prior graph traverse already included this bundle.
-			continue
-		}
-		intersectingBundles, intersectionFound := findIntersectingBundles(ch, ib, head, graph)
-		if !intersectionFound {
-			logger.Debugf("channel head %q not reachable from bundle %q, adding without upgrade graph", head.Name, ib.Name)
-			bundleSet[ib.Name] = ib
-		}
-
-		for _, rb := range intersectingBundles {
-			bundleSet[rb.Name] = rb
-		}
-	}
-	for _, b := range bundleSet {
-		bundles = append(bundles, b)
-	}
-
-	return bundles, nil
-}
-
-// makeUpgradeGraph creates a DAG of bundles with map key Bundle.Replaces.
-func makeUpgradeGraph(ch *model.Channel) map[string][]*model.Bundle {
-	graph := map[string][]*model.Bundle{}
-	for _, b := range ch.Bundles {
-		if b.Replaces != "" {
-			graph[b.Replaces] = append(graph[b.Replaces], b)
-		}
-	}
-	return graph
-}
-
-// findIntersectingBundles finds the intersecting bundle of start and end in the
-// replaces upgrade graph graph by traversing down to the lowest graph node,
-// then returns every bundle higher than the intersection. It is possible
-// to find no intersection; this should only happen when start and end
-// are not part of the same upgrade graph.
-// Output bundle order is not guaranteed.
-// Precondition: start must be a bundle in ch.
-// Precondition: end must be ch's head.
-func findIntersectingBundles(ch *model.Channel, start, end *model.Bundle, graph map[string][]*model.Bundle) ([]*model.Bundle, bool) {
-	// The intersecting set is equal to end if start is end.
-	if start.Name == end.Name {
-		return []*model.Bundle{end}, true
-	}
-
-	// Construct start's replaces chain for comparison against end's.
-	startChain := map[string]*model.Bundle{start.Name: nil}
-	for curr := start; curr != nil && curr.Replaces != ""; curr = ch.Bundles[curr.Replaces] {
-		startChain[curr.Replaces] = curr
-	}
-
-	// Trace end's replaces chain until it intersects with start's, or the root is reached.
-	var intersection string
-	if _, inChain := startChain[end.Name]; inChain {
-		intersection = end.Name
-	} else {
-		for curr := end; curr != nil && curr.Replaces != ""; curr = ch.Bundles[curr.Replaces] {
-			if _, inChain := startChain[curr.Replaces]; inChain {
-				intersection = curr.Replaces
-				break
-			}
-		}
-	}
-
-	// No intersection is found, delegate behavior to caller.
-	if intersection == "" {
-		return nil, false
-	}
-
-	// Find all bundles that replace the intersection via BFS,
-	// i.e. the set of bundles that fill the update graph between start and end.
-	replacesIntersection := graph[intersection]
-	replacesSet := map[string]*model.Bundle{}
-	for _, b := range replacesIntersection {
-		currName := ""
-		for next := []*model.Bundle{b}; len(next) > 0; next = next[1:] {
-			currName = next[0].Name
-			if _, hasReplaces := replacesSet[currName]; !hasReplaces {
-				replacers := graph[currName]
-				next = append(next, replacers...)
-				replacesSet[currName] = ch.Bundles[currName]
-			}
-		}
-	}
-
-	// Remove every bundle between start and intersection exclusively,
-	// since these bundles must already exist in the destination channel.
-	for rep := start; rep != nil && rep.Name != intersection; rep = ch.Bundles[rep.Replaces] {
-		delete(replacesSet, rep.Name)
-	}
-
-	// Ensure both start and end are added to the output.
-	replacesSet[start.Name] = start
-	replacesSet[end.Name] = end
-	var intersectingBundles []*model.Bundle
-	for _, b := range replacesSet {
-		intersectingBundles = append(intersectingBundles, b)
-	}
-	return intersectingBundles, true
-}
diff --git a/alpha/declcfg/diff_include_test.go b/alpha/declcfg/diff_include_test.go
deleted file mode 100644
index 2a5467b0b..000000000
--- a/alpha/declcfg/diff_include_test.go
+++ /dev/null
@@ -1,183 +0,0 @@
-package declcfg
-
-import (
-	"fmt"
-	"sort"
-	"strings"
-	"testing"
-
-	"github.com/stretchr/testify/require"
-
-	"github.com/operator-framework/operator-registry/alpha/model"
-	"github.com/operator-framework/operator-registry/alpha/property"
-)
-
-func TestFindIntersectingBundles(t *testing.T) {
-	type bundleSpec struct {
-		name, replaces string
-		skips          []string
-	}
-
-	inputBundles1 := []bundleSpec{
-		{"foo.v0.1.0", "", nil},
-		{"foo.v0.1.1", "foo.v0.1.0", nil},
-		{"foo.v0.2.0", "foo.v0.1.1", nil},
-		{"foo.v0.3.0", "foo.v0.2.0", nil},
-		{"foo.v1.0.0", "foo.v0.1.0", []string{"foo.v0.1.1", "foo.v0.2.0", "foo.v0.3.0"}},
-		{"foo.v1.1.0", "foo.v1.0.0", nil},
-		{"foo.v2.0.0", "foo.v0.1.0", []string{"foo.v0.1.1", "foo.v0.2.0", "foo.v0.3.0", "foo.v1.0.0", "foo.v1.1.0"}},
-		{"foo.v2.1.0", "foo.v2.0.0", nil},
-		{"foo.v3.0.0", "foo.v1.1.0", []string{"foo.v2.0.0", "foo.v2.1.0"}},
-	}
-
-	type spec struct {
-		name            string
-		pkgName         string
-		channelName     string
-		inputBundles    []bundleSpec
-		start, end      bundleSpec
-		headName        string
-		assertion       require.BoolAssertionFunc
-		expIntersecting []bundleSpec
-	}
-
-	specs := []spec{
-		{
-			name:            "Success/StartEndEqual",
-			inputBundles:    inputBundles1,
-			start:           bundleSpec{"foo.v0.2.0", "foo.v0.1.1", nil},
-			end:             bundleSpec{"foo.v0.2.0", "foo.v0.1.1", nil},
-			headName:        "foo.v3.0.0",
-			assertion:       require.True,
-			expIntersecting: []bundleSpec{{"foo.v0.2.0", "foo.v0.1.1", nil}},
-		},
-		{
-			name:            "Success/FullGraph",
-			inputBundles:    inputBundles1,
-			start:           bundleSpec{"foo.v0.1.0", "", nil},
-			end:             bundleSpec{"foo.v3.0.0", "foo.v1.1.0", nil},
-			headName:        "foo.v3.0.0",
-			assertion:       require.True,
-			expIntersecting: inputBundles1,
-		},
-		{
-			name:         "Success/SubGraph1",
-			inputBundles: inputBundles1,
-			start:        bundleSpec{"foo.v0.2.0", "foo.v0.1.1", nil},
-			end:          bundleSpec{"foo.v3.0.0", "foo.v1.1.0", nil},
-			headName:     "foo.v3.0.0",
-			assertion:    require.True,
-			expIntersecting: []bundleSpec{
-				{"foo.v0.2.0", "foo.v0.1.1", nil},
-				{"foo.v0.3.0", "foo.v0.2.0", nil},
-				{"foo.v1.0.0", "foo.v0.1.0", []string{"foo.v0.1.1", "foo.v0.2.0", "foo.v0.3.0"}},
-				{"foo.v1.1.0", "foo.v1.0.0", nil},
-				{"foo.v2.0.0", "foo.v0.1.0", []string{"foo.v0.1.1", "foo.v0.2.0", "foo.v0.3.0", "foo.v1.0.0", "foo.v1.1.0"}},
-				{"foo.v2.1.0", "foo.v2.0.0", nil},
-				{"foo.v3.0.0", "foo.v1.1.0", []string{"foo.v2.0.0", "foo.v2.1.0"}},
-			},
-		},
-		{
-			name:         "Success/SubGraph2",
-			inputBundles: inputBundles1,
-			start:        bundleSpec{"foo.v0.1.1", "foo.v0.1.0", nil},
-			end:          bundleSpec{"foo.v0.3.0", "foo.v0.2.0", nil},
-			headName:     "foo.v3.0.0",
-			assertion:    require.True,
-			expIntersecting: []bundleSpec{
-				{"foo.v0.1.1", "foo.v0.1.0", nil},
-				{"foo.v0.2.0", "foo.v0.1.1", nil},
-				{"foo.v0.3.0", "foo.v0.2.0", nil},
-			},
-		},
-		{
-			// This case returns inputBundles1 minus foo.v0.1.0, which is the intersection,
-			// because foo.v2.0.0 is a leaf node (disregarding skips).
-			name:            "Success/SubGraph3",
-			inputBundles:    inputBundles1,
-			start:           bundleSpec{"foo.v0.1.1", "foo.v0.1.0", nil},
-			end:             bundleSpec{"foo.v2.0.0", "foo.v0.1.0", nil},
-			headName:        "foo.v3.0.0",
-			assertion:       require.True,
-			expIntersecting: inputBundles1[1:],
-		},
-		{
-			// Even though foo.v0.4.0 is not in the channel, it's replaces (foo.v0.1.1) is.
-			name:         "Success/ReplacesInChannel",
-			inputBundles: inputBundles1,
-			start:        bundleSpec{"foo.v0.2.0", "foo.v0.1.1", nil},
-			end:          bundleSpec{"foo.v0.4.0", "foo.v0.1.1", nil},
-			headName:     "foo.v3.0.0",
-			assertion:    require.True,
-			expIntersecting: []bundleSpec{
-				{"foo.v0.2.0", "foo.v0.1.1", nil},
-				{"foo.v0.3.0", "foo.v0.2.0", nil},
-				{"foo.v0.4.0", "foo.v0.1.1", nil},
-			},
-		},
-		{
-			name:         "Fail/ReplacesNotInChannel",
-			inputBundles: inputBundles1,
-			start:        bundleSpec{"foo.v0.2.0", "foo.v0.1.1", nil},
-			end:          bundleSpec{"foo.v0.4.0", "foo.v0.1.2", nil},
-			headName:     "foo.v3.0.0",
-			assertion:    require.False,
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			// Construct test
-			pkg := &model.Package{Name: "foo"}
-			ch := &model.Channel{Name: "stable", Bundles: make(map[string]*model.Bundle, len(s.inputBundles))}
-			ch.Package = pkg
-			for _, b := range s.inputBundles {
-				ch.Bundles[b.name] = newReplacingBundle(b.name, b.replaces, b.skips, ch, pkg)
-			}
-			expIntersecting := make([]*model.Bundle, len(s.expIntersecting))
-			for i, b := range s.expIntersecting {
-				expIntersecting[i] = newReplacingBundle(b.name, b.replaces, b.skips, ch, pkg)
-			}
-
-			// Ensure the channel is valid and has the correct head.
-			require.NoError(t, ch.Validate())
-			head, err := ch.Head()
-			require.NoError(t, err)
-			require.Equal(t, ch.Bundles[s.headName], head)
-
-			start := newReplacingBundle(s.start.name, s.start.replaces, s.start.skips, ch, pkg)
-			end := newReplacingBundle(s.end.name, s.end.replaces, s.end.skips, ch, pkg)
-			graph := makeUpgradeGraph(ch)
-			intersecting, found := findIntersectingBundles(ch, start, end, graph)
-			s.assertion(t, found)
-			// Compare bundle names only, since mismatch output is too verbose.
-			require.ElementsMatch(t, getBundleNames(expIntersecting), getBundleNames(intersecting))
-		})
-	}
-
-}
-
-func newReplacingBundle(name, replaces string, skips []string, ch *model.Channel, pkg *model.Package) *model.Bundle {
-	split := strings.SplitN(name, ".", 2)
-	nameStr, verStr := split[0], split[1]
-	b := &model.Bundle{
-		Name:     name,
-		Replaces: replaces,
-		Skips:    skips,
-		Channel:  ch,
-		Package:  pkg,
-		Image:    fmt.Sprintf("namespace/%s:%s", nameStr, verStr),
-		Properties: []property.Property{
-			property.MustBuildPackage(ch.Package.Name, verStr),
-		},
-	}
-	return b
-}
-
-func getBundleNames(bundles []*model.Bundle) (names []string) {
-	for _, b := range bundles {
-		names = append(names, b.Name)
-	}
-	sort.Strings(names)
-	return names
-}
diff --git a/alpha/declcfg/diff_test.go b/alpha/declcfg/diff_test.go
deleted file mode 100644
index 18f7dc657..000000000
--- a/alpha/declcfg/diff_test.go
+++ /dev/null
@@ -1,2311 +0,0 @@
-package declcfg
-
-import (
-	"testing"
-
-	"github.com/blang/semver/v4"
-	"github.com/stretchr/testify/require"
-
-	"github.com/operator-framework/operator-registry/alpha/model"
-	"github.com/operator-framework/operator-registry/alpha/property"
-)
-
-type deprecated struct{}
-
-const deprecatedType = "olm.deprecated"
-
-func init() {
-	property.AddToScheme(deprecatedType, &deprecated{})
-}
-
-func TestDiffLatest(t *testing.T) {
-	type spec struct {
-		name      string
-		g         *DiffGenerator
-		oldCfg    DeclarativeConfig
-		newCfg    DeclarativeConfig
-		expCfg    DeclarativeConfig
-		assertion require.ErrorAssertionFunc
-	}
-
-	specs := []spec{
-		{
-			name:   "NoDiff/Empty",
-			oldCfg: DeclarativeConfig{},
-			newCfg: DeclarativeConfig{},
-			g:      &DiffGenerator{},
-			expCfg: DeclarativeConfig{},
-		},
-		{
-			name: "NoDiff/OneEqualBundle",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			g:      &DiffGenerator{},
-			expCfg: DeclarativeConfig{},
-		},
-		{
-			name: "NoDiff/UnsortedBundleProps",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			g:      &DiffGenerator{},
-			expCfg: DeclarativeConfig{},
-		},
-		{
-			name: "HasDiff/OneModifiedBundle",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("bar", ">=1.0.0"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("bar", ">=1.0.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/ManyBundlesAndChannels",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "fast", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0-alpha.0"},
-						{Name: "foo.v0.2.0-alpha.1", Replaces: "foo.v0.2.0-alpha.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0-alpha.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0-alpha.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0-alpha.1",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0-alpha.1"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Skips: []string{"foo.v0.1.0"}},
-					}},
-					{Schema: schemaChannel, Name: "fast", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0-alpha.0"},
-						{Name: "foo.v0.2.0-alpha.1", Replaces: "foo.v0.2.0-alpha.0"},
-					}},
-					{Schema: schemaChannel, Name: "clusterwide", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0-clusterwide"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuild(&deprecated{}),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0-alpha.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0-alpha.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0-alpha.1",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0-alpha.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0-clusterwide",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0-clusterwide"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "clusterwide", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0-clusterwide"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Skips: []string{"foo.v0.1.0"}},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuild(&deprecated{}),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0-clusterwide",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0-clusterwide"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/OldBundleUpdatedDependencyRange",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/BundleNewDependencyRange",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/NewBundleNewDependencyRange",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "clusterwide", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0-clusterwide"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0-clusterwide",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0-clusterwide"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "clusterwide", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0-clusterwide"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0-clusterwide",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0-clusterwide"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/OneNewDependencyRange",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/TwoDependencyRanges",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0 <0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.0 <0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0"),
-							property.MustBuildPackageRequired("etcd", ">=0.9.2"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/BundleNewDependencyGVK",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludePackage",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{{Name: "foo.v0.1.0"}}},
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{{Name: "bar.v0.1.0"}}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.1.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.1.0")},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{{Name: "foo.v0.1.0"}}},
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"}, {Name: "bar.v0.2.0", Replaces: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.1.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.2.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.2.0")},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{{Name: "bar"}},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.2.0", Replaces: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.2.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.2.0")},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludeChannel",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{{Name: "foo.v0.1.0"}}},
-					{Schema: schemaChannel, Name: "alpha", Package: "foo", Entries: []ChannelEntry{{Name: "foo.v0.1.0-alpha.0"}}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0-alpha.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0-alpha.0")},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "alpha"}, // Make sure the default channel is still updated.
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"}, {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"}},
-					},
-					{Schema: schemaChannel, Name: "alpha", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0-alpha.0"}, {Name: "foo.v0.2.0-alpha.0", Replaces: "foo.v0.1.0-alpha.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0-alpha.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0-alpha.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0-alpha.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0-alpha.0")},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{{Name: "foo", Channels: []DiffIncludeChannel{{Name: "stable"}}}},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "alpha"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludeVersion",
-			oldCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"}, {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-				},
-			},
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"}, {Name: "foo.v0.1.1", Replaces: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.1"}, {Name: "foo.v0.3.0", Replaces: "foo.v0.2.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.1", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.1")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.3.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.3.0")},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{
-						{Name: "foo", Channels: []DiffIncludeChannel{
-							{Name: "stable", Versions: []semver.Version{{Major: 0, Minor: 2, Patch: 0}}}},
-						}},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.3.0", Replaces: "foo.v0.2.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.3.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.3.0")},
-					},
-				},
-			},
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			if s.assertion == nil {
-				s.assertion = require.NoError
-			}
-
-			oldModel, err := ConvertToModel(s.oldCfg)
-			require.NoError(t, err)
-
-			newModel, err := ConvertToModel(s.newCfg)
-			require.NoError(t, err)
-
-			outputModel, err := s.g.Run(oldModel, newModel)
-			s.assertion(t, err)
-
-			outputCfg := ConvertFromModel(outputModel)
-			require.Equal(t, s.expCfg, outputCfg)
-		})
-	}
-}
-
-func TestDiffHeadsOnly(t *testing.T) {
-	type spec struct {
-		name      string
-		g         *DiffGenerator
-		newCfg    DeclarativeConfig
-		expCfg    DeclarativeConfig
-		assertion require.ErrorAssertionFunc
-	}
-
-	specs := []spec{
-		{
-			name:   "NoDiff/Empty",
-			newCfg: DeclarativeConfig{},
-			g:      &DiffGenerator{},
-			expCfg: DeclarativeConfig{},
-		},
-		{
-			name: "HasDiff/OneBundle",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/Graph",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-					}},
-					{Schema: schemaChannel, Name: "clusterwide", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1-clusterwide"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "alpha", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0-alpha.0"},
-						{Name: "foo.v0.2.0-alpha.1", Replaces: "foo.v0.2.0-alpha.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.2.0-alpha.1"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0-alpha.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0-alpha.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0-alpha.1",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0-alpha.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1-clusterwide",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1-clusterwide"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "clusterwide", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1-clusterwide"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-					}},
-					{Schema: schemaChannel, Name: "alpha", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.2.0-alpha.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1-clusterwide",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("etcd", "0.9.1-clusterwide"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.2.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.2.0"),
-						},
-					},
-				},
-			},
-		},
-		{
-			// Testing SkipDependencies only really makes sense in heads-only mode,
-			// since new dependencies are always added.
-			name: "HasDiff/SkipDependencies",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackageRequired("etcd", "<=0.9.1"),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				SkipDependencies: true,
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", "<=0.9.1"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/SelectDependencies",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.3", Replaces: "etcd.v0.9.2"},
-						{Name: "etcd.v1.0.0", Replaces: "etcd.v0.9.3", Skips: []string{"etcd.v0.9.1", "etcd.v0.9.2", "etcd.v0.9.3"}},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackageRequired("etcd", "<0.9.2"),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "bar.v0.1.0",
-						Package: "bar",
-						Image:   "reg/bar:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("bar", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.3",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.3"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v1.0.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "1.0.0"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.3", Replaces: "etcd.v0.9.2"},
-						{Name: "etcd.v1.0.0", Replaces: "etcd.v0.9.3", Skips: []string{"etcd.v0.9.1", "etcd.v0.9.2", "etcd.v0.9.3"}},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "bar.v0.1.0",
-						Package: "bar",
-						Image:   "reg/bar:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("bar", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.3",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.3"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v1.0.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "1.0.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", "<0.9.2"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludeAdditive",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.3", Replaces: "etcd.v0.9.2"},
-						{Name: "etcd.v1.0.0", Replaces: "etcd.v0.9.3", Skips: []string{"etcd.v0.9.1", "etcd.v0.9.2", "etcd.v0.9.3"}},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackageRequired("etcd", "<0.9.2"),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "bar.v0.1.0",
-						Package: "bar",
-						Image:   "reg/bar:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("bar", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.3",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.3"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v1.0.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "1.0.0"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				IncludeAdditively: true,
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{
-						{
-							Name: "etcd",
-							Channels: []DiffIncludeChannel{{
-								Name:     "stable",
-								Versions: []semver.Version{{Major: 0, Minor: 9, Patch: 2}}},
-							}},
-						{
-							Name:     "bar",
-							Channels: []DiffIncludeChannel{{Name: "stable"}},
-						},
-					},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.3", Replaces: "etcd.v0.9.2"},
-						{Name: "etcd.v1.0.0", Replaces: "etcd.v0.9.3", Skips: []string{"etcd.v0.9.1", "etcd.v0.9.2", "etcd.v0.9.3"}},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "bar.v0.1.0",
-						Package: "bar",
-						Image:   "reg/bar:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("bar", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.3",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.3"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v1.0.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "1.0.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackage("foo", "0.1.0"),
-							property.MustBuildPackageRequired("etcd", "<0.9.2"),
-						},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludePackage",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{{Name: "foo.v0.1.0"}}},
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"}, {Name: "bar.v0.2.0", Replaces: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.1.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.2.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.2.0")},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{{Name: "bar"}},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"}, {Name: "bar.v0.2.0", Replaces: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.1.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "bar.v0.2.0", Package: "bar", Image: "reg/bar:latest",
-						Properties: []property.Property{property.MustBuildPackage("bar", "0.2.0")},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludeChannel",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "alpha"}, // Make sure the default channel is still updated.
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"}, {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"}},
-					},
-					{Schema: schemaChannel, Name: "alpha", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0-alpha.0"}, {Name: "foo.v0.2.0-alpha.0", Replaces: "foo.v0.1.0-alpha.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0-alpha.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0-alpha.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0-alpha.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0-alpha.0")},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{{Name: "foo", Channels: []DiffIncludeChannel{{Name: "stable"}}}},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "alpha"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"}, {Name: "foo.v0.2.0", Replaces: "foo.v0.1.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludeVersion",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"}, {Name: "foo.v0.1.1", Replaces: "foo.v0.1.0"},
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.1"}, {Name: "foo.v0.3.0", Replaces: "foo.v0.2.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.1.1", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.1.1")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.3.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.3.0")},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{
-						{Name: "foo", Channels: []DiffIncludeChannel{
-							{Name: "stable", Versions: []semver.Version{{Major: 0, Minor: 2, Patch: 0}}}},
-						}},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.2.0", Replaces: "foo.v0.1.1"}, {Name: "foo.v0.3.0", Replaces: "foo.v0.2.0"}},
-					},
-				},
-				Bundles: []Bundle{
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.2.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.2.0")},
-					},
-					{
-						Schema: schemaBundle,
-						Name:   "foo.v0.3.0", Package: "foo", Image: "reg/foo:latest",
-						Properties: []property.Property{property.MustBuildPackage("foo", "0.3.0")},
-					},
-				},
-			},
-		},
-		{
-			name: "HasDiff/IncludeNonAdditive",
-			newCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "foo", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.1", Replaces: "etcd.v0.9.0"},
-						{Name: "etcd.v0.9.2", Replaces: "etcd.v0.9.1"},
-						{Name: "etcd.v0.9.3", Replaces: "etcd.v0.9.2"},
-						{Name: "etcd.v1.0.0", Replaces: "etcd.v0.9.3", Skips: []string{"etcd.v0.9.1", "etcd.v0.9.2", "etcd.v0.9.3"}},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "foo", Entries: []ChannelEntry{
-						{Name: "foo.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "foo.v0.1.0",
-						Package: "foo",
-						Image:   "reg/foo:latest",
-						Properties: []property.Property{
-							property.MustBuildPackageRequired("etcd", "<0.9.2"),
-							property.MustBuildPackage("foo", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "bar.v0.1.0",
-						Package: "bar",
-						Image:   "reg/bar:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("bar", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.1",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.1"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.2",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.2"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.3",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.3"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v1.0.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "1.0.0"),
-						},
-					},
-				},
-			},
-			g: &DiffGenerator{
-				Includer: DiffIncluder{
-					Packages: []DiffIncludePackage{
-						{
-							Name: "etcd",
-							Channels: []DiffIncludeChannel{{
-								Name:     "stable",
-								Versions: []semver.Version{{Major: 0, Minor: 9, Patch: 3}}},
-							}},
-						{
-							Name:     "bar",
-							Channels: []DiffIncludeChannel{{Name: "stable"}},
-						},
-					},
-				},
-			},
-			expCfg: DeclarativeConfig{
-				Packages: []Package{
-					{Schema: schemaPackage, Name: "bar", DefaultChannel: "stable"},
-					{Schema: schemaPackage, Name: "etcd", DefaultChannel: "stable"},
-				},
-				Channels: []Channel{
-					{Schema: schemaChannel, Name: "stable", Package: "bar", Entries: []ChannelEntry{
-						{Name: "bar.v0.1.0"},
-					}},
-					{Schema: schemaChannel, Name: "stable", Package: "etcd", Entries: []ChannelEntry{
-						{Name: "etcd.v0.9.3", Replaces: "etcd.v0.9.2"},
-						{Name: "etcd.v1.0.0", Replaces: "etcd.v0.9.3", Skips: []string{"etcd.v0.9.1", "etcd.v0.9.2", "etcd.v0.9.3"}},
-					}},
-				},
-				Bundles: []Bundle{
-					{
-						Schema:  schemaBundle,
-						Name:    "bar.v0.1.0",
-						Package: "bar",
-						Image:   "reg/bar:latest",
-						Properties: []property.Property{
-							property.MustBuildGVKRequired("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildPackage("bar", "0.1.0"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v0.9.3",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "0.9.3"),
-						},
-					},
-					{
-						Schema:  schemaBundle,
-						Name:    "etcd.v1.0.0",
-						Package: "etcd",
-						Image:   "reg/etcd:latest",
-						Properties: []property.Property{
-							property.MustBuildGVK("etcd.database.coreos.com", "v1", "EtcdBackup"),
-							property.MustBuildGVK("etcd.database.coreos.com", "v1beta2", "EtcdBackup"),
-							property.MustBuildPackage("etcd", "1.0.0"),
-						},
-					},
-				},
-			},
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			if s.assertion == nil {
-				s.assertion = require.NoError
-			}
-
-			newModel, err := ConvertToModel(s.newCfg)
-			require.NoError(t, err)
-
-			outputModel, err := s.g.Run(model.Model{}, newModel)
-			s.assertion(t, err)
-
-			outputCfg := ConvertFromModel(outputModel)
-			require.Equal(t, s.expCfg, outputCfg)
-		})
-	}
-}
diff --git a/alpha/declcfg/helpers_test.go b/alpha/declcfg/helpers_test.go
index 86111c770..1d55f9e2a 100644
--- a/alpha/declcfg/helpers_test.go
+++ b/alpha/declcfg/helpers_test.go
@@ -3,10 +3,10 @@ package declcfg
 import (
 	"encoding/json"
 	"fmt"
-	"path/filepath"
 	"sort"
 	"testing"
 
+	"github.com/blang/semver/v4"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -14,7 +14,12 @@ import (
 	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
-func buildValidDeclarativeConfig(includeUnrecognized bool) DeclarativeConfig {
+type validDeclarativeConfigSpec struct {
+	IncludeUnrecognized bool
+	IncludeDeprecations bool
+}
+
+func buildValidDeclarativeConfig(spec validDeclarativeConfigSpec) DeclarativeConfig {
 	a001 := newTestBundle("anakin", "0.0.1")
 	a010 := newTestBundle("anakin", "0.1.0")
 	a011 := newTestBundle("anakin", "0.1.1")
@@ -22,7 +27,7 @@ func buildValidDeclarativeConfig(includeUnrecognized bool) DeclarativeConfig {
 	b2 := newTestBundle("boba-fett", "2.0.0")
 
 	var others []Meta
-	if includeUnrecognized {
+	if spec.IncludeUnrecognized {
 		others = []Meta{
 			{Schema: "custom.1", Blob: json.RawMessage(`{"schema": "custom.1"}`)},
 			{Schema: "custom.2", Blob: json.RawMessage(`{"schema": "custom.2"}`)},
@@ -39,6 +44,38 @@ func buildValidDeclarativeConfig(includeUnrecognized bool) DeclarativeConfig {
 		}
 	}
 
+	var deprecations []Deprecation
+	if spec.IncludeDeprecations {
+		deprecations = []Deprecation{
+			{
+				Schema:  SchemaDeprecation,
+				Package: "anakin",
+				Entries: []DeprecationEntry{
+					{
+						Reference: PackageScopedReference{
+							Schema: "olm.bundle",
+							Name:   testBundleName("anakin", "0.0.1"),
+						},
+						Message: "This bundle version is deprecated",
+					},
+					{
+						Reference: PackageScopedReference{
+							Schema: "olm.channel",
+							Name:   "light",
+						},
+						Message: "This channel is deprecated",
+					},
+					{
+						Reference: PackageScopedReference{
+							Schema: "olm.package",
+						},
+						Message: "This package is deprecated... there is another",
+					},
+				},
+			},
+		}
+	}
+
 	return DeclarativeConfig{
 		Packages: []Package{
 			newTestPackage("anakin", "dark", svgSmallCircle),
@@ -82,7 +119,8 @@ func buildValidDeclarativeConfig(includeUnrecognized bool) DeclarativeConfig {
 			a001, a010, a011,
 			b1, b2,
 		},
-		Others: others,
+		Others:       others,
+		Deprecations: deprecations,
 	}
 }
 
@@ -108,16 +146,16 @@ func withNoBundleData() func(*Bundle) {
 }
 
 func newTestBundle(packageName, version string, opts ...bundleOpt) Bundle {
-	csvJson := fmt.Sprintf(`{"kind": "ClusterServiceVersion", "apiVersion": "operators.coreos.com/v1alpha1", "metadata":{"name":%q}}`, testBundleName(packageName, version))
+	csvJSON := fmt.Sprintf(`{"kind": "ClusterServiceVersion", "apiVersion": "operators.coreos.com/v1alpha1", "metadata":{"name":%q}}`, testBundleName(packageName, version))
 	b := Bundle{
-		Schema:  schemaBundle,
+		Schema:  SchemaBundle,
 		Name:    testBundleName(packageName, version),
 		Package: packageName,
 		Image:   testBundleImage(packageName, version),
 		Properties: []property.Property{
 			property.MustBuildPackage(packageName, version),
-			property.MustBuildBundleObjectRef(filepath.Join("objects", testBundleName(packageName, version)+".csv.yaml")),
-			property.MustBuildBundleObjectData([]byte(`{"kind": "CustomResourceDefinition", "apiVersion": "apiextensions.k8s.io/v1"}`)),
+			property.MustBuildBundleObject([]byte(csvJSON)),
+			property.MustBuildBundleObject([]byte(`{"kind": "CustomResourceDefinition", "apiVersion": "apiextensions.k8s.io/v1"}`)),
 		},
 		RelatedImages: []RelatedImage{
 			{
@@ -125,9 +163,9 @@ func newTestBundle(packageName, version string, opts ...bundleOpt) Bundle {
 				Image: testBundleImage(packageName, version),
 			},
 		},
-		CsvJSON: csvJson,
+		CsvJSON: csvJSON,
 		Objects: []string{
-			csvJson,
+			csvJSON,
 			`{"kind": "CustomResourceDefinition", "apiVersion": "apiextensions.k8s.io/v1"}`,
 		},
 	}
@@ -150,7 +188,7 @@ const (
 
 func newTestPackage(packageName, defaultChannel, svgData string) Package {
 	p := Package{
-		Schema:         schemaPackage,
+		Schema:         SchemaPackage,
 		Name:           packageName,
 		DefaultChannel: defaultChannel,
 		Icon:           &Icon{Data: []byte(svgData), MediaType: "image/svg+xml"},
@@ -159,15 +197,25 @@ func newTestPackage(packageName, defaultChannel, svgData string) Package {
 	return p
 }
 
+func addPackageProperties(in Package, p []property.Property) Package {
+	in.Properties = p
+	return in
+}
+
 func newTestChannel(packageName, channelName string, entries ...ChannelEntry) Channel {
 	return Channel{
-		Schema:  schemaChannel,
+		Schema:  SchemaChannel,
 		Name:    channelName,
 		Package: packageName,
 		Entries: entries,
 	}
 }
 
+func addChannelProperties(in Channel, p []property.Property) Channel {
+	in.Properties = p
+	return in
+}
+
 func buildTestModel() model.Model {
 	return model.Model{
 		"anakin":    buildAnakinPkgModel(),
@@ -183,8 +231,8 @@ func getBundle(pkg *model.Package, ch *model.Channel, version, replaces string,
 		Image:   testBundleImage(pkg.Name, version),
 		Properties: []property.Property{
 			property.MustBuildPackage(pkg.Name, version),
-			property.MustBuildBundleObjectRef(filepath.Join("objects", testBundleName(pkg.Name, version)+".csv.yaml")),
-			property.MustBuildBundleObjectData([]byte(getCRDJSON())),
+			property.MustBuildBundleObject([]byte(getCSVJson(pkg.Name, version))),
+			property.MustBuildBundleObject([]byte(getCRDJSON())),
 		},
 		Replaces: replaces,
 		Skips:    skips,
@@ -197,6 +245,7 @@ func getBundle(pkg *model.Package, ch *model.Channel, version, replaces string,
 			getCSVJson(pkg.Name, version),
 			getCRDJSON(),
 		},
+		Version: semver.MustParse(version),
 	}
 }
 
diff --git a/alpha/declcfg/load.go b/alpha/declcfg/load.go
index aa601a1d6..5db111b87 100644
--- a/alpha/declcfg/load.go
+++ b/alpha/declcfg/load.go
@@ -1,19 +1,22 @@
 package declcfg
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
 	"io"
 	"io/fs"
-	"path/filepath"
-	"strings"
+	"runtime"
+	"sync"
 
 	"github.com/joelanford/ignore"
-	"github.com/operator-framework/api/pkg/operators"
+	"golang.org/x/sync/errgroup"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/util/yaml"
 
+	"github.com/operator-framework/api/pkg/operators"
+
 	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
@@ -21,6 +24,66 @@ const (
 	indexIgnoreFilename = ".indexignore"
 )
 
+type WalkMetasFSFunc func(path string, meta *Meta, err error) error
+
+// WalkMetasFS walks the filesystem rooted at root and calls walkFn for each individual meta object found in the root.
+// By default, WalkMetasFS is not thread-safe because it invokes walkFn concurrently. In order to make it thread-safe,
+// use the WithConcurrency(1) to avoid concurrent invocations of walkFn.
+func WalkMetasFS(ctx context.Context, root fs.FS, walkFn WalkMetasFSFunc, opts ...LoadOption) error {
+	if root == nil {
+		return fmt.Errorf("no declarative config filesystem provided")
+	}
+
+	options := LoadOptions{
+		concurrency: runtime.NumCPU(),
+	}
+	for _, opt := range opts {
+		opt(&options)
+	}
+
+	pathChan := make(chan string, options.concurrency)
+
+	// Create an errgroup to manage goroutines. The context is closed when any
+	// goroutine returns an error. Goroutines should check the context
+	// to see if they should return early (in the case of another goroutine
+	// returning an error).
+	eg, ctx := errgroup.WithContext(ctx)
+
+	// Walk the FS and send paths to a channel for parsing.
+	eg.Go(func() error {
+		return sendPaths(ctx, root, pathChan)
+	})
+
+	// Parse paths concurrently. The waitgroup ensures that all paths are parsed
+	// before the cfgChan is closed.
+	for i := 0; i < options.concurrency; i++ {
+		eg.Go(func() error {
+			return parseMetaPaths(ctx, root, pathChan, walkFn, options)
+		})
+	}
+	return eg.Wait()
+}
+
+type WalkMetasReaderFunc func(meta *Meta, err error) error
+
+func WalkMetasReader(r io.Reader, walkFn WalkMetasReaderFunc) error {
+	dec := yaml.NewYAMLOrJSONDecoder(r, 4096)
+	for {
+		var in Meta
+		if err := dec.Decode(&in); err != nil {
+			if errors.Is(err, io.EOF) {
+				break
+			}
+			return walkFn(nil, err)
+		}
+
+		if err := walkFn(&in, nil); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
 type WalkFunc func(path string, cfg *DeclarativeConfig, err error) error
 
 // WalkFS walks root using a gitignore-style filename matcher to skip files
@@ -28,9 +91,25 @@ type WalkFunc func(path string, cfg *DeclarativeConfig, err error) error
 // It calls walkFn for each declarative config file it finds. If WalkFS encounters
 // an error loading or parsing any file, the error will be immediately returned.
 func WalkFS(root fs.FS, walkFn WalkFunc) error {
+	return walkFiles(root, func(root fs.FS, path string, err error) error {
+		if err != nil {
+			return walkFn(path, nil, err)
+		}
+
+		cfg, err := LoadFile(root, path)
+		if err != nil {
+			return walkFn(path, cfg, err)
+		}
+
+		return walkFn(path, cfg, nil)
+	})
+}
+
+func walkFiles(root fs.FS, fn func(root fs.FS, path string, err error) error) error {
 	if root == nil {
 		return fmt.Errorf("no declarative config filesystem provided")
 	}
+
 	matcher, err := ignore.NewMatcher(root, indexIgnoreFilename)
 	if err != nil {
 		return err
@@ -38,66 +117,106 @@ func WalkFS(root fs.FS, walkFn WalkFunc) error {
 
 	return fs.WalkDir(root, ".", func(path string, info fs.DirEntry, err error) error {
 		if err != nil {
-			return walkFn(path, nil, err)
+			return fn(root, path, err)
 		}
 		// avoid validating a directory, an .indexignore file, or any file that matches
 		// an ignore pattern outlined in a .indexignore file.
 		if info.IsDir() || info.Name() == indexIgnoreFilename || matcher.Match(path, false) {
 			return nil
 		}
-		file, err := root.Open(path)
-		if err != nil {
-			return walkFn(path, nil, err)
-		}
-		defer file.Close()
-		cfg, err := readYAMLOrJSON(file)
-		if err != nil {
-			return walkFn(path, cfg, err)
-		}
-		if err := readBundleObjects(cfg.Bundles, root, path); err != nil {
-			return fmt.Errorf("read bundle objects: %v", err)
-		}
-		return walkFn(path, cfg, err)
+
+		return fn(root, path, nil)
 	})
 }
 
+type LoadOptions struct {
+	concurrency int
+}
+
+type LoadOption func(*LoadOptions)
+
+func WithConcurrency(concurrency int) LoadOption {
+	return func(opts *LoadOptions) {
+		opts.concurrency = concurrency
+	}
+}
+
 // LoadFS loads a declarative config from the provided root FS. LoadFS walks the
 // filesystem from root and uses a gitignore-style filename matcher to skip files
 // that match patterns found in .indexignore files found throughout the filesystem.
 // If LoadFS encounters an error loading or parsing any file, the error will be
 // immediately returned.
-func LoadFS(root fs.FS) (*DeclarativeConfig, error) {
-	cfg := &DeclarativeConfig{}
-	if err := WalkFS(root, func(path string, fcfg *DeclarativeConfig, err error) error {
+func LoadFS(ctx context.Context, root fs.FS, opts ...LoadOption) (*DeclarativeConfig, error) {
+	builder := fbcBuilder{}
+	if err := WalkMetasFS(ctx, root, func(path string, meta *Meta, err error) error {
 		if err != nil {
 			return err
 		}
-		cfg.Packages = append(cfg.Packages, fcfg.Packages...)
-		cfg.Channels = append(cfg.Channels, fcfg.Channels...)
-		cfg.Bundles = append(cfg.Bundles, fcfg.Bundles...)
-		cfg.Others = append(cfg.Others, fcfg.Others...)
-		return nil
-	}); err != nil {
+		return builder.addMeta(meta)
+	}, opts...); err != nil {
 		return nil, err
 	}
-	return cfg, nil
+	return &builder.cfg, nil
 }
 
-func readBundleObjects(bundles []Bundle, root fs.FS, path string) error {
-	for bi, b := range bundles {
-		props, err := property.Parse(b.Properties)
+func sendPaths(ctx context.Context, root fs.FS, pathChan chan<- string) error {
+	defer close(pathChan)
+	return walkFiles(root, func(_ fs.FS, path string, err error) error {
 		if err != nil {
-			return fmt.Errorf("parse properties for bundle %q: %v", b.Name, err)
+			return err
+		}
+		select {
+		case pathChan <- path:
+		case <-ctx.Done(): // don't block on sending to pathChan
+			return ctx.Err()
 		}
-		for oi, obj := range props.BundleObjects {
-			d, err := obj.GetData(root, filepath.Dir(path))
+		return nil
+	})
+}
+
+func parseMetaPaths(ctx context.Context, root fs.FS, pathChan <-chan string, walkFn WalkMetasFSFunc, _ LoadOptions) error {
+	for {
+		select {
+		case <-ctx.Done(): // don't block on receiving from pathChan
+			return ctx.Err()
+		case path, ok := <-pathChan:
+			if !ok {
+				return nil
+			}
+			err := func() error { // using closure to ensure file is closed immediately after use
+				file, err := root.Open(path)
+				if err != nil {
+					return err
+				}
+				defer file.Close()
+
+				return WalkMetasReader(file, func(meta *Meta, err error) error {
+					return walkFn(path, meta, err)
+				})
+			}()
 			if err != nil {
-				return fmt.Errorf("get data for bundle object[%d]: %v", oi, err)
+				return err
 			}
-			bundles[bi].Objects = append(bundles[bi].Objects, string(d))
 		}
-		bundles[bi].CsvJSON = extractCSV(bundles[bi].Objects)
 	}
+}
+
+func readBundleObjects(b *Bundle) error {
+	var obj property.BundleObject
+	for i, props := range b.Properties {
+		if props.Type != property.TypeBundleObject {
+			continue
+		}
+		if err := json.Unmarshal(props.Value, &obj); err != nil {
+			return fmt.Errorf("package %q, bundle %q: parse property at index %d as bundle object: %v", b.Package, b.Name, i, err)
+		}
+		objJSON, err := yaml.ToJSON(obj.Data)
+		if err != nil {
+			return fmt.Errorf("package %q, bundle %q: convert bundle object property at index %d to JSON: %v", b.Package, b.Name, i, err)
+		}
+		b.Objects = append(b.Objects, string(objJSON))
+	}
+	b.CsvJSON = extractCSV(b.Objects)
 	return nil
 }
 
@@ -114,48 +233,101 @@ func extractCSV(objs []string) string {
 	return ""
 }
 
-func readYAMLOrJSON(r io.Reader) (*DeclarativeConfig, error) {
-	cfg := &DeclarativeConfig{}
-	dec := yaml.NewYAMLOrJSONDecoder(r, 4096)
-	for {
-		doc := json.RawMessage{}
-		if err := dec.Decode(&doc); err != nil {
-			if errors.Is(err, io.EOF) {
-				break
-			}
-			return nil, err
+// LoadReader reads yaml or json from the passed in io.Reader and unmarshals it into a DeclarativeConfig struct.
+func LoadReader(r io.Reader) (*DeclarativeConfig, error) {
+	builder := fbcBuilder{}
+	if err := WalkMetasReader(r, func(meta *Meta, err error) error {
+		if err != nil {
+			return err
 		}
-		doc = []byte(strings.NewReplacer(`\u003c`, "<", `\u003e`, ">", `\u0026`, "&").Replace(string(doc)))
+		return builder.addMeta(meta)
+	}); err != nil {
+		return nil, err
+	}
+	return &builder.cfg, nil
+}
 
-		var in Meta
-		if err := json.Unmarshal(doc, &in); err != nil {
+// LoadFile will unmarshall declarative config components from a single filename provided in 'path'
+// located at a filesystem hierarchy 'root'
+func LoadFile(root fs.FS, path string) (*DeclarativeConfig, error) {
+	file, err := root.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+
+	cfg, err := LoadReader(file)
+	if err != nil {
+		return nil, err
+	}
+
+	return cfg, nil
+}
+
+// LoadSlice will compose declarative config components from a slice of Meta objects
+func LoadSlice(metas []*Meta) (*DeclarativeConfig, error) {
+	builder := fbcBuilder{}
+	for _, meta := range metas {
+		if err := builder.addMeta(meta); err != nil {
 			return nil, err
 		}
+	}
+	return &builder.cfg, nil
+}
 
-		switch in.Schema {
-		case schemaPackage:
-			var p Package
-			if err := json.Unmarshal(doc, &p); err != nil {
-				return nil, fmt.Errorf("parse package: %v", err)
-			}
-			cfg.Packages = append(cfg.Packages, p)
-		case schemaChannel:
-			var c Channel
-			if err := json.Unmarshal(doc, &c); err != nil {
-				return nil, fmt.Errorf("parse channel: %v", err)
-			}
-			cfg.Channels = append(cfg.Channels, c)
-		case schemaBundle:
-			var b Bundle
-			if err := json.Unmarshal(doc, &b); err != nil {
-				return nil, fmt.Errorf("parse bundle: %v", err)
-			}
-			cfg.Bundles = append(cfg.Bundles, b)
-		case "":
-			return nil, fmt.Errorf("object '%s' is missing root schema field", string(doc))
-		default:
-			cfg.Others = append(cfg.Others, in)
+type fbcBuilder struct {
+	cfg DeclarativeConfig
+
+	packagesMu     sync.Mutex
+	channelsMu     sync.Mutex
+	bundlesMu      sync.Mutex
+	deprecationsMu sync.Mutex
+	othersMu       sync.Mutex
+}
+
+func (c *fbcBuilder) addMeta(in *Meta) error {
+	switch in.Schema {
+	case SchemaPackage:
+		var p Package
+		if err := json.Unmarshal(in.Blob, &p); err != nil {
+			return fmt.Errorf("parse package: %v", err)
 		}
+		c.packagesMu.Lock()
+		c.cfg.Packages = append(c.cfg.Packages, p)
+		c.packagesMu.Unlock()
+	case SchemaChannel:
+		var ch Channel
+		if err := json.Unmarshal(in.Blob, &ch); err != nil {
+			return fmt.Errorf("parse channel: %v", err)
+		}
+		c.channelsMu.Lock()
+		c.cfg.Channels = append(c.cfg.Channels, ch)
+		c.channelsMu.Unlock()
+	case SchemaBundle:
+		var b Bundle
+		if err := json.Unmarshal(in.Blob, &b); err != nil {
+			return fmt.Errorf("parse bundle: %v", err)
+		}
+		if err := readBundleObjects(&b); err != nil {
+			return fmt.Errorf("read bundle objects: %v", err)
+		}
+		c.bundlesMu.Lock()
+		c.cfg.Bundles = append(c.cfg.Bundles, b)
+		c.bundlesMu.Unlock()
+	case SchemaDeprecation:
+		var d Deprecation
+		if err := json.Unmarshal(in.Blob, &d); err != nil {
+			return fmt.Errorf("parse deprecation: %w", err)
+		}
+		c.deprecationsMu.Lock()
+		c.cfg.Deprecations = append(c.cfg.Deprecations, d)
+		c.deprecationsMu.Unlock()
+	case "":
+		return fmt.Errorf("object '%s' is missing root schema field", string(in.Blob))
+	default:
+		c.othersMu.Lock()
+		c.cfg.Others = append(c.cfg.Others, *in)
+		c.othersMu.Unlock()
 	}
-	return cfg, nil
+	return nil
 }
diff --git a/alpha/declcfg/load_benchmark_test.go b/alpha/declcfg/load_benchmark_test.go
new file mode 100644
index 000000000..46f3138be
--- /dev/null
+++ b/alpha/declcfg/load_benchmark_test.go
@@ -0,0 +1,312 @@
+package declcfg_test
+
+import (
+	"context"
+	"crypto/rand"
+	"encoding/base64"
+	"fmt"
+	"math/big"
+	"os"
+	"runtime"
+	"testing"
+
+	"github.com/blang/semver/v4"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/operator-framework/api/pkg/lib/version"
+	"github.com/operator-framework/api/pkg/operators/v1alpha1"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/property"
+)
+
+func BenchmarkLoadFS(b *testing.B) {
+	fbc := generateFBC(b, 300, 450, 3000)
+	b.ResetTimer()
+
+	for _, n := range []int{1, runtime.NumCPU(), 2 * runtime.NumCPU()} {
+		b.Run(fmt.Sprintf("%d routines", n), func(b *testing.B) {
+			for i := 0; i < b.N; i++ {
+				b.StopTimer()
+				tempDir := b.TempDir()
+				if err := declcfg.WriteFS(*fbc, tempDir, declcfg.WriteJSON, ".json"); err != nil {
+					b.Error(err)
+				}
+				b.StartTimer()
+
+				_, err := declcfg.LoadFS(context.Background(), os.DirFS(tempDir), declcfg.WithConcurrency(n))
+				if err != nil {
+					b.Error(err)
+				}
+			}
+		})
+	}
+}
+
+const randomPng = "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"
+
+func generateFBC(b *testing.B, numPackages, numChannels, numBundles int) *declcfg.DeclarativeConfig {
+	pngData, err := base64.StdEncoding.DecodeString(randomPng)
+	if err != nil {
+		b.Error(err)
+	}
+
+	fbc := &declcfg.DeclarativeConfig{}
+
+	for i := 0; i < numPackages; i++ {
+		pkgName := fmt.Sprintf("pkg-%d", i)
+		fbc.Packages = append(fbc.Packages, declcfg.Package{
+			Schema:      declcfg.SchemaPackage,
+			Name:        pkgName,
+			Description: fmt.Sprintf("%s description", pkgName),
+			Icon: &declcfg.Icon{
+				Data:      pngData,
+				MediaType: "image/png",
+			},
+		})
+	}
+	for i := 0; i < numChannels; i++ {
+		r, err := rand.Int(rand.Reader, big.NewInt(int64(numPackages)))
+		if err != nil {
+			b.Error(err)
+		}
+		pkgName := fbc.Packages[r.Int64()].Name
+		channelName := fmt.Sprintf("channel-%d", i)
+		fbc.Channels = append(fbc.Channels, declcfg.Channel{
+			Schema:  declcfg.SchemaChannel,
+			Package: pkgName,
+			Name:    channelName,
+		})
+	}
+	for i := 0; i < numBundles; i++ {
+		r, err := rand.Int(rand.Reader, big.NewInt(int64(numPackages)))
+		if err != nil {
+			b.Error(err)
+		}
+		pkgName := fbc.Packages[r.Int64()].Name
+		bundleName := fmt.Sprintf("bundle-%d", i)
+		version := fmt.Sprintf("0.%d.0", i)
+		bundle := declcfg.Bundle{
+			Schema:  declcfg.SchemaBundle,
+			Package: pkgName,
+			Image:   fmt.Sprintf("bundles/%s", bundleName),
+			Properties: []property.Property{
+				property.MustBuildPackage(pkgName, version),
+				property.MustBuildGVK("apps", "Deployment", "v1"),
+				property.MustBuildGVK("apps", "DaemonSet", "v1"),
+				property.MustBuildGVKRequired("", "Service", "v1"),
+				property.MustBuildPackageRequired("foo", "0.0.1"),
+			},
+		}
+
+		csv := genCsv(pkgName, version)
+		bundle.Properties = append(bundle.Properties, property.MustBuildCSVMetadata(csv))
+		fbc.Bundles = append(fbc.Bundles, bundle)
+
+		p, err := rand.Int(rand.Reader, big.NewInt(int64(numChannels)))
+		if err != nil {
+			b.Error(err)
+		}
+		chIdx := p.Int64()
+		ch := fbc.Channels[chIdx]
+		replaces := ""
+		if len(ch.Entries) > 0 {
+			replaces = ch.Entries[len(ch.Entries)-1].Name
+		}
+		ch.Entries = append(ch.Entries, declcfg.ChannelEntry{
+			Name:     bundleName,
+			Replaces: replaces,
+		})
+		fbc.Channels[chIdx] = ch
+	}
+
+	return fbc
+}
+
+func genCsv(pkgName, ver string) v1alpha1.ClusterServiceVersion {
+	csv := v1alpha1.ClusterServiceVersion{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "ClusterServiceVersion",
+			APIVersion: "operators.coreos.com/v1alpha1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: fmt.Sprintf("%s.v%s", pkgName, ver),
+			Annotations: map[string]string{
+				"alm-examples": `[
+					{
+						"apiVersion": "example.com/v1alpha1",
+						"kind": "Example",
+						"metadata": {
+							"name": "example-sample"
+						},
+						"spec": {
+							"image":{
+								"repository":"example/example",
+								"tag":"v0.0.1",
+								"pullPolicy":"IfNotPresent",
+								"credentials":{}
+							},
+							"labels":{},
+							"conf":{
+								"log":{"enabled":false,"config":{}},
+								"logtostderr":"INFO",
+								"port":26257,
+								"http-port":8080,
+								"store":{"enabled":false,"type":null,"size":null,"attrs":null}},
+								"statefulset":{
+									"replicas":3,
+									"updateStrategy":{"type":"RollingUpdate"},
+									"podManagementPolicy":"Parallel",
+									"budget":{"maxUnavailable":1},
+									"args":[],
+									"env":[],
+									"secretMounts":[],
+									"labels":{"app.kubernetes.io/component":"example"},
+									"annotations":{},
+									"nodeAffinity":{},
+									"podAffinity":{},
+									"podAntiAffinity":{"topologyKey":"kubernetes.io/hostname","type":"soft","weight":100},
+									"nodeSelector":{},
+									"priorityClassName":"",
+									"tolerations":[],
+									"topologySpreadConstraints":{"maxSkew":1,"topologyKey":"topology.kubernetes.io/zone","whenUnsatisfiable":"ScheduleAnyway"},
+									"resources":{},
+									"customLivenessProbe":{},
+									"customReadinessProbe":{}
+								},
+								"ingress":{"enabled":false,"labels":{},"annotations":{},"paths":["/"],"hosts":[],"tls":[]},
+								"prometheus":{"enabled":true},
+								"serviceMonitor":{"enabled":false,"labels":{},"annotations":{},"interval":"10s","namespaced":false},
+								"storage":{"hostPath":"","persistentVolume":{"enabled":true,"size":"100Gi","storageClass":"","labels":{},"annotations":{}}}
+							}
+						}
+					}
+				]`,
+				"capabilities":                           "Basic Install",
+				"categories":                             "Application",
+				"certified":                              "false",
+				"containerImage":                         "quay.io/example/example:v0.0.1",
+				"createdAt":                              "1970-01-01T00-00-00Z",
+				"description":                            "Example Operator",
+				"operators.operatorframework.io/builder": "operator-sdk-v1.0.0",
+				"operators.operatorframework.io/project_layout": "go.sdk.operatorframework.io/v3",
+				"repository":    "https://github.com/example/example",
+				"support":       "Example, Inc.",
+				"olm.skipRange": "<0.0.1",
+			},
+		},
+		Spec: v1alpha1.ClusterServiceVersionSpec{
+			Icon: []v1alpha1.Icon{
+				{
+					Data:      randomPng,
+					MediaType: "image/png",
+				},
+			},
+			CustomResourceDefinitions: v1alpha1.CustomResourceDefinitions{
+				Owned: []v1alpha1.CRDDescription{
+					{
+						Description: "Represents an Example instance",
+						DisplayName: "Example",
+						Kind:        "Example",
+						Version:     "v1alpha1",
+						Name:        "examples.example.com",
+						Resources: []v1alpha1.APIResourceReference{
+							{
+								Kind:    "Deployment",
+								Version: "apps/v1",
+							},
+							{
+								Kind:    "Service",
+								Version: "v1",
+							},
+							{
+								Kind:    "ReplicaSet",
+								Version: "apps/v1",
+							},
+							{
+								Kind:    "Pod",
+								Version: "v1",
+							},
+							{
+								Kind:    "Secret",
+								Version: "v1",
+							},
+							{
+								Kind:    "ConfigMap",
+								Version: "v1",
+							},
+							{
+								Kind:    "PresistentVolumeClaim",
+								Version: "v1",
+							},
+							{
+								Kind:    "StatefulSet",
+								Version: "apps/v1",
+							},
+							{
+								Kind:    "Job",
+								Version: "batch/v1",
+							},
+						},
+					},
+				},
+			},
+			DisplayName: "Example Operator",
+			InstallModes: []v1alpha1.InstallMode{
+				{
+					Type:      v1alpha1.InstallModeTypeOwnNamespace,
+					Supported: false,
+				},
+				{
+					Type:      v1alpha1.InstallModeTypeSingleNamespace,
+					Supported: false,
+				},
+				{
+					Type:      v1alpha1.InstallModeTypeMultiNamespace,
+					Supported: false,
+				},
+				{
+					Type:      v1alpha1.InstallModeTypeAllNamespaces,
+					Supported: true,
+				},
+			},
+			Keywords: []string{"example", "application", "sample", "foobar"},
+			Links: []v1alpha1.AppLink{
+				{
+					Name: "Example Operator",
+					URL:  "https://www.example.com/operator",
+				},
+				{
+					Name: "Example Operator Documentation",
+					URL:  "https://www.example.com/operator/docs",
+				},
+				{
+					Name: "Example Operator Support",
+					URL:  "https://www.example.com/operator/support",
+				},
+				{
+					Name: "Example Operator Source Code",
+					URL:  "https://github.com/example/operator",
+				},
+			},
+			Maintainers: []v1alpha1.Maintainer{
+				{
+					Email: "janedoe@example.com",
+					Name:  "Jane Doe",
+				},
+				{
+					Email: "johndoe@example.com",
+					Name:  "John Doe",
+				},
+			},
+			Maturity:       "alpha",
+			MinKubeVersion: "1.21.0",
+			Provider: v1alpha1.AppLink{
+				Name: "Example, Inc.",
+				URL:  "https://www.example.com",
+			},
+			Version: version.OperatorVersion{Version: semver.MustParse(ver)},
+		},
+	}
+	return csv
+}
diff --git a/alpha/declcfg/load_test.go b/alpha/declcfg/load_test.go
index 995861c78..392fbd795 100644
--- a/alpha/declcfg/load_test.go
+++ b/alpha/declcfg/load_test.go
@@ -1,19 +1,24 @@
 package declcfg
 
 import (
+	"context"
+	"encoding/base64"
 	"encoding/json"
+	"fmt"
 	"io/fs"
 	"os"
+	"sync"
 	"testing"
 	"testing/fstest"
 
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"k8s.io/apimachinery/pkg/util/yaml"
 
 	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
-func TestReadYAMLOrJSON(t *testing.T) {
+func TestLoadReader(t *testing.T) {
 	type spec struct {
 		name              string
 		fsys              fs.FS
@@ -79,7 +84,7 @@ func TestReadYAMLOrJSON(t *testing.T) {
 			f, err := s.fsys.Open(s.path)
 			require.NoError(t, err)
 
-			cfg, err := readYAMLOrJSON(f)
+			cfg, err := LoadReader(f)
 			s.assertion(t, err)
 			if err == nil {
 				require.NotNil(t, cfg)
@@ -91,6 +96,80 @@ func TestReadYAMLOrJSON(t *testing.T) {
 	}
 }
 
+func TestWalkMetasFS(t *testing.T) {
+	type spec struct {
+		name                  string
+		fsys                  fs.FS
+		assertion             require.ErrorAssertionFunc
+		expectNumPackages     int
+		expectNumChannels     int
+		expectNumBundles      int
+		expectNumDeprecations int
+		expectNumOthers       int
+	}
+	specs := []spec{
+		{
+			name:      "Error/NilFS",
+			fsys:      nil,
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/NonExistentDir",
+			fsys:      os.DirFS("non/existent/dir/"),
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/Invalid",
+			fsys:      invalidFS,
+			assertion: require.Error,
+		},
+		{
+			name:                  "Success/ValidDir",
+			fsys:                  validFS,
+			assertion:             require.NoError,
+			expectNumPackages:     3,
+			expectNumChannels:     0,
+			expectNumBundles:      12,
+			expectNumDeprecations: 1,
+			expectNumOthers:       1,
+		},
+	}
+
+	for _, s := range specs {
+		t.Run(s.name, func(t *testing.T) {
+			var mu sync.Mutex
+			numPackages, numChannels, numBundles, numDeprecations, numOthers := 0, 0, 0, 0, 0
+			err := WalkMetasFS(context.Background(), s.fsys, func(path string, meta *Meta, err error) error {
+				if err != nil {
+					return err
+				}
+				mu.Lock()
+				defer mu.Unlock()
+				switch meta.Schema {
+				case SchemaPackage:
+					numPackages++
+				case SchemaChannel:
+					numChannels++
+				case SchemaBundle:
+					numBundles++
+				case SchemaDeprecation:
+					numDeprecations++
+				default:
+					numOthers++
+				}
+				return nil
+			})
+			s.assertion(t, err)
+			if err == nil {
+				assert.Equal(t, s.expectNumPackages, numPackages, "unexpected package count")
+				assert.Equal(t, s.expectNumChannels, numChannels, "unexpected channel count")
+				assert.Equal(t, s.expectNumBundles, numBundles, "unexpected bundle count")
+				assert.Equal(t, s.expectNumOthers, numOthers, "unexpected others count")
+			}
+		})
+	}
+}
+
 func TestLoadFS(t *testing.T) {
 	type spec struct {
 		name      string
@@ -185,11 +264,11 @@ func TestLoadFS(t *testing.T) {
 							{Type: "olm.gvk", Value: json.RawMessage(`{"group":"etcd.database.coreos.com","kind":"EtcdCluster","version":"v1beta2"}`)},
 							{Type: "olm.channel", Value: json.RawMessage(`{"name":"alpha"}`)},
 							{Type: "olm.skipRange", Value: json.RawMessage(`"<0.6.1"`)},
-							{Type: "olm.bundle.object", Value: json.RawMessage(`{"ref":"etcdoperator.v0.6.1.clusterserviceversion.yaml"}`)},
+							{Type: "olm.bundle.object", Value: json.RawMessage(fmt.Sprintf(`{"data": %q}`, base64.StdEncoding.EncodeToString(etcdCSV.Data)))},
 						},
 						RelatedImages: []RelatedImage{{Name: "etcdv0.6.1", Image: "quay.io/coreos/etcd-operator@sha256:bd944a211eaf8f31da5e6d69e8541e7cada8f16a9f7a5a570b22478997819943"}},
-						Objects:       []string{string(etcdCSV.Data)},
-						CsvJSON:       string(etcdCSV.Data),
+						Objects:       []string{toJSON(t, etcdCSV.Data)},
+						CsvJSON:       toJSON(t, etcdCSV.Data),
 					},
 					{
 						Schema:  "olm.bundle",
@@ -261,6 +340,17 @@ func TestLoadFS(t *testing.T) {
 						Schema: "olm.bundle",
 					},
 				},
+				Deprecations: []Deprecation{
+					{
+						Schema:  SchemaDeprecation,
+						Package: "kiali",
+						Entries: []DeprecationEntry{
+							{Reference: PackageScopedReference{Schema: SchemaBundle, Name: "kiali-operator.v1.68.0"}, Message: "kiali-operator.v1.68.0 is deprecated. Uninstall and install kiali-operator.v1.72.0 for support.\n"},
+							{Reference: PackageScopedReference{Schema: SchemaPackage}, Message: "package kiali is end of life.  Please use 'kiali-new' package for support.\n"},
+							{Reference: PackageScopedReference{Schema: SchemaChannel, Name: "alpha"}, Message: "channel alpha is no longer supported.  Please switch to channel 'stable'.\n"},
+						},
+					},
+				},
 				Others: []Meta{
 					{Schema: "unexpected", Package: "", Blob: json.RawMessage(`{ "schema":  "unexpected" }`)},
 				},
@@ -270,7 +360,7 @@ func TestLoadFS(t *testing.T) {
 
 	for _, s := range specs {
 		t.Run(s.name, func(t *testing.T) {
-			cfg, err := LoadFS(s.fsys)
+			cfg, err := LoadFS(context.Background(), s.fsys)
 			s.assertion(t, err)
 			if err == nil {
 				require.NotNil(t, cfg)
@@ -280,6 +370,15 @@ func TestLoadFS(t *testing.T) {
 	}
 }
 
+func toJSON(t *testing.T, in []byte) string {
+	t.Helper()
+	out, err := yaml.ToJSON(in)
+	if err != nil {
+		t.Fatalf("failed converting testdata to JSON: %v", err)
+	}
+	return string(out)
+}
+
 var (
 	invalidBundle = &fstest.MapFile{
 		Data: []byte(`{"schema": "olm.bundle","relatedImages": {}}`),
@@ -430,7 +529,7 @@ var (
 }`),
 	}
 	etcd = &fstest.MapFile{
-		Data: []byte(`---
+		Data: []byte(fmt.Sprintf(`---
 schema: olm.package
 name: etcd
 defaultChannel: singlenamespace-alpha
@@ -461,7 +560,7 @@ properties:
     value: <0.6.1
   - type: olm.bundle.object
     value:
-      ref: etcdoperator.v0.6.1.clusterserviceversion.yaml
+      data: %q
 relatedImages:
   - image: quay.io/coreos/etcd-operator@sha256:bd944a211eaf8f31da5e6d69e8541e7cada8f16a9f7a5a570b22478997819943
     name: etcdv0.6.1
@@ -596,7 +695,7 @@ properties:
       replaces: etcdoperator.v0.9.2-clusterwide
 relatedImages:
   - image: quay.io/coreos/etcd-operator@sha256:66a37fd61a06a43969854ee6d3e21087a98b93838e284a6086b13917f96b0d9b
-    name: etcdv0.9.2`),
+    name: etcdv0.9.2`, base64.StdEncoding.EncodeToString(etcdCSV.Data))),
 	}
 	etcdCSV = &fstest.MapFile{
 		Data: []byte(`apiVersion: operators.coreos.com/v1alpha1
@@ -801,6 +900,26 @@ present in the .indexignore file.`),
 	unrecognizedSchema = &fstest.MapFile{
 		Data: []byte(`{"schema":"olm.package"}{"schema":"unexpected"}{"schema":"olm.bundle"}`),
 	}
+	deprecations = &fstest.MapFile{
+		Data: []byte(`---
+schema: olm.deprecations
+package: kiali
+entries:
+- reference:
+    schema: olm.bundle
+    name: kiali-operator.v1.68.0
+  message: |
+     kiali-operator.v1.68.0 is deprecated. Uninstall and install kiali-operator.v1.72.0 for support.
+- reference: 
+    schema: olm.package
+  message: |
+     package kiali is end of life.  Please use 'kiali-new' package for support.
+- reference:
+    schema: olm.channel
+    name: alpha
+  message: |
+       channel alpha is no longer supported.  Please switch to channel 'stable'.`),
+	}
 
 	validFS = fstest.MapFS{
 		".indexignore":     indexIgnore,
@@ -809,5 +928,105 @@ present in the .indexignore file.`),
 		"etcdoperator.v0.6.1.clusterserviceversion.yaml": etcdCSV,
 		"README.md":                readme,
 		"unrecognized-schema.json": unrecognizedSchema,
+		"deprecations.yaml":        deprecations,
 	}
 )
+
+type EvaluationFunc func(*testing.T, *DeclarativeConfig)
+
+func TestLoadFile(t *testing.T) {
+	type spec struct {
+		name      string
+		fsys      fs.FS
+		path      string
+		assertion require.ErrorAssertionFunc
+		expect    EvaluationFunc
+	}
+	specs := []spec{
+		{
+			name:      "Error/NonExistentDir",
+			fsys:      os.DirFS("non/existent/dir/"),
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/Invalid",
+			fsys:      invalidFS,
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/NotYAMLOrJSON",
+			fsys:      invalidFS,
+			path:      "invalid-format.txt",
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/NotJSONObject",
+			fsys:      invalidFS,
+			path:      "not-object.json",
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/NoSchema",
+			fsys:      invalidFS,
+			path:      "no-schema.yaml",
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/InvalidPackageJSON",
+			fsys:      invalidFS,
+			path:      "invalid-package.json",
+			assertion: require.Error,
+		},
+		{
+			name:      "Error/InvalidBundleJSON",
+			fsys:      invalidFS,
+			path:      "invalid-bundle.json",
+			assertion: require.Error,
+		},
+		{
+			name:      "Success/UnrecognizedSchema",
+			fsys:      validFS,
+			path:      "unrecognized-schema.json",
+			assertion: require.NoError,
+			expect: func(t *testing.T, d *DeclarativeConfig) {
+				require.Len(t, d.Packages, 1)
+				require.Len(t, d.Bundles, 1)
+				require.Len(t, d.Others, 1)
+			},
+		},
+		{
+			name:      "Success/ValidFile",
+			fsys:      validFS,
+			path:      "etcd.yaml",
+			assertion: require.NoError,
+			expect: func(t *testing.T, d *DeclarativeConfig) {
+				require.Len(t, d.Packages, 1)
+				require.Len(t, d.Bundles, 6)
+				require.Empty(t, d.Others)
+			},
+		},
+		{
+			name:      "Success/ValidFile/Deprecations",
+			fsys:      validFS,
+			path:      "deprecations.yaml",
+			assertion: require.NoError,
+			expect: func(t *testing.T, d *DeclarativeConfig) {
+				require.Empty(t, d.Packages)
+				require.Empty(t, d.Bundles)
+				require.Empty(t, d.Others)
+				require.Len(t, d.Deprecations, 1)
+			},
+		},
+	}
+
+	for _, s := range specs {
+		t.Run(s.name, func(t *testing.T) {
+			cfg, err := LoadFile(s.fsys, s.path)
+			s.assertion(t, err)
+			if err == nil {
+				require.NotNil(t, cfg)
+				s.expect(t, cfg)
+			}
+		})
+	}
+}
diff --git a/alpha/declcfg/model_to_declcfg.go b/alpha/declcfg/model_to_declcfg.go
index 9d6651e8b..fabb0d0d2 100644
--- a/alpha/declcfg/model_to_declcfg.go
+++ b/alpha/declcfg/model_to_declcfg.go
@@ -24,7 +24,7 @@ func ConvertFromModel(mpkgs model.Model) DeclarativeConfig {
 			defaultChannel = mpkg.DefaultChannel.Name
 		}
 		cfg.Packages = append(cfg.Packages, Package{
-			Schema:         schemaPackage,
+			Schema:         SchemaPackage,
 			Name:           mpkg.Name,
 			DefaultChannel: defaultChannel,
 			Icon:           i,
@@ -60,10 +60,14 @@ func traverseModelChannels(mpkg model.Package) ([]Channel, []Bundle) {
 	for _, ch := range mpkg.Channels {
 		// initialize channel
 		c := Channel{
-			Schema:  schemaChannel,
+			Schema:  SchemaChannel,
 			Name:    ch.Name,
 			Package: ch.Package.Name,
 			Entries: []ChannelEntry{},
+			// NOTICE: The field Properties of the type Channel is for internal use only.
+			//   DO NOT use it for any public-facing functionalities.
+			//   This API is in alpha stage and it is subject to change.
+			Properties: ch.Properties,
 		}
 
 		for _, chb := range ch.Bundles {
@@ -79,11 +83,11 @@ func traverseModelChannels(mpkg model.Package) ([]Channel, []Bundle) {
 			b, ok := bundleMap[chb.Name]
 			if !ok {
 				b = &Bundle{
-					Schema:        schemaBundle,
+					Schema:        SchemaBundle,
 					Name:          chb.Name,
 					Package:       chb.Package.Name,
 					Image:         chb.Image,
-					RelatedImages: modelRelatedImagesToRelatedImages(chb.RelatedImages),
+					RelatedImages: ModelRelatedImagesToRelatedImages(chb.RelatedImages),
 					CsvJSON:       chb.CsvJSON,
 					Objects:       chb.Objects,
 				}
@@ -99,6 +103,7 @@ func traverseModelChannels(mpkg model.Package) ([]Channel, []Bundle) {
 		channels = append(channels, c)
 	}
 
+	// nolint:prealloc
 	var bundles []Bundle
 	for _, b := range bundleMap {
 		b.Properties = property.Deduplicate(b.Properties)
@@ -115,7 +120,8 @@ func traverseModelChannels(mpkg model.Package) ([]Channel, []Bundle) {
 	return channels, bundles
 }
 
-func modelRelatedImagesToRelatedImages(relatedImages []model.RelatedImage) []RelatedImage {
+func ModelRelatedImagesToRelatedImages(relatedImages []model.RelatedImage) []RelatedImage {
+	// nolint:prealloc
 	var out []RelatedImage
 	for _, ri := range relatedImages {
 		out = append(out, RelatedImage{
diff --git a/alpha/declcfg/model_to_declcfg_test.go b/alpha/declcfg/model_to_declcfg_test.go
index a24a70661..07fe7d577 100644
--- a/alpha/declcfg/model_to_declcfg_test.go
+++ b/alpha/declcfg/model_to_declcfg_test.go
@@ -4,6 +4,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 
 	"github.com/operator-framework/operator-registry/alpha/model"
 )
@@ -19,14 +20,14 @@ func TestConvertFromModel(t *testing.T) {
 		{
 			name:      "Success",
 			m:         buildTestModel(),
-			expectCfg: buildValidDeclarativeConfig(false),
+			expectCfg: buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: false, IncludeDeprecations: false}),
 		},
 	}
 
 	for _, s := range specs {
 		t.Run(s.name, func(t *testing.T) {
 			s.m.Normalize()
-			assert.NoError(t, s.m.Validate())
+			require.NoError(t, s.m.Validate())
 			actual := ConvertFromModel(s.m)
 
 			removeJSONWhitespace(&s.expectCfg)
diff --git a/alpha/declcfg/write.go b/alpha/declcfg/write.go
index d03e1315f..293d9363b 100644
--- a/alpha/declcfg/write.go
+++ b/alpha/declcfg/write.go
@@ -3,13 +3,353 @@ package declcfg
 import (
 	"bytes"
 	"encoding/json"
+	"fmt"
 	"io"
+	"os"
+	"path/filepath"
 	"sort"
+	"strings"
 
+	"github.com/blang/semver/v4"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"sigs.k8s.io/yaml"
+
+	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
+type MermaidWriter struct {
+	MinEdgeName          string
+	SpecifiedPackageName string
+}
+
+type MermaidOption func(*MermaidWriter)
+
+func NewMermaidWriter(opts ...MermaidOption) *MermaidWriter {
+	const (
+		minEdgeName          = ""
+		specifiedPackageName = ""
+	)
+	m := &MermaidWriter{
+		MinEdgeName:          minEdgeName,
+		SpecifiedPackageName: specifiedPackageName,
+	}
+
+	for _, opt := range opts {
+		opt(m)
+	}
+	return m
+}
+
+func WithMinEdgeName(minEdgeName string) MermaidOption {
+	return func(o *MermaidWriter) {
+		o.MinEdgeName = minEdgeName
+	}
+}
+
+func WithSpecifiedPackageName(specifiedPackageName string) MermaidOption {
+	return func(o *MermaidWriter) {
+		o.SpecifiedPackageName = specifiedPackageName
+	}
+}
+
+// writes out the channel edges of the declarative config graph in a mermaid format capable of being pasted into
+// mermaid renderers like github, mermaid.live, etc.
+// output is sorted lexicographically by package name, and then by channel name
+// if provided, minEdgeName will be used as the lower bound for edges in the output graph
+//
+// Example output:
+// graph LR
+//
+//	  %% package "neuvector-certified-operator-rhmp"
+//	  subgraph "neuvector-certified-operator-rhmp"
+//	     %% channel "beta"
+//	     subgraph neuvector-certified-operator-rhmp-beta["beta"]
+//		      neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.8["neuvector-operator.v1.2.8"]
+//		      neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.9["neuvector-operator.v1.2.9"]
+//		      neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]
+//		      neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]-- replaces --> neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.8["neuvector-operator.v1.2.8"]
+//		      neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]-- skips --> neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.9["neuvector-operator.v1.2.9"]
+//	    end
+//	  end
+//
+// end
+func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer) error {
+	pkgs := map[string]*strings.Builder{}
+
+	sort.Slice(cfg.Channels, func(i, j int) bool {
+		return cfg.Channels[i].Name < cfg.Channels[j].Name
+	})
+
+	versionMap, err := getBundleVersions(&cfg)
+	if err != nil {
+		return err
+	}
+
+	// establish a 'floor' version, either specified by user or entirely open
+	minVersion := semver.Version{Major: 0, Minor: 0, Patch: 0}
+
+	if writer.MinEdgeName != "" {
+		if _, ok := versionMap[writer.MinEdgeName]; !ok {
+			return fmt.Errorf("unknown minimum edge name: %q", writer.MinEdgeName)
+		}
+		minVersion = versionMap[writer.MinEdgeName]
+	}
+
+	// build increasing-version-ordered bundle names, so we can meaningfully iterate over a range
+	orderedBundles := []string{}
+	for n := range versionMap {
+		orderedBundles = append(orderedBundles, n)
+	}
+	sort.Slice(orderedBundles, func(i, j int) bool {
+		return versionMap[orderedBundles[i]].LT(versionMap[orderedBundles[j]])
+	})
+
+	minEdgePackage := writer.getMinEdgePackage(&cfg)
+
+	depByPackage := sets.Set[string]{}
+	depByChannel := sets.Set[string]{}
+	depByBundle := sets.Set[string]{}
+
+	for _, d := range cfg.Deprecations {
+		for _, e := range d.Entries {
+			switch e.Reference.Schema {
+			case SchemaPackage:
+				depByPackage.Insert(d.Package)
+			case SchemaChannel:
+				depByChannel.Insert(e.Reference.Name)
+			case SchemaBundle:
+				depByBundle.Insert(e.Reference.Name)
+			}
+		}
+	}
+
+	var deprecatedPackage string
+	deprecatedChannels := []string{}
+
+	for _, c := range cfg.Channels {
+		filteredChannel := writer.filterChannel(&c, versionMap, minVersion, minEdgePackage)
+		// nolint:nestif
+		if filteredChannel != nil {
+			pkgBuilder, ok := pkgs[c.Package]
+			if !ok {
+				pkgBuilder = &strings.Builder{}
+				pkgs[c.Package] = pkgBuilder
+			}
+
+			channelID := fmt.Sprintf("%s-%s", filteredChannel.Package, filteredChannel.Name)
+			pkgBuilder.WriteString(fmt.Sprintf("    %%%% channel %q\n", filteredChannel.Name))
+			pkgBuilder.WriteString(fmt.Sprintf("    subgraph %s[%q]\n", channelID, filteredChannel.Name))
+
+			if depByPackage.Has(filteredChannel.Package) {
+				deprecatedPackage = filteredChannel.Package
+			}
+
+			if depByChannel.Has(filteredChannel.Name) {
+				deprecatedChannels = append(deprecatedChannels, channelID)
+			}
+
+			for _, ce := range filteredChannel.Entries {
+				if versionMap[ce.Name].GE(minVersion) {
+					bundleDeprecation := ""
+					if depByBundle.Has(ce.Name) {
+						bundleDeprecation = ":::deprecated"
+					}
+
+					entryID := fmt.Sprintf("%s-%s", channelID, ce.Name)
+					pkgBuilder.WriteString(fmt.Sprintf("      %s[%q]%s\n", entryID, ce.Name, bundleDeprecation))
+
+					if len(ce.Replaces) > 0 {
+						replacesID := fmt.Sprintf("%s-%s", channelID, ce.Replaces)
+						pkgBuilder.WriteString(fmt.Sprintf("      %s[%q]-- %s --> %s[%q]\n", replacesID, ce.Replaces, "replace", entryID, ce.Name))
+					}
+					if len(ce.Skips) > 0 {
+						for _, s := range ce.Skips {
+							skipsID := fmt.Sprintf("%s-%s", channelID, s)
+							pkgBuilder.WriteString(fmt.Sprintf("      %s[%q]-- %s --> %s[%q]\n", skipsID, s, "skip", entryID, ce.Name))
+						}
+					}
+					if len(ce.SkipRange) > 0 {
+						skipRange, err := semver.ParseRange(ce.SkipRange)
+						if err == nil {
+							for _, edgeName := range filteredChannel.Entries {
+								if skipRange(versionMap[edgeName.Name]) {
+									skipRangeID := fmt.Sprintf("%s-%s", channelID, edgeName.Name)
+									pkgBuilder.WriteString(fmt.Sprintf("      %s[%q]-- \"%s(%s)\" --> %s[%q]\n", skipRangeID, edgeName.Name, "skipRange", ce.SkipRange, entryID, ce.Name))
+								}
+							}
+						} else {
+							fmt.Fprintf(os.Stderr, "warning: ignoring invalid SkipRange for package/edge %q/%q: %v\n", c.Package, ce.Name, err)
+						}
+					}
+				}
+			}
+			pkgBuilder.WriteString("    end\n")
+		}
+	}
+
+	_, _ = out.Write([]byte("graph LR\n"))
+	_, _ = out.Write([]byte("  classDef deprecated fill:#E8960F\n"))
+	pkgNames := []string{}
+	for pname := range pkgs {
+		pkgNames = append(pkgNames, pname)
+	}
+	sort.Slice(pkgNames, func(i, j int) bool {
+		return pkgNames[i] < pkgNames[j]
+	})
+	for _, pkgName := range pkgNames {
+		_, _ = out.Write([]byte(fmt.Sprintf("  %%%% package %q\n", pkgName)))
+		_, _ = out.Write([]byte(fmt.Sprintf("  subgraph %q\n", pkgName)))
+		_, _ = out.Write([]byte(pkgs[pkgName].String()))
+		_, _ = out.Write([]byte("  end\n"))
+	}
+
+	if deprecatedPackage != "" {
+		_, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#989695\n", deprecatedPackage)))
+	}
+
+	if len(deprecatedChannels) > 0 {
+		for _, deprecatedChannel := range deprecatedChannels {
+			_, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#DCD0FF\n", deprecatedChannel)))
+		}
+	}
+
+	return nil
+}
+
+// filters the channel edges to include only those which are greater-than-or-equal to the edge named by startVersion
+// returns a nil channel if all edges are filtered out
+func (writer *MermaidWriter) filterChannel(c *Channel, versionMap map[string]semver.Version, minVersion semver.Version, minEdgePackage string) *Channel {
+	// short-circuit if no active filters
+	if writer.MinEdgeName == "" && writer.SpecifiedPackageName == "" {
+		return c
+	}
+
+	// short-circuit if channel's package doesn't match filter
+	if writer.SpecifiedPackageName != "" && c.Package != writer.SpecifiedPackageName {
+		return nil
+	}
+
+	// short-circuit if channel package is mismatch from filter
+	if minEdgePackage != "" && c.Package != minEdgePackage {
+		return nil
+	}
+
+	out := &Channel{Name: c.Name, Package: c.Package, Properties: c.Properties, Entries: []ChannelEntry{}}
+	for _, ce := range c.Entries {
+		filteredCe := ChannelEntry{Name: ce.Name}
+		// nolint:nestif
+		if writer.MinEdgeName == "" {
+			// no minimum-edge specified
+			filteredCe.SkipRange = ce.SkipRange
+			filteredCe.Replaces = ce.Replaces
+			filteredCe.Skips = append(filteredCe.Skips, ce.Skips...)
+
+			// accumulate IFF there are any relevant skips/skipRange/replaces remaining or there never were any to begin with
+			// for the case where all skip/skipRange/replaces are retained, this is effectively the original edge with validated linkages
+			if len(filteredCe.Replaces) > 0 || len(filteredCe.Skips) > 0 || len(filteredCe.SkipRange) > 0 {
+				out.Entries = append(out.Entries, filteredCe)
+			} else {
+				if len(ce.Replaces) == 0 && len(ce.SkipRange) == 0 && len(ce.Skips) == 0 {
+					out.Entries = append(out.Entries, filteredCe)
+				}
+			}
+		} else {
+			if ce.Name == writer.MinEdgeName {
+				// edge is the 'floor', meaning that since all references are "backward references", and we don't want any references from this edge
+				// accumulate w/o references
+				out.Entries = append(out.Entries, filteredCe)
+			} else {
+				// edge needs to be filtered to determine if it is below the floor (bad) or on/above (good)
+				if len(ce.Replaces) > 0 && versionMap[ce.Replaces].GTE(minVersion) {
+					filteredCe.Replaces = ce.Replaces
+				}
+				if len(ce.Skips) > 0 {
+					filteredSkips := []string{}
+					for _, s := range ce.Skips {
+						if versionMap[s].GTE(minVersion) {
+							filteredSkips = append(filteredSkips, s)
+						}
+					}
+					if len(filteredSkips) > 0 {
+						filteredCe.Skips = filteredSkips
+					}
+				}
+				if len(ce.SkipRange) > 0 {
+					skipRange, err := semver.ParseRange(ce.SkipRange)
+					// if skipRange can't be parsed, just don't filter based on it
+					if err == nil && skipRange(minVersion) {
+						// specified range includes our floor
+						filteredCe.SkipRange = ce.SkipRange
+					}
+				}
+				// accumulate IFF there are any relevant skips/skipRange/replaces remaining, or there never were any to begin with (NOP)
+				// but the edge name satisfies the minimum-edge constraint
+				// for the case where all skip/skipRange/replaces are retained, this is effectively `ce` but with validated linkages
+				if len(filteredCe.Replaces) > 0 || len(filteredCe.Skips) > 0 || len(filteredCe.SkipRange) > 0 {
+					out.Entries = append(out.Entries, filteredCe)
+				} else {
+					if len(ce.Replaces) == 0 && len(ce.SkipRange) == 0 && len(ce.Skips) == 0 && versionMap[filteredCe.Name].GTE(minVersion) {
+						out.Entries = append(out.Entries, filteredCe)
+					}
+				}
+			}
+		}
+	}
+
+	if len(out.Entries) > 0 {
+		return out
+	} else {
+		return nil
+	}
+}
+
+func parseVersionProperty(b *Bundle) (*semver.Version, error) {
+	props, err := property.Parse(b.Properties)
+	if err != nil {
+		return nil, fmt.Errorf("parse properties for bundle %q: %v", b.Name, err)
+	}
+	if len(props.Packages) != 1 {
+		return nil, fmt.Errorf("bundle %q has multiple %q properties, expected exactly 1", b.Name, property.TypePackage)
+	}
+	v, err := semver.Parse(props.Packages[0].Version)
+	if err != nil {
+		return nil, fmt.Errorf("bundle %q has invalid version %q: %v", b.Name, props.Packages[0].Version, err)
+	}
+
+	return &v, nil
+}
+
+func getBundleVersions(cfg *DeclarativeConfig) (map[string]semver.Version, error) {
+	entries := make(map[string]semver.Version)
+	for index := range cfg.Bundles {
+		if _, ok := entries[cfg.Bundles[index].Name]; !ok {
+			ver, err := parseVersionProperty(&cfg.Bundles[index])
+			if err != nil {
+				return entries, err
+			}
+			entries[cfg.Bundles[index].Name] = *ver
+		}
+	}
+
+	return entries, nil
+}
+
+func (writer *MermaidWriter) getMinEdgePackage(cfg *DeclarativeConfig) string {
+	if writer.MinEdgeName == "" {
+		return ""
+	}
+
+	for _, c := range cfg.Channels {
+		for _, ce := range c.Entries {
+			if writer.MinEdgeName == ce.Name {
+				return c.Package
+			}
+		}
+	}
+
+	return ""
+}
+
 func WriteJSON(cfg DeclarativeConfig, w io.Writer) error {
 	enc := json.NewEncoder(w)
 	enc.SetIndent("", "    ")
@@ -83,6 +423,12 @@ func writeToEncoder(cfg DeclarativeConfig, enc encoder) error {
 		pkgNames.Insert(pkgName)
 		othersByPackage[pkgName] = append(othersByPackage[pkgName], o)
 	}
+	deprecationsByPackage := map[string][]Deprecation{}
+	for _, d := range cfg.Deprecations {
+		pkgName := d.Package
+		pkgNames.Insert(pkgName)
+		deprecationsByPackage[pkgName] = append(deprecationsByPackage[pkgName], d)
+	}
 
 	for _, pName := range pkgNames.List() {
 		if len(pName) == 0 {
@@ -124,6 +470,23 @@ func writeToEncoder(cfg DeclarativeConfig, enc encoder) error {
 				return err
 			}
 		}
+
+		//
+		// Normally we would order the deprecations, but it really doesn't make sense since
+		// - there will be 0 or 1 of them for any given package
+		// - they have no other useful field for ordering
+		//
+		// validation is typically via conversion to a model.Model and invoking model.Package.Validate()
+		// It's possible that a user of the object could create a slice containing more then 1
+		// Deprecation object for a package, and it would bypass validation if this
+		// function gets called without conversion.
+		//
+		deprecations := deprecationsByPackage[pName]
+		for _, d := range deprecations {
+			if err := enc.Encode(d); err != nil {
+				return err
+			}
+		}
 	}
 
 	for _, o := range othersByPackage[""] {
@@ -131,5 +494,51 @@ func writeToEncoder(cfg DeclarativeConfig, enc encoder) error {
 			return err
 		}
 	}
+
+	return nil
+}
+
+type WriteFunc func(config DeclarativeConfig, w io.Writer) error
+
+func WriteFS(cfg DeclarativeConfig, rootDir string, writeFunc WriteFunc, fileExt string) error {
+	channelsByPackage := map[string][]Channel{}
+	for _, c := range cfg.Channels {
+		channelsByPackage[c.Package] = append(channelsByPackage[c.Package], c)
+	}
+	bundlesByPackage := map[string][]Bundle{}
+	for _, b := range cfg.Bundles {
+		bundlesByPackage[b.Package] = append(bundlesByPackage[b.Package], b)
+	}
+
+	if err := os.MkdirAll(rootDir, 0777); err != nil {
+		return err
+	}
+
+	for _, p := range cfg.Packages {
+		fcfg := DeclarativeConfig{
+			Packages: []Package{p},
+			Channels: channelsByPackage[p.Name],
+			Bundles:  bundlesByPackage[p.Name],
+		}
+		pkgDir := filepath.Join(rootDir, p.Name)
+		if err := os.MkdirAll(pkgDir, 0777); err != nil {
+			return err
+		}
+		filename := filepath.Join(pkgDir, fmt.Sprintf("catalog%s", fileExt))
+		if err := writeFile(fcfg, filename, writeFunc); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func writeFile(cfg DeclarativeConfig, filename string, writeFunc WriteFunc) error {
+	buf := &bytes.Buffer{}
+	if err := writeFunc(cfg, buf); err != nil {
+		return fmt.Errorf("write to buffer for %q: %v", filename, err)
+	}
+	if err := os.WriteFile(filename, buf.Bytes(), 0600); err != nil {
+		return fmt.Errorf("write file %q: %v", filename, err)
+	}
 	return nil
 }
diff --git a/alpha/declcfg/write_test.go b/alpha/declcfg/write_test.go
index d8c909d8f..eca428768 100644
--- a/alpha/declcfg/write_test.go
+++ b/alpha/declcfg/write_test.go
@@ -17,7 +17,7 @@ func TestWriteJSON(t *testing.T) {
 	specs := []spec{
 		{
 			name: "Success",
-			cfg:  buildValidDeclarativeConfig(true),
+			cfg:  buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}),
 			expected: `{
     "schema": "olm.package",
     "name": "anakin",
@@ -78,7 +78,7 @@ func TestWriteJSON(t *testing.T) {
         {
             "type": "olm.bundle.object",
             "value": {
-                "ref": "objects/anakin.v0.0.1.csv.yaml"
+                "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMC4xIn19"
             }
         },
         {
@@ -111,7 +111,7 @@ func TestWriteJSON(t *testing.T) {
         {
             "type": "olm.bundle.object",
             "value": {
-                "ref": "objects/anakin.v0.1.0.csv.yaml"
+                "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4wIn19"
             }
         },
         {
@@ -144,7 +144,7 @@ func TestWriteJSON(t *testing.T) {
         {
             "type": "olm.bundle.object",
             "value": {
-                "ref": "objects/anakin.v0.1.1.csv.yaml"
+                "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4xIn19"
             }
         },
         {
@@ -167,6 +167,32 @@ func TestWriteJSON(t *testing.T) {
     "package": "anakin",
     "schema": "custom.3"
 }
+{
+    "schema": "olm.deprecations",
+    "package": "anakin",
+    "entries": [
+        {
+            "reference": {
+                "schema": "olm.bundle",
+                "name": "anakin.v0.0.1"
+            },
+            "message": "This bundle version is deprecated"
+        },
+        {
+            "reference": {
+                "schema": "olm.channel",
+                "name": "light"
+            },
+            "message": "This channel is deprecated"
+        },
+        {
+            "reference": {
+                "schema": "olm.package"
+            },
+            "message": "This package is deprecated... there is another"
+        }
+    ]
+}
 {
     "schema": "olm.package",
     "name": "boba-fett",
@@ -206,7 +232,7 @@ func TestWriteJSON(t *testing.T) {
         {
             "type": "olm.bundle.object",
             "value": {
-                "ref": "objects/boba-fett.v1.0.0.csv.yaml"
+                "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjEuMC4wIn19"
             }
         },
         {
@@ -239,7 +265,7 @@ func TestWriteJSON(t *testing.T) {
         {
             "type": "olm.bundle.object",
             "value": {
-                "ref": "objects/boba-fett.v2.0.0.csv.yaml"
+                "data": "eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjIuMC4wIn19"
             }
         },
         {
@@ -290,7 +316,7 @@ func TestWriteYAML(t *testing.T) {
 	specs := []spec{
 		{
 			name: "Success",
-			cfg:  buildValidDeclarativeConfig(true),
+			cfg:  buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}),
 			expected: `---
 defaultChannel: dark
 description: anakin operator
@@ -329,7 +355,7 @@ properties:
     data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=
 - type: olm.bundle.object
   value:
-    ref: objects/anakin.v0.0.1.csv.yaml
+    data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMC4xIn19
 - type: olm.package
   value:
     packageName: anakin
@@ -348,7 +374,7 @@ properties:
     data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=
 - type: olm.bundle.object
   value:
-    ref: objects/anakin.v0.1.0.csv.yaml
+    data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4wIn19
 - type: olm.package
   value:
     packageName: anakin
@@ -367,7 +393,7 @@ properties:
     data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=
 - type: olm.bundle.object
   value:
-    ref: objects/anakin.v0.1.1.csv.yaml
+    data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJhbmFraW4udjAuMS4xIn19
 - type: olm.package
   value:
     packageName: anakin
@@ -381,6 +407,21 @@ myField: foobar
 package: anakin
 schema: custom.3
 ---
+entries:
+- message: This bundle version is deprecated
+  reference:
+    name: anakin.v0.0.1
+    schema: olm.bundle
+- message: This channel is deprecated
+  reference:
+    name: light
+    schema: olm.channel
+- message: This package is deprecated... there is another
+  reference:
+    schema: olm.package
+package: anakin
+schema: olm.deprecations
+---
 defaultChannel: mando
 description: boba-fett operator
 icon:
@@ -406,7 +447,7 @@ properties:
     data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=
 - type: olm.bundle.object
   value:
-    ref: objects/boba-fett.v1.0.0.csv.yaml
+    data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjEuMC4wIn19
 - type: olm.package
   value:
     packageName: boba-fett
@@ -425,7 +466,7 @@ properties:
     data: eyJraW5kIjogIkN1c3RvbVJlc291cmNlRGVmaW5pdGlvbiIsICJhcGlWZXJzaW9uIjogImFwaWV4dGVuc2lvbnMuazhzLmlvL3YxIn0=
 - type: olm.bundle.object
   value:
-    ref: objects/boba-fett.v2.0.0.csv.yaml
+    data: eyJraW5kIjogIkNsdXN0ZXJTZXJ2aWNlVmVyc2lvbiIsICJhcGlWZXJzaW9uIjogIm9wZXJhdG9ycy5jb3Jlb3MuY29tL3YxYWxwaGExIiwgIm1ldGFkYXRhIjp7Im5hbWUiOiJib2JhLWZldHQudjIuMC4wIn19
 - type: olm.package
   value:
     packageName: boba-fett
@@ -459,13 +500,114 @@ func removeJSONWhitespace(cfg *DeclarativeConfig) {
 	for ib := range cfg.Bundles {
 		for ip := range cfg.Bundles[ib].Properties {
 			var buf bytes.Buffer
-			json.Compact(&buf, cfg.Bundles[ib].Properties[ip].Value)
+			_ = json.Compact(&buf, cfg.Bundles[ib].Properties[ip].Value)
 			cfg.Bundles[ib].Properties[ip].Value = buf.Bytes()
 		}
 	}
 	for io := range cfg.Others {
 		var buf bytes.Buffer
-		json.Compact(&buf, cfg.Others[io].Blob)
+		_ = json.Compact(&buf, cfg.Others[io].Blob)
 		cfg.Others[io].Blob = buf.Bytes()
 	}
 }
+
+func TestWriteMermaidChannels(t *testing.T) {
+	type spec struct {
+		name          string
+		cfg           DeclarativeConfig
+		startEdge     string
+		packageFilter string
+		expected      string
+	}
+	specs := []spec{
+		{
+			name:          "SuccessNoFilters",
+			cfg:           buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}),
+			startEdge:     "",
+			packageFilter: "",
+			expected: `graph LR
+  classDef deprecated fill:#E8960F
+  %% package "anakin"
+  subgraph "anakin"
+    %% channel "dark"
+    subgraph anakin-dark["dark"]
+      anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated
+      anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
+      anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
+      anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
+      anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
+      anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
+    end
+    %% channel "light"
+    subgraph anakin-light["light"]
+      anakin-light-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated
+      anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
+      anakin-light-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
+    end
+  end
+  %% package "boba-fett"
+  subgraph "boba-fett"
+    %% channel "mando"
+    subgraph boba-fett-mando["mando"]
+      boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
+      boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
+      boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
+    end
+  end
+style anakin fill:#989695
+style anakin-light fill:#DCD0FF
+`,
+		},
+		{
+			name:          "SuccessMinEdgeFilter",
+			cfg:           buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}),
+			startEdge:     "anakin.v0.1.0",
+			packageFilter: "",
+			expected: `graph LR
+  classDef deprecated fill:#E8960F
+  %% package "anakin"
+  subgraph "anakin"
+    %% channel "dark"
+    subgraph anakin-dark["dark"]
+      anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
+      anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
+      anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
+    end
+    %% channel "light"
+    subgraph anakin-light["light"]
+      anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
+    end
+  end
+style anakin fill:#989695
+style anakin-light fill:#DCD0FF
+`,
+		},
+		{
+			name:          "SuccessPackageNameFilter",
+			cfg:           buildValidDeclarativeConfig(validDeclarativeConfigSpec{IncludeUnrecognized: true, IncludeDeprecations: true}),
+			startEdge:     "",
+			packageFilter: "boba-fett",
+			expected: `graph LR
+  classDef deprecated fill:#E8960F
+  %% package "boba-fett"
+  subgraph "boba-fett"
+    %% channel "mando"
+    subgraph boba-fett-mando["mando"]
+      boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
+      boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
+      boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
+    end
+  end
+`,
+		},
+	}
+	for _, s := range specs {
+		t.Run(s.name, func(t *testing.T) {
+			var buf bytes.Buffer
+			writer := NewMermaidWriter(WithMinEdgeName(s.startEdge), WithSpecifiedPackageName(s.packageFilter))
+			err := writer.WriteChannels(s.cfg, &buf)
+			require.NoError(t, err)
+			require.Equal(t, s.expected, buf.String())
+		})
+	}
+}
diff --git a/alpha/model/error.go b/alpha/model/error.go
index 0ad0f7adb..e99cb2ca8 100644
--- a/alpha/model/error.go
+++ b/alpha/model/error.go
@@ -2,6 +2,7 @@ package model
 
 import (
 	"bytes"
+	"errors"
 	"fmt"
 	"strings"
 )
@@ -31,7 +32,7 @@ func (v *validationError) Error() string {
 
 func (v *validationError) errorPrefix(prefix []rune, last bool, seen []error) string {
 	for _, s := range seen {
-		if v == s {
+		if errors.Is(v, s) {
 			return ""
 		}
 	}
@@ -56,7 +57,9 @@ func (v *validationError) errorPrefix(prefix []rune, last bool, seen []error) st
 		} else {
 			subPrefix = append(subPrefix, []rune("├── ")...)
 		}
-		if verr, ok := serr.(*validationError); ok {
+
+		var verr *validationError
+		if errors.As(serr, &verr) {
 			errMsg.WriteString(verr.errorPrefix(subPrefix, subLast, seen))
 		} else {
 			errMsg.WriteString(fmt.Sprintf("%s%s\n", string(subPrefix), serr))
diff --git a/alpha/model/model.go b/alpha/model/model.go
index 75042469a..9b4e3ae85 100644
--- a/alpha/model/model.go
+++ b/alpha/model/model.go
@@ -11,11 +11,16 @@ import (
 	"github.com/h2non/filetype/matchers"
 	"github.com/h2non/filetype/types"
 	svg "github.com/h2non/go-is-svg"
+	"golang.org/x/exp/maps"
 	"k8s.io/apimachinery/pkg/util/sets"
 
 	"github.com/operator-framework/operator-registry/alpha/property"
 )
 
+type Deprecation struct {
+	Message string `json:"message"`
+}
+
 func init() {
 	t := types.NewType("svg", "image/svg+xml")
 	filetype.AddMatcher(t, svg.Is)
@@ -44,6 +49,7 @@ type Package struct {
 	Icon           *Icon
 	DefaultChannel *Channel
 	Channels       map[string]*Channel
+	Deprecation    *Deprecation
 }
 
 func (m *Package) Validate() error {
@@ -81,15 +87,54 @@ func (m *Package) Validate() error {
 		}
 	}
 
+	if err := m.validateUniqueBundleVersions(); err != nil {
+		result.subErrors = append(result.subErrors, err)
+	}
+
 	if m.DefaultChannel != nil && !foundDefault {
 		result.subErrors = append(result.subErrors, fmt.Errorf("default channel %q not found in channels list", m.DefaultChannel.Name))
 	}
+
+	if err := m.Deprecation.Validate(); err != nil {
+		result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err))
+	}
+
 	return result.orNil()
 }
 
+func (m *Package) validateUniqueBundleVersions() error {
+	versionsMap := map[string]semver.Version{}
+	bundlesWithVersion := map[string]sets.Set[string]{}
+	for _, ch := range m.Channels {
+		for _, b := range ch.Bundles {
+			versionsMap[b.Version.String()] = b.Version
+			if bundlesWithVersion[b.Version.String()] == nil {
+				bundlesWithVersion[b.Version.String()] = sets.New[string]()
+			}
+			bundlesWithVersion[b.Version.String()].Insert(b.Name)
+		}
+	}
+
+	versionsSlice := maps.Values(versionsMap)
+	semver.Sort(versionsSlice)
+
+	var errs []error
+	for _, v := range versionsSlice {
+		bundles := sets.List(bundlesWithVersion[v.String()])
+		if len(bundles) > 1 {
+			errs = append(errs, fmt.Errorf("{%s: [%s]}", v, strings.Join(bundles, ", ")))
+		}
+	}
+
+	if len(errs) > 0 {
+		return fmt.Errorf("duplicate versions found in bundles: %v", errs)
+	}
+	return nil
+}
+
 type Icon struct {
-	Data      []byte
-	MediaType string
+	Data      []byte `json:"base64data"`
+	MediaType string `json:"mediatype"`
 }
 
 func (i *Icon) Validate() error {
@@ -116,6 +161,7 @@ func (i *Icon) Validate() error {
 	return result.orNil()
 }
 
+// nolint:unused
 func (i *Icon) validateData() error {
 	if !filetype.IsImage(i.Data) {
 		return errors.New("icon data is not an image")
@@ -131,14 +177,20 @@ func (i *Icon) validateData() error {
 }
 
 type Channel struct {
-	Package *Package
-	Name    string
-	Bundles map[string]*Bundle
+	Package     *Package
+	Name        string
+	Bundles     map[string]*Bundle
+	Deprecation *Deprecation
+	// NOTICE: The field Properties of the type Channel is for internal use only.
+	//   DO NOT use it for any public-facing functionalities.
+	//   This API is in alpha stage and it is subject to change.
+	Properties []property.Property
 }
 
 // TODO(joelanford): This function determines the channel head by finding the bundle that has 0
-//   incoming edges, based on replaces and skips. It also expects to find exactly one such bundle.
-//   Is this the correct algorithm?
+//
+//	incoming edges, based on replaces and skips. It also expects to find exactly one such bundle.
+//	Is this the correct algorithm?
 func (c Channel) Head() (*Bundle, error) {
 	incoming := map[string]int{}
 	for _, b := range c.Bundles {
@@ -201,16 +253,21 @@ func (c *Channel) Validate() error {
 			result.subErrors = append(result.subErrors, fmt.Errorf("bundle %q not correctly linked to parent channel", b.Name))
 		}
 	}
+
+	if err := c.Deprecation.Validate(); err != nil {
+		result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err))
+	}
+
 	return result.orNil()
 }
 
 // validateReplacesChain checks the replaces chain of a channel.
 // Specifically the following rules must be followed:
-// 1. There must be exactly 1 channel head.
-// 2. Beginning at the head, the replaces chain must reach all non-skipped entries.
-//    Non-skipped entries are defined as entries that are not skipped by any other entry in the channel.
-// 3. There must be no cycles in the replaces chain.
-// 4. The tail entry in the replaces chain is permitted to replace a non-existent entry.
+//  1. There must be exactly 1 channel head.
+//  2. Beginning at the head, the replaces chain must reach all non-skipped entries.
+//     Non-skipped entries are defined as entries that are not skipped by any other entry in the channel.
+//  3. There must be no cycles in the replaces chain.
+//  4. The tail entry in the replaces chain is permitted to replace a non-existent entry.
 func (c *Channel) validateReplacesChain() error {
 	head, err := c.Head()
 	if err != nil {
@@ -259,6 +316,7 @@ type Bundle struct {
 	SkipRange     string
 	Properties    []property.Property
 	RelatedImages []RelatedImage
+	Deprecation   *Deprecation
 
 	// These fields are present so that we can continue serving
 	// the GRPC API the way packageserver expects us to in a
@@ -313,6 +371,10 @@ func (b *Bundle) Validate() error {
 		result.subErrors = append(result.subErrors, errors.New("bundle image must be set"))
 	}
 
+	if err := b.Deprecation.Validate(); err != nil {
+		result.subErrors = append(result.subErrors, fmt.Errorf("invalid deprecation: %v", err))
+	}
+
 	return result.orNil()
 }
 
@@ -369,3 +431,13 @@ func (m Model) AddBundle(b Bundle) {
 		p.DefaultChannel = b.Channel
 	}
 }
+
+func (d *Deprecation) Validate() error {
+	if d == nil {
+		return nil
+	}
+	if d.Message == "" {
+		return errors.New("message must be set")
+	}
+	return nil
+}
diff --git a/alpha/model/model_test.go b/alpha/model/model_test.go
index c286dcdb4..11391b74c 100644
--- a/alpha/model/model_test.go
+++ b/alpha/model/model_test.go
@@ -3,8 +3,10 @@ package model
 import (
 	"encoding/base64"
 	"encoding/json"
+	"errors"
 	"testing"
 
+	"github.com/blang/semver/v4"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 
@@ -183,7 +185,8 @@ func hasError(expectedError string) require.ErrorAssertionFunc {
 			if err == nil {
 				continue
 			}
-			if verr, ok := err.(*validationError); ok {
+			var verr *validationError
+			if errors.As(err, &verr) {
 				if verr.message == expectedError {
 					return
 				}
@@ -258,6 +261,25 @@ func TestValidators(t *testing.T) {
 			},
 			assertion: hasError("package must contain at least one channel"),
 		},
+		{
+			name: "Package/Error/DuplicateBundleVersions",
+			v: &Package{
+				Name: "anakin",
+				Channels: map[string]*Channel{
+					"light": {
+						Package: pkg,
+						Name:    "light",
+						Bundles: map[string]*Bundle{
+							"anakin.v0.0.1": {Name: "anakin.v0.0.1", Version: semver.MustParse("0.0.1")},
+							"anakin.v0.0.2": {Name: "anakin.v0.0.2", Version: semver.MustParse("0.0.1")},
+							"anakin.v1.0.1": {Name: "anakin.v1.0.1", Version: semver.MustParse("1.0.1")},
+							"anakin.v1.0.2": {Name: "anakin.v1.0.2", Version: semver.MustParse("1.0.1")},
+						},
+					},
+				},
+			},
+			assertion: hasError(`duplicate versions found in bundles: [{0.0.1: [anakin.v0.0.1, anakin.v0.0.2]} {1.0.1: [anakin.v1.0.1, anakin.v1.0.2]}]`),
+		},
 		{
 			name: "Package/Error/NoDefaultChannel",
 			v: &Package{
@@ -478,7 +500,7 @@ func TestValidators(t *testing.T) {
 				Properties: []property.Property{
 					property.MustBuildPackage("anakin", "0.1.0"),
 					property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"),
-					property.MustBuildBundleObjectRef("path/to/data"),
+					property.MustBuildBundleObject([]byte("testdata")),
 				},
 				Objects: []string{"testdata"},
 				CsvJSON: "CSVjson",
@@ -612,6 +634,7 @@ func makePackageChannelBundle() (*Package, *Channel) {
 			property.MustBuildPackage("anakin", "0.0.1"),
 			property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"),
 		},
+		Version: semver.MustParse("0.0.1"),
 	}
 	bundle2 := &Bundle{
 		Name:     "anakin.v0.0.2",
@@ -621,6 +644,7 @@ func makePackageChannelBundle() (*Package, *Channel) {
 			property.MustBuildPackage("anakin", "0.0.2"),
 			property.MustBuildGVK("skywalker.me", "v1alpha1", "PodRacer"),
 		},
+		Version: semver.MustParse("0.0.2"),
 	}
 	ch := &Channel{
 		Name: "light",
diff --git a/alpha/property/property.go b/alpha/property/property.go
index c8bc6ad78..6fb792dda 100644
--- a/alpha/property/property.go
+++ b/alpha/property/property.go
@@ -5,10 +5,11 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/fs"
-	"io/ioutil"
-	"path/filepath"
 	"reflect"
+
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"github.com/operator-framework/api/pkg/operators/v1alpha1"
 )
 
 type Property struct {
@@ -39,6 +40,16 @@ type Package struct {
 	Version     string `json:"version"`
 }
 
+// NOTICE: The Channel properties are for internal use only.
+//
+//	DO NOT use it for any public-facing functionalities.
+//	This API is in alpha stage and it is subject to change.
+type Channel struct {
+	ChannelName string `json:"channelName"`
+	//Priority    string `json:"priority"`
+	Priority int `json:"priority"`
+}
+
 type PackageRequired struct {
 	PackageName  string `json:"packageName"`
 	VersionRange string `json:"versionRange"`
@@ -57,59 +68,24 @@ type GVKRequired struct {
 }
 
 type BundleObject struct {
-	File `json:",inline"`
-}
-
-type File struct {
-	ref  string
-	data []byte
-}
-
-type fileJSON struct {
-	Ref  string `json:"ref,omitempty"`
-	Data []byte `json:"data,omitempty"`
-}
-
-func (f *File) UnmarshalJSON(data []byte) error {
-	var t fileJSON
-	if err := json.Unmarshal(data, &t); err != nil {
-		return err
-	}
-	if len(t.Ref) > 0 && len(t.Data) > 0 {
-		return errors.New("fields 'ref' and 'data' are mutually exclusive")
-	}
-	f.ref = t.Ref
-	f.data = t.Data
-	return nil
-}
-
-func (f File) MarshalJSON() ([]byte, error) {
-	return json.Marshal(fileJSON{
-		Ref:  f.ref,
-		Data: f.data,
-	})
-}
-
-func (f File) IsRef() bool {
-	return len(f.ref) > 0
+	Data []byte `json:"data"`
 }
 
-func (f File) GetRef() string {
-	return f.ref
-}
-
-func (f File) GetData(root fs.FS, cwd string) ([]byte, error) {
-	if !f.IsRef() {
-		return f.data, nil
-	}
-	if filepath.IsAbs(f.ref) {
-		return nil, fmt.Errorf("reference must be a relative path")
-	}
-	file, err := root.Open(filepath.Join(cwd, f.ref))
-	if err != nil {
-		return nil, err
-	}
-	return ioutil.ReadAll(file)
+type CSVMetadata struct {
+	Annotations               map[string]string                  `json:"annotations,omitempty"`
+	APIServiceDefinitions     v1alpha1.APIServiceDefinitions     `json:"apiServiceDefinitions,omitempty"`
+	CustomResourceDefinitions v1alpha1.CustomResourceDefinitions `json:"crdDescriptions,omitempty"`
+	Description               string                             `json:"description,omitempty"`
+	DisplayName               string                             `json:"displayName,omitempty"`
+	InstallModes              []v1alpha1.InstallMode             `json:"installModes,omitempty"`
+	Keywords                  []string                           `json:"keywords,omitempty"`
+	Labels                    map[string]string                  `json:"labels,omitempty"`
+	Links                     []v1alpha1.AppLink                 `json:"links,omitempty"`
+	Maintainers               []v1alpha1.Maintainer              `json:"maintainers,omitempty"`
+	Maturity                  string                             `json:"maturity,omitempty"`
+	MinKubeVersion            string                             `json:"minKubeVersion,omitempty"`
+	NativeAPIs                []metav1.GroupVersionKind          `json:"nativeAPIs,omitempty"`
+	Provider                  v1alpha1.AppLink                   `json:"provider,omitempty"`
 }
 
 type Properties struct {
@@ -118,6 +94,8 @@ type Properties struct {
 	GVKs             []GVK             `hash:"set"`
 	GVKsRequired     []GVKRequired     `hash:"set"`
 	BundleObjects    []BundleObject    `hash:"set"`
+	Channels         []Channel         `hash:"set"`
+	CSVMetadatas     []CSVMetadata     `hash:"set"`
 
 	Others []Property `hash:"set"`
 }
@@ -128,6 +106,9 @@ const (
 	TypeGVK             = "olm.gvk"
 	TypeGVKRequired     = "olm.gvk.required"
 	TypeBundleObject    = "olm.bundle.object"
+	TypeCSVMetadata     = "olm.csv.metadata"
+	TypeConstraint      = "olm.constraint"
+	TypeChannel         = "olm.channel"
 )
 
 func Parse(in []Property) (*Properties, error) {
@@ -164,6 +145,21 @@ func Parse(in []Property) (*Properties, error) {
 				return nil, ParseError{Idx: i, Typ: prop.Type, Err: err}
 			}
 			out.BundleObjects = append(out.BundleObjects, p)
+		case TypeCSVMetadata:
+			var p CSVMetadata
+			if err := json.Unmarshal(prop.Value, &p); err != nil {
+				return nil, ParseError{Idx: i, Typ: prop.Type, Err: err}
+			}
+			out.CSVMetadatas = append(out.CSVMetadatas, p)
+		// NOTICE: The Channel properties are for internal use only.
+		//   DO NOT use it for any public-facing functionalities.
+		//   This API is in alpha stage and it is subject to change.
+		case TypeChannel:
+			var p Channel
+			if err := json.Unmarshal(prop.Value, &p); err != nil {
+				return nil, ParseError{Idx: i, Typ: prop.Type, Err: err}
+			}
+			out.Channels = append(out.Channels, p)
 		default:
 			var p json.RawMessage
 			if err := json.Unmarshal(prop.Value, &p); err != nil {
@@ -182,6 +178,7 @@ func Deduplicate(in []Property) []Property {
 	}
 
 	props := map[key]Property{}
+	// nolint:prealloc
 	var out []Property
 	for _, p := range in {
 		k := key{p.Type, string(p.Value)}
@@ -259,9 +256,33 @@ func MustBuildGVK(group, version, kind string) Property {
 func MustBuildGVKRequired(group, version, kind string) Property {
 	return MustBuild(&GVKRequired{group, kind, version})
 }
-func MustBuildBundleObjectRef(ref string) Property {
-	return MustBuild(&BundleObject{File: File{ref: ref}})
+func MustBuildBundleObject(data []byte) Property {
+	return MustBuild(&BundleObject{Data: data})
 }
-func MustBuildBundleObjectData(data []byte) Property {
-	return MustBuild(&BundleObject{File: File{data: data}})
+
+func MustBuildCSVMetadata(csv v1alpha1.ClusterServiceVersion) Property {
+	return MustBuild(&CSVMetadata{
+		Annotations:               csv.GetAnnotations(),
+		APIServiceDefinitions:     csv.Spec.APIServiceDefinitions,
+		CustomResourceDefinitions: csv.Spec.CustomResourceDefinitions,
+		Description:               csv.Spec.Description,
+		DisplayName:               csv.Spec.DisplayName,
+		InstallModes:              csv.Spec.InstallModes,
+		Keywords:                  csv.Spec.Keywords,
+		Labels:                    csv.GetLabels(),
+		Links:                     csv.Spec.Links,
+		Maintainers:               csv.Spec.Maintainers,
+		Maturity:                  csv.Spec.Maturity,
+		MinKubeVersion:            csv.Spec.MinKubeVersion,
+		NativeAPIs:                csv.Spec.NativeAPIs,
+		Provider:                  csv.Spec.Provider,
+	})
+}
+
+// NOTICE: The Channel properties are for internal use only.
+//
+//	DO NOT use it for any public-facing functionalities.
+//	This API is in alpha stage and it is subject to change.
+func MustBuildChannelPriority(name string, priority int) Property {
+	return MustBuild(&Channel{ChannelName: name, Priority: priority})
 }
diff --git a/alpha/property/property_test.go b/alpha/property/property_test.go
index 8c24f8016..171cec7a0 100644
--- a/alpha/property/property_test.go
+++ b/alpha/property/property_test.go
@@ -1,12 +1,7 @@
 package property
 
 import (
-	"encoding/base64"
 	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -70,160 +65,6 @@ func TestValidate(t *testing.T) {
 	}
 }
 
-func TestFile_MarshalJSON(t *testing.T) {
-	type spec struct {
-		name      string
-		file      File
-		json      string
-		assertion require.ErrorAssertionFunc
-	}
-	specs := []spec{
-		{
-			name:      "Success/Ref",
-			file:      File{ref: "foo"},
-			json:      `{"ref":"foo"}`,
-			assertion: require.NoError,
-		},
-		{
-			name:      "Success/Data",
-			file:      File{data: []byte("foo")},
-			json:      fmt.Sprintf(`{"data":%q}`, base64.StdEncoding.EncodeToString([]byte("foo"))),
-			assertion: require.NoError,
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			d, err := json.Marshal(s.file)
-			s.assertion(t, err)
-			assert.Equal(t, s.json, string(d))
-		})
-	}
-}
-
-func TestFile_UnmarshalJSON(t *testing.T) {
-	type spec struct {
-		name      string
-		file      File
-		json      string
-		assertion require.ErrorAssertionFunc
-	}
-	specs := []spec{
-		{
-			name:      "Success/Ref",
-			file:      File{ref: "foo"},
-			json:      `{"ref":"foo"}`,
-			assertion: require.NoError,
-		},
-		{
-			name:      "Success/Data",
-			file:      File{data: []byte("foo")},
-			json:      fmt.Sprintf(`{"data":%q}`, base64.StdEncoding.EncodeToString([]byte("foo"))),
-			assertion: require.NoError,
-		},
-		{
-			name:      "Error/RefAndData",
-			json:      fmt.Sprintf(`{"ref":"foo","data":%q}`, base64.StdEncoding.EncodeToString([]byte("bar"))),
-			assertion: require.Error,
-		},
-		{
-			name:      "Error/InvalidJSON",
-			json:      `["ref","data"]`,
-			assertion: require.Error,
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			var actual File
-			err := json.Unmarshal([]byte(s.json), &actual)
-			s.assertion(t, err)
-			assert.Equal(t, s.file, actual)
-		})
-	}
-}
-
-func TestFile_IsRef(t *testing.T) {
-	assert.True(t, File{ref: "foo"}.IsRef())
-	assert.False(t, File{data: []byte("bar")}.IsRef())
-}
-
-func TestFile_GetRef(t *testing.T) {
-	assert.Equal(t, "foo", File{ref: "foo"}.GetRef())
-	assert.Equal(t, "", File{data: []byte("bar")}.GetRef())
-}
-
-func TestFile_GetData(t *testing.T) {
-	type spec struct {
-		name       string
-		createFile func(root string) error
-		file       File
-		assertion  assert.ErrorAssertionFunc
-		expectData []byte
-	}
-
-	createFile := func(root string) error {
-		dir := filepath.Join(root, "tmp")
-		if err := os.MkdirAll(dir, 0777); err != nil {
-			return err
-		}
-		return ioutil.WriteFile(filepath.Join(dir, "foo.txt"), []byte("bar"), 0666)
-	}
-
-	specs := []spec{
-		{
-			name:       "Success/NilData",
-			file:       File{},
-			assertion:  assert.NoError,
-			expectData: nil,
-		},
-		{
-			name:       "Success/WithData",
-			file:       File{data: []byte("bar")},
-			assertion:  assert.NoError,
-			expectData: []byte("bar"),
-		},
-		{
-			name:       "Success/WithRef",
-			createFile: createFile,
-			file:       File{ref: "tmp/foo.txt"},
-			assertion:  assert.NoError,
-			expectData: []byte("bar"),
-		},
-		{
-			name:      "Error/WithRef/FileDoesNotExist",
-			file:      File{ref: "non-existent.txt"},
-			assertion: assert.Error,
-		},
-		{
-			name:      "Error/WithRef/RefIsAbsolutePath",
-			file:      File{ref: "/etc/hosts"},
-			assertion: assert.Error,
-		},
-		{
-			name:      "Error/WithRef/RefIsOutsideRoot",
-			file:      File{ref: "../etc/hosts"},
-			assertion: assert.Error,
-		},
-	}
-
-	for _, s := range specs {
-		t.Run(s.name, func(t *testing.T) {
-			dir, err := ioutil.TempDir("", "operator-registry-test-file-")
-			require.NoError(t, err)
-			defer os.RemoveAll(dir)
-
-			if s.createFile != nil {
-				require.NoError(t, s.createFile(dir))
-			}
-
-			data, err := s.file.GetData(os.DirFS(dir), ".")
-			s.assertion(t, err)
-			assert.Equal(t, s.expectData, data)
-		})
-	}
-}
-
 func TestParse(t *testing.T) {
 	type spec struct {
 		name        string
@@ -285,8 +126,7 @@ func TestParse(t *testing.T) {
 				MustBuildGVK("group", "v1", "Kind2"),
 				MustBuildGVKRequired("other", "v2", "Kind3"),
 				MustBuildGVKRequired("other", "v2", "Kind4"),
-				MustBuildBundleObjectRef("testref1"),
-				MustBuildBundleObjectData([]byte("testdata2")),
+				MustBuildBundleObject([]byte("testdata2")),
 				{Type: "otherType1", Value: json.RawMessage(`{"v":"otherValue1"}`)},
 				{Type: "otherType2", Value: json.RawMessage(`["otherValue2"]`)},
 			},
@@ -308,8 +148,7 @@ func TestParse(t *testing.T) {
 					{"other", "Kind4", "v2"},
 				},
 				BundleObjects: []BundleObject{
-					{File: File{ref: "testref1"}},
-					{File: File{data: []byte("testdata2")}},
+					{Data: []byte("testdata2")},
 				},
 				Others: []Property{
 					{Type: "otherType1", Value: json.RawMessage(`{"v":"otherValue1"}`)},
@@ -391,9 +230,9 @@ func TestBuild(t *testing.T) {
 		},
 		{
 			name:             "Success/BundleObject",
-			input:            &BundleObject{File: File{ref: "test"}},
+			input:            &BundleObject{Data: []byte("test")},
 			assertion:        require.NoError,
-			expectedProperty: propPtr(MustBuildBundleObjectRef("test")),
+			expectedProperty: propPtr(MustBuildBundleObject([]byte("test"))),
 		},
 		{
 			name:             "Success/Property",
diff --git a/alpha/property/scheme.go b/alpha/property/scheme.go
index b2d893660..ab176856f 100644
--- a/alpha/property/scheme.go
+++ b/alpha/property/scheme.go
@@ -12,6 +12,11 @@ func init() {
 		reflect.TypeOf(&GVK{}):             TypeGVK,
 		reflect.TypeOf(&GVKRequired{}):     TypeGVKRequired,
 		reflect.TypeOf(&BundleObject{}):    TypeBundleObject,
+		reflect.TypeOf(&CSVMetadata{}):     TypeCSVMetadata,
+		// NOTICE: The Channel properties are for internal use only.
+		//   DO NOT use it for any public-facing functionalities.
+		//   This API is in alpha stage and it is subject to change.
+		reflect.TypeOf(&Channel{}): TypeChannel,
 	}
 }
 
diff --git a/alpha/template/basic/basic.go b/alpha/template/basic/basic.go
new file mode 100644
index 000000000..a34d7541d
--- /dev/null
+++ b/alpha/template/basic/basic.go
@@ -0,0 +1,110 @@
+package basic
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+
+	"k8s.io/apimachinery/pkg/util/yaml"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+)
+
+const schema string = "olm.template.basic"
+
+type Template struct {
+	RenderBundle func(context.Context, string) (*declcfg.DeclarativeConfig, error)
+}
+
+type BasicTemplate struct {
+	Schema  string          `json:"schema"`
+	Entries []*declcfg.Meta `json:"entries"`
+}
+
+func parseSpec(reader io.Reader) (*BasicTemplate, error) {
+	bt := &BasicTemplate{}
+	btDoc := json.RawMessage{}
+	btDecoder := yaml.NewYAMLOrJSONDecoder(reader, 4096)
+	err := btDecoder.Decode(&btDoc)
+	if err != nil {
+		return nil, fmt.Errorf("decoding template schema: %v", err)
+	}
+	err = json.Unmarshal(btDoc, bt)
+	if err != nil {
+		return nil, fmt.Errorf("unmarshalling template: %v", err)
+	}
+
+	if bt.Schema != schema {
+		return nil, fmt.Errorf("template has unknown schema (%q), should be %q", bt.Schema, schema)
+	}
+
+	return bt, nil
+}
+
+func (t Template) Render(ctx context.Context, reader io.Reader) (*declcfg.DeclarativeConfig, error) {
+	bt, err := parseSpec(reader)
+	if err != nil {
+		return nil, err
+	}
+	cfg, err := declcfg.LoadSlice(bt.Entries)
+	if err != nil {
+		return cfg, err
+	}
+
+	outb := cfg.Bundles[:0]
+	for _, b := range cfg.Bundles {
+		if !isBundleTemplate(&b) {
+			return nil, fmt.Errorf("unexpected fields present in basic template bundle")
+		}
+		contributor, err := t.RenderBundle(ctx, b.Image)
+		if err != nil {
+			return nil, err
+		}
+		outb = append(outb, contributor.Bundles...)
+	}
+
+	cfg.Bundles = outb
+	return cfg, nil
+}
+
+// isBundleTemplate identifies a Bundle template source as having a Schema and Image defined
+// but no Properties, RelatedImages or Package defined
+func isBundleTemplate(b *declcfg.Bundle) bool {
+	return b.Schema != "" && b.Image != "" && b.Package == "" && len(b.Properties) == 0 && len(b.RelatedImages) == 0
+}
+
+// FromReader reads FBC from a reader and generates a BasicTemplate from it
+func FromReader(r io.Reader) (*BasicTemplate, error) {
+	var entries []*declcfg.Meta
+	if err := declcfg.WalkMetasReader(r, func(meta *declcfg.Meta, err error) error {
+		if err != nil {
+			return err
+		}
+		if meta.Schema == declcfg.SchemaBundle {
+			var b declcfg.Bundle
+			if err := json.Unmarshal(meta.Blob, &b); err != nil {
+				return fmt.Errorf("parse bundle: %v", err)
+			}
+			b2 := declcfg.Bundle{
+				Schema: b.Schema,
+				Image:  b.Image,
+			}
+			meta.Blob, err = json.Marshal(b2)
+			if err != nil {
+				return fmt.Errorf("re-serialize bundle: %v", err)
+			}
+		}
+		entries = append(entries, meta)
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+
+	bt := &BasicTemplate{
+		Schema:  schema,
+		Entries: entries,
+	}
+
+	return bt, nil
+}
diff --git a/alpha/template/converter/converter.go b/alpha/template/converter/converter.go
new file mode 100644
index 000000000..03e3e0a97
--- /dev/null
+++ b/alpha/template/converter/converter.go
@@ -0,0 +1,40 @@
+package converter
+
+import (
+	"encoding/json"
+	"fmt"
+	"io"
+	"os"
+
+	"sigs.k8s.io/yaml"
+
+	"github.com/operator-framework/operator-registry/alpha/template/basic"
+	"github.com/operator-framework/operator-registry/pkg/image"
+)
+
+type Converter struct {
+	FbcReader    io.Reader
+	OutputFormat string
+	Registry     image.Registry
+}
+
+func (c *Converter) Convert() error {
+	bt, err := basic.FromReader(c.FbcReader)
+	if err != nil {
+		return err
+	}
+
+	b, _ := json.MarshalIndent(bt, "", "    ")
+	if c.OutputFormat == "json" {
+		fmt.Fprintln(os.Stdout, string(b))
+	} else {
+		y, err := yaml.JSONToYAML(b)
+		if err != nil {
+			return err
+		}
+		y = append([]byte("---\n"), y...)
+		fmt.Fprintln(os.Stdout, string(y))
+	}
+
+	return nil
+}
diff --git a/alpha/template/semver/README.md b/alpha/template/semver/README.md
new file mode 100644
index 000000000..ace33746a
--- /dev/null
+++ b/alpha/template/semver/README.md
@@ -0,0 +1,286 @@
+## Semver Template:
+
+Since a `catalog template` is identified as an input schema which may be processed to generate a valid FBC, we can define a `semver template` as a schema which uses channel conventions to facilitate the auto-generation of channels along `semver` delimiters.  
+
+[**DISCLAIMER:** since version build metadata [MUST be ignored when determining version precedence](https://semver.org) when using semver, rendering the template will result in an error if two bundles differ only by the build metadata.]
+
+### Schema Goals
+The `semver template` must have:
+- terse grammar to minimize creation/maintenance effort
+- deterministic output
+- simple channel promotion for maturing bundles
+- demonstration of a common type of channel maturity model
+- minor-version (Y-stream), major-version (X-stream) versioning optionality
+
+The resulting FBC must clearly indicate how generated channels relate to template entities
+
+### Schema Anatomy
+For convenience and simplicity, this template currently supports hard-coded channel names `Candidate`, `Fast`, and `Stable`, in order of increasing channel stability.  We leverage this relationship to calculate the default channel for the package. 
+
+`GenerateMajorChannels` and `GenerateMinorChannels` dictate whether this template will generate X-stream or Y-stream channels (attributes can be set independently).  If omitted, only minor (Y-stream) channels will be generated.  
+
+Under each channel are a list of bundle image references which contribute to that channel.  
+
+With the following (hypothetical) example we define a mock bundle which has 11 versions, represented across each of the channel types:
+```yaml
+Schema: olm.semver
+GenerateMajorChannels: true
+GenerateMinorChannels: true
+Candidate:
+  Bundles:
+  - Image: quay.io/foo/olm:testoperator.v0.1.0
+  - Image: quay.io/foo/olm:testoperator.v0.1.1
+  - Image: quay.io/foo/olm:testoperator.v0.1.2
+  - Image: quay.io/foo/olm:testoperator.v0.1.3
+  - Image: quay.io/foo/olm:testoperator.v0.2.0
+  - Image: quay.io/foo/olm:testoperator.v0.2.1
+  - Image: quay.io/foo/olm:testoperator.v0.2.2
+  - Image: quay.io/foo/olm:testoperator.v0.3.0
+  - Image: quay.io/foo/olm:testoperator.v1.0.0
+  - Image: quay.io/foo/olm:testoperator.v1.0.1
+  - Image: quay.io/foo/olm:testoperator.v1.1.0
+Fast:
+  Bundles:
+  - Image: quay.io/foo/olm:testoperator.v0.2.1
+  - Image: quay.io/foo/olm:testoperator.v0.2.2
+  - Image: quay.io/foo/olm:testoperator.v0.3.0
+  - Image: quay.io/foo/olm:testoperator.v1.0.1
+  - Image: quay.io/foo/olm:testoperator.v1.1.0
+Stable:
+  Bundles:
+  - Image: quay.io/foo/olm:testoperator.v1.0.1
+```
+In this example, `Candidate` has the entire version range of bundles,  `Fast` has a mix of older and more-recent versions, and `Stable` channel only has a single published entry. 
+
+### CLI Tool Usage
+```
+% ./bin/opm alpha render-template semver -h
+Generate a file-based catalog from a single 'semver template' file
+When FILE is '-' or not provided, the template is read from standard input
+
+Usage:
+  opm alpha render-template semver [FILE] [flags]
+
+Flags:
+  -h, --help            help for semver
+  -o, --output string   Output format (json|yaml|mermaid) (default "json")
+
+Global Flags:
+      --skip-tls-verify   skip TLS certificate verification for container image registries while pulling bundles
+      --use-http          use plain HTTP for container image registries while pulling bundles
+```
+
+Example command usage:
+```
+# Example with file argument passed in
+opm alpha render-template semver infile.semver.template.yaml
+
+# Example with no file argument passed in
+opm alpha render-template semver -o yaml < infile.semver.template.yaml > outfile.yaml
+
+# Example with "-" as the file argument passed in
+cat infile.semver.template.yaml | opm alpha render-template semver -o mermaid -
+```
+Note that if the command is called without a file argument and nothing passed in on standard input,
+the command will hang indefinitely. Either a file argument or file information passed 
+in on standard input is required by the command.
+
+With the template attribute `GenerateMajorChannels: true` resulting major channels from the command are (filtering out `olm.bundle` content):
+```yaml
+---
+defaultChannel: stable-v1
+name: testoperator
+schema: olm.package
+---
+entries:
+  - name: testoperator.v0.1.0
+  - name: testoperator.v0.1.1
+  - name: testoperator.v0.1.2
+  - name: testoperator.v0.1.3
+    skips:
+      - testoperator.v0.1.0
+      - testoperator.v0.1.1
+      - testoperator.v0.1.2
+  - name: testoperator.v0.2.0
+  - name: testoperator.v0.2.1
+  - name: testoperator.v0.2.2
+    replaces: testoperator.v0.1.3
+    skips:
+      - testoperator.v0.1.0
+      - testoperator.v0.1.1
+      - testoperator.v0.1.2
+      - testoperator.v0.2.0
+      - testoperator.v0.2.1
+  - name: testoperator.v0.3.0
+    replaces: testoperator.v0.2.2
+    skips:
+      - testoperator.v0.1.0
+      - testoperator.v0.1.1
+      - testoperator.v0.1.2
+      - testoperator.v0.1.3
+      - testoperator.v0.2.0
+      - testoperator.v0.2.1
+name: candidate-v0
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.0.0
+  - name: testoperator.v1.0.1
+    skips:
+      - testoperator.v1.0.0
+  - name: testoperator.v1.1.0
+    replaces: testoperator.v1.0.1
+    skips:
+      - testoperator.v1.0.0
+name: candidate-v1
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v0.2.1
+  - name: testoperator.v0.2.2
+    skips:
+      - testoperator.v0.2.1
+  - name: testoperator.v0.3.0
+    replaces: testoperator.v0.2.2
+    skips:
+      - testoperator.v0.2.1
+name: fast-v0
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.0.1
+  - name: testoperator.v1.1.0
+    replaces: testoperator.v1.0.1
+name: fast-v1
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.0.1
+name: stable-v1
+package: testoperator
+schema: olm.channel
+```
+
+We generated a channel for each template channel entity corresponding to each of the 0.\#.\#, 1.\#.\# major version ranges with skips to the head of the highest semver in a channel.  We also generated a replaces edge to traverse across minor version transitions within each major channel.  Finally, we generated an `olm.package` object, setting as default the most-stable channel head we created.  This process will prefer `Stable` channel over `Fast`, over `Candidate` and then a higher bundle version over a lower version.   
+(Please note that the naming of the generated channels indicates the digits of significance for that channel.  For example, `fast-v1` is a decomposed channel of the `fast` type which contains only major versions of contributing bundles matching `v1`.)  
+
+For contrast, with the template attribute `GenerateMinorChannels: true` and running the command again (again skipping rendered bundle image output) we get a bunch more channels:
+```yaml
+---
+defaultChannel: stable-v1.0
+name: testoperator
+schema: olm.package
+---
+entries:
+  - name: testoperator.v0.1.0
+  - name: testoperator.v0.1.1
+  - name: testoperator.v0.1.2
+  - name: testoperator.v0.1.3
+    skips:
+      - testoperator.v0.1.0
+      - testoperator.v0.1.1
+      - testoperator.v0.1.2
+name: candidate-v0.1
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v0.2.0
+  - name: testoperator.v0.2.1
+  - name: testoperator.v0.2.2
+    replaces: testoperator.v0.1.3
+    skips:
+      - testoperator.v0.1.0
+      - testoperator.v0.1.1
+      - testoperator.v0.1.2
+      - testoperator.v0.2.0
+      - testoperator.v0.2.1
+name: candidate-v0.2
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v0.3.0
+    replaces: testoperator.v0.2.2
+    skips:
+      - testoperator.v0.1.0
+      - testoperator.v0.1.1
+      - testoperator.v0.1.2
+      - testoperator.v0.1.3
+      - testoperator.v0.2.0
+      - testoperator.v0.2.1
+name: candidate-v0.3
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.0.0
+  - name: testoperator.v1.0.1
+    skips:
+      - testoperator.v1.0.0
+name: candidate-v1.0
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.1.0
+    replaces: testoperator.v1.0.1
+    skips:
+      - testoperator.v1.0.0
+name: candidate-v1.1
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v0.2.1
+  - name: testoperator.v0.2.2
+    skips:
+      - testoperator.v0.2.1
+name: fast-v0.2
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v0.3.0
+    replaces: testoperator.v0.2.2
+    skips:
+      - testoperator.v0.2.1
+name: fast-v0.3
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.0.1
+name: fast-v1.0
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.1.0
+    replaces: testoperator.v1.0.1
+name: fast-v1.1
+package: testoperator
+schema: olm.channel
+---
+entries:
+  - name: testoperator.v1.0.1
+name: stable-v1.0
+package: testoperator
+schema: olm.channel
+```
+Here, a channel is generated for each template channel which differs by minor version, each channel has a `replaces` edge from the highest version entry in the predecessor channel, and the highest version entry in each channel also has a skips list composed of all lower version entries within the same minor (Y).  Please note that at no time do we transgress across major-version boundaries with the channels, to be consistent with [the semver convention](https://semver.org/) for major versions, where the purpose is to make incompatible API changes.
+
+
+### DEMOS
+
+#### Major Channel Generation
+![`GenerateMajorChannels`](./major-version-demo.gif)
+
+#### Minor Channel Generation
+![`GenerateMinorChannels`](./minor-version-demo.gif)
+
+
diff --git a/alpha/template/semver/major-version-demo.gif b/alpha/template/semver/major-version-demo.gif
new file mode 100644
index 000000000..21d46519c
Binary files /dev/null and b/alpha/template/semver/major-version-demo.gif differ
diff --git a/alpha/template/semver/minor-version-demo.gif b/alpha/template/semver/minor-version-demo.gif
new file mode 100644
index 000000000..fbe9bf1ac
Binary files /dev/null and b/alpha/template/semver/minor-version-demo.gif differ
diff --git a/alpha/template/semver/semver.go b/alpha/template/semver/semver.go
new file mode 100644
index 000000000..afd7e898c
--- /dev/null
+++ b/alpha/template/semver/semver.go
@@ -0,0 +1,467 @@
+package semver
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"sort"
+
+	"github.com/blang/semver/v4"
+	"k8s.io/apimachinery/pkg/util/errors"
+	"sigs.k8s.io/yaml"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/property"
+)
+
+func (t Template) Render(ctx context.Context) (*declcfg.DeclarativeConfig, error) {
+	var out declcfg.DeclarativeConfig
+
+	sv, err := readFile(t.Data)
+	if err != nil {
+		return nil, fmt.Errorf("render: unable to read file: %v", err)
+	}
+
+	// nolint:prealloc
+	var cfgs []declcfg.DeclarativeConfig
+
+	bundleDict := buildBundleList(*sv)
+	for b := range bundleDict {
+		c, err := t.RenderBundle(ctx, b)
+		if err != nil {
+			return nil, err
+		}
+		if len(c.Bundles) != 1 {
+			return nil, fmt.Errorf("bundle reference %q resulted in %d bundles, expected 1", b, len(c.Bundles))
+		}
+		bundleDict[b] = c.Bundles[0].Image
+		cfgs = append(cfgs, *c)
+	}
+	out = *combineConfigs(cfgs)
+
+	if len(out.Bundles) == 0 {
+		return nil, fmt.Errorf("render: no bundles specified or no bundles could be rendered")
+	}
+
+	channelBundleVersions, err := sv.getVersionsFromStandardChannels(&out, bundleDict)
+	if err != nil {
+		return nil, fmt.Errorf("render: unable to post-process bundle info: %v", err)
+	}
+
+	channels := sv.generateChannels(channelBundleVersions)
+	out.Channels = channels
+	out.Packages[0].DefaultChannel = sv.defaultChannel
+
+	return &out, nil
+}
+
+func buildBundleList(t semverTemplate) map[string]string {
+	dict := make(map[string]string)
+	for _, bl := range []semverTemplateChannelBundles{t.Candidate, t.Fast, t.Stable} {
+		for _, b := range bl.Bundles {
+			if _, ok := dict[b.Image]; !ok {
+				dict[b.Image] = b.Image
+			}
+		}
+	}
+	return dict
+}
+
+func readFile(reader io.Reader) (*semverTemplate, error) {
+	data, err := io.ReadAll(reader)
+	if err != nil {
+		return nil, err
+	}
+
+	sv := semverTemplate{}
+	if err := yaml.UnmarshalStrict(data, &sv); err != nil {
+		return nil, err
+	}
+
+	if sv.Schema != schema {
+		return nil, fmt.Errorf("readFile: input file has unknown schema, should be %q", schema)
+	}
+
+	// if no generate option is selected, default to GenerateMinorChannels
+	if !sv.GenerateMajorChannels && !sv.GenerateMinorChannels {
+		sv.GenerateMinorChannels = true
+	}
+
+	// for default channel preference,
+	// if un-set, default to align to the selected generate option
+	// if set, error out if we mismatch the two
+	switch sv.DefaultChannelTypePreference {
+	case defaultStreamType:
+		if sv.GenerateMinorChannels {
+			sv.DefaultChannelTypePreference = minorStreamType
+		} else if sv.GenerateMajorChannels {
+			sv.DefaultChannelTypePreference = majorStreamType
+		}
+	case minorStreamType:
+		if !sv.GenerateMinorChannels {
+			return nil, fmt.Errorf("schema attribute mismatch: DefaultChannelTypePreference set to 'minor' doesn't make sense if not generating minor-version channels")
+		}
+	case majorStreamType:
+		if !sv.GenerateMajorChannels {
+			return nil, fmt.Errorf("schema attribute mismatch: DefaultChannelTypePreference set to 'major' doesn't make sense if not generating major-version channels")
+		}
+	default:
+		return nil, fmt.Errorf("unknown DefaultChannelTypePreference: %q\nValid values are 'major' or 'minor'", sv.DefaultChannelTypePreference)
+	}
+
+	return &sv, nil
+}
+
+func (sv *semverTemplate) getVersionsFromStandardChannels(cfg *declcfg.DeclarativeConfig, bundleDict map[string]string) (*bundleVersions, error) {
+	versions := bundleVersions{}
+
+	bdm, err := sv.getVersionsFromChannel(sv.Candidate.Bundles, bundleDict, cfg)
+	if err != nil {
+		return nil, err
+	}
+	if err = validateVersions(&bdm); err != nil {
+		return nil, err
+	}
+	versions[candidateChannelArchetype] = bdm
+
+	bdm, err = sv.getVersionsFromChannel(sv.Fast.Bundles, bundleDict, cfg)
+	if err != nil {
+		return nil, err
+	}
+	if err = validateVersions(&bdm); err != nil {
+		return nil, err
+	}
+	versions[fastChannelArchetype] = bdm
+
+	bdm, err = sv.getVersionsFromChannel(sv.Stable.Bundles, bundleDict, cfg)
+	if err != nil {
+		return nil, err
+	}
+	if err = validateVersions(&bdm); err != nil {
+		return nil, err
+	}
+	versions[stableChannelArchetype] = bdm
+
+	return &versions, nil
+}
+
+func (sv *semverTemplate) getVersionsFromChannel(semverBundles []semverTemplateBundleEntry, bundleDict map[string]string, cfg *declcfg.DeclarativeConfig) (map[string]semver.Version, error) {
+	entries := make(map[string]semver.Version)
+
+	// we iterate over the channel bundles from the template, to:
+	// - identify if any required bundles for the channel are missing/not rendered/otherwise unavailable
+	// - maintain the channel-bundle relationship as we map from un-rendered semver template bundles to rendered bundles in `entries` which is accumulated by the caller
+	//   in a per-channel structure to which we can safely refer when generating/linking channels
+	for _, semverBundle := range semverBundles {
+		// test if the bundle specified in the template is present in the successfully-rendered bundles
+		index := 0
+		for index < len(cfg.Bundles) {
+			if cfg.Bundles[index].Image == bundleDict[semverBundle.Image] {
+				break
+			}
+			index++
+		}
+		if index == len(cfg.Bundles) {
+			return nil, fmt.Errorf("supplied bundle image name %q not found in rendered bundle images", semverBundle.Image)
+		}
+		b := cfg.Bundles[index]
+
+		props, err := property.Parse(b.Properties)
+		if err != nil {
+			return nil, fmt.Errorf("parse properties for bundle %q: %v", b.Name, err)
+		}
+		if len(props.Packages) != 1 {
+			return nil, fmt.Errorf("bundle %q has multiple %q properties, expected exactly 1", b.Name, property.TypePackage)
+		}
+		v, err := semver.Parse(props.Packages[0].Version)
+		if err != nil {
+			return nil, fmt.Errorf("bundle %q has invalid version %q: %v", b.Name, props.Packages[0].Version, err)
+		}
+
+		// package name detection
+		if sv.pkg != "" {
+			// if we have a known package name, then ensure all subsequent packages match
+			if props.Packages[0].PackageName != sv.pkg {
+				return nil, fmt.Errorf("bundle %q does not belong to this package: %q", props.Packages[0].PackageName, sv.pkg)
+			}
+		} else {
+			// else cache the first
+			p := newPackage(props.Packages[0].PackageName)
+			cfg.Packages = append(cfg.Packages, *p)
+			sv.pkg = props.Packages[0].PackageName
+		}
+
+		if _, ok := entries[b.Name]; ok {
+			return nil, fmt.Errorf("duplicate bundle name %q", b.Name)
+		}
+
+		entries[b.Name] = v
+	}
+
+	return entries, nil
+}
+
+// generates an unlinked channel for each channel as per the input template config (major || minor), then link up the edges of the set of channels so that:
+// - for minor version increase, the new edge replaces the previous
+// - (for major channels) iterating to a new minor version channel (traversing between Y-streams) creates a 'replaces' edge between the predecessor and successor bundles
+// - within the same minor version (Y-stream), the head of the channel should have a 'skips' encompassing all lesser Y.Z versions of the bundle enumerated in the template.
+// along the way, uses a highwaterChannel marker to identify the "most stable" channel head to be used as the default channel for the generated package
+
+func (sv *semverTemplate) generateChannels(semverChannels *bundleVersions) []declcfg.Channel {
+	outChannels := []declcfg.Channel{}
+
+	// sort the channel archetypes in ascending order so we can traverse the bundles in order of
+	// their source channel's priority
+	// nolint:prealloc
+	var archetypesByPriority []channelArchetype
+	for k := range channelPriorities {
+		archetypesByPriority = append(archetypesByPriority, k)
+	}
+	sort.Sort(byChannelPriority(archetypesByPriority))
+
+	// set to the least-priority channel
+	hwc := highwaterChannel{archetype: archetypesByPriority[0], version: semver.Version{Major: 0, Minor: 0}}
+
+	unlinkedChannels := make(map[string]*declcfg.Channel)
+
+	for _, archetype := range archetypesByPriority {
+		bundles := (*semverChannels)[archetype]
+		// skip channel if empty
+		if len(bundles) == 0 {
+			continue
+		}
+
+		// sort the bundle names according to their semver, so we can walk in ascending order
+		bundleNamesByVersion := []string{}
+		for b := range bundles {
+			bundleNamesByVersion = append(bundleNamesByVersion, b)
+		}
+		sort.Slice(bundleNamesByVersion, func(i, j int) bool {
+			return bundles[bundleNamesByVersion[i]].LT(bundles[bundleNamesByVersion[j]])
+		})
+
+		// for each bundle (by version):
+		//   for each of Major/Minor setting (since they're independent)
+		//     retrieve the existing channel object, or create a channel (by criteria major/minor) if one doesn't exist
+		//     add a new edge entry based on the bundle name
+		//     save the channel name --> channel archetype mapping
+		//     test the channel object for 'more stable' than previous best
+		for _, bundleName := range bundleNamesByVersion {
+			// a dodge to avoid duplicating channel processing body; accumulate a map of the channels which need creating from the bundle
+			// we need to associate by kind so we can partition the resulting entries
+			channelNameKeys := make(map[streamType]string)
+			if sv.GenerateMajorChannels {
+				channelNameKeys[majorStreamType] = channelNameFromMajor(archetype, bundles[bundleName])
+			}
+			if sv.GenerateMinorChannels {
+				channelNameKeys[minorStreamType] = channelNameFromMinor(archetype, bundles[bundleName])
+			}
+
+			for cKey, cName := range channelNameKeys {
+				ch, ok := unlinkedChannels[cName]
+				if !ok {
+					ch = newChannel(sv.pkg, cName)
+
+					unlinkedChannels[cName] = ch
+
+					hwcCandidate := highwaterChannel{archetype: archetype, kind: cKey, version: bundles[bundleName], name: cName}
+					if hwcCandidate.gt(&hwc, sv.DefaultChannelTypePreference) {
+						hwc = hwcCandidate
+					}
+				}
+				ch.Entries = append(ch.Entries, declcfg.ChannelEntry{Name: bundleName})
+			}
+		}
+	}
+
+	// save off the name of the high-water-mark channel for the default for this package
+	sv.defaultChannel = hwc.name
+
+	outChannels = append(outChannels, sv.linkChannels(unlinkedChannels, semverChannels)...)
+
+	return outChannels
+}
+
+func (sv *semverTemplate) linkChannels(unlinkedChannels map[string]*declcfg.Channel, harvestedVersions *bundleVersions) []declcfg.Channel {
+	channels := []declcfg.Channel{}
+
+	// bundle --> version lookup
+	bundleVersions := make(map[string]semver.Version)
+	for _, vs := range *harvestedVersions {
+		for b, v := range vs {
+			if _, ok := bundleVersions[b]; !ok {
+				bundleVersions[b] = v
+			}
+		}
+	}
+
+	for _, channel := range unlinkedChannels {
+		entries := &channel.Entries
+		sort.Slice(*entries, func(i, j int) bool {
+			return bundleVersions[(*entries)[i].Name].LT(bundleVersions[(*entries)[j].Name])
+		})
+
+		// "inchworm" through the sorted entries, iterating curEdge but extending yProbe to the next Y-transition
+		// then catch up curEdge to yProbe as 'skips', and repeat until we reach the end of the entries
+		// finally, because the inchworm will always fail to pick up the last Y-transition, we test for it and link it up as a 'replaces'
+		curEdge, yProbe := 0, 0
+		zmaxQueue := ""
+		entryCount := len(*entries)
+
+		for curEdge < entryCount {
+			for yProbe < entryCount {
+				curVersion := bundleVersions[(*entries)[curEdge].Name]
+				yProbeVersion := bundleVersions[(*entries)[yProbe].Name]
+				if getMinorVersion(yProbeVersion).EQ(getMinorVersion(curVersion)) {
+					yProbe += 1
+				} else {
+					break
+				}
+			}
+			// if yProbe crossed a threshold, the previous entry is the last of the previous Y-stream
+			preChangeIndex := yProbe - 1
+
+			if curEdge != yProbe {
+				if zmaxQueue != "" {
+					// add skips edge to allow skipping over y iterations within an x stream
+					(*entries)[preChangeIndex].Skips = append((*entries)[preChangeIndex].Skips, zmaxQueue)
+					(*entries)[preChangeIndex].Replaces = zmaxQueue
+				}
+				zmaxQueue = (*entries)[preChangeIndex].Name
+			}
+			for curEdge < preChangeIndex {
+				// add skips edges to y-1 from z < y
+				(*entries)[preChangeIndex].Skips = append((*entries)[preChangeIndex].Skips, (*entries)[curEdge].Name)
+				curEdge += 1
+			}
+			curEdge += 1
+			yProbe = curEdge + 1
+		}
+		// since probe will always fail to pick up a y-change in the last item, test for it
+		if entryCount > 1 {
+			penultimateEntry := &(*entries)[len(*entries)-2]
+			ultimateEntry := &(*entries)[len(*entries)-1]
+			penultimateVersion := bundleVersions[penultimateEntry.Name]
+			ultimateVersion := bundleVersions[ultimateEntry.Name]
+			if ultimateVersion.Minor != penultimateVersion.Minor {
+				ultimateEntry.Replaces = penultimateEntry.Name
+			}
+		}
+		channels = append(channels, *channel)
+	}
+
+	return channels
+}
+
+func channelNameFromMinor(prefix channelArchetype, version semver.Version) string {
+	return fmt.Sprintf("%s-v%d.%d", prefix, version.Major, version.Minor)
+}
+
+func channelNameFromMajor(prefix channelArchetype, version semver.Version) string {
+	return fmt.Sprintf("%s-v%d", prefix, version.Major)
+}
+
+func newPackage(name string) *declcfg.Package {
+	return &declcfg.Package{
+		Schema:         "olm.package",
+		Name:           name,
+		DefaultChannel: "",
+	}
+}
+
+func newChannel(pkgName string, chName string) *declcfg.Channel {
+	return &declcfg.Channel{
+		Schema:  "olm.channel",
+		Name:    chName,
+		Package: pkgName,
+		Entries: []declcfg.ChannelEntry{},
+	}
+}
+
+func combineConfigs(cfgs []declcfg.DeclarativeConfig) *declcfg.DeclarativeConfig {
+	out := &declcfg.DeclarativeConfig{}
+	for _, in := range cfgs {
+		out.Merge(&in)
+	}
+	return out
+}
+
+func getMinorVersion(v semver.Version) semver.Version {
+	return semver.Version{
+		Major: v.Major,
+		Minor: v.Minor,
+	}
+}
+
+// nolint:unused
+func getMajorVersion(v semver.Version) semver.Version {
+	return semver.Version{
+		Major: v.Major,
+	}
+}
+
+func withoutBuildMetadataConflict(versions *map[string]semver.Version) error {
+	errs := []error{}
+
+	// using the stringified semver because the semver package generates deterministic representations,
+	// and because the semver.Version contains slice fields which make it unsuitable as a map key
+	//      stringified-semver.Version ==> incidence count
+	seen := make(map[string]int)
+	for b := range *versions {
+		stripped := stripBuildMetadata((*versions)[b])
+		if _, ok := seen[stripped]; !ok {
+			seen[stripped] = 1
+		} else {
+			seen[stripped] = seen[stripped] + 1
+			errs = append(errs, fmt.Errorf("bundle version %q cannot be compared to %q", (*versions)[b].String(), stripped))
+		}
+	}
+
+	if len(errs) != 0 {
+		return fmt.Errorf("encountered bundle versions which differ only by build metadata, which cannot be ordered: %v", errors.NewAggregate(errs))
+	}
+
+	return nil
+}
+
+func validateVersions(versions *map[string]semver.Version) error {
+	// short-circuit if empty, since that is not an error
+	if len(*versions) == 0 {
+		return nil
+	}
+	return withoutBuildMetadataConflict(versions)
+}
+
+// strips out the build metadata from a semver.Version and then stringifies it to make it suitable for collision detection
+func stripBuildMetadata(v semver.Version) string {
+	v.Build = nil
+	return v.String()
+}
+
+// prefer (in descending order of preference):
+// - higher-rank archetype,
+// - semver version,
+// - a channel type matching the set preference, or
+// - a 'better' (higher value) channel type
+func (h *highwaterChannel) gt(ih *highwaterChannel, pref streamType) bool {
+	if channelPriorities[h.archetype] != channelPriorities[ih.archetype] {
+		return channelPriorities[h.archetype] > channelPriorities[ih.archetype]
+	}
+	if h.version.NE(ih.version) {
+		return h.version.GT(ih.version)
+	}
+	if h.kind != ih.kind {
+		if h.kind == pref {
+			return true
+		}
+		if ih.kind == pref {
+			return false
+		}
+		return h.kind.gt((*ih).kind)
+	}
+	return false
+}
+
+func (t streamType) gt(in streamType) bool {
+	return streamTypePriorities[t] > streamTypePriorities[in]
+}
diff --git a/alpha/template/semver/semver_test.go b/alpha/template/semver/semver_test.go
new file mode 100644
index 000000000..68cd84e66
--- /dev/null
+++ b/alpha/template/semver/semver_test.go
@@ -0,0 +1,713 @@
+package semver
+
+import (
+	"fmt"
+	"strings"
+	"testing"
+
+	"github.com/blang/semver/v4"
+	"github.com/stretchr/testify/require"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/property"
+)
+
+func TestLinkChannels(t *testing.T) {
+	// type bundleVersions map[string]map[string]semver.Version // e.g. d["stable"]["example-operator.v1.0.0"] = 1.0.0
+	channelOperatorVersions := bundleVersions{
+		"stable": {
+			"a-v0.1.0":       semver.MustParse("0.1.0"),
+			"a-v0.1.1":       semver.MustParse("0.1.1"),
+			"a-v1.1.0":       semver.MustParse("1.1.0"),
+			"a-v1.2.1":       semver.MustParse("1.2.1"),
+			"a-v1.3.1":       semver.MustParse("1.3.1"),
+			"a-v2.1.0":       semver.MustParse("2.1.0"),
+			"a-v1.3.1-beta":  semver.MustParse(("1.3.1-beta")),
+			"a-v2.1.1":       semver.MustParse("2.1.1"),
+			"a-v2.3.1":       semver.MustParse("2.3.1"),
+			"a-v2.3.2":       semver.MustParse("2.3.2"),
+			"a-v3.1.0":       semver.MustParse("3.1.0"),
+			"a-v3.1.1":       semver.MustParse("3.1.1"),
+			"a-v1.3.1-alpha": semver.MustParse("1.3.1-alpha"),
+			"a-v1.4.1":       semver.MustParse("1.4.1"),
+			"a-v1.4.1-beta1": semver.MustParse("1.4.1-beta1"),
+			"a-v1.4.1-beta2": semver.MustParse("1.4.1-beta2"),
+		},
+	}
+
+	majorGeneratedUnlinkedChannels := map[string]*declcfg.Channel{
+		"stable-v0": {
+			Schema:  "olm.channel",
+			Name:    "stable-v0",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v0.1.0"},
+				{Name: "a-v0.1.1"},
+			},
+		},
+		"stable-v1": {
+			Schema:  "olm.channel",
+			Name:    "stable-v1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.1.0"},
+				{Name: "a-v1.2.1"},
+				{Name: "a-v1.3.1"},
+			},
+		},
+		"stable-v2": {
+			Schema:  "olm.channel",
+			Name:    "stable-v2",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.1.0"},
+				{Name: "a-v2.1.1"},
+				{Name: "a-v2.3.1"},
+				{Name: "a-v2.3.2"},
+			},
+		},
+	}
+
+	majorGeneratedUnlinkedChannelsLastXChange := map[string]*declcfg.Channel{
+		"stable-v0": {
+			Schema:  "olm.channel",
+			Name:    "stable-v0",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v0.1.0"},
+				{Name: "a-v0.1.1"},
+			},
+		},
+		"stable-v1": {
+			Schema:  "olm.channel",
+			Name:    "stable-v1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.1.0"},
+				{Name: "a-v1.2.1"},
+				{Name: "a-v1.3.1"},
+			},
+		},
+		"stable-v2": {
+			Schema:  "olm.channel",
+			Name:    "stable-v2",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.1.0"},
+			},
+		},
+	}
+
+	majorGeneratedUnlinkedChannelsLastArchChange := map[string]*declcfg.Channel{
+		"candidate-v2": {
+			Schema:  "olm.channel",
+			Name:    "candidate-v2",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.3.2"},
+			},
+		},
+		"stable-v1": {
+			Schema:  "olm.channel",
+			Name:    "stable-v1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.1.0"},
+				{Name: "a-v1.2.1"},
+				{Name: "a-v1.3.1"},
+			},
+		},
+		"stable-v2": {
+			Schema:  "olm.channel",
+			Name:    "stable-v2",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.1.0"},
+				{Name: "a-v2.1.1"},
+				{Name: "a-v2.3.1"},
+			},
+		},
+	}
+
+	tests := []struct {
+		name                  string
+		unlinkedChannels      map[string]*declcfg.Channel
+		generateMinorChannels bool
+		generateMajorChannels bool
+		out                   []declcfg.Channel
+	}{
+		{
+			name:                  "No edges between successive major channels",
+			unlinkedChannels:      majorGeneratedUnlinkedChannels,
+			generateMinorChannels: false,
+			generateMajorChannels: true,
+			out: []declcfg.Channel{
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v0",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v0.1.0", Replaces: ""},
+						{Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}},
+					},
+				},
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v1",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v1.1.0", Replaces: ""},
+						{Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}},
+						{Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1"}},
+					},
+				},
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v2",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v2.1.0", Replaces: ""},
+						{Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}},
+						{Name: "a-v2.3.1", Replaces: ""},
+						{Name: "a-v2.3.2", Replaces: "a-v2.1.1", Skips: []string{"a-v2.1.1", "a-v2.3.1"}},
+					},
+				},
+			},
+		},
+		{
+			name:                  "No edges between successive major channels where last edge is X change",
+			unlinkedChannels:      majorGeneratedUnlinkedChannelsLastXChange,
+			generateMinorChannels: false,
+			generateMajorChannels: true,
+			out: []declcfg.Channel{
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v0",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v0.1.0", Replaces: ""},
+						{Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}},
+					},
+				},
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v1",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v1.1.0", Replaces: ""},
+						{Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}},
+						{Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1"}},
+					},
+				},
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v2",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v2.1.0", Replaces: ""},
+					},
+				},
+			},
+		},
+		{
+			name:                  "No edges between successive major channels where last edge is archetype change",
+			unlinkedChannels:      majorGeneratedUnlinkedChannelsLastArchChange,
+			generateMinorChannels: false,
+			generateMajorChannels: true,
+			out: []declcfg.Channel{
+				{
+					Schema:  "olm.channel",
+					Name:    "candidate-v2",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v2.3.2", Replaces: ""},
+					},
+				},
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v1",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v1.1.0", Replaces: ""},
+						{Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}},
+						{Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1"}},
+					},
+				},
+				{
+					Schema:  "olm.channel",
+					Name:    "stable-v2",
+					Package: "a",
+					Entries: []declcfg.ChannelEntry{
+						{Name: "a-v2.1.0", Replaces: ""},
+						{Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}},
+						{Name: "a-v2.3.1", Replaces: "a-v2.1.1", Skips: []string{"a-v2.1.1"}},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			sv := &semverTemplate{pkg: "a", GenerateMajorChannels: tt.generateMajorChannels, GenerateMinorChannels: tt.generateMinorChannels}
+			require.ElementsMatch(t, tt.out, sv.linkChannels(tt.unlinkedChannels, &channelOperatorVersions))
+		})
+	}
+}
+
+func TestGenerateChannels(t *testing.T) {
+	// type bundleVersions map[string]map[string]semver.Version // e.g. d["stable"]["example-operator.v1.0.0"] = 1.0.0
+	channelOperatorVersions := bundleVersions{
+		"stable": {
+			"a-v0.1.0":       semver.MustParse("0.1.0"),
+			"a-v0.1.1":       semver.MustParse("0.1.1"),
+			"a-v1.1.0":       semver.MustParse("1.1.0"),
+			"a-v1.2.1":       semver.MustParse("1.2.1"),
+			"a-v1.3.1":       semver.MustParse("1.3.1"),
+			"a-v2.1.0":       semver.MustParse("2.1.0"),
+			"a-v1.3.1-beta":  semver.MustParse(("1.3.1-beta")),
+			"a-v2.1.1":       semver.MustParse("2.1.1"),
+			"a-v2.3.1":       semver.MustParse("2.3.1"),
+			"a-v2.3.2":       semver.MustParse("2.3.2"),
+			"a-v3.1.0":       semver.MustParse("3.1.0"),
+			"a-v3.1.1":       semver.MustParse("3.1.1"),
+			"a-v1.3.1-alpha": semver.MustParse("1.3.1-alpha"),
+			"a-v1.4.1":       semver.MustParse("1.4.1"),
+			"a-v1.4.1-beta1": semver.MustParse("1.4.1-beta1"),
+			"a-v1.4.1-beta2": semver.MustParse("1.4.1-beta2"),
+		},
+	}
+
+	majorLinkedChannels := []declcfg.Channel{
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v0",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v0.1.0", Replaces: ""},
+				{Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.1.0", Replaces: ""},
+				{Name: "a-v1.2.1", Replaces: "a-v1.1.0", Skips: []string{"a-v1.1.0"}},
+				{Name: "a-v1.3.1-alpha", Replaces: ""},
+				{Name: "a-v1.3.1-beta", Replaces: ""},
+				{Name: "a-v1.3.1", Replaces: "a-v1.2.1", Skips: []string{"a-v1.2.1", "a-v1.3.1-alpha", "a-v1.3.1-beta"}},
+				{Name: "a-v1.4.1-beta1", Replaces: ""},
+				{Name: "a-v1.4.1-beta2", Replaces: ""},
+				{Name: "a-v1.4.1", Replaces: "a-v1.3.1", Skips: []string{"a-v1.3.1", "a-v1.4.1-beta1", "a-v1.4.1-beta2"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v2",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.1.0", Replaces: ""},
+				{Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}},
+				{Name: "a-v2.3.1", Replaces: ""},
+				{Name: "a-v2.3.2", Replaces: "a-v2.1.1", Skips: []string{"a-v2.1.1", "a-v2.3.1"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v3",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v3.1.0", Replaces: ""},
+				{Name: "a-v3.1.1", Replaces: "", Skips: []string{"a-v3.1.0"}},
+			},
+		},
+	}
+
+	minorLinkedChannels := []declcfg.Channel{
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v0.1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v0.1.0", Replaces: ""},
+				{Name: "a-v0.1.1", Replaces: "", Skips: []string{"a-v0.1.0"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v1.1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.1.0", Replaces: ""},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v1.2",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.2.1", Replaces: ""},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v1.3",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.3.1-alpha", Replaces: ""},
+				{Name: "a-v1.3.1-beta", Replaces: ""},
+				{Name: "a-v1.3.1", Replaces: "", Skips: []string{"a-v1.3.1-alpha", "a-v1.3.1-beta"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v1.4",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v1.4.1-beta1", Replaces: ""},
+				{Name: "a-v1.4.1-beta2", Replaces: ""},
+				{Name: "a-v1.4.1", Replaces: "", Skips: []string{"a-v1.4.1-beta1", "a-v1.4.1-beta2"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v2.1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.1.0", Replaces: ""},
+				{Name: "a-v2.1.1", Replaces: "", Skips: []string{"a-v2.1.0"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v2.3",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v2.3.1", Replaces: ""},
+				{Name: "a-v2.3.2", Replaces: "", Skips: []string{"a-v2.3.1"}},
+			},
+		},
+		{
+			Schema:  "olm.channel",
+			Name:    "stable-v3.1",
+			Package: "a",
+			Entries: []declcfg.ChannelEntry{
+				{Name: "a-v3.1.0", Replaces: ""},
+				{Name: "a-v3.1.1", Replaces: "", Skips: []string{"a-v3.1.0"}},
+			},
+		},
+	}
+
+	var combinedLinkedChannels []declcfg.Channel
+	combinedLinkedChannels = append(combinedLinkedChannels, minorLinkedChannels...)
+	combinedLinkedChannels = append(combinedLinkedChannels, majorLinkedChannels...)
+
+	tests := []struct {
+		name                  string
+		generateMinorChannels bool
+		generateMajorChannels bool
+		defaultChannel        string
+		channelTypePreference streamType
+		out                   []declcfg.Channel
+	}{
+		{
+			name:                  "Edges between minor channels",
+			generateMinorChannels: true,
+			generateMajorChannels: false,
+			defaultChannel:        "stable-v3.1",
+			channelTypePreference: minorStreamType,
+			out:                   minorLinkedChannels,
+		},
+		{
+			name:                  "No edges between major channels",
+			generateMinorChannels: false,
+			generateMajorChannels: true,
+			defaultChannel:        "stable-v3",
+			channelTypePreference: majorStreamType,
+			out:                   majorLinkedChannels,
+		},
+		{
+			name:                  "Preference for minor default channel",
+			generateMinorChannels: true,
+			generateMajorChannels: true,
+			defaultChannel:        "stable-v3.1",
+			channelTypePreference: minorStreamType,
+			out:                   combinedLinkedChannels,
+		},
+		{
+			name:                  "Preference for major default channel",
+			generateMinorChannels: true,
+			generateMajorChannels: true,
+			defaultChannel:        "stable-v3",
+			channelTypePreference: majorStreamType,
+			out:                   combinedLinkedChannels,
+		},
+		{
+			name:                  "Mismatch generate/preference minor/major default channel",
+			generateMinorChannels: true,
+			generateMajorChannels: false,
+			defaultChannel:        "stable-v3.1",
+			channelTypePreference: majorStreamType,
+			out:                   minorLinkedChannels,
+		},
+		{
+			name:                  "Mismatch generate/preference major/minor default channel",
+			generateMinorChannels: false,
+			generateMajorChannels: true,
+			defaultChannel:        "stable-v3",
+			channelTypePreference: minorStreamType,
+			out:                   majorLinkedChannels,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			sv := &semverTemplate{GenerateMajorChannels: tt.generateMajorChannels, GenerateMinorChannels: tt.generateMinorChannels, pkg: "a", DefaultChannelTypePreference: tt.channelTypePreference}
+			out := sv.generateChannels(&channelOperatorVersions)
+			require.ElementsMatch(t, tt.out, out)
+			require.Equal(t, tt.defaultChannel, sv.defaultChannel)
+		})
+	}
+}
+
+func TestGetVersionsFromStandardChannel(t *testing.T) {
+	tests := []struct {
+		name        string
+		sv          semverTemplate
+		outVersions bundleVersions
+		dc          declcfg.DeclarativeConfig
+	}{
+		{
+			name: "sunny day case",
+			sv: semverTemplate{
+				Stable: semverTemplateChannelBundles{
+					[]semverTemplateBundleEntry{
+						{Image: "repo/origin/a-v0.1.0"},
+						{Image: "repo/origin/a-v0.1.1"},
+						{Image: "repo/origin/a-v1.1.0"},
+						{Image: "repo/origin/a-v1.2.1"},
+						{Image: "repo/origin/a-v1.3.1"},
+						{Image: "repo/origin/a-v2.1.0"},
+						{Image: "repo/origin/a-v2.1.1"},
+						{Image: "repo/origin/a-v2.3.1"},
+						{Image: "repo/origin/a-v2.3.2"},
+						{Image: "repo/origin/a-v1.3.1-alpha"},
+					},
+				},
+			},
+			outVersions: bundleVersions{
+				"candidate": map[string]semver.Version{},
+				"fast":      map[string]semver.Version{},
+				"stable": {
+					"a-v0.1.0":       semver.MustParse("0.1.0"),
+					"a-v0.1.1":       semver.MustParse("0.1.1"),
+					"a-v1.1.0":       semver.MustParse("1.1.0"),
+					"a-v1.2.1":       semver.MustParse("1.2.1"),
+					"a-v1.3.1":       semver.MustParse("1.3.1"),
+					"a-v2.1.0":       semver.MustParse("2.1.0"),
+					"a-v2.1.1":       semver.MustParse("2.1.1"),
+					"a-v2.3.1":       semver.MustParse("2.3.1"),
+					"a-v2.3.2":       semver.MustParse("2.3.2"),
+					"a-v1.3.1-alpha": semver.MustParse("1.3.1-alpha"),
+				},
+			},
+			dc: declcfg.DeclarativeConfig{
+				Packages: []declcfg.Package{
+					{
+						Schema: "olm.package",
+						Name:   "a",
+					},
+				},
+				Bundles: []declcfg.Bundle{
+					{Schema: "olm.bundle", Image: "repo/origin/a-v0.1.0", Name: "a-v0.1.0", Properties: []property.Property{property.MustBuildPackage("a", "0.1.0")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v0.1.1", Name: "a-v0.1.1", Properties: []property.Property{property.MustBuildPackage("a", "0.1.1")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v1.1.0", Name: "a-v1.1.0", Properties: []property.Property{property.MustBuildPackage("a", "1.1.0")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v1.2.1", Name: "a-v1.2.1", Properties: []property.Property{property.MustBuildPackage("a", "1.2.1")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha", Name: "a-v1.3.1-alpha", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1", Name: "a-v1.3.1", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v2.1.0", Name: "a-v2.1.0", Properties: []property.Property{property.MustBuildPackage("a", "2.1.0")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v2.1.1", Name: "a-v2.1.1", Properties: []property.Property{property.MustBuildPackage("a", "2.1.1")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v2.3.1", Name: "a-v2.3.1", Properties: []property.Property{property.MustBuildPackage("a", "2.3.1")}},
+					{Schema: "olm.bundle", Image: "repo/origin/a-v2.3.2", Name: "a-v2.3.2", Properties: []property.Property{property.MustBuildPackage("a", "2.3.2")}},
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			iosv := tt.sv
+			versions, err := iosv.getVersionsFromStandardChannels(&tt.dc, buildBundleList(tt.sv))
+			require.NoError(t, err)
+			require.EqualValues(t, tt.outVersions, *versions)
+			require.EqualValues(t, "a", iosv.pkg) // verify that we learned the package name and stashed it in the receiver
+		})
+	}
+}
+
+func TestBailOnVersionBuildMetadata(t *testing.T) {
+	sv := semverTemplate{
+		Stable: semverTemplateChannelBundles{
+			[]semverTemplateBundleEntry{
+				{Image: "repo/origin/a-v0.1.0"},
+				{Image: "repo/origin/a-v0.1.1"},
+				{Image: "repo/origin/a-v1.1.0"},
+				{Image: "repo/origin/a-v1.2.1"},
+				{Image: "repo/origin/a-v1.3.1"},
+				{Image: "repo/origin/a-v2.1.0"},
+				{Image: "repo/origin/a-v2.1.1"},
+				{Image: "repo/origin/a-v2.3.1"},
+				{Image: "repo/origin/a-v2.3.2"},
+				{Image: "repo/origin/a-v1.3.1-alpha"},
+				{Image: "repo/origin/a-v1.3.1-alpha+2001Jan21"},
+				{Image: "repo/origin/a-v1.3.1-alpha+2003May06"},
+			},
+		},
+	}
+
+	dc := declcfg.DeclarativeConfig{
+		Packages: []declcfg.Package{
+			{
+				Schema: "olm.package",
+				Name:   "a",
+			},
+		},
+		Bundles: []declcfg.Bundle{
+			{Schema: "olm.bundle", Image: "repo/origin/a-v0.1.0", Name: "a-v0.1.0", Properties: []property.Property{property.MustBuildPackage("a", "0.1.0")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v0.1.1", Name: "a-v0.1.1", Properties: []property.Property{property.MustBuildPackage("a", "0.1.1")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v1.1.0", Name: "a-v1.1.0", Properties: []property.Property{property.MustBuildPackage("a", "1.1.0")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v1.2.1", Name: "a-v1.2.1", Properties: []property.Property{property.MustBuildPackage("a", "1.2.1")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha", Name: "a-v1.3.1-alpha", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha+2001Jan21", Name: "a-v1.3.1-alpha+2001Jan21", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha+2001Jan21")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1", Name: "a-v1.3.1", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v2.1.0", Name: "a-v2.1.0", Properties: []property.Property{property.MustBuildPackage("a", "2.1.0")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v2.1.1", Name: "a-v2.1.1", Properties: []property.Property{property.MustBuildPackage("a", "2.1.1")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v2.3.1", Name: "a-v2.3.1", Properties: []property.Property{property.MustBuildPackage("a", "2.3.1")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v2.3.2", Name: "a-v2.3.2", Properties: []property.Property{property.MustBuildPackage("a", "2.3.2")}},
+			{Schema: "olm.bundle", Image: "repo/origin/a-v1.3.1-alpha+2003May06", Name: "a-v1.3.1-alpha+2003May06", Properties: []property.Property{property.MustBuildPackage("a", "1.3.1-alpha+2003May06")}},
+		},
+	}
+
+	t.Run("Abort on unorderable build metadata version data", func(t *testing.T) {
+		_, err := sv.getVersionsFromStandardChannels(&dc, buildBundleList(sv))
+		require.Error(t, err)
+	})
+}
+
+func TestReadFile(t *testing.T) {
+	templateFstr := `---
+schema: olm.semver
+generateMajorChannels: %s
+generateMinorChannels: %s
+defaultChannelTypePreference: %s
+candidate:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v0.1.0
+        - image: quay.io/foo/olm:testoperator.v0.1.1
+        - image: quay.io/foo/olm:testoperator.v0.1.2
+        - image: quay.io/foo/olm:testoperator.v0.1.3
+        - image: quay.io/foo/olm:testoperator.v0.2.0
+        - image: quay.io/foo/olm:testoperator.v0.2.1
+        - image: quay.io/foo/olm:testoperator.v0.2.2
+        - image: quay.io/foo/olm:testoperator.v0.3.0
+        - image: quay.io/foo/olm:testoperator.v1.0.0
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+        - image: quay.io/foo/olm:testoperator.v1.1.0
+fast:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v0.2.1
+        - image: quay.io/foo/olm:testoperator.v0.2.2
+        - image: quay.io/foo/olm:testoperator.v0.3.0
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+        - image: quay.io/foo/olm:testoperator.v1.1.0
+stable:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+`
+
+	type testCase struct {
+		name       string
+		input      string
+		assertions func(*testing.T, *semverTemplate, error)
+	}
+	testCases := []testCase{
+		{
+			name:  "valid",
+			input: fmt.Sprintf(templateFstr, "true", "true", "minor"),
+			assertions: func(t *testing.T, template *semverTemplate, err error) {
+				require.NotNil(t, template)
+				require.NoError(t, err)
+			},
+		},
+		{
+			name: "unknown channel prefix",
+			input: `---
+schema: olm.semver
+generateMajorChannels: true
+generateMinorChannels: true
+candidate:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v0.1.0
+        - image: quay.io/foo/olm:testoperator.v0.1.1
+        - image: quay.io/foo/olm:testoperator.v0.1.2
+        - image: quay.io/foo/olm:testoperator.v0.1.3
+        - image: quay.io/foo/olm:testoperator.v0.2.0
+        - image: quay.io/foo/olm:testoperator.v0.2.1
+        - image: quay.io/foo/olm:testoperator.v0.2.2
+        - image: quay.io/foo/olm:testoperator.v0.3.0
+        - image: quay.io/foo/olm:testoperator.v1.0.0
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+        - image: quay.io/foo/olm:testoperator.v1.1.0
+fast:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v0.2.1
+        - image: quay.io/foo/olm:testoperator.v0.2.2
+        - image: quay.io/foo/olm:testoperator.v0.3.0
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+        - image: quay.io/foo/olm:testoperator.v1.1.0
+stable:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+invalid:
+    bundles:
+        - image: quay.io/foo/olm:testoperator.v1.0.1
+`,
+			assertions: func(t *testing.T, template *semverTemplate, err error) {
+				require.Nil(t, template)
+				require.EqualError(t, err, `error unmarshaling JSON: while decoding JSON: json: unknown field "invalid"`)
+			},
+		},
+		{
+			name:  "generate/default mismatch, minor/major",
+			input: fmt.Sprintf(templateFstr, "true", "false", "minor"),
+			assertions: func(t *testing.T, template *semverTemplate, err error) {
+				require.Nil(t, template)
+				require.ErrorContains(t, err, "schema attribute mismatch")
+			},
+		},
+		{
+			name:  "generate/default mismatch, major/minor",
+			input: fmt.Sprintf(templateFstr, "false", "true", "major"),
+			assertions: func(t *testing.T, template *semverTemplate, err error) {
+				require.Nil(t, template)
+				require.ErrorContains(t, err, "schema attribute mismatch")
+			},
+		},
+		{
+			name:  "unknown defaultchanneltypepreference",
+			input: fmt.Sprintf(templateFstr, "false", "true", "foo"),
+			assertions: func(t *testing.T, template *semverTemplate, err error) {
+				require.Nil(t, template)
+				require.ErrorContains(t, err, "unknown DefaultChannelTypePreference")
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			sv, err := readFile(strings.NewReader(tc.input))
+			tc.assertions(t, sv, err)
+		})
+	}
+}
diff --git a/alpha/template/semver/types.go b/alpha/template/semver/types.go
new file mode 100644
index 000000000..b0846a64f
--- /dev/null
+++ b/alpha/template/semver/types.go
@@ -0,0 +1,84 @@
+package semver
+
+import (
+	"context"
+	"io"
+
+	"github.com/blang/semver/v4"
+
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+)
+
+// data passed into this module externally
+type Template struct {
+	Data         io.Reader
+	RenderBundle func(context.Context, string) (*declcfg.DeclarativeConfig, error)
+}
+
+// IO structs -- BEGIN
+type semverTemplateBundleEntry struct {
+	Image string `json:"image,omitempty"`
+}
+
+type semverTemplateChannelBundles struct {
+	Bundles []semverTemplateBundleEntry `json:"bundles,omitempty"`
+}
+
+type semverTemplate struct {
+	Schema                       string                       `json:"schema"`
+	GenerateMajorChannels        bool                         `json:"generateMajorChannels,omitempty"`
+	GenerateMinorChannels        bool                         `json:"generateMinorChannels,omitempty"`
+	DefaultChannelTypePreference streamType                   `json:"defaultChannelTypePreference,omitempty"`
+	Candidate                    semverTemplateChannelBundles `json:"candidate,omitempty"`
+	Fast                         semverTemplateChannelBundles `json:"fast,omitempty"`
+	Stable                       semverTemplateChannelBundles `json:"stable,omitempty"`
+
+	pkg            string `json:"-"` // the derived package name
+	defaultChannel string `json:"-"` // detected "most stable" channel head
+}
+
+// IO structs -- END
+
+const schema string = "olm.semver"
+
+// channel "archetypes", restricted in this iteration to just these
+type channelArchetype string
+
+const (
+	candidateChannelArchetype channelArchetype = "candidate"
+	fastChannelArchetype      channelArchetype = "fast"
+	stableChannelArchetype    channelArchetype = "stable"
+)
+
+// mapping channel name --> stability, where higher values indicate greater stability
+var channelPriorities = map[channelArchetype]int{candidateChannelArchetype: 0, fastChannelArchetype: 1, stableChannelArchetype: 2}
+
+// sorting capability for a slice according to the assigned channelPriorities
+type byChannelPriority []channelArchetype
+
+func (b byChannelPriority) Len() int { return len(b) }
+func (b byChannelPriority) Less(i, j int) bool {
+	return channelPriorities[b[i]] < channelPriorities[b[j]]
+}
+func (b byChannelPriority) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+type streamType string
+
+const defaultStreamType streamType = ""
+const minorStreamType streamType = "minor"
+const majorStreamType streamType = "major"
+
+// general preference for minor channels
+var streamTypePriorities = map[streamType]int{minorStreamType: 2, majorStreamType: 1, defaultStreamType: 0}
+
+// map of archetypes --> bundles --> bundle-version from the input file
+type bundleVersions map[channelArchetype]map[string]semver.Version // e.g. srcv["stable"]["example-operator.v1.0.0"] = 1.0.0
+
+// the "high-water channel" struct functions as a freely-rising indicator of the "most stable" channel head, so we can use that
+// later as the package's defaultChannel attribute
+type highwaterChannel struct {
+	archetype channelArchetype
+	kind      streamType
+	version   semver.Version
+	name      string
+}
diff --git a/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml b/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml
index 69266c011..6eba3fd65 100644
--- a/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml
+++ b/bundles/etcd.0.9.0/manifests/etcdoperator.v0.9.0.yaml
@@ -17,7 +17,7 @@ spec:
 
     ### Reading and writing to etcd
 
-    Communicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service.
+    Communicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service.
 
     [Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)
 
diff --git a/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml b/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml
index 137d88095..2d7909001 100644
--- a/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml
+++ b/bundles/etcd.0.9.2/manifests/etcdoperator.v0.9.2.clusterserviceversion.yaml
@@ -17,7 +17,7 @@ spec:
 
     ### Reading and writing to etcd
 
-    Communicate with etcd though its command line utility `etcdctl` or with the API using the automatically generated Kubernetes Service.
+    Communicate with etcd though its command line utility `etcdctl` or with the API using the Kubernetes Service.
 
     [Read the complete guide to using the etcd Open Cloud Service](https://coreos.com/tectonic/docs/latest/alm/etcd-ocs.html)
 
diff --git a/bundles/etcd.0.9.2/metadata/dependencies.yaml b/bundles/etcd.0.9.2/metadata/dependencies.yaml
index a4d95d4d9..41903694a 100644
--- a/bundles/etcd.0.9.2/metadata/dependencies.yaml
+++ b/bundles/etcd.0.9.2/metadata/dependencies.yaml
@@ -4,3 +4,8 @@ dependencies:
     group: testapi.coreos.com
     kind: testapi
     version: v1
+- type: olm.constraint
+  value:
+    failureMessage: 'require to have "certified"'
+    cel:
+        rule: 'properties.exists(p, p.type == "certified")'
diff --git a/cmd/configmap-server/main.go b/cmd/configmap-server/main.go
index a5d8179e8..0bf97474b 100644
--- a/cmd/configmap-server/main.go
+++ b/cmd/configmap-server/main.go
@@ -8,6 +8,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"google.golang.org/grpc"
+	health "google.golang.org/grpc/health/grpc_health_v1"
 	"google.golang.org/grpc/reflection"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
@@ -15,9 +16,7 @@ import (
 	"k8s.io/client-go/tools/clientcmd"
 
 	"github.com/operator-framework/operator-registry/pkg/api"
-	health "github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1"
 	"github.com/operator-framework/operator-registry/pkg/lib/dns"
-	"github.com/operator-framework/operator-registry/pkg/lib/graceful"
 	"github.com/operator-framework/operator-registry/pkg/lib/log"
 	"github.com/operator-framework/operator-registry/pkg/registry"
 	"github.com/operator-framework/operator-registry/pkg/server"
@@ -59,6 +58,9 @@ func main() {
 }
 
 func runCmdFunc(cmd *cobra.Command, args []string) error {
+	ctx, cancel := context.WithCancel(cmd.Context())
+	defer cancel()
+
 	// Immediately set up termination log
 	terminationLogPath, err := cmd.Flags().GetString("termination-log")
 	if err != nil {
@@ -99,7 +101,7 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
 	logger := logrus.WithFields(logrus.Fields{"configMapName": configMapName, "configMapNamespace": configMapNamespace, "port": port})
 
 	client := NewClientFromConfig(kubeconfig, logger.Logger)
-	configMap, err := client.CoreV1().ConfigMaps(configMapNamespace).Get(context.TODO(), configMapName, metav1.GetOptions{})
+	configMap, err := client.CoreV1().ConfigMaps(configMapNamespace).Get(ctx, configMapName, metav1.GetOptions{})
 	if err != nil {
 		logger.Fatalf("error getting configmap: %s", err)
 	}
@@ -113,7 +115,7 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
 	if err != nil {
 		return err
 	}
-	if err := sqlLoader.Migrate(context.TODO()); err != nil {
+	if err := sqlLoader.Migrate(ctx); err != nil {
 		return err
 	}
 
@@ -127,16 +129,18 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
 	}
 
 	var store registry.Query
+	// nolint:staticcheck
 	store, err = sqlite.NewSQLLiteQuerier(dbName)
 	if err != nil {
 		logger.WithError(err).Warnf("failed to load db")
 	}
+	// nolint:staticcheck
 	if store == nil {
 		store = registry.NewEmptyQuerier()
 	}
 
 	// sanity check that the db is available
-	tables, err := store.ListTables(context.TODO())
+	tables, err := store.ListTables(ctx)
 	if err != nil {
 		logger.WithError(err).Warnf("couldn't list tables in db")
 	}
@@ -154,12 +158,14 @@ func runCmdFunc(cmd *cobra.Command, args []string) error {
 	health.RegisterHealthServer(s, server.NewHealthServer())
 	reflection.Register(s)
 
-	logger.Info("serving registry")
-	return graceful.Shutdown(logger, func() error {
-		return s.Serve(lis)
-	}, func() {
+	go func() {
+		<-ctx.Done()
+		logger.Info("shutting down server")
 		s.GracefulStop()
-	})
+	}()
+
+	logger.Info("serving registry")
+	return s.Serve(lis)
 }
 
 // NewClient creates a kubernetes client or bails out on on failures.
diff --git a/cmd/opm/alpha/bundle/build.go b/cmd/opm/alpha/bundle/build.go
index c35ce80c9..b428813cc 100644
--- a/cmd/opm/alpha/bundle/build.go
+++ b/cmd/opm/alpha/bundle/build.go
@@ -1,9 +1,10 @@
 package bundle
 
 import (
-	"github.com/operator-framework/operator-registry/pkg/lib/bundle"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/pkg/lib/bundle"
 )
 
 var (
@@ -15,6 +16,7 @@ var (
 	defaultChannel string
 	outputDir      string
 	overwrite      bool
+	baseImage      string
 )
 
 // newBundleBuildCmd returns a command that will build operator bundle image.
@@ -76,6 +78,9 @@ Note:
 	bundleBuildCmd.Flags().StringVarP(&outputDir, "output-dir", "u", "",
 		"Optional output directory for operator manifests")
 
+	bundleBuildCmd.Flags().StringVar(&baseImage, "base-image", "scratch",
+		"Use a custom image pullspec as the base bundle image")
+
 	return bundleBuildCmd
 }
 
@@ -89,5 +94,6 @@ func buildFunc(cmd *cobra.Command, _ []string) error {
 		channels,
 		defaultChannel,
 		overwrite,
+		baseImage,
 	)
 }
diff --git a/cmd/opm/alpha/bundle/extract.go b/cmd/opm/alpha/bundle/extract.go
index d07273b3c..3cc7e968f 100644
--- a/cmd/opm/alpha/bundle/extract.go
+++ b/cmd/opm/alpha/bundle/extract.go
@@ -12,7 +12,7 @@ import (
 var extractCmd = &cobra.Command{
 	Use:   "extract",
 	Short: "Extracts the data in a bundle directory via ConfigMap",
-	Long:  "Extract takes as input a directory containing manifests and writes the per file contents to a ConfipMap",
+	Long:  "Extract takes as input a directory containing manifests and writes the per file contents to a ConfigMap",
 
 	PreRunE: func(cmd *cobra.Command, _ []string) error {
 		if debug, _ := cmd.Flags().GetBool("debug"); debug {
@@ -33,7 +33,7 @@ func init() {
 	extractCmd.Flags().StringP("namespace", "n", "openshift-operator-lifecycle-manager", "namespace to write configmap data")
 	extractCmd.Flags().Uint64P("datalimit", "l", 1<<20, "maximum limit in bytes for total bundle data")
 	extractCmd.Flags().BoolP("gzip", "z", false, "enable gzip compression of configmap data")
-	extractCmd.MarkPersistentFlagRequired("configmapname")
+	_ = extractCmd.MarkPersistentFlagRequired("configmapname")
 }
 
 func runExtractCmd(cmd *cobra.Command, _ []string) error {
diff --git a/cmd/opm/alpha/bundle/generate.go b/cmd/opm/alpha/bundle/generate.go
index 417a22c37..3a65f2ae3 100644
--- a/cmd/opm/alpha/bundle/generate.go
+++ b/cmd/opm/alpha/bundle/generate.go
@@ -45,6 +45,7 @@ Note:
 	bundleGenerateCmd.Flags().StringVarP(&outputDir, "output-dir", "u", "",
 		"Optional output directory for operator manifests")
 
+	bundleGenerateCmd.Flags().StringVar(&baseImage, "base-image", "scratch", "Use a custom image pullspec as the base bundle image")
 	return bundleGenerateCmd
 }
 
@@ -56,5 +57,6 @@ func generateFunc(cmd *cobra.Command, _ []string) error {
 		channels,
 		defaultChannel,
 		true,
+		baseImage,
 	)
 }
diff --git a/cmd/opm/alpha/bundle/unpack.go b/cmd/opm/alpha/bundle/unpack.go
index 67f3b311a..369442eb0 100644
--- a/cmd/opm/alpha/bundle/unpack.go
+++ b/cmd/opm/alpha/bundle/unpack.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"crypto/x509"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -12,6 +11,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/image"
 	"github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
 	"github.com/operator-framework/operator-registry/pkg/lib/bundle"
@@ -28,11 +28,16 @@ func newBundleUnpackCmd() *cobra.Command {
 		RunE: unpackBundle,
 	}
 	unpack.Flags().BoolP("debug", "d", false, "enable debug log output")
-	unpack.Flags().BoolP("skip-tls", "s", false, "disable TLS verification")
+	unpack.Flags().BoolP("skip-tls", "s", false, "use plain HTTP")
+	unpack.Flags().Bool("skip-tls-verify", false, "disable TLS verification")
+	unpack.Flags().Bool("use-http", false, "use plain HTTP")
 	unpack.Flags().BoolP("skip-validation", "v", false, "disable bundle validation")
 	unpack.Flags().StringP("root-ca", "c", "", "file path of a root CA to use when communicating with image registries")
 	unpack.Flags().StringP("out", "o", "./", "directory in which to unpack operator bundle content")
 
+	if err := unpack.Flags().MarkDeprecated("skip-tls", "use --use-http and --skip-tls-verify instead"); err != nil {
+		logrus.Panic(err.Error())
+	}
 	return unpack
 }
 
@@ -53,6 +58,7 @@ func unpackBundle(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
+	// nolint:nestif
 	if info, err := os.Stat(out); err != nil {
 		if os.IsNotExist(err) {
 			err = os.MkdirAll(out, 0755)
@@ -71,13 +77,14 @@ func unpackBundle(cmd *cobra.Command, args []string) error {
 
 	var (
 		registryOpts []containerdregistry.RegistryOption
-		skipTLS      bool
 	)
-	skipTLS, err = cmd.Flags().GetBool("skip-tls")
+
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
-	registryOpts = append(registryOpts, containerdregistry.SkipTLS(skipTLS))
+
+	registryOpts = append(registryOpts, containerdregistry.SkipTLSVerify(skipTLSVerify), containerdregistry.WithPlainHTTP(useHTTP))
 
 	var skipValidation bool
 	skipValidation, err = cmd.Flags().GetBool("skip-validation")
@@ -92,7 +99,7 @@ func unpackBundle(cmd *cobra.Command, args []string) error {
 	}
 	if rootCA != "" {
 		rootCAs := x509.NewCertPool()
-		certs, err := ioutil.ReadFile(rootCA)
+		certs, err := os.ReadFile(rootCA)
 		if err != nil {
 			return err
 		}
@@ -122,7 +129,7 @@ func unpackBundle(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	dir, err := ioutil.TempDir("", "bundle-")
+	dir, err := os.MkdirTemp("", "bundle-")
 	if err != nil {
 		return err
 	}
diff --git a/cmd/opm/alpha/bundle/validate.go b/cmd/opm/alpha/bundle/validate.go
index 9406e79a3..c1044c05c 100644
--- a/cmd/opm/alpha/bundle/validate.go
+++ b/cmd/opm/alpha/bundle/validate.go
@@ -2,7 +2,6 @@ package bundle
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -35,10 +34,13 @@ Optional validators. These validators are disabled by default and can be enabled
  * Operatorhub validator - performs operatorhub.io validation. To validate a bundle using custom categories use with the OPERATOR_BUNDLE_CATEGORIES environmental variable to point to a json-encoded categories file.
  * Bundle objects validator - performs validation on resources like PodDisruptionBudgets and PriorityClasses. 
 
-See https://olm.operatorframework.io/docs/tasks/validate-package/#validation for more info.`,
-		Example: `$ opm alpha bundle validate --tag quay.io/test/test-operator:latest --image-builder docker`,
-		RunE:    validateFunc,
-		Args:    cobra.NoArgs,
+See https://olm.operatorframework.io/docs/tasks/validate-package/#validation for more info.
+
+Note that this subcommand is deprecated and will be removed in a future release. Migrate to operator-sdk bundle validate.`,
+		Example:    `$ opm alpha bundle validate --tag quay.io/test/test-operator:latest --image-builder docker`,
+		RunE:       validateFunc,
+		Args:       cobra.NoArgs,
+		Deprecated: "This subcommand is deprecated and will be removed in a future release. Migrate to operator-sdk bundle validate",
 	}
 
 	bundleValidateCmd.Flags().StringVarP(&tag, "tag", "t", "",
@@ -77,7 +79,7 @@ func validateFunc(cmd *cobra.Command, _ []string) error {
 	}
 	imageValidator := bundle.NewImageValidator(registry, logger, optional)
 
-	dir, err := ioutil.TempDir("", "bundle-")
+	dir, err := os.MkdirTemp("", "bundle-")
 	logger.Infof("Create a temp directory at %s", dir)
 	if err != nil {
 		return err
diff --git a/cmd/opm/alpha/cmd.go b/cmd/opm/alpha/cmd.go
index 7afed8b09..b0077f9cc 100644
--- a/cmd/opm/alpha/cmd.go
+++ b/cmd/opm/alpha/cmd.go
@@ -4,24 +4,30 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/operator-framework/operator-registry/cmd/opm/alpha/bundle"
-	"github.com/operator-framework/operator-registry/cmd/opm/alpha/diff"
-	"github.com/operator-framework/operator-registry/cmd/opm/alpha/generate"
+	converttemplate "github.com/operator-framework/operator-registry/cmd/opm/alpha/convert-template"
 	"github.com/operator-framework/operator-registry/cmd/opm/alpha/list"
+	rendergraph "github.com/operator-framework/operator-registry/cmd/opm/alpha/render-graph"
+	"github.com/operator-framework/operator-registry/cmd/opm/alpha/template"
 )
 
-func NewCmd() *cobra.Command {
+func NewCmd(showAlphaHelp bool) *cobra.Command {
 	runCmd := &cobra.Command{
-		Hidden: true,
-		Use:    "alpha",
-		Short:  "Run an alpha subcommand",
-		Args:   cobra.NoArgs,
+		Use:   "alpha",
+		Short: "Run an alpha subcommand",
+		Args:  cobra.NoArgs,
+		Run:   func(_ *cobra.Command, _ []string) {}, // adding an empty function here to preserve non-zero exit status for misstated subcommands/flags for the command hierarchy
+	}
+
+	if !showAlphaHelp {
+		runCmd.Hidden = true
 	}
 
 	runCmd.AddCommand(
 		bundle.NewCmd(),
 		list.NewCmd(),
-		generate.NewCmd(),
-		diff.NewCmd(),
+		rendergraph.NewCmd(),
+		template.NewCmd(),
+		converttemplate.NewCmd(),
 	)
 	return runCmd
 }
diff --git a/cmd/opm/alpha/convert-template/convert.go b/cmd/opm/alpha/convert-template/convert.go
new file mode 100644
index 000000000..a5587c004
--- /dev/null
+++ b/cmd/opm/alpha/convert-template/convert.go
@@ -0,0 +1,63 @@
+package converttemplate
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/alpha/template/converter"
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
+)
+
+func NewCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "convert-template",
+		Short: "Convert existing FBC to a supported template type",
+	}
+	cmd.AddCommand(
+		newBasicConvertCmd(),
+	)
+	return cmd
+}
+
+func newBasicConvertCmd() *cobra.Command {
+	var (
+		converter converter.Converter
+		output    string
+	)
+	cmd := &cobra.Command{
+		Use:   "basic [<fbc-file> | -]",
+		Args:  cobra.MaximumNArgs(1),
+		Short: "Generate a basic template from existing FBC",
+		Long: `Generate a basic template from existing FBC.
+
+This command outputs a basic catalog template to STDOUT from input FBC.
+If no argument is specified or is '-' input is assumed from STDIN.
+`,
+		RunE: func(c *cobra.Command, args []string) error {
+			switch output {
+			case "yaml", "json":
+				converter.OutputFormat = output
+			default:
+				log.Fatalf("invalid --output value %q, expected (json|yaml)", output)
+			}
+
+			reader, name, err := util.OpenFileOrStdin(c, args)
+			if err != nil {
+				return fmt.Errorf("unable to open input: %q", name)
+			}
+
+			converter.FbcReader = reader
+			err = converter.Convert()
+			if err != nil {
+				return fmt.Errorf("converting: %v", err)
+			}
+
+			return nil
+		},
+	}
+	cmd.Flags().StringVarP(&output, "output", "o", "json", "Output format (json|yaml)")
+
+	return cmd
+}
diff --git a/cmd/opm/alpha/diff/cmd.go b/cmd/opm/alpha/diff/cmd.go
deleted file mode 100644
index 752e4d343..000000000
--- a/cmd/opm/alpha/diff/cmd.go
+++ /dev/null
@@ -1,228 +0,0 @@
-package diff
-
-import (
-	"context"
-	"fmt"
-	"io"
-	"os"
-	"strings"
-	"time"
-
-	"github.com/sirupsen/logrus"
-	"github.com/spf13/cobra"
-	"k8s.io/kubectl/pkg/util/templates"
-
-	"github.com/operator-framework/operator-registry/alpha/action"
-	"github.com/operator-framework/operator-registry/alpha/declcfg"
-	containerd "github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
-	"github.com/operator-framework/operator-registry/pkg/lib/certs"
-)
-
-const (
-	retryInterval = time.Second * 5
-	timeout       = time.Minute * 1
-)
-
-type diff struct {
-	oldRefs         []string
-	newRefs         []string
-	skipDeps        bool
-	includeAdditive bool
-	includeFile     string
-
-	output string
-	caFile string
-
-	debug  bool
-	logger *logrus.Entry
-}
-
-// Example include file needs to be formatted separately so indentation is not messed up.
-var includeFileExample = fmt.Sprintf(`packages:
-%[1]s- name: foo
-%[1]s- name: bar
-%[1]s  channels:
-%[1]s  - name: stable
-%[1]s- name: baz
-%[1]s  channels:
-%[1]s  - name: alpha
-%[1]s    versions:
-%[1]s    - 0.2.0-alpha.0`, templates.Indentation)
-
-func NewCmd() *cobra.Command {
-	a := diff{
-		logger: logrus.NewEntry(logrus.New()),
-	}
-	cmd := &cobra.Command{
-		Use:   "diff [old-refs]... new-refs...",
-		Short: "Diff old and new catalog references into a declarative config",
-		Long: templates.LongDesc(`
-'diff' returns a declarative config containing packages, channels, and versions
-from new-refs, optionally removing those in old-refs or those omitted by an include config file.
-
-Each set of refs is passed to 'opm render <refs>' to produce a single, normalized delcarative config.
-
-Depending on what arguments are provided to the command, a particular "mode" is invoked to produce a diff:
-
-- If in heads-only mode (old-refs is not specified), then the heads of channels in new-refs are added to the output.
-- If in latest mode (old-refs is specified), a diff between old-refs and new-refs is added to the output.
-- If --include-file is set, items from that file will be added to the diff:
-	- If --include-additive is false (the default), a diff will be generated only on those objects, depending on the mode.
-	- If --include-additive is true, the diff will contain included objects, plus those added by the mode's invocation.
-
-Dependencies are added in all modes if --skip-deps is false (the default).
-Dependencies are assumed to be provided by either an old-ref, in which case they are not included in the diff,
-or a new-ref, in which case they are included.
-Dependencies provided by some catalog unknown to 'diff' will not cause the command to error,
-but an error will occur if that catalog is not serving these dependencies at runtime.
-While dependency inclusion can be turned off with --skip-deps, doing so is not recommended
-unless you are certain some in-cluster catalog satisfies all dependencies.
-`),
-		Example: fmt.Sprintf(templates.Examples(`
-# Create a directory for your declarative config diff.
-mkdir -p my-catalog-index
-
-# THEN:
-# Create a new catalog from a diff between an old and the latest
-# state of a catalog as a declarative config index.
-opm alpha diff registry.org/my-catalog:abc123 registry.org/my-catalog:def456 -o yaml > ./my-catalog-index/index.yaml
-
-# OR:
-# Create a new catalog from the heads of an existing catalog.
-opm alpha diff registry.org/my-catalog:def456 -o yaml > my-catalog-index/index.yaml
-
-# OR:
-# Only include all of package "foo", package "bar" channel "stable",
-# and package "baz" channel "alpha" version "0.2.0-alpha.0" (and its upgrade graph) in the diff.
-cat <<EOF > include.yaml
-%s
-EOF
-opm alpha diff registry.org/my-catalog:def456 -i include.yaml -o yaml > pruned-index/index.yaml
-
-# OR:
-# Include all of package "foo", package "bar" channel "stable",
-# and package "baz" channel "alpha" version "0.2.0-alpha.0" in the diff
-# on top of heads of all other channels in all packages (using the above include.yaml).
-opm alpha diff registry.org/my-catalog:def456 -i include.yaml --include-additive -o yaml > pruned-index/index.yaml
-
-# FINALLY:
-# Build an index image containing the diff-ed declarative config,
-# then tag and push it.
-opm alpha generate dockerfile ./my-catalog-index
-docker build -t registry.org/my-catalog:diff-latest -f index.Dockerfile .
-docker push registry.org/my-catalog:diff-latest
-`), includeFileExample),
-		Args: cobra.RangeArgs(1, 2),
-		PreRunE: func(cmd *cobra.Command, args []string) error {
-			if a.debug {
-				a.logger.Logger.SetLevel(logrus.DebugLevel)
-			}
-			a.logger.Logger.SetOutput(os.Stderr)
-			return nil
-		},
-		RunE: a.addFunc,
-	}
-
-	cmd.Flags().BoolVar(&a.skipDeps, "skip-deps", false, "do not include bundle dependencies in the output catalog")
-
-	cmd.Flags().StringVarP(&a.output, "output", "o", "yaml", "Output format (json|yaml)")
-	cmd.Flags().StringVar(&a.caFile, "ca-file", "", "the root Certificates to use with this command")
-	cmd.Flags().StringVarP(&a.includeFile, "include-file", "i", "",
-		"YAML defining packages, channels, and/or bundles/versions to extract from the new refs. "+
-			"Upgrade graphs from individual bundles/versions to their channel's head are also included")
-	cmd.Flags().BoolVar(&a.includeAdditive, "include-additive", false,
-		"Ref objects from --include-file are returned on top of 'heads-only' or 'latest' output")
-
-	cmd.Flags().BoolVar(&a.debug, "debug", false, "enable debug logging")
-	return cmd
-}
-
-func (a *diff) addFunc(cmd *cobra.Command, args []string) error {
-	a.parseArgs(args)
-
-	if cmd.Flags().Changed("include-additive") && a.includeFile == "" {
-		a.logger.Fatal("must set --include-file if --include-additive is set")
-	}
-
-	var write func(declcfg.DeclarativeConfig, io.Writer) error
-	switch a.output {
-	case "yaml":
-		write = declcfg.WriteYAML
-	case "json":
-		write = declcfg.WriteJSON
-	default:
-		return fmt.Errorf("invalid --output value: %q", a.output)
-	}
-
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
-	if err != nil {
-		logrus.Panic(err)
-	}
-	rootCAs, err := certs.RootCAs(a.caFile)
-	if err != nil {
-		a.logger.Fatalf("error getting root CAs: %v", err)
-	}
-	reg, err := containerd.NewRegistry(containerd.SkipTLS(skipTLS), containerd.WithLog(a.logger), containerd.WithRootCAs(rootCAs))
-	if err != nil {
-		a.logger.Fatalf("error creating containerd registry: %v", err)
-	}
-	defer func() {
-		if err := reg.Destroy(); err != nil {
-			a.logger.Errorf("error destroying local cache: %v", err)
-		}
-	}()
-
-	diff := action.Diff{
-		Registry:          reg,
-		OldRefs:           a.oldRefs,
-		NewRefs:           a.newRefs,
-		SkipDependencies:  a.skipDeps,
-		IncludeAdditively: a.includeAdditive,
-		Logger:            a.logger,
-	}
-
-	if a.includeFile != "" {
-		f, err := os.Open(a.includeFile)
-		if err != nil {
-			a.logger.Fatalf("error opening include file: %v", err)
-		}
-		defer func() {
-			if cerr := f.Close(); cerr != nil {
-				a.logger.Error(cerr)
-			}
-		}()
-		if diff.IncludeConfig, err = action.LoadDiffIncludeConfig(f); err != nil {
-			a.logger.Fatalf("error loading include file: %v", err)
-		}
-	}
-
-	ctx, cancel := context.WithTimeout(context.TODO(), timeout)
-	defer cancel()
-
-	cfg, err := diff.Run(ctx)
-	if err != nil {
-		a.logger.Fatalf("error generating diff: %v", err)
-	}
-
-	if err := write(*cfg, os.Stdout); err != nil {
-		a.logger.Fatalf("error writing diff: %v", err)
-	}
-
-	return nil
-}
-
-func (a *diff) parseArgs(args []string) {
-	var old, new string
-	switch len(args) {
-	case 1:
-		new = args[0]
-	case 2:
-		old, new = args[0], args[1]
-	default:
-		logrus.Panic("should never be here, CLI must enforce arg size")
-	}
-	if old != "" {
-		a.oldRefs = strings.Split(old, ",")
-	}
-	a.newRefs = strings.Split(new, ",")
-}
diff --git a/cmd/opm/alpha/generate/cmd.go b/cmd/opm/alpha/generate/cmd.go
deleted file mode 100644
index 092f2310a..000000000
--- a/cmd/opm/alpha/generate/cmd.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package generate
-
-import (
-	"fmt"
-	"log"
-	"os"
-	"path/filepath"
-	"strings"
-
-	"github.com/sirupsen/logrus"
-	"github.com/spf13/cobra"
-
-	"github.com/operator-framework/operator-registry/alpha/action"
-	"github.com/operator-framework/operator-registry/pkg/containertools"
-)
-
-func NewCmd() *cobra.Command {
-	cmd := &cobra.Command{
-		Use:   "generate",
-		Short: "Generate various artifacts for declarative config indexes",
-	}
-	cmd.AddCommand(
-		newDockerfileCmd(),
-	)
-	return cmd
-}
-
-func newDockerfileCmd() *cobra.Command {
-	var (
-		baseImage      string
-		extraLabelStrs []string
-	)
-	cmd := &cobra.Command{
-		Use:   "dockerfile <dcRootDir>",
-		Args:  cobra.ExactArgs(1),
-		Short: "Generate a Dockerfile for a declarative config index",
-		Long: `Generate a Dockerfile for a declarative config index.
-
-This command creates a Dockerfile in the same directory as the <dcRootDir>
-(named <dcDirName>.Dockerfile) that can be used to build the index. If a
-Dockerfile with the same name already exists, this command will fail.
-
-When specifying extra labels, note that if duplicate keys exist, only the last
-value of each duplicate key will be added to the generated Dockerfile.
-`,
-		RunE: func(_ *cobra.Command, args []string) error {
-			fromDir := args[0]
-
-			extraLabels, err := parseLabels(extraLabelStrs)
-			if err != nil {
-				return err
-			}
-
-			dir, indexName := filepath.Split(fromDir)
-			dockerfilePath := filepath.Join(dir, fmt.Sprintf("%s.Dockerfile", indexName))
-
-			if err := ensureNotExist(dockerfilePath); err != nil {
-				logrus.Fatal(err)
-			}
-
-			if s, err := os.Stat(fromDir); err != nil {
-				return err
-			} else if !s.IsDir() {
-				return fmt.Errorf("provided root path %q is not a directory", fromDir)
-			}
-
-			f, err := os.OpenFile(dockerfilePath, os.O_CREATE|os.O_WRONLY, 0666)
-			if err != nil {
-				logrus.Fatal(err)
-			}
-			defer f.Close()
-
-			gen := action.GenerateDockerfile{
-				BaseImage:   baseImage,
-				IndexDir:    indexName,
-				ExtraLabels: extraLabels,
-				Writer:      f,
-			}
-			if err := gen.Run(); err != nil {
-				log.Fatal(err)
-			}
-			return nil
-		},
-	}
-	cmd.Flags().StringVarP(&baseImage, "binary-image", "i", containertools.DefaultBinarySourceImage, "Image in which to build catalog.")
-	cmd.Flags().StringSliceVarP(&extraLabelStrs, "extra-labels", "l", []string{}, "Extra labels to include in the generated Dockerfile. Labels should be of the form 'key=value'.")
-	return cmd
-}
-
-func parseLabels(labelStrs []string) (map[string]string, error) {
-	labels := map[string]string{}
-	for _, l := range labelStrs {
-		spl := strings.SplitN(l, "=", 2)
-		if len(spl) != 2 {
-			return nil, fmt.Errorf("invalid label %q", l)
-		}
-		labels[spl[0]] = spl[1]
-	}
-	return labels, nil
-}
-
-func ensureNotExist(path string) error {
-	_, err := os.Stat(path)
-	if err != nil && !os.IsNotExist(err) {
-		return err
-	}
-	if err == nil {
-		return fmt.Errorf("path %q: %w", path, os.ErrExist)
-	}
-	return nil
-}
diff --git a/cmd/opm/alpha/list/cmd.go b/cmd/opm/alpha/list/cmd.go
index c1c09ab0f..79f9fd9c8 100644
--- a/cmd/opm/alpha/list/cmd.go
+++ b/cmd/opm/alpha/list/cmd.go
@@ -7,6 +7,7 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 )
 
 const humanReadabilityOnlyNote = `NOTE: This is meant to be used for convenience and human-readability only. The
@@ -22,6 +23,7 @@ func NewCmd() *cobra.Command {
 
 ` + humanReadabilityOnlyNote,
 	}
+
 	list.AddCommand(newPackagesCmd(), newChannelsCmd(), newBundlesCmd())
 	return list
 }
@@ -37,7 +39,14 @@ func newPackagesCmd() *cobra.Command {
 ` + humanReadabilityOnlyNote,
 		Args: cobra.ExactArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
-			lp := action.ListPackages{IndexReference: args[0]}
+			reg, err := util.CreateCLIRegistry(cmd)
+			if err != nil {
+				logger.Fatal(err)
+			}
+			defer func() {
+				_ = reg.Destroy()
+			}()
+			lp := action.ListPackages{IndexReference: args[0], Registry: reg}
 			res, err := lp.Run(cmd.Context())
 			if err != nil {
 				logger.Fatal(err)
@@ -61,7 +70,14 @@ func newChannelsCmd() *cobra.Command {
 ` + humanReadabilityOnlyNote,
 		Args: cobra.RangeArgs(1, 2),
 		RunE: func(cmd *cobra.Command, args []string) error {
-			lc := action.ListChannels{IndexReference: args[0]}
+			reg, err := util.CreateCLIRegistry(cmd)
+			if err != nil {
+				logger.Fatal(err)
+			}
+			defer func() {
+				_ = reg.Destroy()
+			}()
+			lc := action.ListChannels{IndexReference: args[0], Registry: reg}
 			if len(args) > 1 {
 				lc.PackageName = args[1]
 			}
@@ -90,7 +106,14 @@ for each channel in which the bundle is present).
 ` + humanReadabilityOnlyNote,
 		Args: cobra.RangeArgs(1, 2),
 		RunE: func(cmd *cobra.Command, args []string) error {
-			lb := action.ListBundles{IndexReference: args[0]}
+			reg, err := util.CreateCLIRegistry(cmd)
+			if err != nil {
+				logger.Fatal(err)
+			}
+			defer func() {
+				_ = reg.Destroy()
+			}()
+			lb := action.ListBundles{IndexReference: args[0], Registry: reg}
 			if len(args) > 1 {
 				lb.PackageName = args[1]
 			}
diff --git a/cmd/opm/alpha/render-graph/cmd.go b/cmd/opm/alpha/render-graph/cmd.go
new file mode 100644
index 000000000..29d36eef9
--- /dev/null
+++ b/cmd/opm/alpha/render-graph/cmd.go
@@ -0,0 +1,79 @@
+package rendergraph
+
+import (
+	"io"
+	"log"
+	"os"
+
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
+)
+
+func NewCmd() *cobra.Command {
+	var (
+		render               action.Render
+		minEdge              string
+		specifiedPackageName string
+	)
+	cmd := &cobra.Command{
+		Use:   "render-graph [index-image | fbc-dir]",
+		Short: "Generate mermaid-formatted view of upgrade graph of operators in an index",
+		Long:  `Generate mermaid-formatted view of upgrade graphs of operators in an index`,
+		Args:  cobra.MinimumNArgs(1),
+		Example: `
+#
+# Output channel graph of a catalog in mermaid format
+#
+$ opm alpha render-graph quay.io/operatorhubio/catalog:latest
+
+#
+# Output channel graph of a catalog and generate a scaled vector graphic (SVG) representation
+#
+$ opm alpha render-graph quay.io/operatorhubio/catalog:latest | \
+    docker run --rm -i -v "$PWD":/data ghcr.io/mermaid-js/mermaid-cli/mermaid-cli -o /data/operatorhubio-catalog.svg
+
+# Note:  mermaid has a default maxTextSize of 30 000 characters.  To override this, generate a JSON-formatted initialization file for
+# mermaid like this (using 300 000 for the limit):
+$ cat << EOF > ./mermaid.json
+{ "maxTextSize": 300000 }
+EOF
+# and then pass the file for initialization configuration, via the '-c' option, like:
+$ opm alpha render-graph quay.io/operatorhubio/catalog:latest | \
+    docker run --rm -i -v "$PWD":/data ghcr.io/mermaid-js/mermaid-cli/mermaid-cli -c /data/mermaid.json -o /data/operatorhubio-catalog.svg
+
+
+		`,
+		Run: func(cmd *cobra.Command, args []string) {
+			// The bundle loading impl is somewhat verbose, even on the happy path,
+			// so discard all logrus default logger logs. Any important failures will be
+			// returned from render.Run and logged as fatal errors.
+			logrus.SetOutput(io.Discard)
+
+			registry, err := util.CreateCLIRegistry(cmd)
+			if err != nil {
+				log.Fatal(err)
+			}
+
+			render.Refs = args
+			render.AllowedRefMask = action.RefDCImage | action.RefDCDir | action.RefSqliteImage | action.RefSqliteFile
+			render.Registry = registry
+
+			cfg, err := render.Run(cmd.Context())
+			if err != nil {
+				log.Fatal(err)
+			}
+
+			writer := declcfg.NewMermaidWriter(declcfg.WithMinEdgeName(minEdge), declcfg.WithSpecifiedPackageName(specifiedPackageName))
+			if err := writer.WriteChannels(*cfg, os.Stdout); err != nil {
+				log.Fatal(err)
+			}
+		},
+	}
+	cmd.Flags().StringVar(&minEdge, "minimum-edge", "", "the channel edge to be used as the lower bound of the set of edges composing the upgrade graph; default is to include all edges")
+	cmd.Flags().StringVarP(&specifiedPackageName, "package-name", "p", "", "a specific package name to filter output; default is to include all packages in reference")
+	return cmd
+}
diff --git a/cmd/opm/alpha/template/basic.go b/cmd/opm/alpha/template/basic.go
new file mode 100644
index 000000000..de6aed367
--- /dev/null
+++ b/cmd/opm/alpha/template/basic.go
@@ -0,0 +1,103 @@
+package template
+
+import (
+	"context"
+	"io"
+	"log"
+	"os"
+
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/alpha/action/migrations"
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/template/basic"
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
+)
+
+func newBasicTemplateCmd() *cobra.Command {
+	var (
+		template     basic.Template
+		migrateLevel string
+	)
+	cmd := &cobra.Command{
+		Use: "basic basic-template-file",
+		Short: `Generate a file-based catalog from a single 'basic template' file
+When FILE is '-' or not provided, the template is read from standard input`,
+		Long: `Generate a file-based catalog from a single 'basic template' file
+When FILE is '-' or not provided, the template is read from standard input`,
+		Args: cobra.MaximumNArgs(1),
+		Run: func(cmd *cobra.Command, args []string) {
+			// Handle different input argument types
+			// When no arguments or "-" is passed to the command,
+			// assume input is coming from stdin
+			// Otherwise open the file passed to the command
+			data, source, err := util.OpenFileOrStdin(cmd, args)
+			if err != nil {
+				log.Fatalf("unable to open %q: %v", source, err)
+			}
+			defer data.Close()
+
+			var write func(declcfg.DeclarativeConfig, io.Writer) error
+			output, err := cmd.Flags().GetString("output")
+			if err != nil {
+				log.Fatalf("unable to determine output format")
+			}
+			switch output {
+			case "yaml":
+				write = declcfg.WriteYAML
+			case "json":
+				write = declcfg.WriteJSON
+			default:
+				log.Fatalf("invalid --output value %q, expected (json|yaml)", output)
+			}
+
+			// The bundle loading impl is somewhat verbose, even on the happy path,
+			// so discard all logrus default logger logs. Any important failures will be
+			// returned from template.Render and logged as fatal errors.
+			logrus.SetOutput(io.Discard)
+
+			reg, err := util.CreateCLIRegistry(cmd)
+			if err != nil {
+				log.Fatalf("creating containerd registry: %v", err)
+			}
+			defer func() {
+				_ = reg.Destroy()
+			}()
+
+			var m *migrations.Migrations
+			if migrateLevel != "" {
+				m, err = migrations.NewMigrations(migrateLevel)
+				if err != nil {
+					log.Fatal(err)
+				}
+			}
+
+			template.RenderBundle = func(ctx context.Context, image string) (*declcfg.DeclarativeConfig, error) {
+				// populate registry, incl any flags from CLI, and enforce only rendering bundle images
+				r := action.Render{
+					Refs:           []string{image},
+					Registry:       reg,
+					AllowedRefMask: action.RefBundleImage,
+					Migrations:     m,
+				}
+				return r.Run(ctx)
+			}
+
+			// only taking first file argument
+			cfg, err := template.Render(cmd.Context(), data)
+			if err != nil {
+				log.Fatal(err)
+			}
+
+			if err := write(*cfg, os.Stdout); err != nil {
+				log.Fatal(err)
+			}
+		},
+	}
+
+	cmd.Flags().StringVar(&migrateLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText())
+
+	return cmd
+}
diff --git a/cmd/opm/alpha/template/cmd.go b/cmd/opm/alpha/template/cmd.go
new file mode 100644
index 000000000..55ac55187
--- /dev/null
+++ b/cmd/opm/alpha/template/cmd.go
@@ -0,0 +1,27 @@
+package template
+
+import (
+	"github.com/spf13/cobra"
+)
+
+func NewCmd() *cobra.Command {
+	var output string
+
+	runCmd := &cobra.Command{
+		Use:   "render-template",
+		Short: "Render a catalog template type",
+		Args:  cobra.NoArgs,
+	}
+
+	bc := newBasicTemplateCmd()
+	// bc.Hidden = true
+	runCmd.AddCommand(bc)
+
+	sc := newSemverTemplateCmd()
+	// sc.Hidden = true
+	runCmd.AddCommand(sc)
+
+	runCmd.PersistentFlags().StringVarP(&output, "output", "o", "json", "Output format (json|yaml)")
+
+	return runCmd
+}
diff --git a/cmd/opm/alpha/template/semver.go b/cmd/opm/alpha/template/semver.go
new file mode 100644
index 000000000..eb07ab568
--- /dev/null
+++ b/cmd/opm/alpha/template/semver.go
@@ -0,0 +1,114 @@
+package template
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"log"
+	"os"
+
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/alpha/action/migrations"
+	"github.com/operator-framework/operator-registry/alpha/declcfg"
+	"github.com/operator-framework/operator-registry/alpha/template/semver"
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
+)
+
+func newSemverTemplateCmd() *cobra.Command {
+	var (
+		migrateLevel string
+	)
+
+	cmd := &cobra.Command{
+		Use: "semver [FILE]",
+		Short: `Generate a file-based catalog from a single 'semver template' file
+When FILE is '-' or not provided, the template is read from standard input`,
+		Long: `Generate a file-based catalog from a single 'semver template' file
+When FILE is '-' or not provided, the template is read from standard input`,
+		Args: cobra.MaximumNArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			// Handle different input argument types
+			// When no arguments or "-" is passed to the command,
+			// assume input is coming from stdin
+			// Otherwise open the file passed to the command
+			data, source, err := util.OpenFileOrStdin(cmd, args)
+			if err != nil {
+				return err
+			}
+			defer data.Close()
+
+			var write func(declcfg.DeclarativeConfig, io.Writer) error
+			output, err := cmd.Flags().GetString("output")
+			if err != nil {
+				log.Fatalf("unable to determine output format")
+			}
+			switch output {
+			case "json":
+				write = declcfg.WriteJSON
+			case "yaml":
+				write = declcfg.WriteYAML
+			case "mermaid":
+				write = func(cfg declcfg.DeclarativeConfig, writer io.Writer) error {
+					mermaidWriter := declcfg.NewMermaidWriter()
+					return mermaidWriter.WriteChannels(cfg, writer)
+				}
+			default:
+				return fmt.Errorf("invalid output format %q", output)
+			}
+
+			// The bundle loading impl is somewhat verbose, even on the happy path,
+			// so discard all logrus default logger logs. Any important failures will be
+			// returned from template.Render and logged as fatal errors.
+			logrus.SetOutput(io.Discard)
+
+			reg, err := util.CreateCLIRegistry(cmd)
+			if err != nil {
+				log.Fatalf("creating containerd registry: %v", err)
+			}
+			defer func() {
+				_ = reg.Destroy()
+			}()
+
+			var m *migrations.Migrations
+			if migrateLevel != "" {
+				m, err = migrations.NewMigrations(migrateLevel)
+				if err != nil {
+					log.Fatal(err)
+				}
+			}
+
+			template := semver.Template{
+				Data: data,
+				RenderBundle: func(ctx context.Context, ref string) (*declcfg.DeclarativeConfig, error) {
+					renderer := action.Render{
+						Refs:           []string{ref},
+						Registry:       reg,
+						AllowedRefMask: action.RefBundleImage,
+						Migrations:     m,
+					}
+					return renderer.Run(ctx)
+				},
+			}
+
+			out, err := template.Render(cmd.Context())
+			if err != nil {
+				log.Fatalf("semver %q: %v", source, err)
+			}
+
+			if out != nil {
+				if err := write(*out, os.Stdout); err != nil {
+					log.Fatal(err)
+				}
+			}
+
+			return nil
+		},
+	}
+
+	cmd.Flags().StringVar(&migrateLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText())
+
+	return cmd
+}
diff --git a/cmd/opm/generate/cmd.go b/cmd/opm/generate/cmd.go
new file mode 100644
index 000000000..7eb2315d8
--- /dev/null
+++ b/cmd/opm/generate/cmd.go
@@ -0,0 +1,128 @@
+package generate
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"github.com/sirupsen/logrus"
+	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/pkg/containertools"
+)
+
+func NewCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "generate",
+		Short: "Generate various artifacts for file-based catalogs",
+	}
+	cmd.AddCommand(
+		newDockerfileCmd(),
+	)
+	return cmd
+}
+
+func newDockerfileCmd() *cobra.Command {
+	var (
+		baseImage      string
+		builderImage   string
+		extraLabelStrs []string
+	)
+	cmd := &cobra.Command{
+		Use:   "dockerfile <fbcRootDir>",
+		Args:  cobra.ExactArgs(1),
+		Short: "Generate a Dockerfile for a file-based catalog",
+		Long: `Generate a Dockerfile for a file-based catalog.
+
+This command creates a Dockerfile in the same directory as the <fbcRootDir>
+(named <fbcRootDir>.Dockerfile) that can be used to build the index. If a
+Dockerfile with the same name already exists, this command will fail.
+
+When specifying extra labels, note that if duplicate keys exist, only the last
+value of each duplicate key will be added to the generated Dockerfile.
+
+A separate builder and base image can be specified. The builder image may not be "scratch".
+`,
+		RunE: func(inCmd *cobra.Command, args []string) error {
+			fromDir := filepath.Clean(args[0])
+
+			if builderImage == "scratch" {
+				return fmt.Errorf("invalid builder image: %q", builderImage)
+			}
+
+			// preserving old behavior, if binary-image is set but not builder-image, set builder-image to binary-image
+			if inCmd.Flags().Changed("binary-image") && !inCmd.Flags().Changed("builder-image") {
+				builderImage = baseImage
+			}
+
+			extraLabels, err := parseLabels(extraLabelStrs)
+			if err != nil {
+				return err
+			}
+
+			dir, indexName := filepath.Split(fromDir)
+			dockerfilePath := filepath.Join(dir, fmt.Sprintf("%s.Dockerfile", indexName))
+
+			if err := ensureNotExist(dockerfilePath); err != nil {
+				logrus.Fatal(err)
+			}
+
+			if s, err := os.Stat(fromDir); err != nil {
+				return err
+			} else if !s.IsDir() {
+				return fmt.Errorf("provided root path %q is not a directory", fromDir)
+			}
+
+			f, err := os.OpenFile(dockerfilePath, os.O_CREATE|os.O_WRONLY, 0666)
+			if err != nil {
+				logrus.Fatal(err)
+			}
+			defer f.Close()
+
+			gen := action.GenerateDockerfile{
+				BaseImage:    baseImage,
+				BuilderImage: builderImage,
+				IndexDir:     indexName,
+				ExtraLabels:  extraLabels,
+				Writer:       f,
+			}
+			if err := gen.Run(); err != nil {
+				log.Fatal(err)
+			}
+			return nil
+		},
+	}
+	cmd.Flags().StringVar(&baseImage, "binary-image", containertools.DefaultBinarySourceImage, "Image in which to build catalog.")
+	cmd.Flags().StringVarP(&baseImage, "base-image", "i", containertools.DefaultBinarySourceImage, "Image base to use to build catalog.")
+	cmd.Flags().StringVarP(&builderImage, "builder-image", "b", containertools.DefaultBinarySourceImage, "Image to use as a build stage.")
+	cmd.Flags().StringSliceVarP(&extraLabelStrs, "extra-labels", "l", []string{}, "Extra labels to include in the generated Dockerfile. Labels should be of the form 'key=value'.")
+	_ = cmd.Flags().MarkDeprecated("binary-image", "use --base-image instead")
+	cmd.MarkFlagsMutuallyExclusive("binary-image", "base-image")
+	return cmd
+}
+
+func parseLabels(labelStrs []string) (map[string]string, error) {
+	labels := map[string]string{}
+	for _, l := range labelStrs {
+		spl := strings.SplitN(l, "=", 2)
+		if len(spl) != 2 {
+			return nil, fmt.Errorf("invalid label %q", l)
+		}
+		labels[spl[0]] = spl[1]
+	}
+	return labels, nil
+}
+
+func ensureNotExist(path string) error {
+	_, err := os.Stat(path)
+	if err != nil && !os.IsNotExist(err) {
+		return err
+	}
+	if err == nil {
+		return fmt.Errorf("path %q: %w", path, os.ErrExist)
+	}
+	return nil
+}
diff --git a/cmd/opm/index/add.go b/cmd/opm/index/add.go
index ea218d6e0..7e8c8cb39 100644
--- a/cmd/opm/index/add.go
+++ b/cmd/opm/index/add.go
@@ -7,6 +7,7 @@ import (
 	"github.com/spf13/cobra"
 	"k8s.io/kubectl/pkg/util/templates"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/indexer"
 	"github.com/operator-framework/operator-registry/pkg/registry"
@@ -40,7 +41,7 @@ var (
 	`)
 )
 
-func addIndexAddCmd(parent *cobra.Command) {
+func addIndexAddCmd(parent *cobra.Command, showAlphaHelp bool) {
 	indexCmd := &cobra.Command{
 		Use:   "add",
 		Short: "Add operator bundles to an index.",
@@ -77,8 +78,10 @@ func addIndexAddCmd(parent *cobra.Command) {
 		logrus.Panic(err.Error())
 	}
 	indexCmd.Flags().Bool("enable-alpha", false, "enable unsupported alpha features of the OPM CLI")
-	if err := indexCmd.Flags().MarkHidden("enable-alpha"); err != nil {
-		logrus.Panic(err.Error())
+	if !showAlphaHelp {
+		if err := indexCmd.Flags().MarkHidden("enable-alpha"); err != nil {
+			logrus.Panic(err.Error())
+		}
 	}
 	if err := indexCmd.Flags().MarkHidden("debug"); err != nil {
 		logrus.Panic(err.Error())
@@ -87,7 +90,6 @@ func addIndexAddCmd(parent *cobra.Command) {
 	// Set the example after the parent has been set to get the correct command path
 	parent.AddCommand(indexCmd)
 	indexCmd.Example = fmt.Sprintf(addExample, indexCmd.CommandPath())
-
 }
 
 func runIndexAddCmdFunc(cmd *cobra.Command, _ []string) error {
@@ -126,7 +128,7 @@ func runIndexAddCmdFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
@@ -174,7 +176,8 @@ func runIndexAddCmdFunc(cmd *cobra.Command, _ []string) error {
 		Bundles:           bundles,
 		Permissive:        permissive,
 		Mode:              modeEnum,
-		SkipTLS:           skipTLS,
+		SkipTLSVerify:     skipTLSVerify,
+		PlainHTTP:         useHTTP,
 		Overwrite:         overwrite,
 		EnableAlpha:       enableAlpha,
 	}
@@ -209,7 +212,7 @@ func getContainerTools(cmd *cobra.Command) (string, string, error) {
 		return "", "", err
 	}
 
-	// Backwards compatiblity mode
+	// Backwards compatibility mode
 	if containerTool != "" {
 		if pullTool == "" && buildTool == "" {
 			return containerTool, containerTool, nil
diff --git a/cmd/opm/index/cmd.go b/cmd/opm/index/cmd.go
index b7cdd14d1..8ee008e09 100644
--- a/cmd/opm/index/cmd.go
+++ b/cmd/opm/index/cmd.go
@@ -8,7 +8,7 @@ import (
 )
 
 // AddCommand adds the index subcommand to the given parent command.
-func AddCommand(parent *cobra.Command) {
+func AddCommand(parent *cobra.Command, showAlphaHelp bool) {
 	cmd := &cobra.Command{
 		Use:   "index",
 		Short: "generate operator index container images",
@@ -32,9 +32,9 @@ func AddCommand(parent *cobra.Command) {
 	}
 
 	parent.AddCommand(cmd)
-	parent.PersistentFlags().Bool("skip-tls", false, "skip TLS certificate verification for container image registries while pulling bundles or index")
+
 	cmd.AddCommand(newIndexDeleteCmd())
-	addIndexAddCmd(cmd)
+	addIndexAddCmd(cmd, showAlphaHelp)
 	cmd.AddCommand(newIndexExportCmd())
 	cmd.AddCommand(newIndexPruneCmd())
 	cmd.AddCommand(newIndexDeprecateTruncateCmd())
diff --git a/cmd/opm/index/delete.go b/cmd/opm/index/delete.go
index c9472b8ed..39a905f10 100644
--- a/cmd/opm/index/delete.go
+++ b/cmd/opm/index/delete.go
@@ -4,6 +4,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/indexer"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
@@ -51,7 +52,6 @@ func newIndexDeleteCmd() *cobra.Command {
 	}
 
 	return indexCmd
-
 }
 
 func runIndexDeleteCmdFunc(cmd *cobra.Command, _ []string) error {
@@ -95,7 +95,7 @@ func runIndexDeleteCmdFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
@@ -117,7 +117,8 @@ func runIndexDeleteCmdFunc(cmd *cobra.Command, _ []string) error {
 		Operators:         operators,
 		Tag:               tag,
 		Permissive:        permissive,
-		SkipTLS:           skipTLS,
+		SkipTLSVerify:     skipTLSVerify,
+		PlainHTTP:         useHTTP,
 	}
 
 	err = indexDeleter.DeleteFromIndex(request)
diff --git a/cmd/opm/index/deprecatetruncate.go b/cmd/opm/index/deprecatetruncate.go
index 9324d35b8..33206e323 100644
--- a/cmd/opm/index/deprecatetruncate.go
+++ b/cmd/opm/index/deprecatetruncate.go
@@ -5,6 +5,7 @@ import (
 	"github.com/spf13/cobra"
 	"k8s.io/kubectl/pkg/util/templates"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/indexer"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
@@ -110,7 +111,7 @@ func runIndexDeprecateTruncateCmdFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
@@ -137,7 +138,8 @@ func runIndexDeprecateTruncateCmdFunc(cmd *cobra.Command, _ []string) error {
 		Tag:                 tag,
 		Bundles:             bundles,
 		Permissive:          permissive,
-		SkipTLS:             skipTLS,
+		SkipTLSVerify:       skipTLSVerify,
+		PlainHTTP:           useHTTP,
 		AllowPackageRemoval: allowPackageRemoval,
 	}
 
diff --git a/cmd/opm/index/export.go b/cmd/opm/index/export.go
index f4e32672e..f18674b09 100644
--- a/cmd/opm/index/export.go
+++ b/cmd/opm/index/export.go
@@ -7,6 +7,7 @@ import (
 	"github.com/spf13/cobra"
 	"k8s.io/kubectl/pkg/util/templates"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/indexer"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
@@ -56,7 +57,6 @@ func newIndexExportCmd() *cobra.Command {
 	}
 
 	return indexCmd
-
 }
 
 func runIndexExportCmdFunc(cmd *cobra.Command, _ []string) error {
@@ -100,7 +100,7 @@ func runIndexExportCmdFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
@@ -116,7 +116,8 @@ func runIndexExportCmdFunc(cmd *cobra.Command, _ []string) error {
 		Packages:      packages,
 		DownloadPath:  downloadPath,
 		ContainerTool: containertools.NewContainerTool(containerTool, containertools.NoneTool),
-		SkipTLS:       skipTLS,
+		SkipTLSVerify: skipTLSVerify,
+		PlainHTTP:     useHTTP,
 	}
 
 	err = indexExporter.ExportFromIndex(request)
diff --git a/cmd/opm/index/prune.go b/cmd/opm/index/prune.go
index c80ebf619..d457b2d7f 100644
--- a/cmd/opm/index/prune.go
+++ b/cmd/opm/index/prune.go
@@ -6,6 +6,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/indexer"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
@@ -51,7 +52,6 @@ func newIndexPruneCmd() *cobra.Command {
 	}
 
 	return indexCmd
-
 }
 
 func runIndexPruneCmdFunc(cmd *cobra.Command, _ []string) error {
@@ -99,7 +99,7 @@ func runIndexPruneCmdFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
@@ -118,7 +118,8 @@ func runIndexPruneCmdFunc(cmd *cobra.Command, _ []string) error {
 		Packages:          packages,
 		Tag:               tag,
 		Permissive:        permissive,
-		SkipTLS:           skipTLS,
+		SkipTLSVerify:     skipTLSVerify,
+		PlainHTTP:         useHTTP,
 	}
 
 	err = indexPruner.PruneFromIndex(request)
diff --git a/cmd/opm/index/prunestranded.go b/cmd/opm/index/prunestranded.go
index 03e739cff..8b6f397dd 100644
--- a/cmd/opm/index/prunestranded.go
+++ b/cmd/opm/index/prunestranded.go
@@ -6,6 +6,7 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/indexer"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
@@ -46,7 +47,6 @@ func newIndexPruneStrandedCmd() *cobra.Command {
 	}
 
 	return indexCmd
-
 }
 
 func runIndexPruneStrandedCmdFunc(cmd *cobra.Command, _ []string) error {
@@ -84,7 +84,7 @@ func runIndexPruneStrandedCmdFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
 	if err != nil {
 		return err
 	}
@@ -101,7 +101,8 @@ func runIndexPruneStrandedCmdFunc(cmd *cobra.Command, _ []string) error {
 		BinarySourceImage: binaryImage,
 		OutDockerfile:     outDockerfile,
 		Tag:               tag,
-		SkipTLS:           skipTLS,
+		SkipTLSVerify:     skipTLSVerify,
+		PlainHTTP:         useHTTP,
 	}
 
 	err = indexPruner.PruneStrandedFromIndex(request)
diff --git a/cmd/opm/internal/util/util.go b/cmd/opm/internal/util/util.go
new file mode 100644
index 000000000..e007caa48
--- /dev/null
+++ b/cmd/opm/internal/util/util.go
@@ -0,0 +1,77 @@
+package util
+
+import (
+	"errors"
+	"io"
+	"os"
+
+	"github.com/spf13/cobra"
+
+	"github.com/operator-framework/operator-registry/pkg/image/containerdregistry"
+	"github.com/operator-framework/operator-registry/pkg/lib/log"
+)
+
+// GetTLSOptions validates and returns TLS options set by opm flags
+func GetTLSOptions(cmd *cobra.Command) (bool, bool, error) {
+	skipTLS, err := cmd.Flags().GetBool("skip-tls")
+	if err != nil {
+		return false, false, err
+	}
+	skipTLSVerify, err := cmd.Flags().GetBool("skip-tls-verify")
+	if err != nil {
+		return false, false, err
+	}
+	useHTTP, err := cmd.Flags().GetBool("use-http")
+	if err != nil {
+		return false, false, err
+	}
+
+	switch {
+	case cmd.Flags().Changed("skip-tls") && cmd.Flags().Changed("use-http"):
+		return false, false, errors.New("invalid flag combination: cannot use --use-http with --skip-tls")
+	case cmd.Flags().Changed("skip-tls") && cmd.Flags().Changed("skip-tls-verify"):
+		return false, false, errors.New("invalid flag combination: cannot use --skip-tls-verify with --skip-tls")
+	case skipTLSVerify && useHTTP:
+		return false, false, errors.New("invalid flag combination: --use-http and --skip-tls-verify cannot both be true")
+	default:
+		// return use HTTP true if just skipTLS
+		// is set for functional parity with existing
+		if skipTLS {
+			return false, true, nil
+		}
+		return skipTLSVerify, useHTTP, nil
+	}
+}
+
+// This works in tandem with opm/index/cmd, which adds the relevant flags as persistent
+// as part of the root command (cmd/root/cmd) initialization
+func CreateCLIRegistry(cmd *cobra.Command) (*containerdregistry.Registry, error) {
+	skipTLSVerify, useHTTP, err := GetTLSOptions(cmd)
+	if err != nil {
+		return nil, err
+	}
+
+	cacheDir, err := os.MkdirTemp("", "opm-registry-")
+	if err != nil {
+		return nil, err
+	}
+
+	reg, err := containerdregistry.NewRegistry(
+		containerdregistry.WithCacheDir(cacheDir),
+		containerdregistry.SkipTLSVerify(skipTLSVerify),
+		containerdregistry.WithPlainHTTP(useHTTP),
+		containerdregistry.WithLog(log.Null()),
+	)
+	if err != nil {
+		return nil, err
+	}
+	return reg, nil
+}
+
+func OpenFileOrStdin(cmd *cobra.Command, args []string) (io.ReadCloser, string, error) {
+	if len(args) == 0 || args[0] == "-" {
+		return io.NopCloser(cmd.InOrStdin()), "stdin", nil
+	}
+	reader, err := os.Open(args[0])
+	return reader, args[0], err
+}
diff --git a/cmd/opm/main.go b/cmd/opm/main.go
index bd3c29166..ce734a1a0 100644
--- a/cmd/opm/main.go
+++ b/cmd/opm/main.go
@@ -1,7 +1,11 @@
 package main
 
 import (
+	"context"
+	"errors"
 	"os"
+	"os/signal"
+	"syscall"
 
 	utilerrors "k8s.io/apimachinery/pkg/util/errors"
 
@@ -10,17 +14,24 @@ import (
 )
 
 func main() {
-	cmd := root.NewCmd()
-	if err := cmd.Execute(); err != nil {
-		agg, ok := err.(utilerrors.Aggregate)
-		if !ok {
+	showAlphaHelp := os.Getenv("HELP_ALPHA") == "true"
+	cmd := root.NewCmd(showAlphaHelp)
+
+	ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+	defer cancel()
+
+	if err := cmd.ExecuteContext(ctx); err != nil {
+		var agg utilerrors.Aggregate
+		if !errors.As(err, &agg) {
 			os.Exit(1)
 		}
 		for _, e := range agg.Errors() {
-			if _, ok := e.(registrylib.BundleImageAlreadyAddedErr); ok {
+			var bundleAlreadyAddedErr registrylib.BundleImageAlreadyAddedErr
+			if errors.As(e, &bundleAlreadyAddedErr) {
 				os.Exit(2)
 			}
-			if _, ok := e.(registrylib.PackageVersionAlreadyAddedErr); ok {
+			var packageVersionAlreadyAddedErr registrylib.PackageVersionAlreadyAddedErr
+			if errors.As(e, &packageVersionAlreadyAddedErr) {
 				os.Exit(3)
 			}
 		}
diff --git a/cmd/opm/migrate/cmd.go b/cmd/opm/migrate/cmd.go
index 6405060b0..edf496a33 100644
--- a/cmd/opm/migrate/cmd.go
+++ b/cmd/opm/migrate/cmd.go
@@ -7,25 +7,28 @@ import (
 	"github.com/spf13/cobra"
 
 	"github.com/operator-framework/operator-registry/alpha/action"
+	"github.com/operator-framework/operator-registry/alpha/action/migrations"
 	"github.com/operator-framework/operator-registry/alpha/declcfg"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
 )
 
 func NewCmd() *cobra.Command {
 	var (
-		migrate action.Migrate
-		output  string
+		migrate      action.Migrate
+		migrateLevel string
+		output       string
 	)
 	cmd := &cobra.Command{
 		Use:   "migrate <indexRef> <outputDir>",
 		Short: "Migrate a sqlite-based index image or database file to a file-based catalog",
 		Long: `Migrate a sqlite-based index image or database file to a file-based catalog.
 
+NOTE: the --output=json format produces streamable, concatenated JSON files.
+These are suitable to opm and jq, but may not be supported by arbitrary JSON
+parsers that assume that a file contains exactly one valid JSON object.
+
 ` + sqlite.DeprecationMessage,
 		Args: cobra.ExactArgs(2),
-		PersistentPreRun: func(_ *cobra.Command, _ []string) {
-			sqlite.LogSqliteDeprecation()
-		},
 		RunE: func(cmd *cobra.Command, args []string) error {
 			migrate.CatalogRef = args[0]
 			migrate.OutputDir = args[1]
@@ -41,6 +44,14 @@ func NewCmd() *cobra.Command {
 				log.Fatalf("invalid --output value %q, expected (json|yaml)", output)
 			}
 
+			if migrateLevel != "" {
+				m, err := migrations.NewMigrations(migrateLevel)
+				if err != nil {
+					log.Fatal(err)
+				}
+				migrate.Migrations = m
+			}
+
 			logrus.Infof("rendering index %q as file-based catalog", migrate.CatalogRef)
 			if err := migrate.Run(cmd.Context()); err != nil {
 				logrus.New().Fatal(err)
@@ -50,5 +61,7 @@ func NewCmd() *cobra.Command {
 		},
 	}
 	cmd.Flags().StringVarP(&output, "output", "o", "json", "Output format (json|yaml)")
+	cmd.Flags().StringVar(&migrateLevel, "migrate-level", "", "Name of the last migration to run (default: none)\n"+migrations.HelpText())
+
 	return cmd
 }
diff --git a/cmd/opm/registry/add.go b/cmd/opm/registry/add.go
index ceb3fcd1a..12e1fa308 100644
--- a/cmd/opm/registry/add.go
+++ b/cmd/opm/registry/add.go
@@ -7,13 +7,14 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
+	"github.com/operator-framework/operator-registry/cmd/opm/internal/util"
 	"github.com/operator-framework/operator-registry/pkg/containertools"
 	"github.com/operator-framework/operator-registry/pkg/lib/registry"
 	reg "github.com/operator-framework/operator-registry/pkg/registry"
 	"github.com/operator-framework/operator-registry/pkg/sqlite"
 )
 
-func newRegistryAddCmd() *cobra.Command {
+func newRegistryAddCmd(showAlphaHelp bool) *cobra.Command {
 	rootCmd := &cobra.Command{
 		Use:   "add",
 		Short: "add operator bundle to operator registry DB",
@@ -36,7 +37,9 @@ func newRegistryAddCmd() *cobra.Command {
 	rootCmd.Flags().StringP("database", "d", "bundles.db", "relative path to database file")
 	rootCmd.Flags().StringSliceP("bundle-images", "b", []string{}, "comma separated list of links to bundle image")
 	rootCmd.Flags().Bool("permissive", false, "allow registry load errors")
-	rootCmd.Flags().Bool("skip-tls", false, "skip TLS certificate verification for container image registries while pulling bundles")
+	rootCmd.Flags().Bool("skip-tls", false, "use Plain HTTP for container image registries while pulling bundles")
+	rootCmd.Flags().Bool("skip-tls-verify", false, "skip TLS certificate verification for container image registries while pulling bundles")
+	rootCmd.Flags().Bool("use-http", false, "use plain HTTP for container image registries while pulling bundles")
 	rootCmd.Flags().String("ca-file", "", "the root certificates to use when --container-tool=none; see docker/podman docs for certificate loading instructions")
 	rootCmd.Flags().StringP("mode", "", "replaces", "graph update mode that defines how channel graphs are updated. One of: [replaces, semver, semver-skippatch]")
 	rootCmd.Flags().StringP("container-tool", "c", "none", "tool to interact with container images (save, build, etc.). One of: [none, docker, podman]")
@@ -45,7 +48,12 @@ func newRegistryAddCmd() *cobra.Command {
 		logrus.Panic(err.Error())
 	}
 	rootCmd.Flags().Bool("enable-alpha", false, "enable unsupported alpha features of the OPM CLI")
-	if err := rootCmd.Flags().MarkHidden("enable-alpha"); err != nil {
+	if !showAlphaHelp {
+		if err := rootCmd.Flags().MarkHidden("enable-alpha"); err != nil {
+			logrus.Panic(err.Error())
+		}
+	}
+	if err := rootCmd.Flags().MarkDeprecated("skip-tls", "use --use-http and --skip-tls-verify instead"); err != nil {
 		logrus.Panic(err.Error())
 	}
 	return rootCmd
@@ -56,10 +64,6 @@ func addFunc(cmd *cobra.Command, _ []string) error {
 	if err != nil {
 		return err
 	}
-	skipTLS, err := cmd.Flags().GetBool("skip-tls")
-	if err != nil {
-		return err
-	}
 	caFile, err := cmd.Flags().GetString("ca-file")
 	if err != nil {
 		return err
@@ -95,9 +99,14 @@ func addFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
+	skipTLSVerify, useHTTP, err := util.GetTLSOptions(cmd)
+	if err != nil {
+		return err
+	}
+
 	if caFile != "" {
-		if skipTLS {
-			return errors.New("--skip-tls must be false when --ca-file is set")
+		if skipTLSVerify {
+			return errors.New("--skip-tls-verify must be false when --ca-file is set")
 		}
 		if containerTool != containertools.NoneTool {
 			return fmt.Errorf("--ca-file cannot be set with --container-tool=%[1]s; "+
@@ -107,7 +116,8 @@ func addFunc(cmd *cobra.Command, _ []string) error {
 
 	request := registry.AddToRegistryRequest{
 		Permissive:    permissive,
-		SkipTLS:       skipTLS,
+		SkipTLSVerify: skipTLSVerify,
+		PlainHTTP:     useHTTP,
 		CaFile:        caFile,
 		InputDatabase: fromFilename,
 		Bundles:       bundleImages,
@@ -119,8 +129,12 @@ func addFunc(cmd *cobra.Command, _ []string) error {
 
 	logger := logrus.WithFields(logrus.Fields{"bundles": bundleImages})
 
-	if skipTLS {
-		logger.Warn("--skip-tls flag is set: this mode is insecure and meant for development purposes only.")
+	if skipTLSVerify {
+		logger.Warn("--skip-tls-verify flag is set: this mode is insecure and meant for development purposes only.")
+	}
+
+	if useHTTP {
+		logger.Warn("--use-http flag is set: this mode is insecure and meant for development purposes only.")
 	}
 
 	logger.Info("adding to the registry")
diff --git a/cmd/opm/registry/cmd.go b/cmd/opm/registry/cmd.go
index f4b058bc8..dde29cf0a 100644
--- a/cmd/opm/registry/cmd.go
+++ b/cmd/opm/registry/cmd.go
@@ -8,7 +8,7 @@ import (
 )
 
 // NewOpmRegistryCmd returns the appregistry-server command
-func NewOpmRegistryCmd() *cobra.Command {
+func NewOpmRegistryCmd(showAlphaHelp bool) *cobra.Command {
 	rootCmd := &cobra.Command{
 		Use:   "registry",
 		Short: "interact with operator-registry database",
@@ -28,7 +28,7 @@ func NewOpmRegistryCmd() *cobra.Command {
 	}
 
 	rootCmd.AddCommand(newRegistryServeCmd())
-	rootCmd.AddCommand(newRegistryAddCmd())
+	rootCmd.AddCommand(newRegistryAddCmd(showAlphaHelp))
 	rootCmd.AddCommand(newRegistryRmCmd())
 	rootCmd.AddCommand(newRegistryPruneCmd())
 	rootCmd.AddCommand(newRegistryPruneStrandedCmd())
diff --git a/cmd/opm/registry/serve.go b/cmd/opm/registry/serve.go
index b6defb75e..a5bd65e12 100644
--- a/cmd/opm/registry/serve.go
+++ b/cmd/opm/registry/serve.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"database/sql"
 	"fmt"
+	"math"
 	"net"
 	"os"
 	"strconv"
@@ -12,12 +13,11 @@ import (
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"google.golang.org/grpc"
+	health "google.golang.org/grpc/health/grpc_health_v1"
 	"google.golang.org/grpc/reflection"
 
 	"github.com/operator-framework/operator-registry/pkg/api"
-	health "github.com/operator-framework/operator-registry/pkg/api/grpc_health_v1"
 	"github.com/operator-framework/operator-registry/pkg/lib/dns"
-	"github.com/operator-framework/operator-registry/pkg/lib/graceful"
 	"github.com/operator-framework/operator-registry/pkg/lib/log"
 	"github.com/operator-framework/operator-registry/pkg/lib/tmp"
 	"github.com/operator-framework/operator-registry/pkg/server"
@@ -54,6 +54,9 @@ func newRegistryServeCmd() *cobra.Command {
 }
 
 func serveFunc(cmd *cobra.Command, _ []string) error {
+	ctx, cancel := context.WithCancel(cmd.Context())
+	defer cancel()
+
 	// Immediately set up termination log
 	terminationLogPath, err := cmd.Flags().GetString("termination-log")
 	if err != nil {
@@ -93,19 +96,23 @@ func serveFunc(cmd *cobra.Command, _ []string) error {
 		return err
 	}
 
-	if _, err := db.ExecContext(context.TODO(), `PRAGMA soft_heap_limit=1`); err != nil {
+	if _, err := db.ExecContext(ctx, `PRAGMA soft_heap_limit=1`); err != nil {
 		logger.WithError(err).Warnf("error setting soft heap limit for sqlite")
 	}
 
 	// migrate to the latest version
-	if err := migrate(cmd, db); err != nil {
+	shouldSkipMigrate, err := cmd.Flags().GetBool("skip-migrate")
+	if err != nil {
+		return err
+	}
+	if err := migrate(ctx, shouldSkipMigrate, db); err != nil {
 		logger.WithError(err).Warnf("couldn't migrate db")
 	}
 
 	store := sqlite.NewSQLLiteQuerierFromDb(db, sqlite.OmitManifests(true))
 
 	// sanity check that the db is available
-	tables, err := store.ListTables(context.TODO())
+	tables, err := store.ListTables(ctx)
 	if err != nil {
 		logger.WithError(err).Warnf("couldn't list tables in db")
 	}
@@ -115,7 +122,7 @@ func serveFunc(cmd *cobra.Command, _ []string) error {
 
 	lis, err := net.Listen("tcp", ":"+port)
 	if err != nil {
-		logger.Fatalf("failed to listen: %s", err)
+		return fmt.Errorf("failed to listen: %s", err)
 	}
 
 	timeout, err := cmd.Flags().GetString("timeout-seconds")
@@ -126,10 +133,18 @@ func serveFunc(cmd *cobra.Command, _ []string) error {
 	s := grpc.NewServer()
 	logger.Printf("Keeping server open for %s seconds", timeout)
 	if timeout != "infinite" {
-		timeoutSeconds, err := strconv.ParseUint(timeout, 10, 16)
+		timeoutInputSeconds, err := strconv.ParseUint(timeout, 10, 16)
 		if err != nil {
 			return err
 		}
+		// duration is a signed int, so capping it to prevent overflow
+		if timeoutInputSeconds > math.MaxInt64 {
+			timeoutInputSeconds = math.MaxInt64
+			logger.Infof("Timeout value too large. Capping to %v.", math.MaxInt64)
+		}
+		// having capped the value to safe ranges, quiet the linter
+		// nolint:gosec
+		timeoutSeconds := int64(timeoutInputSeconds)
 
 		timeoutDuration := time.Duration(timeoutSeconds) * time.Second
 		timer := time.AfterFunc(timeoutDuration, func() {
@@ -142,19 +157,18 @@ func serveFunc(cmd *cobra.Command, _ []string) error {
 	a