From 2c044834ca09b9f0f80d31a575a78141988f418c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charlotte=20=F0=9F=A6=9D=20Delenk?= Date: Sun, 12 Jun 2022 14:06:20 +0100 Subject: [PATCH] Add matrix-media-repo --- .github/workflows/update-flake.yaml | 6 +- flake.lock | 87 +- flake.nix | 5 + matrix/matrix-media-repo/async-media.patch | 1179 ++++++++++++ matrix/matrix-media-repo/default.nix | 28 + matrix/matrix-media-repo/gomod2nix.toml | 1971 ++++++++++++++++++++ matrix/matrix-media-repo/update.sh | 22 + 7 files changed, 3295 insertions(+), 3 deletions(-) create mode 100644 matrix/matrix-media-repo/async-media.patch create mode 100644 matrix/matrix-media-repo/default.nix create mode 100644 matrix/matrix-media-repo/gomod2nix.toml create mode 100755 matrix/matrix-media-repo/update.sh diff --git a/.github/workflows/update-flake.yaml b/.github/workflows/update-flake.yaml index 60da6bb..ecf8917 100644 --- a/.github/workflows/update-flake.yaml +++ b/.github/workflows/update-flake.yaml @@ -17,9 +17,11 @@ jobs: - name: Update flake.lockfile run: nix flake update - name: Run update script for minecraft - run: ./minecraft/update.sh + run: cd minecraft && ./update.sh - name: Run update script for mastodon - run: ./mastodon/update.sh + run: cd mastodon && ./update.sh + - name: Run update script for matrix-media-repo + run: cd matrix/matrix-media-repo && ./update.sh - name: Run nix formatter run: nix fmt - name: Commit and push diff --git a/flake.lock b/flake.lock index 832730e..f70be90 100644 --- a/flake.lock +++ b/flake.lock @@ -31,6 +31,25 @@ "type": "github" } }, + "gomod2nix": { + "inputs": { + "nixpkgs": "nixpkgs", + "utils": "utils" + }, + "locked": { + "lastModified": 1654019497, + "narHash": "sha256-yj53tEaOAJoZ1iEBbZ4TArpgAsLZnmivfr4eD0xF52c=", + "owner": "tweag", + "repo": "gomod2nix", + "rev": "71c797eb0d83f33de7e0247b3ffe7120d98c6b49", + "type": "github" + }, + "original": { + "owner": "tweag", + "repo": "gomod2nix", + "type": "github" + } + }, "mastodon": { "flake": false, "locked": { @@ -47,6 +66,22 @@ "type": "github" } }, + "matrix-media-repo": { + "flake": false, + "locked": { + "lastModified": 1648768263, + "narHash": "sha256-H1S9l5S4gcVU482qYCpDW+Ki0r8VkwBgkbUCk6k63sg=", + "owner": "turt2live", + "repo": "matrix-media-repo", + "rev": "3184dbc7720fc103aaf4704be894eac69535e887", + "type": "github" + }, + "original": { + "owner": "turt2live", + "repo": "matrix-media-repo", + "type": "github" + } + }, "miifox-net": { "flake": false, "locked": { @@ -64,6 +99,38 @@ } }, "nixpkgs": { + "locked": { + "lastModified": 1653581809, + "narHash": "sha256-Uvka0V5MTGbeOfWte25+tfRL3moECDh1VwokWSZUdoY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "83658b28fe638a170a19b8933aa008b30640fbd1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-go116": { + "locked": { + "lastModified": 1653232931, + "narHash": "sha256-t9cmSEy9HRkQ3kO560qI75sDijkWk1k2U7DFa5C7uNY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "dab5668f6be905a7f0de39a7d67fd8f78a13d600", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "dab5668f6be905a7f0de39a7d67fd8f78a13d600", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1654953433, "narHash": "sha256-TwEeh4r50NdWHFAHQSyjCk2cZxgwUfcCCAJOhPdXB28=", @@ -82,9 +149,27 @@ "inputs": { "clean-s3-cache": "clean-s3-cache", "flake-utils": "flake-utils", + "gomod2nix": "gomod2nix", "mastodon": "mastodon", + "matrix-media-repo": "matrix-media-repo", "miifox-net": "miifox-net", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs_2", + "nixpkgs-go116": "nixpkgs-go116" + } + }, + "utils": { + "locked": { + "lastModified": 1653893745, + "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index 327b3d6..380c5e6 100644 --- a/flake.nix +++ b/flake.nix @@ -12,6 +12,10 @@ miifox-net.flake = false; mastodon.url = "github:glitch-soc/mastodon"; mastodon.flake = false; + nixpkgs-go116.url = "github:NixOS/nixpkgs/dab5668f6be905a7f0de39a7d67fd8f78a13d600"; + matrix-media-repo.url = "github:turt2live/matrix-media-repo"; + matrix-media-repo.flake = false; + gomod2nix.url = "github:tweag/gomod2nix"; }; outputs = { @@ -38,6 +42,7 @@ ./web/miifox-net.nix ./minecraft/paper.nix ./mastodon + ./matrix/matrix-media-repo ]); hydraJobs = { diff --git a/matrix/matrix-media-repo/async-media.patch b/matrix/matrix-media-repo/async-media.patch new file mode 100644 index 0000000..2906f3b --- /dev/null +++ b/matrix/matrix-media-repo/async-media.patch @@ -0,0 +1,1179 @@ +diff --git a/api/r0/download.go b/api/r0/download.go +index d84c74e..e431385 100644 +--- a/api/r0/download.go ++++ b/api/r0/download.go +@@ -48,6 +48,21 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI + downloadRemote = parsedFlag + } + ++ var asyncWaitMs *int = nil ++ if rctx.Config.Features.MSC2246Async.Enabled { ++ // request default wait time if feature enabled ++ var parsedInt int = -1 ++ maxStallMs := r.URL.Query().Get("fi.mau.msc2246.max_stall_ms") ++ if maxStallMs != "" { ++ var err error ++ parsedInt, err = strconv.Atoi(maxStallMs) ++ if err != nil { ++ return api.InternalServerError("fi.mau.msc2246.max_stall_ms does not appear to be a number") ++ } ++ } ++ asyncWaitMs = &parsedInt ++ } ++ + rctx = rctx.LogWithFields(logrus.Fields{ + "mediaId": mediaId, + "server": server, +@@ -55,7 +70,7 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI + "allowRemote": downloadRemote, + }) + +- streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, false, rctx) ++ streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, false, asyncWaitMs, rctx) + if err != nil { + if err == common.ErrMediaNotFound { + return api.NotFoundError() +@@ -63,6 +78,8 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI + return api.RequestTooLarge() + } else if err == common.ErrMediaQuarantined { + return api.NotFoundError() // We lie for security ++ } else if err == common.ErrNotYetUploaded { ++ return api.NotYetUploaded() + } + rctx.Log.Error("Unexpected error locating media: " + err.Error()) + sentry.CaptureException(err) +diff --git a/api/r0/thumbnail.go b/api/r0/thumbnail.go +index b1b73f0..8392596 100644 +--- a/api/r0/thumbnail.go ++++ b/api/r0/thumbnail.go +@@ -29,6 +29,21 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User + downloadRemote = parsedFlag + } + ++ var asyncWaitMs *int = nil ++ if rctx.Config.Features.MSC2246Async.Enabled { ++ // request default wait time if feature enabled ++ var parsedInt int = -1 ++ maxStallMs := r.URL.Query().Get("fi.mau.msc2246.max_stall_ms") ++ if maxStallMs != "" { ++ var err error ++ parsedInt, err = strconv.Atoi(maxStallMs) ++ if err != nil { ++ return api.InternalServerError("fi.mau.msc2246.max_stall_ms does not appear to be a number") ++ } ++ } ++ asyncWaitMs = &parsedInt ++ } ++ + rctx = rctx.LogWithFields(logrus.Fields{ + "mediaId": mediaId, + "server": server, +@@ -87,12 +102,14 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User + return api.BadRequest("Width and height must be greater than zero") + } + +- streamedThumbnail, err := thumbnail_controller.GetThumbnail(server, mediaId, width, height, animated, method, downloadRemote, rctx) ++ streamedThumbnail, err := thumbnail_controller.GetThumbnail(server, mediaId, width, height, animated, method, downloadRemote, asyncWaitMs, rctx) + if err != nil { + if err == common.ErrMediaNotFound { + return api.NotFoundError() + } else if err == common.ErrMediaTooLarge { + return api.RequestTooLarge() ++ } else if err == common.ErrNotYetUploaded { ++ return api.NotYetUploaded() + } + rctx.Log.Error("Unexpected error locating media: " + err.Error()) + sentry.CaptureException(err) +diff --git a/api/r0/upload.go b/api/r0/upload.go +index 63b0170..b47ae99 100644 +--- a/api/r0/upload.go ++++ b/api/r0/upload.go +@@ -6,7 +6,9 @@ import ( + "io/ioutil" + "net/http" + "path/filepath" ++ "time" + ++ "github.com/gorilla/mux" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api" + "github.com/turt2live/matrix-media-repo/common" +@@ -14,6 +16,7 @@ import ( + "github.com/turt2live/matrix-media-repo/controllers/info_controller" + "github.com/turt2live/matrix-media-repo/controllers/upload_controller" + "github.com/turt2live/matrix-media-repo/quota" ++ "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/cleanup" + ) + +@@ -22,14 +25,52 @@ type MediaUploadedResponse struct { + Blurhash string `json:"xyz.amorgan.blurhash,omitempty"` + } + ++type MediaCreatedResponse struct { ++ ContentUri string `json:"content_uri"` ++ UnusedExpiresAt int64 `json:"unused_expires_at"` ++} ++ ++func CreateMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { ++ media, _, err := upload_controller.CreateMedia(r.Host, rctx) ++ if err != nil { ++ rctx.Log.Error("Unexpected error creating media reference: " + err.Error()) ++ return api.InternalServerError("Unexpected Error") ++ } ++ ++ if err = upload_controller.PersistMedia(media, user.UserId, rctx); err != nil { ++ rctx.Log.Error("Unexpected error persisting media reference: " + err.Error()) ++ return api.InternalServerError("Unexpected Error") ++ } ++ ++ return &MediaCreatedResponse{ ++ ContentUri: media.MxcUri(), ++ UnusedExpiresAt: time.Now().Unix() + int64(rctx.Config.Features.MSC2246Async.AsyncUploadExpirySecs), ++ } ++} ++ + func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { ++ var server = "" ++ var mediaId = "" ++ + filename := filepath.Base(r.URL.Query().Get("filename")) + defer cleanup.DumpAndCloseStream(r.Body) + ++ if rctx.Config.Features.MSC2246Async.Enabled { ++ params := mux.Vars(r) ++ server = params["server"] ++ mediaId = params["mediaId"] ++ } ++ + rctx = rctx.LogWithFields(logrus.Fields{ ++ "server": server, ++ "mediaId": mediaId, + "filename": filename, + }) + ++ if server != "" && (!util.IsServerOurs(server) || server != r.Host) { ++ return api.NotFoundError() ++ } ++ + contentType := r.Header.Get("Content-Type") + if contentType == "" { + contentType = "application/octet-stream" // binary +@@ -59,12 +100,16 @@ func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInf + + contentLength := upload_controller.EstimateContentLength(r.ContentLength, r.Header.Get("Content-Length")) + +- media, err := upload_controller.UploadMedia(r.Body, contentLength, contentType, filename, user.UserId, r.Host, rctx) ++ media, err := upload_controller.UploadMedia(r.Body, contentLength, contentType, filename, user.UserId, r.Host, mediaId, rctx) + if err != nil { + io.Copy(ioutil.Discard, r.Body) // Ditch the entire request + + if err == common.ErrMediaQuarantined { + return api.BadRequest("This file is not permitted on this server") ++ } else if err == common.ErrCannotOverwriteMedia { ++ return api.CannotOverwriteMedia() ++ } else if err == common.ErrMediaNotFound { ++ return api.NotFoundError() + } + + rctx.Log.Error("Unexpected error storing media: " + err.Error()) +diff --git a/api/responses.go b/api/responses.go +index 93d2c39..6fd8f23 100644 +--- a/api/responses.go ++++ b/api/responses.go +@@ -57,3 +57,11 @@ func BadRequest(message string) *ErrorResponse { + func QuotaExceeded() *ErrorResponse { + return &ErrorResponse{common.ErrCodeForbidden, "Quota Exceeded", common.ErrCodeQuotaExceeded} + } ++ ++func CannotOverwriteMedia() *ErrorResponse { ++ return &ErrorResponse{common.ErrCodeCannotOverwriteMedia, "Cannot overwrite media", common.ErrCodeCannotOverwriteMedia} ++} ++ ++func NotYetUploaded() *ErrorResponse { ++ return &ErrorResponse{common.ErrCodeNotYetUploaded, "Media not yet uploaded", common.ErrCodeNotYetUploaded} ++} +diff --git a/api/unstable/info.go b/api/unstable/info.go +index 448e018..b04ff1e 100644 +--- a/api/unstable/info.go ++++ b/api/unstable/info.go +@@ -69,7 +69,7 @@ func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) + "allowRemote": downloadRemote, + }) + +- streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, rctx) ++ streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, nil, rctx) + if err != nil { + if err == common.ErrMediaNotFound { + return api.NotFoundError() +diff --git a/api/unstable/local_copy.go b/api/unstable/local_copy.go +index 30d5f26..885633b 100644 +--- a/api/unstable/local_copy.go ++++ b/api/unstable/local_copy.go +@@ -40,7 +40,7 @@ func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) + + // TODO: There's a lot of room for improvement here. Instead of re-uploading media, we should just update the DB. + +- streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, rctx) ++ streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, nil, rctx) + if err != nil { + if err == common.ErrMediaNotFound { + return api.NotFoundError() +@@ -60,7 +60,7 @@ func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) + return &r0.MediaUploadedResponse{ContentUri: streamedMedia.KnownMedia.MxcUri()} + } + +- newMedia, err := upload_controller.UploadMedia(streamedMedia.Stream, streamedMedia.KnownMedia.SizeBytes, streamedMedia.KnownMedia.ContentType, streamedMedia.KnownMedia.UploadName, user.UserId, r.Host, rctx) ++ newMedia, err := upload_controller.UploadMedia(streamedMedia.Stream, streamedMedia.KnownMedia.SizeBytes, streamedMedia.KnownMedia.ContentType, streamedMedia.KnownMedia.UploadName, user.UserId, r.Host, "", rctx) + if err != nil { + rctx.Log.Error("Unexpected error storing media: " + err.Error()) + sentry.CaptureException(err) +diff --git a/api/webserver/route_handler.go b/api/webserver/route_handler.go +index 3d04714..a120d7a 100644 +--- a/api/webserver/route_handler.go ++++ b/api/webserver/route_handler.go +@@ -146,7 +146,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + case common.ErrCodeUnknownToken: + statusCode = http.StatusUnauthorized + break +- case common.ErrCodeNotFound: ++ case common.ErrCodeNotYetUploaded, common.ErrCodeNotFound: + statusCode = http.StatusNotFound + break + case common.ErrCodeMediaTooLarge: +@@ -161,6 +161,9 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + case common.ErrCodeForbidden: + statusCode = http.StatusForbidden + break ++ case common.ErrCodeCannotOverwriteMedia: ++ statusCode = http.StatusConflict ++ break + default: // Treat as unknown (a generic server error) + statusCode = http.StatusInternalServerError + break +diff --git a/api/webserver/webserver.go b/api/webserver/webserver.go +index fb9c7dd..583d270 100644 +--- a/api/webserver/webserver.go ++++ b/api/webserver/webserver.go +@@ -44,6 +44,7 @@ func Init() *sync.WaitGroup { + counter := &requestCounter{} + + optionsHandler := handler{api.EmptyResponseHandler, "options_request", counter, false} ++ createHandler := handler{api.AccessTokenRequiredRoute(r0.CreateMedia), "create", counter, false} + uploadHandler := handler{api.AccessTokenRequiredRoute(r0.UploadMedia), "upload", counter, false} + downloadHandler := handler{api.AccessTokenOptionalRoute(r0.DownloadMedia), "download", counter, false} + thumbnailHandler := handler{api.AccessTokenOptionalRoute(r0.ThumbnailMedia), "thumbnail", counter, false} +@@ -160,6 +161,12 @@ func Init() *sync.WaitGroup { + } + } + ++ if config.Get().Features.MSC2246Async.Enabled { ++ logrus.Info("Asynchronous uploads (MSC2246) enabled") ++ routes = append(routes, definedRoute{"/_matrix/media/unstable/fi.mau.msc2246/create", route{"POST", createHandler}}) ++ routes = append(routes, definedRoute{"/_matrix/media/unstable/fi.mau.msc2246/upload/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"PUT", uploadHandler}}) ++ } ++ + if config.Get().Features.IPFS.Enabled { + routes = append(routes, definedRoute{features.IPFSDownloadRoute, route{"GET", ipfsDownloadHandler}}) + routes = append(routes, definedRoute{features.IPFSLiveDownloadRouteR0, route{"GET", ipfsDownloadHandler}}) +diff --git a/common/config/conf_min_shared.go b/common/config/conf_min_shared.go +index e43dffc..ae0344a 100644 +--- a/common/config/conf_min_shared.go ++++ b/common/config/conf_min_shared.go +@@ -53,6 +53,11 @@ func NewDefaultMinimumRepoConfig() MinimumRepoConfig { + YComponents: 3, + Punch: 1, + }, ++ MSC2246Async: MSC2246Config{ ++ Enabled: false, ++ AsyncUploadExpirySecs: 60, ++ AsyncDownloadDefaultWaitSecs: 20, ++ }, + IPFS: IPFSConfig{ + Enabled: false, + Daemon: IPFSDaemonConfig{ +diff --git a/common/config/models_domain.go b/common/config/models_domain.go +index 3242724..c30abd9 100644 +--- a/common/config/models_domain.go ++++ b/common/config/models_domain.go +@@ -88,6 +88,7 @@ type TimeoutsConfig struct { + + type FeatureConfig struct { + MSC2448Blurhash MSC2448Config `yaml:"MSC2448"` ++ MSC2246Async MSC2246Config `yaml:"MSC2246"` + IPFS IPFSConfig `yaml:"IPFS"` + Redis RedisConfig `yaml:"redis"` + } +@@ -103,6 +104,12 @@ type MSC2448Config struct { + Punch int `yaml:"punch"` + } + ++type MSC2246Config struct { ++ Enabled bool `yaml:"enabled"` ++ AsyncUploadExpirySecs int `yaml:"asyncUploadExpirySecs"` ++ AsyncDownloadDefaultWaitSecs int `yaml:"asyncDownloadDefaultWaitSecs"` ++} ++ + type IPFSConfig struct { + Enabled bool `yaml:"enabled"` + Daemon IPFSDaemonConfig `yaml:"builtInDaemon"` +diff --git a/common/errorcodes.go b/common/errorcodes.go +index 599b32c..b9a3274 100644 +--- a/common/errorcodes.go ++++ b/common/errorcodes.go +@@ -16,3 +16,5 @@ const ErrCodeRateLimitExceeded = "M_LIMIT_EXCEEDED" + const ErrCodeUnknown = "M_UNKNOWN" + const ErrCodeForbidden = "M_FORBIDDEN" + const ErrCodeQuotaExceeded = "M_QUOTA_EXCEEDED" ++const ErrCodeCannotOverwriteMedia = "FI.MAU.MSC2246_CANNOT_OVEWRITE_MEDIA" ++const ErrCodeNotYetUploaded = "FI.MAU.MSC2246_NOT_YET_UPLOADED" +diff --git a/common/errors.go b/common/errors.go +index 5fc0e69..09f5310 100644 +--- a/common/errors.go ++++ b/common/errors.go +@@ -10,3 +10,5 @@ var ErrInvalidHost = errors.New("invalid host") + var ErrHostNotFound = errors.New("host not found") + var ErrHostBlacklisted = errors.New("host not allowed") + var ErrMediaQuarantined = errors.New("media quarantined") ++var ErrCannotOverwriteMedia = errors.New("cannot overwrite media") ++var ErrNotYetUploaded = errors.New("not yet uploaded") +diff --git a/config.sample.yaml b/config.sample.yaml +index fa49e74..0f506f1 100644 +--- a/config.sample.yaml ++++ b/config.sample.yaml +@@ -544,6 +544,20 @@ featureSupport: + # make the effect more subtle, larger values make it stronger. + punch: 1 + ++ # MSC2246 - Asynchronous uploads ++ MSC2246: ++ # Whether or not this MSC is enabled for use in the media repo ++ enabled: false ++ ++ # The number of seconds an asynchronous upload is valid to be started after requesting a media ++ # id. After expiring the upload endpoint will return an error for the client. ++ asyncUploadExpirySecs: 60 ++ ++ # The number of seconds a download request for an asynchronous upload will stall before ++ # returning an error. This affects clients that do not support async uploads by making them ++ # wait by default. Setting to zero will disable this behavior unless the client requests it. ++ asyncDownloadDefaultWaitSecs: 20 ++ + # IPFS Support + # This is currently experimental and might not work at all. + IPFS: +diff --git a/controllers/download_controller/download_controller.go b/controllers/download_controller/download_controller.go +index 4d7f354..e3d6c92 100644 +--- a/controllers/download_controller/download_controller.go ++++ b/controllers/download_controller/download_controller.go +@@ -26,14 +26,14 @@ import ( + + var localCache = cache.New(30*time.Second, 60*time.Second) + +-func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia bool, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { ++func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { + cacheKey := fmt.Sprintf("%s/%s?r=%t&b=%t", origin, mediaId, downloadRemote, blockForMedia) + v, _, err := globals.DefaultRequestGroup.Do(cacheKey, func() (interface{}, error) { + var media *types.Media + var minMedia *types.MinimalMedia + var err error + if blockForMedia { +- media, err = FindMediaRecord(origin, mediaId, downloadRemote, ctx) ++ media, err = FindMediaRecord(origin, mediaId, downloadRemote, asyncWaitMs, ctx) + if media != nil { + minMedia = &types.MinimalMedia{ + Origin: media.Origin, +@@ -46,7 +46,7 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia + } + } + } else { +- minMedia, err = FindMinimalMediaRecord(origin, mediaId, downloadRemote, ctx) ++ minMedia, err = FindMinimalMediaRecord(origin, mediaId, downloadRemote, asyncWaitMs, ctx) + if minMedia != nil { + media = minMedia.KnownMedia + } +@@ -159,7 +159,54 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia + return value, err + } + +-func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { ++func waitForUpload(media *types.Media, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.Media, error) { ++ if media == nil { ++ return nil, errors.New("waited for nil media") ++ } ++ ++ if util.IsServerOurs(media.Origin) && media.SizeBytes == 0 { ++ // we're not allowed to wait by requester ++ if asyncWaitMs == nil { ++ return nil, common.ErrMediaNotFound ++ } ++ ++ waitMs := *asyncWaitMs ++ ++ // max wait one minute ++ if waitMs > 60_000 { ++ waitMs = 60_000 ++ } ++ ++ // use default wait if negative ++ if waitMs < 0 { ++ waitMs = ctx.Config.Features.MSC2246Async.AsyncDownloadDefaultWaitSecs * 1000 ++ ++ // if the default is zero and client didn't request any then waiting is disabled ++ if waitMs == 0 { ++ return nil, common.ErrMediaNotFound ++ } ++ } ++ ++ // if the upload did not complete in 6 hours, consider it never will ++ if util.NowMillis()-media.CreationTs > 3600*6*1000 { ++ ctx.Log.Info("Tried to download expired asynchronous upload") ++ return nil, common.ErrMediaNotFound ++ } ++ ++ ctx.Log.Info("Asynchronous upload not complete, waiting") ++ if ok := util.WaitForUpload(media.Origin, media.MediaId, time.Millisecond*time.Duration(waitMs)); !ok { ++ return nil, common.ErrNotYetUploaded ++ } ++ ++ // fetch the entry from database again after we're notified it should be complete ++ db := storage.GetDatabase().GetMediaStore(ctx) ++ return db.Get(media.Origin, media.MediaId) ++ } ++ ++ return media, nil ++} ++ ++func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.MinimalMedia, error) { + db := storage.GetDatabase().GetMediaStore(ctx) + + var media *types.Media +@@ -217,7 +264,10 @@ func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, + KnownMedia: nil, // unknown + }, nil + } else { +- media = dbMedia ++ media, err = waitForUpload(dbMedia, asyncWaitMs, ctx) ++ if err != nil { ++ return nil, err ++ } + } + } + +@@ -252,7 +302,7 @@ func FindMinimalMediaRecord(origin string, mediaId string, downloadRemote bool, + }, nil + } + +-func FindMediaRecord(origin string, mediaId string, downloadRemote bool, ctx rcontext.RequestContext) (*types.Media, error) { ++func FindMediaRecord(origin string, mediaId string, downloadRemote bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.Media, error) { + cacheKey := origin + "/" + mediaId + v, _, err := globals.DefaultRequestGroup.DoWithoutPost(cacheKey, func() (interface{}, error) { + db := storage.GetDatabase().GetMediaStore(ctx) +@@ -290,7 +340,10 @@ func FindMediaRecord(origin string, mediaId string, downloadRemote bool, ctx rco + } + media = result.media + } else { +- media = dbMedia ++ media, err = waitForUpload(dbMedia, asyncWaitMs, ctx) ++ if err != nil { ++ return nil, err ++ } + } + } + +diff --git a/controllers/info_controller/info_controller.go b/controllers/info_controller/info_controller.go +index 281ec60..7eee6c6 100644 +--- a/controllers/info_controller/info_controller.go ++++ b/controllers/info_controller/info_controller.go +@@ -27,7 +27,7 @@ func GetOrCalculateBlurhash(media *types.Media, rctx rcontext.RequestContext) (s + } + + rctx.Log.Info("Getting minimal media record to calculate blurhash") +- minMedia, err := download_controller.FindMinimalMediaRecord(media.Origin, media.MediaId, true, rctx) ++ minMedia, err := download_controller.FindMinimalMediaRecord(media.Origin, media.MediaId, true, nil, rctx) + if err != nil { + return "", err + } +diff --git a/controllers/maintenance_controller/maintainance_controller.go b/controllers/maintenance_controller/maintainance_controller.go +index 1df60a3..dfdd1f8 100644 +--- a/controllers/maintenance_controller/maintainance_controller.go ++++ b/controllers/maintenance_controller/maintainance_controller.go +@@ -387,7 +387,7 @@ func PurgeDomainMedia(serverName string, beforeTs int64, ctx rcontext.RequestCon + } + + func PurgeMedia(origin string, mediaId string, ctx rcontext.RequestContext) error { +- media, err := download_controller.FindMediaRecord(origin, mediaId, false, ctx) ++ media, err := download_controller.FindMediaRecord(origin, mediaId, false, nil, ctx) + if err != nil { + return err + } +diff --git a/controllers/preview_controller/preview_resource_handler.go b/controllers/preview_controller/preview_resource_handler.go +index 86c42b9..cd99dba 100644 +--- a/controllers/preview_controller/preview_resource_handler.go ++++ b/controllers/preview_controller/preview_resource_handler.go +@@ -133,7 +133,7 @@ func urlPreviewWorkFn(request *resource_handler.WorkRequest) (resp *urlPreviewRe + contentLength := upload_controller.EstimateContentLength(preview.Image.ContentLength, preview.Image.ContentLengthHeader) + + // UploadMedia will close the read stream for the thumbnail and dedupe the image +- media, err := upload_controller.UploadMedia(preview.Image.Data, contentLength, preview.Image.ContentType, preview.Image.Filename, info.forUserId, info.onHost, ctx) ++ media, err := upload_controller.UploadMedia(preview.Image.Data, contentLength, preview.Image.ContentType, preview.Image.Filename, info.forUserId, info.onHost, "", ctx) + if err != nil { + ctx.Log.Warn("Non-fatal error storing preview thumbnail: " + err.Error()) + sentry.CaptureException(err) +diff --git a/controllers/thumbnail_controller/thumbnail_controller.go b/controllers/thumbnail_controller/thumbnail_controller.go +index 9b5e121..c464790 100644 +--- a/controllers/thumbnail_controller/thumbnail_controller.go ++++ b/controllers/thumbnail_controller/thumbnail_controller.go +@@ -26,8 +26,8 @@ import ( + + var localCache = cache.New(30*time.Second, 60*time.Second) + +-func GetThumbnail(origin string, mediaId string, desiredWidth int, desiredHeight int, animated bool, method string, downloadRemote bool, ctx rcontext.RequestContext) (*types.StreamedThumbnail, error) { +- media, err := download_controller.FindMediaRecord(origin, mediaId, downloadRemote, ctx) ++func GetThumbnail(origin string, mediaId string, desiredWidth int, desiredHeight int, animated bool, method string, downloadRemote bool, asyncWaitMs *int, ctx rcontext.RequestContext) (*types.StreamedThumbnail, error) { ++ media, err := download_controller.FindMediaRecord(origin, mediaId, downloadRemote, asyncWaitMs, ctx) + if err != nil { + return nil, err + } +diff --git a/controllers/upload_controller/upload_controller.go b/controllers/upload_controller/upload_controller.go +index 7936faa..25759ff 100644 +--- a/controllers/upload_controller/upload_controller.go ++++ b/controllers/upload_controller/upload_controller.go +@@ -1,6 +1,7 @@ + package upload_controller + + import ( ++ "database/sql" + "fmt" + "github.com/getsentry/sentry-go" + "io" +@@ -92,39 +93,26 @@ func EstimateContentLength(contentLength int64, contentLengthHeader string) int6 + return -1 // unknown + } + +-func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string, filename string, userId string, origin string, ctx rcontext.RequestContext) (*types.Media, error) { +- defer cleanup.DumpAndCloseStream(contents) +- +- var data io.ReadCloser +- if ctx.Config.Uploads.MaxSizeBytes > 0 { +- data = ioutil.NopCloser(io.LimitReader(contents, ctx.Config.Uploads.MaxSizeBytes)) +- } else { +- data = contents +- } +- +- dataBytes, err := ioutil.ReadAll(data) +- if err != nil { +- return nil, err +- } +- ++func CreateMedia(origin string, ctx rcontext.RequestContext) (*types.Media, *datastore.DatastoreRef, error) { + metadataDb := storage.GetDatabase().GetMetadataStore(ctx) + + mediaTaken := true + var mediaId string ++ var err error + attempts := 0 + for mediaTaken { + attempts += 1 + if attempts > 10 { +- return nil, errors.New("failed to generate a media ID after 10 rounds") ++ return nil, nil, errors.New("failed to generate a media ID after 10 rounds") + } + + mediaId, err = util.GenerateRandomString(64) + if err != nil { +- return nil, err ++ return nil, nil, err + } + mediaId, err = util.GetSha1OfString(mediaId + strconv.FormatInt(util.NowMillis(), 10)) + if err != nil { +- return nil, err ++ return nil, nil, err + } + + // Because we use the current time in the media ID, we don't need to worry about +@@ -136,17 +124,88 @@ func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string + + mediaTaken, err = metadataDb.IsReserved(origin, mediaId) + if err != nil { +- return nil, err ++ return nil, nil, err + } + } + + _ = recentMediaIds.Add(mediaId, true, cache.DefaultExpiration) + +- var existingFile *AlreadyUploadedFile = nil + ds, err := datastore.PickDatastore(common.KindLocalMedia, ctx) ++ if err != nil { ++ return nil, nil, err ++ } ++ ++ return &types.Media{MediaId: mediaId, Origin: origin, DatastoreId: ds.DatastoreId}, ds, nil ++} ++ ++func PersistMedia(media *types.Media, userId string, ctx rcontext.RequestContext) error { ++ db := storage.GetDatabase().GetMediaStore(ctx) ++ ++ ctx.Log.Info("Persisting async media record") ++ ++ media.UserId = userId ++ media.CreationTs = util.NowMillis() ++ ++ return db.Insert(media) ++} ++ ++func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string, filename string, userId string, origin string, asyncMediaId string, ctx rcontext.RequestContext) (*types.Media, error) { ++ defer cleanup.DumpAndCloseStream(contents) ++ ++ var data io.ReadCloser ++ if ctx.Config.Uploads.MaxSizeBytes > 0 { ++ data = ioutil.NopCloser(io.LimitReader(contents, ctx.Config.Uploads.MaxSizeBytes)) ++ } else { ++ data = contents ++ } ++ ++ dataBytes, err := ioutil.ReadAll(data) + if err != nil { + return nil, err + } ++ ++ var mediaId string ++ var ds *datastore.DatastoreRef ++ if asyncMediaId == "" { ++ media, newDs, err := CreateMedia(origin, ctx) ++ if err != nil { ++ return nil, err ++ } ++ ++ mediaId = media.MediaId ++ ds = newDs ++ } else { ++ db := storage.GetDatabase().GetMediaStore(ctx) ++ ++ media, err := db.Get(origin, asyncMediaId) ++ if err != nil { ++ return nil, err ++ } ++ ++ if media == nil { ++ return nil, common.ErrMediaNotFound ++ } ++ ++ if media.UserId != userId { ++ return nil, common.ErrMediaNotFound ++ } ++ ++ if media.SizeBytes > 0 { ++ return nil, common.ErrCannotOverwriteMedia ++ } ++ ++ if util.NowMillis()-media.CreationTs > int64(ctx.Config.Features.MSC2246Async.AsyncUploadExpirySecs*1000) { ++ return nil, common.ErrMediaNotFound ++ } ++ ++ mediaId = asyncMediaId ++ ds, err = datastore.LocateDatastore(ctx, media.DatastoreId) ++ if err != nil { ++ return nil, err ++ } ++ } ++ ++ var existingFile *AlreadyUploadedFile = nil + if ds.Type == "ipfs" { + // Do the upload now so we can pick the media ID to point to IPFS + info, err := ds.UploadFile(util_byte_seeker.NewByteSeeker(dataBytes), contentLength, ctx) +@@ -160,15 +219,22 @@ func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string + mediaId = fmt.Sprintf("ipfs:%s", info.Location[len("ipfs/"):]) + } + +- m, err := StoreDirect(existingFile, util_byte_seeker.NewByteSeeker(dataBytes), contentLength, contentType, filename, userId, origin, mediaId, common.KindLocalMedia, ctx, true) ++ m, err := StoreDirect(existingFile, util_byte_seeker.NewByteSeeker(dataBytes), contentLength, contentType, filename, userId, origin, mediaId, common.KindLocalMedia, ctx, asyncMediaId == "") + if err != nil { + return m, err + } + if m != nil { +- err = internal_cache.Get().UploadMedia(m.Sha256Hash, util_byte_seeker.NewByteSeeker(dataBytes), ctx) +- if err != nil { ++ util.NotifyUpload(origin, mediaId) ++ ++ cache := internal_cache.Get() ++ if err := cache.UploadMedia(m.Sha256Hash, util_byte_seeker.NewByteSeeker(dataBytes), ctx); err != nil { + ctx.Log.Warn("Unexpected error trying to cache media: " + err.Error()) + } ++ if asyncMediaId != "" { ++ if err := cache.NotifyUpload(origin, mediaId, ctx); err != nil { ++ ctx.Log.Warn("Unexpected error trying to notify cache about media: " + err.Error()) ++ } ++ } + } + return m, err + } +@@ -193,8 +259,7 @@ func checkSpam(contents []byte, filename string, contentType string, userId stri + return nil + } + +-func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize int64, contentType string, filename string, userId string, origin string, mediaId string, kind string, ctx rcontext.RequestContext, filterUserDuplicates bool) (*types.Media, error) { +- var err error ++func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize int64, contentType string, filename string, userId string, origin string, mediaId string, kind string, ctx rcontext.RequestContext, filterUserDuplicates bool) (ret *types.Media, err error) { + var ds *datastore.DatastoreRef + var info *types.ObjectInfo + var contentBytes []byte +@@ -229,15 +294,16 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in + return nil, err + } + } ++ defer func() { ++ // always delete temp object if we return an error ++ if err != nil { ++ ds.DeleteObject(info.Location) ++ } ++ }() + + db := storage.GetDatabase().GetMediaStore(ctx) + records, err := db.GetByHash(info.Sha256Hash) + if err != nil { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) +- } + return nil, err + } + +@@ -270,22 +336,12 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in + + err = checkSpam(contentBytes, filename, contentType, userId, origin, mediaId) + if err != nil { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) +- } + return nil, err + } + + // We'll use the location from the first record + record := records[0] + if record.Quarantined { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) +- } + ctx.Log.Warn("User attempted to upload quarantined content - rejecting") + return nil, common.ErrMediaQuarantined + } +@@ -304,21 +360,37 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in + } + } + +- media := record +- media.Origin = origin +- media.MediaId = mediaId +- media.UserId = userId +- media.UploadName = filename +- media.ContentType = contentType +- media.CreationTs = util.NowMillis() ++ // Check if we have reserved the metadata already ++ media, err := db.Get(origin, mediaId) ++ if err == sql.ErrNoRows { ++ media = record ++ media.Origin = origin ++ media.MediaId = mediaId ++ media.UserId = userId ++ media.UploadName = filename ++ media.ContentType = contentType ++ media.CreationTs = util.NowMillis() ++ ++ if err = db.Insert(media); err != nil { ++ return nil, err ++ } ++ } else if err == nil { ++ // last minute check if the file was already uploaded ++ if media.SizeBytes > 0 { ++ return nil, common.ErrCannotOverwriteMedia ++ } + +- err = db.Insert(media) +- if err != nil { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) ++ media.UploadName = filename ++ media.ContentType = contentType ++ media.Sha256Hash = info.Sha256Hash ++ media.SizeBytes = info.SizeBytes ++ media.DatastoreId = ds.DatastoreId ++ media.Location = info.Location ++ ++ if err = db.Update(media); err != nil { ++ return nil, err + } ++ } else { + return nil, err + } + +@@ -327,11 +399,6 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in + if media.DatastoreId != ds.DatastoreId && media.Location != info.Location { + ds2, err := datastore.LocateDatastore(ctx, media.DatastoreId) + if err != nil { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) +- } + return nil, err + } + if !ds2.ObjectExists(media.Location) { +@@ -366,46 +433,54 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in + // The media doesn't already exist - save it as new + + if info.SizeBytes <= 0 { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) +- } + return nil, errors.New("file has no contents") + } + + err = checkSpam(contentBytes, filename, contentType, userId, origin, mediaId) + if err != nil { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) +- } + return nil, err + } + +- ctx.Log.Info("Persisting new media record") +- +- media := &types.Media{ +- Origin: origin, +- MediaId: mediaId, +- UploadName: filename, +- ContentType: contentType, +- UserId: userId, +- Sha256Hash: info.Sha256Hash, +- SizeBytes: info.SizeBytes, +- DatastoreId: ds.DatastoreId, +- Location: info.Location, +- CreationTs: util.NowMillis(), +- } ++ // Check if we have reserved the metadata already, validate uploader ++ media, err := db.Get(origin, mediaId) ++ if err == sql.ErrNoRows { ++ ctx.Log.Info("Persisting new media record") ++ ++ media = &types.Media{ ++ Origin: origin, ++ MediaId: mediaId, ++ UploadName: filename, ++ ContentType: contentType, ++ UserId: userId, ++ Sha256Hash: info.Sha256Hash, ++ SizeBytes: info.SizeBytes, ++ DatastoreId: ds.DatastoreId, ++ Location: info.Location, ++ CreationTs: util.NowMillis(), ++ } + +- err = db.Insert(media) +- if err != nil { +- err2 := ds.DeleteObject(info.Location) // delete temp object +- if err2 != nil { +- ctx.Log.Warn("Error deleting temporary upload", err2) +- sentry.CaptureException(err2) ++ if err = db.Insert(media); err != nil { ++ return nil, err + } ++ } else if err == nil { ++ ctx.Log.Info("Updating existing media record") ++ ++ // last minute check if the file was already uploaded ++ if media.SizeBytes > 0 { ++ return nil, common.ErrCannotOverwriteMedia ++ } ++ ++ media.UploadName = filename ++ media.ContentType = contentType ++ media.Sha256Hash = info.Sha256Hash ++ media.SizeBytes = info.SizeBytes ++ media.DatastoreId = ds.DatastoreId ++ media.Location = info.Location ++ ++ if err = db.Update(media); err != nil { ++ return nil, err ++ } ++ } else { + return nil, err + } + +diff --git a/internal_cache/cache.go b/internal_cache/cache.go +index b871a07..0b0a5af 100644 +--- a/internal_cache/cache.go ++++ b/internal_cache/cache.go +@@ -18,4 +18,5 @@ type ContentCache interface { + MarkDownload(fileHash string) + GetMedia(sha256hash string, contents FetchFunction, ctx rcontext.RequestContext) (*CachedContent, error) + UploadMedia(sha256hash string, content io.ReadCloser, ctx rcontext.RequestContext) error ++ NotifyUpload(origin string, mediaId string, ctx rcontext.RequestContext) error + } +diff --git a/internal_cache/noop.go b/internal_cache/noop.go +index 8a4f936..9d4a264 100644 +--- a/internal_cache/noop.go ++++ b/internal_cache/noop.go +@@ -35,3 +35,8 @@ func (n *NoopCache) UploadMedia(sha256hash string, content io.ReadCloser, ctx rc + // do nothing + return nil + } ++ ++func (n *NoopCache) NotifyUpload(origin string, mediaId string, ctx rcontext.RequestContext) error { ++ // do nothing ++ return nil ++} +diff --git a/internal_cache/redis.go b/internal_cache/redis.go +index aeb4c2c..baacab0 100644 +--- a/internal_cache/redis.go ++++ b/internal_cache/redis.go +@@ -67,3 +67,7 @@ func (c *RedisCache) UploadMedia(sha256hash string, content io.ReadCloser, ctx r + defer content.Close() + return c.redis.SetStream(ctx, sha256hash, content) + } ++ ++func (c *RedisCache) NotifyUpload(origin string, mediaId string, ctx rcontext.RequestContext) error { ++ return c.redis.NotifyUpload(ctx, origin, mediaId) ++} +diff --git a/redis_cache/redis.go b/redis_cache/redis.go +index c129490..13a6434 100644 +--- a/redis_cache/redis.go ++++ b/redis_cache/redis.go +@@ -12,6 +12,8 @@ import ( + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/common/rcontext" ++ "github.com/turt2live/matrix-media-repo/types" ++ "github.com/turt2live/matrix-media-repo/util" + ) + + var ErrCacheMiss = errors.New("missed cache") +@@ -32,14 +34,45 @@ func NewCache(conf config.RedisConfig) *RedisCache { + DB: conf.DbNum, + }) + ++ ctx := context.Background() ++ + logrus.Info("Contacting Redis shards...") +- _ = ring.ForEachShard(context.Background(), func(ctx context.Context, client *redis.Client) error { ++ _ = ring.ForEachShard(ctx, func(ctx context.Context, client *redis.Client) error { + logrus.Infof("Pinging %s", client.String()) + r, err := client.Ping(ctx).Result() + if err != nil { + return err + } + logrus.Infof("%s replied with: %s", client.String(), r) ++ ++ psub := client.Subscribe(ctx, "upload") ++ go func() { ++ logrus.Infof("Client %s going to subscribe to uploads", client.String()) ++ for { ++ for { ++ msg, err := psub.ReceiveMessage(ctx) ++ if err != nil { ++ break ++ } ++ ++ ref := types.MediaRef{} ++ if err := ref.UnmarshalBinary([]byte(msg.Payload)); err != nil { ++ logrus.Warn("Failed to unmarshal published upload, ignoring") ++ continue ++ } ++ ++ logrus.Infof("Client %s notified about %s/%s being uploaded", client.String(), ref.Origin, ref.MediaId) ++ util.NotifyUpload(ref.Origin, ref.MediaId) ++ } ++ ++ if ctx.Done() != nil { ++ return ++ } ++ ++ time.Sleep(time.Second * 1) ++ } ++ }() ++ + return nil + }) + +@@ -97,3 +130,21 @@ func (c *RedisCache) GetBytes(ctx rcontext.RequestContext, key string) ([]byte, + b, err := r.Bytes() + return b, err + } ++ ++func (c *RedisCache) NotifyUpload(ctx rcontext.RequestContext, origin string, mediaId string) error { ++ if c.ring.PoolStats().TotalConns == 0 { ++ return ErrCacheDown ++ } ++ r := c.ring.Publish(ctx, "upload", types.MediaRef{Origin: origin, MediaId: mediaId}) ++ if r.Err() != nil { ++ if r.Err() == redis.Nil { ++ return ErrCacheMiss ++ } ++ if c.ring.PoolStats().TotalConns == 0 { ++ ctx.Log.Error(r.Err()) ++ return ErrCacheDown ++ } ++ return r.Err() ++ } ++ return nil ++} +diff --git a/storage/stores/media_store.go b/storage/stores/media_store.go +index 958f1b0..71aaa3a 100644 +--- a/storage/stores/media_store.go ++++ b/storage/stores/media_store.go +@@ -16,6 +16,7 @@ import ( + const selectMedia = "SELECT origin, media_id, upload_name, content_type, user_id, sha256_hash, size_bytes, datastore_id, location, creation_ts, quarantined FROM media WHERE origin = $1 and media_id = $2;" + const selectMediaByHash = "SELECT origin, media_id, upload_name, content_type, user_id, sha256_hash, size_bytes, datastore_id, location, creation_ts, quarantined FROM media WHERE sha256_hash = $1;" + const insertMedia = "INSERT INTO media (origin, media_id, upload_name, content_type, user_id, sha256_hash, size_bytes, datastore_id, location, creation_ts, quarantined) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11);" ++const updateMedia = "UPDATE media SET upload_name = $3, content_type = $4, sha256_hash = $5, size_bytes = $6, datastore_id = $7, location = $8 WHERE origin = $1 AND media_id = $2;" + const selectOldMedia = "SELECT m.origin, m.media_id, m.upload_name, m.content_type, m.user_id, m.sha256_hash, m.size_bytes, m.datastore_id, m.location, m.creation_ts, quarantined FROM media AS m WHERE m.origin <> ANY($1) AND m.creation_ts < $2 AND (SELECT COUNT(*) FROM media AS d WHERE d.sha256_hash = m.sha256_hash AND d.creation_ts >= $2) = 0 AND (SELECT COUNT(*) FROM media AS d WHERE d.sha256_hash = m.sha256_hash AND d.origin = ANY($1)) = 0;" + const selectOrigins = "SELECT DISTINCT origin FROM media;" + const deleteMedia = "DELETE FROM media WHERE origin = $1 AND media_id = $2;" +@@ -47,6 +48,7 @@ type mediaStoreStatements struct { + selectMedia *sql.Stmt + selectMediaByHash *sql.Stmt + insertMedia *sql.Stmt ++ updateMedia *sql.Stmt + selectOldMedia *sql.Stmt + selectOrigins *sql.Stmt + deleteMedia *sql.Stmt +@@ -97,6 +99,9 @@ func InitMediaStore(sqlDb *sql.DB) (*MediaStoreFactory, error) { + if store.stmts.insertMedia, err = store.sqlDb.Prepare(insertMedia); err != nil { + return nil, err + } ++ if store.stmts.updateMedia, err = store.sqlDb.Prepare(updateMedia); err != nil { ++ return nil, err ++ } + if store.stmts.selectOldMedia, err = store.sqlDb.Prepare(selectOldMedia); err != nil { + return nil, err + } +@@ -190,6 +195,22 @@ func (s *MediaStore) Insert(media *types.Media) error { + return err + } + ++func (s *MediaStore) Update(media *types.Media) error { ++ _, err := s.statements.updateMedia.ExecContext( ++ s.ctx, ++ media.Origin, ++ media.MediaId, ++ media.UploadName, ++ media.ContentType, ++ media.Sha256Hash, ++ media.SizeBytes, ++ media.DatastoreId, ++ media.Location, ++ ) ++ ++ return err ++} ++ + func (s *MediaStore) GetByHash(hash string) ([]*types.Media, error) { + rows, err := s.statements.selectMediaByHash.QueryContext(s.ctx, hash) + if err != nil { +diff --git a/types/media.go b/types/media.go +index 873da95..9172ae2 100644 +--- a/types/media.go ++++ b/types/media.go +@@ -1,6 +1,22 @@ + package types + +-import "io" ++import ( ++ "encoding/json" ++ "io" ++) ++ ++type MediaRef struct { ++ Origin string ++ MediaId string ++} ++ ++func (ref MediaRef) MarshalBinary() ([]byte, error) { ++ return json.Marshal(ref) ++} ++ ++func (ref *MediaRef) UnmarshalBinary(data []byte) error { ++ return json.Unmarshal(data, ref) ++} + + type Media struct { + Origin string +diff --git a/util/upload_notifier.go b/util/upload_notifier.go +new file mode 100644 +index 0000000..84a9bd4 +--- /dev/null ++++ b/util/upload_notifier.go +@@ -0,0 +1,61 @@ ++package util ++ ++import ( ++ "sync" ++ "time" ++) ++ ++type mediaSet map[chan struct{}]struct{} ++ ++var waiterLock = &sync.Mutex{} ++var waiters = map[string]mediaSet{} ++ ++func WaitForUpload(origin string, mediaId string, timeout time.Duration) bool { ++ key := origin + mediaId ++ ch := make(chan struct{}, 1) ++ ++ waiterLock.Lock() ++ var set mediaSet ++ var ok bool ++ if set, ok = waiters[key]; !ok { ++ set = make(mediaSet) ++ waiters[key] = set ++ } ++ set[ch] = struct{}{} ++ waiterLock.Unlock() ++ ++ defer func() { ++ waiterLock.Lock() ++ ++ delete(set, ch) ++ close(ch) ++ ++ if len(set) == 0 { ++ delete(waiters, key) ++ } ++ ++ waiterLock.Unlock() ++ }() ++ ++ select { ++ case <-ch: ++ return true ++ case <-time.After(timeout): ++ return false ++ } ++} ++ ++func NotifyUpload(origin string, mediaId string) { ++ waiterLock.Lock() ++ defer waiterLock.Unlock() ++ ++ set := waiters[origin+mediaId] ++ ++ if set == nil { ++ return ++ } ++ ++ for channel := range set { ++ channel <- struct{}{} ++ } ++} diff --git a/matrix/matrix-media-repo/default.nix b/matrix/matrix-media-repo/default.nix new file mode 100644 index 0000000..8a700cc --- /dev/null +++ b/matrix/matrix-media-repo/default.nix @@ -0,0 +1,28 @@ +{inputs, ...} @ args: let + pkgs = import inputs.nixpkgs-go116 {inherit (args.pkgs) system;}; + buildGoApplication = pkgs.callPackage "${inputs.gomod2nix}/builder" {}; +in { + matrix-media-repo = buildGoApplication rec { + pname = "matrix-media-repo"; + version = inputs.matrix-media-repo.lastModifiedDate; + src = inputs.matrix-media-repo; + patches = [ + ./async-media.patch + ]; + go = pkgs.go_1_16; + proxyVendor = true; + modules = ./gomod2nix.toml; + nativeBuildInputs = [ + pkgs.git + ]; + buildPhase = '' + GOBIN=$PWD/bin go install -v ./cmd/compile_assets + $PWD/bin/compile_assets + GOBIN=$PWD/bin go install -ldflags "-X github.com/turt2live/matrix-media-repo/common/version.GitCommit=$(git rev-list -1 HEAD) -X github.com/turt2live/matrix-media-repo/common/version.Version=$(git describe --tags)" -v ./cmd/... + ''; + installPhase = '' + mkdir $out + cp -rv bin $out + ''; + }; +} diff --git a/matrix/matrix-media-repo/gomod2nix.toml b/matrix/matrix-media-repo/gomod2nix.toml new file mode 100644 index 0000000..728dbe3 --- /dev/null +++ b/matrix/matrix-media-repo/gomod2nix.toml @@ -0,0 +1,1971 @@ +schema = 1 + +[mod] + [mod."bazil.org/fuse"] + version = "v0.0.0-20200117225306-7b5117fecadc" + hash = "sha256-SJHNNHVMhSopYQcUILj+IyZ8vuWH5eIs7WhR4+dyzhw=" + [mod."cloud.google.com/go"] + version = "v0.53.0" + hash = "sha256-eotssMUbmYNCj8YSE9ctrhQ8bMqRpSkZpcmopy5SaBQ=" + [mod."cloud.google.com/go/bigquery"] + version = "v1.3.0" + hash = "sha256-rSEyksqULDn225RzdNKHGYJ2o1h//nMdQV8zDNOtPFo=" + [mod."cloud.google.com/go/datastore"] + version = "v1.0.0" + hash = "sha256-zsrEec4SFRHfYXd/1RyNg5FVjBlLNh8Jc5IH4hZejL8=" + [mod."cloud.google.com/go/pubsub"] + version = "v1.1.0" + hash = "sha256-9qZhE8w/TRLpxivSJIYFPn26j/gDJ1atSzskIXb0JCg=" + [mod."cloud.google.com/go/storage"] + version = "v1.5.0" + hash = "sha256-BzaeIu2VUpz6ApDcWde6KPGRbP41LPi0Z7/aTHOD8VY=" + [mod."contrib.go.opencensus.io/exporter/prometheus"] + version = "v0.2.0" + hash = "sha256-vIqx4wDRW78FyNGM/YuGuyAApvu3It0+5qLsJhel4VU=" + [mod."dmitri.shuralyov.com/app/changes"] + version = "v0.0.0-20180602232624-0a106ad413e3" + hash = "sha256-UwAyLMevfLr0pdylYrEkSxph3HpWAVfLIcsLgH0kiwY=" + [mod."dmitri.shuralyov.com/gpu/mtl"] + version = "v0.0.0-20190408044501-666a987793e9" + hash = "sha256-H+xcbVdCNDahWZPgwk4k+XxnM73g0hwaFY7x+OAATcc=" + [mod."dmitri.shuralyov.com/html/belt"] + version = "v0.0.0-20180602232347-f7d459c86be0" + hash = "sha256-cXt+9PiAbV2Nz2FDah8qBIsk7o6hoI5HHsAOtUbuCj8=" + [mod."dmitri.shuralyov.com/service/change"] + version = "v0.0.0-20181023043359-a85b471d5412" + hash = "sha256-gKreDQdJUgjQBxo8gvzcXop4Ma+8vWaAQ/KQksT8nJ8=" + [mod."dmitri.shuralyov.com/state"] + version = "v0.0.0-20180228185332-28bcc343414c" + hash = "sha256-YsleSiI5W7XqGvUBxUAvo9rSACyxT+9C2sPos4As5ik=" + [mod."git.apache.org/thrift.git"] + version = "v0.0.0-20180902110319-2566ecd5d999" + hash = "sha256-OIicnmgxzYQx7m/2VOeV0qQqxQOuJ22cdEP/3n4NZFs=" + [mod."github.com/AndreasBriese/bbloom"] + version = "v0.0.0-20190825152654-46b345b51c96" + hash = "sha256-ydIJ4QKvQsDSAook9y0doDaTeXpyQUy1T+ySfOgFLAg=" + [mod."github.com/BurntSushi/toml"] + version = "v0.3.1" + hash = "sha256-Rqak1dE/Aj/+Kx1/pl3Hifgt+Q3OzuZ5fJR+/x3nTbo=" + [mod."github.com/BurntSushi/xgb"] + version = "v0.0.0-20160522181843-27f122750802" + hash = "sha256-ck+gNOSXNYy/ji6mpSX3OTHgCDm2nww+3ZKu4lAXl6I=" + [mod."github.com/CloudyKit/fastprinter"] + version = "v0.0.0-20200109182630-33d98a066a53" + hash = "sha256-KUuNS6OlaDUfpKIvZWJr8fiUR8ki/hUwMZiunNj0cxo=" + [mod."github.com/CloudyKit/jet/v3"] + version = "v3.0.0" + hash = "sha256-OYPE9VXq2kNTrPxEzaDHi4UXfZ0kKRpYlvypRjYN5qM=" + [mod."github.com/DavidHuie/gomigrate"] + version = "v0.0.0-20190826182718-4adc4b3de142" + hash = "sha256-TprT0kezFl+AbDaMvZOeQMNvCyG+5RtRnMGUk4ZUdtk=" + [mod."github.com/Jeffail/gabs"] + version = "v1.4.0" + hash = "sha256-Za8Lg0vfQPmuwzu1pUWFwqIoKuHM6TDt1Pe37i4ZOZU=" + [mod."github.com/Jeffail/tunny"] + version = "v0.0.0-20210126202424-1b37d6cb867a" + hash = "sha256-imYNheEmnZs/6/naQWVmRj0Rnj6673+eWf9AedodOBI=" + [mod."github.com/Joker/hpp"] + version = "v1.0.0" + hash = "sha256-Ar8wC5myjeKCZZnNSyNrKKtXGc/kKAwQR0Q2XKec2PY=" + [mod."github.com/Knetic/govaluate"] + version = "v3.0.1-0.20171022003610-9aa49832a739+incompatible" + hash = "sha256-Qs7qeK+Mrlm4ToAEYvN+OY6X7SRFV808frvKNr6gNhE=" + [mod."github.com/Kubuxu/go-os-helper"] + version = "v0.0.1" + hash = "sha256-2bcGwJ8PbjHIdsZ0XVb89zIrHCbpXpFxg8XsDalHaCM=" + [mod."github.com/OneOfOne/xxhash"] + version = "v1.2.2" + hash = "sha256-JvJnJFr9NFh5u+b7BgNEIwZR6scXW8l8RkT1DXmGTtY=" + [mod."github.com/PuerkitoBio/goquery"] + version = "v1.6.1" + hash = "sha256-U5NpGPohDc9tlnEBylPWYeo/gP1YbZEGoKp0xoihbcQ=" + [mod."github.com/Shopify/goreferrer"] + version = "v0.0.0-20181106222321-ec9c9a553398" + hash = "sha256-tkpjX4XQ89BCukLKUJgdmC/HM7UmW0Bh0PMzJPUF5DQ=" + [mod."github.com/Shopify/sarama"] + version = "v1.19.0" + hash = "sha256-kU5TtVhy9HctSKm6Lu4xRE4/xSnQLXnsQjeFGWGOm3c=" + [mod."github.com/Shopify/toxiproxy"] + version = "v2.1.4+incompatible" + hash = "sha256-RYVa3BtYTYvATCTADda1piGbQFnxJrEFKpMSLjw+ExI=" + [mod."github.com/Stebalien/go-bitfield"] + version = "v0.0.1" + hash = "sha256-D5XzndD1G/auE/ozlMM/58cvRJNk9qvsCM0j/Yj9c24=" + [mod."github.com/VividCortex/gohistogram"] + version = "v1.0.0" + hash = "sha256-zubR+TIR7DgyESAOLM/DC0DqR1K7zXM+YL+OmGfed/o=" + [mod."github.com/aead/siphash"] + version = "v1.0.1" + hash = "sha256-zP7VoPA7YHxa+lMwnOXRJo3rfVZFsCTtgJYwLdAPbQY=" + [mod."github.com/afex/hystrix-go"] + version = "v0.0.0-20180502004556-fa1af6a1f4f5" + hash = "sha256-Vmss3HtnycQWVwde+Gi/L76wN2lEx803dSYgCcYAkn4=" + [mod."github.com/ajg/form"] + version = "v1.5.1" + hash = "sha256-wHKZnoL8gW3YL8frdMIbs703ZX/NruuW5dV13PhxlG8=" + [mod."github.com/ajstarks/svgo"] + version = "v0.0.0-20200725142600-7a3c8b57fecb" + hash = "sha256-y9D4RddhxULcaNnart9u3PNXuQFp1AqRQjo7d3InDC0=" + [mod."github.com/alecthomas/template"] + version = "v0.0.0-20190718012654-fb15b899a751" + hash = "sha256-RsS4qxdRQ3q+GejA8D9Iu31A/mZNms4LbJ7518jWiu4=" + [mod."github.com/alecthomas/units"] + version = "v0.0.0-20190924025748-f65c72e2690d" + hash = "sha256-bC2xzCx7LOE8pYbWnzA6evO8MZk9ueDdvQHUUU/FXhI=" + [mod."github.com/alexbrainman/goissue34681"] + version = "v0.0.0-20191006012335-3fc7a47baff5" + hash = "sha256-TFISoXWlKMawUevo8376o98R6MPG0FBZv5Gdo7TISAM=" + [mod."github.com/alioygur/is"] + version = "v1.0.3" + hash = "sha256-PDROYkpqujdG0e3yz1xhuSnjP8+U9K46xzBrm41wG6o=" + [mod."github.com/andybalholm/cascadia"] + version = "v1.2.0" + hash = "sha256-qZ0c7v8kNuLRRX0f906XmdSh+FWxd9q8uCDIryyrpVg=" + [mod."github.com/anmitsu/go-shlex"] + version = "v0.0.0-20161002113705-648efa622239" + hash = "sha256-ZyXCXxCVsYS7dwZKTWBTSRPizEQsFvGfjtGA0MptL4M=" + [mod."github.com/apache/thrift"] + version = "v0.13.0" + hash = "sha256-7YbRWRTYVF1bWyFvkpxvMvcP2NzbV00zOHBT/Sxt8x8=" + [mod."github.com/armon/circbuf"] + version = "v0.0.0-20150827004946-bbbad097214e" + hash = "sha256-klQjllsJZqZ2KPNx1mZT9XP+UAJkuBhmTnZdNlAflEM=" + [mod."github.com/armon/consul-api"] + version = "v0.0.0-20180202201655-eb2c6b5be1b6" + hash = "sha256-aVqUesaJyU/nrgwlfG2p16VxcF6Hyk4s8diMp0Nuzsg=" + [mod."github.com/armon/go-metrics"] + version = "v0.0.0-20180917152333-f0300d1749da" + hash = "sha256-+zqX1hlJgc+IrXRzBQDMhR8GYQdc0Oj6PiIDfctgh44=" + [mod."github.com/armon/go-radix"] + version = "v0.0.0-20180808171621-7fddfc383310" + hash = "sha256-ZHU4pyBqHHRuQJuYr2K+LqeAnLX9peX07cmSYK+GDHk=" + [mod."github.com/aryann/difflib"] + version = "v0.0.0-20170710044230-e206f873d14a" + hash = "sha256-tQk7egU+OcLzLBlJx6H8QFCoPf2FdBIM/mIZarpO6wM=" + [mod."github.com/aws/aws-lambda-go"] + version = "v1.13.3" + hash = "sha256-qd4LhYF3pE6qtIwMIuR0KwpIMVc1+tG6lrL1lJ/BPxE=" + [mod."github.com/aws/aws-sdk-go"] + version = "v1.27.0" + hash = "sha256-aVMyhNu4srYrrjVTJDGvCBOdCvDqGV140tJcmjdxxBU=" + [mod."github.com/aws/aws-sdk-go-v2"] + version = "v0.18.0" + hash = "sha256-0PiIcJC9CddaMGU1JSExce97htt+cLClTNp2cwu7I7k=" + [mod."github.com/aymerick/raymond"] + version = "v2.0.3-0.20180322193309-b565731e1464+incompatible" + hash = "sha256-/Vj9a/AO/6+K2g2vfCy+oRB9rYLmTAR9Oa0lsgHtmeM=" + [mod."github.com/benbjohnson/clock"] + version = "v1.0.3" + hash = "sha256-1hYm/tTZcVyRvxTQf+6juk0oe4DfoP8LNodmxCCZ97Q=" + [mod."github.com/beorn7/perks"] + version = "v1.0.1" + hash = "sha256-h75GUqfwJKngCJQVE5Ao5wnO3cfKD9lSIteoLp/3xJ4=" + [mod."github.com/bep/debounce"] + version = "v1.2.0" + hash = "sha256-pbhi5V3YH40/+Mzgg0VLPtLvULhOvvF7lJWBLz5Lqu8=" + [mod."github.com/bgentry/speakeasy"] + version = "v0.1.0" + hash = "sha256-Gt1vj6CFovLnO6wX5u2O4UfecY9V2J9WGw1ez4HMrgk=" + [mod."github.com/blang/semver"] + version = "v3.5.1+incompatible" + hash = "sha256-vmoIH5J0esVFmLDT2ecwtalvJqRRoLwomysyvlIRmo8=" + [mod."github.com/bradfitz/go-smtpd"] + version = "v0.0.0-20170404230938-deb6d6237625" + hash = "sha256-5qZJJJw9+nQVcEP4XiI2DjwHgZqU2bZgUgAS0nBeY8Q=" + [mod."github.com/bren2010/proquint"] + version = "v0.0.0-20160323162903-38337c27106d" + hash = "sha256-tEfkICXHfYWPHUiNMUbazUCWCrNJuiuuq4QRe8SCQ/M=" + [mod."github.com/btcsuite/btcd"] + version = "v0.20.1-beta" + hash = "sha256-2yyEl5NvpzzOCAtIgy/vwb9ojTGioVBg6H7D5lSF7h8=" + [mod."github.com/btcsuite/btclog"] + version = "v0.0.0-20170628155309-84c8d2346e9f" + hash = "sha256-1QPk5K1P5oTgo8CuvJioDkU/uUe42aejPro4mc45ctA=" + [mod."github.com/btcsuite/btcutil"] + version = "v0.0.0-20190425235716-9e5f4b9a998d" + hash = "sha256-DmFuG7mBg5ZEIJOsW8TyrYV/VUqucZGBJtUedySDQiQ=" + [mod."github.com/btcsuite/go-socks"] + version = "v0.0.0-20170105172521-4720035b7bfd" + hash = "sha256-67Qxks78SQ0CIze4EZ9wRSsKQ4Le3JQ0wTQVIFkUm6E=" + [mod."github.com/btcsuite/goleveldb"] + version = "v0.0.0-20160330041536-7834afc9e8cd" + hash = "sha256-WzoKz6NdVzQ3TpEMtepq8gGDj0MF3BGjqsIzYbUpwT8=" + [mod."github.com/btcsuite/snappy-go"] + version = "v0.0.0-20151229074030-0bdef8d06723" + hash = "sha256-XJI2BYLpOzxW7OLbfJ6Xf7Gj0ryLOxmo4k04HpZ2JQI=" + [mod."github.com/btcsuite/websocket"] + version = "v0.0.0-20150119174127-31079b680792" + hash = "sha256-ikuWaDjy3H8xKFXaUXv3pQEbCOsdnv2au87Qeopw83Y=" + [mod."github.com/btcsuite/winsvc"] + version = "v1.0.0" + hash = "sha256-P3Daw2hlug+lererp+0qkrGbfU2QGTmUyB8WZZBHXFs=" + [mod."github.com/buckket/go-blurhash"] + version = "v1.1.0" + hash = "sha256-ddu9+KfgqxnBbRNg8LQGJa7oxEHVHihx7etW5cqK9Kc=" + [mod."github.com/buger/jsonparser"] + version = "v0.0.0-20181115193947-bf1c66bbce23" + hash = "sha256-ho3b4mE4sF5vTZOdQqaFhGj1WSqT07Sbn2jtHshk7WQ=" + [mod."github.com/casbin/casbin/v2"] + version = "v2.1.2" + hash = "sha256-KaHzZox0+O6h039UydHubNiBvzkmlDKHeEZkysk+vpw=" + [mod."github.com/cenk/backoff"] + version = "v2.2.1+incompatible" + hash = "sha256-aMpsIH8tC5An/Ldb4yTweEbi/4e5gi7InGitPKimxNU=" + [mod."github.com/cenkalti/backoff"] + version = "v2.2.1+incompatible" + hash = "sha256-aMpsIH8tC5An/Ldb4yTweEbi/4e5gi7InGitPKimxNU=" + [mod."github.com/census-instrumentation/opencensus-proto"] + version = "v0.2.1" + hash = "sha256-3RWTfGGuKbkrOQ91ociOgp9igGvU/FAv3NAidPVoYP8=" + [mod."github.com/cespare/xxhash"] + version = "v1.1.0" + hash = "sha256-nVDTtXH9PC3yJ0THaQZEN243UP9xgLi/clt5xRqj3+M=" + [mod."github.com/cespare/xxhash/v2"] + version = "v2.1.1" + hash = "sha256-cF+sDnnTZ1xRwjsy08SVSV/JoZalwY+dg0Zkghy6BNw=" + [mod."github.com/cheekybits/genny"] + version = "v1.0.0" + hash = "sha256-Qx5Jb+6dr1EOhE4S0RKO+xtOnnv5d3aTU32arFy+MUs=" + [mod."github.com/cheekybits/is"] + version = "v0.0.0-20150225183255-68e9c0620927" + hash = "sha256-jbwqhZZJedT65ImkUXWfzMqxuwUAzygG8isPzOH3a9Y=" + [mod."github.com/cheggaaa/pb"] + version = "v1.0.29" + hash = "sha256-G0LynvELyT0XBFH/Xp4OcTr10OKsV3/K6sHNEyz4gn8=" + [mod."github.com/chzyer/logex"] + version = "v1.1.10" + hash = "sha256-BNOaV/CFAqOymWW3R2m1sCikdCwFZM/pVkylzoeU6yI=" + [mod."github.com/chzyer/readline"] + version = "v0.0.0-20180603132655-2972be24d48e" + hash = "sha256-2Uj5LGpHEbLQG3d/7z9AL8DknUBZyoTAMs4j+VVDmIA=" + [mod."github.com/chzyer/test"] + version = "v0.0.0-20180213035817-a1ea475d72b1" + hash = "sha256-U0irpUSqegh7Nzg1ErPuyjESOcIXXOWf7ikKMbES2mY=" + [mod."github.com/clbanning/x2j"] + version = "v0.0.0-20191024224557-825249438eec" + hash = "sha256-R8zypK+YhSbbnDosHVwQsLor+Q260OdDsZg3slc5p3o=" + [mod."github.com/client9/misspell"] + version = "v0.3.4" + hash = "sha256-MIKnt4va/nPl+5cCgOvCyRGIORTnguieQhlj8ery4BU=" + [mod."github.com/cncf/udpa/go"] + version = "v0.0.0-20201120205902-5459f2c99403" + hash = "sha256-L95UntjNyEIbr4AuquYiH4aIDu6DEiK14UsRYHJIR9E=" + [mod."github.com/cockroachdb/datadriven"] + version = "v0.0.0-20190809214429-80d97fb3cbaa" + hash = "sha256-l9bswpYsaqhhls7BsJjfhbpDBEreIQtKNjHDn9Tcamc=" + [mod."github.com/codahale/hdrhistogram"] + version = "v0.0.0-20161010025455-3a0bb77429bd" + hash = "sha256-p9BZ4OPNXcssJwM1k6pSvcVADXonNr6YSMH3Jd27Vf0=" + [mod."github.com/codegangsta/inject"] + version = "v0.0.0-20150114235600-33e0aa1cb7c0" + hash = "sha256-UjG3ItBHuFybFQ9wHatiM6JJs1n6t/wYxMDQ9EeeCss=" + [mod."github.com/coreos/etcd"] + version = "v3.3.10+incompatible" + hash = "sha256-fCyJRKX9dgcb2JwqiQL/OshS3Ilmm7bY3OCISxZ6l68=" + [mod."github.com/coreos/go-etcd"] + version = "v2.0.0+incompatible" + hash = "sha256-Uo5heUPCLTGZ8ns1Zi48kuNnPtvJ/7kLXpMGpT4kY/U=" + [mod."github.com/coreos/go-semver"] + version = "v0.3.0" + hash = "sha256-ielBK5+kGscOuygfFNNr5iKuuF1qKBiXLlK8eGuA4Bw=" + [mod."github.com/coreos/go-systemd"] + version = "v0.0.0-20181012123002-c6f51f82210d" + hash = "sha256-oRX6MkG3Jx/MG7OW2uhjgdYQBz2cg8XbNVm7MS0u6Ks=" + [mod."github.com/coreos/go-systemd/v22"] + version = "v22.1.0" + hash = "sha256-F8i7xqOsUq47bHbhCzdNREIHQ4t1+5SuCVfs1yyES9I=" + [mod."github.com/coreos/pkg"] + version = "v0.0.0-20160727233714-3ac0863d7acf" + hash = "sha256-32E2UkIQwI7CQOCcCFHbRcd43a87nNXtGFBVOJVy314=" + [mod."github.com/cpuguy83/go-md2man"] + version = "v1.0.10" + hash = "sha256-XP8oKAx5LgQ0fO1rjO9tWnbXB431VOzXVaRDPUP900g=" + [mod."github.com/cpuguy83/go-md2man/v2"] + version = "v2.0.0-20190314233015-f79a8a8ca69d" + hash = "sha256-Pi84FPmTnz+Oq8tV9Lx7cMopiMculHkUtUmtWCuaX1s=" + [mod."github.com/crackcomm/go-gitignore"] + version = "v0.0.0-20170627025303-887ab5e44cc3" + hash = "sha256-dPLTmVoRFY2nk6IhuXMQaTzEmYoDDrXccA0MgKBBfs0=" + [mod."github.com/creack/pty"] + version = "v1.1.7" + hash = "sha256-o235RbsTlx++gnUf46iU5SPgxX5tQblrT5wYFAWnqvE=" + [mod."github.com/cskr/pubsub"] + version = "v1.0.2" + hash = "sha256-Lsk/IM8XCyErOhwfhiDCqcdy58Yt5TFeT5/mrspjKHM=" + [mod."github.com/cupcake/sigil"] + version = "v0.0.0-20131127230922-6bf9722f2ae8" + hash = "sha256-zj78W+DugvlxoiIcjLIbKTb10ZhNz3HjBVLlqsVVWLk=" + [mod."github.com/davecgh/go-spew"] + version = "v1.1.1" + hash = "sha256-nhzSUrE1fCkN0+RL04N4h8jWmRFPPPWbCuDc7Ss0akI=" + [mod."github.com/davidlazar/go-crypto"] + version = "v0.0.0-20170701192655-dcfb0a7ac018" + hash = "sha256-l1GcBWlIkPDISXpSzGYCfJLXNBZC0vJWgcBOz6lGOdI=" + [mod."github.com/dgraph-io/badger"] + version = "v1.6.2" + hash = "sha256-D/iXyiNZ8/7tBtA9msk10vVWfohWEPqFdobzRwKlvQQ=" + [mod."github.com/dgraph-io/ristretto"] + version = "v0.0.2" + hash = "sha256-iDVBuJDNQbLlSjPQfife1j0Lv0IYIejkCX8h5Sse6Eo=" + [mod."github.com/dgrijalva/jwt-go"] + version = "v3.2.0+incompatible" + hash = "sha256-t5rhczm+60rYmMg0mZTp86dJkzuGp/OLd5ccXek+oiI=" + [mod."github.com/dgryski/go-farm"] + version = "v0.0.0-20190423205320-6a90982ecee2" + hash = "sha256-PQ7kbI/liOpUeja/PpnkejJwG5HTENK2XGEDfZ8kdPQ=" + [mod."github.com/dgryski/go-rendezvous"] + version = "v0.0.0-20200823014737-9f7001d12a5f" + hash = "sha256-n/7xo5CQqo4yLaWMSzSN1Muk/oqK6O5dgDOFWapeDUI=" + [mod."github.com/dhowden/tag"] + version = "v0.0.0-20201120070457-d52dcb253c63" + hash = "sha256-Mw6oT/gSGet6V92jhVlhqD4J0OP77suQCvGDvJKFKVg=" + [mod."github.com/didip/tollbooth"] + version = "v4.0.2+incompatible" + hash = "sha256-M8K9oYioGBJnSH+Jrf16uwKbC0uacj6I2YiS1bD9W8o=" + [mod."github.com/disintegration/imaging"] + version = "v1.6.2" + hash = "sha256-pSeMTPvSkxlthh65LjNYYhPLvCZDkBgVgAGYWW0Aguo=" + [mod."github.com/djherbis/stream"] + version = "v1.3.1" + hash = "sha256-yliKr1LHfUh2Mp/3Doi5RFcEMSRXxqgT7kvD9cO+0UA=" + [mod."github.com/dsoprea/go-exif/v2"] + version = "v2.0.0-20200321225314-640175a69fe4" + hash = "sha256-cj74lakWkQU3pI/69E+bEBcZtxe4zoaWqak3U+ToYGQ=" + [mod."github.com/dsoprea/go-exif/v3"] + version = "v3.0.0-20210131231135-d154f10435cc" + hash = "sha256-VCtjHQ9UejzI/jFUPT9x8RxCBuEGsGDWZbt83eqseBQ=" + [mod."github.com/dsoprea/go-logging"] + version = "v0.0.0-20200710184922-b02d349568dd" + hash = "sha256-qc4Nzj7uHl5VRc5Q+iXVCjOmfDQl5wIoiuJKque5jCY=" + [mod."github.com/dsoprea/go-utility"] + version = "v0.0.0-20200711062821-fab8125e9bdf" + hash = "sha256-CJydHGcXtl0xU94rKj1AFbuyDV0FdMWEhUycdnpUpvw=" + [mod."github.com/dsoprea/go-utility/v2"] + version = "v2.0.0-20200717064901-2fccff4aa15e" + hash = "sha256-fFgy5LuP6chSY+4K0GbqIGAiZdQ9PwKJdGhHxmpSvg4=" + [mod."github.com/dustin/go-humanize"] + version = "v1.0.0" + hash = "sha256-gy4G1PnHD9iw2MitHX6y1y93qr3C9IncmXL7ttUMDs8=" + [mod."github.com/dyatlov/go-oembed"] + version = "v0.0.0-20191103150536-a57c85b3b37c" + hash = "sha256-QX3b7h0mkslDh5QtUU1ZS6f1YH9lGEjz5xdxdmUb7l8=" + [mod."github.com/dyatlov/go-opengraph"] + version = "v0.0.0-20210112100619-dae8665a5b09" + hash = "sha256-5bs7CYaVEM5IaG4VXSL9adrkcIwiTO+0PmHMokM4ek4=" + [mod."github.com/eapache/go-resiliency"] + version = "v1.1.0" + hash = "sha256-/Ynpe49dMLxerhl/veyog9JCC5PEAjKyqCYXTtjgr/4=" + [mod."github.com/eapache/go-xerial-snappy"] + version = "v0.0.0-20180814174437-776d5712da21" + hash = "sha256-LUUdtFE10fzGDhDZ4MD/rkijNzvw1+/tD4v3s1sgjFk=" + [mod."github.com/eapache/queue"] + version = "v1.1.0" + hash = "sha256-z2MXjC0gr8c7rGr1FzHmx98DsTclTta2fsM+kiwptx0=" + [mod."github.com/edsrzf/mmap-go"] + version = "v1.0.0" + hash = "sha256-k1DYvCqO3BKNcGEve/nMW0RxzMkK2tGfXbUbycqcVSo=" + [mod."github.com/eknkc/amber"] + version = "v0.0.0-20171010120322-cdade1c07385" + hash = "sha256-qXW4k+4Y20OnOH3T3y3wxnMAGmpvS04Pf8zyyfxJXJQ=" + [mod."github.com/elgris/jsondiff"] + version = "v0.0.0-20160530203242-765b5c24c302" + hash = "sha256-mDTyEvoTjsvxp/xOeBUhVvtfr4MXS9QbnhWGUTTAoUo=" + [mod."github.com/envoyproxy/go-control-plane"] + version = "v0.9.9-0.20201210154907-fd9021fe5dad" + hash = "sha256-sOgNhgnmhHZVhI55N6lG0wNIkey+3uk6f8n9J0aBm2k=" + [mod."github.com/envoyproxy/protoc-gen-validate"] + version = "v0.1.0" + hash = "sha256-2htufg3hdOHfbDVI5wFpsuaiDIhH6O1taUGJMdVbjlQ=" + [mod."github.com/etcd-io/bbolt"] + version = "v1.3.3" + hash = "sha256-DM/GTsa/Oi+i+lVLgj4xFL5xXAhprJwz+LEnPZ/9wDY=" + [mod."github.com/facebookgo/atomicfile"] + version = "v0.0.0-20151019160806-2de1f203e7d5" + hash = "sha256-Zgu5YTeVIz1wgKi13l07A4Rd8l26Iobl7jIA4002Xe8=" + [mod."github.com/facebookgo/clock"] + version = "v0.0.0-20150410010913-600d898af40a" + hash = "sha256-Qh3po2B69wTmUwMS8QcJ3Lz3GpGlN5YPjcVQijXvcvw=" + [mod."github.com/faiface/beep"] + version = "v1.0.2" + hash = "sha256-u9+N7vppatehMZPpgUoIqtFW3Z7EKv3dcQgHbj2YQB4=" + [mod."github.com/fasthttp-contrib/websocket"] + version = "v0.0.0-20160511215533-1f3b11f56072" + hash = "sha256-J620vRd+Z+bSRSRWx+UyS8VqW4IAIPkvuEUYGiuvTPk=" + [mod."github.com/fastly/go-utils"] + version = "v0.0.0-20180712184237-d95a45783239" + hash = "sha256-qB9zUQgDG7W2kvbsUSZ+Qb1Lwgd4vBSeIp0+p1JK8Yc=" + [mod."github.com/fatih/color"] + version = "v1.10.0" + hash = "sha256-8iRHT86JzKRgxVG+Ip9b+0JyCgd5ZAL5UIAqkWI1Vmg=" + [mod."github.com/fatih/structs"] + version = "v1.1.0" + hash = "sha256-OCmubTLF1anwNnkvFZDYHnF6hFlX0WDoe/9+dDlaMPM=" + [mod."github.com/flynn/go-shlex"] + version = "v0.0.0-20150515145356-3f9db97f8568" + hash = "sha256-KmpvjrFQJgzWCIHsXwJ7fR0pRu4ixie0UHc+rz0d5Mg=" + [mod."github.com/flynn/noise"] + version = "v0.0.0-20180327030543-2492fe189ae6" + hash = "sha256-eHzhhwGQ5tKapBJ61Cwso6VqJHlYvoML0ljLolROzrk=" + [mod."github.com/fogleman/gg"] + version = "v1.3.0" + hash = "sha256-Fs2JI0FmF4N5EzXJzGAPZMxZxo6wKyebkN/iBZ9sdNo=" + [mod."github.com/francoispqt/gojay"] + version = "v1.2.13" + hash = "sha256-BrRZd2lEF5CQVmUTLW9AwQ0DY5ZbFJ8c7NVJ5Rsuqcc=" + [mod."github.com/franela/goblin"] + version = "v0.0.0-20200105215937-c9ffbefa60db" + hash = "sha256-zm2juQIvmoSI/sKOtgOn7DCQwW6rCfyrjcaxRaJ5sGE=" + [mod."github.com/franela/goreq"] + version = "v0.0.0-20171204163338-bcd34c9993f8" + hash = "sha256-Sx911OBB67XYUSbjoGtJ5I/WL+aXR67FpCu4wiwQqhQ=" + [mod."github.com/fsnotify/fsnotify"] + version = "v1.4.9" + hash = "sha256-HZBMhbFqcZM9oxSbWqISzEE7GF7JZpco5tyta6c4OcQ=" + [mod."github.com/gabriel-vasile/mimetype"] + version = "v1.1.2" + hash = "sha256-jfWUFg6EZjM8Jxlfi+irRpW2q3QoO9HonFRrGtRtFiY=" + [mod."github.com/gavv/httpexpect"] + version = "v2.0.0+incompatible" + hash = "sha256-eo/yVBdSCAlQyXp5oRdX5JG5M0zlSYNJKj8yGzU9Czc=" + [mod."github.com/gdamore/encoding"] + version = "v1.0.0" + hash = "sha256-aV6wbQTwdOBHXMqWbhIxQ6YLun+gY6lIdSKKROkvte4=" + [mod."github.com/gdamore/tcell"] + version = "v1.1.1" + hash = "sha256-LeEQj8eFHYTr6hhFWUTbw8bkbCtBJFLH8REzcbu1gkY=" + [mod."github.com/getsentry/sentry-go"] + version = "v0.10.0" + hash = "sha256-wbpQJxBPECFqNfhaLzSPPoA1OZXjH5KPPOfwkM6Nhjw=" + [mod."github.com/ghodss/yaml"] + version = "v1.0.0" + hash = "sha256-D+2i+EwF2YptR0m/OG4WIVVLL7tUC7XvgRQef2usfGo=" + [mod."github.com/gin-contrib/sse"] + version = "v0.0.0-20190301062529-5545eab6dad3" + hash = "sha256-ZWXW9G3h2+tpYelMDwg7k+5MvT74uDweD+zYbEzcDEo=" + [mod."github.com/gin-gonic/gin"] + version = "v1.4.0" + hash = "sha256-LfAoZNW1/RjOYy+jwkh8ljkRaWmXnxvuoUiLi8iN3aY=" + [mod."github.com/gliderlabs/ssh"] + version = "v0.1.1" + hash = "sha256-tVUzbIHBVqLENlGu6lhJtkTKv2UzQgad632h5w+b1C8=" + [mod."github.com/go-bindata/go-bindata/v3"] + version = "v3.1.3" + hash = "sha256-fjSF/djx1wlcCOMC3+o/zp1eKyZFhyl4u7TByh2tccM=" + [mod."github.com/go-check/check"] + version = "v0.0.0-20180628173108-788fd7840127" + hash = "sha256-KsRJNTprd1UijnJusbHwQGM7Bdm45Jt/QL+cIUGNa2w=" + [mod."github.com/go-errors/errors"] + version = "v1.1.1" + hash = "sha256-iLvEHXBeEu+31VsvP+Dcqh842/C1eiMx7bO1pnPkPL0=" + [mod."github.com/go-gl/glfw"] + version = "v0.0.0-20190409004039-e6da0acd62b1" + hash = "sha256-tqPStzM1xOuEWqAv4pBbzB+lNIxEqqyCCP0wWCbrlyY=" + [mod."github.com/go-gl/glfw/v3.3/glfw"] + version = "v0.0.0-20191125211704-12ad95a8df72" + hash = "sha256-eTW2DetpGKouzaorbcPRejOYwCshASEV5io8WtTlHE8=" + [mod."github.com/go-kit/kit"] + version = "v0.10.0" + hash = "sha256-fkr/mndYfh5dSepwRggu3ZIpwAomvwrg4LQ/foBpAd4=" + [mod."github.com/go-logfmt/logfmt"] + version = "v0.5.0" + hash = "sha256-0vvTRggBz57ItUOK+IFDwVi9/hRk13ohLEEZZ2t8m1U=" + [mod."github.com/go-martini/martini"] + version = "v0.0.0-20170121215854-22fa46961aab" + hash = "sha256-kHpDnnH+PeH8gjBfQlKxxrK1sx+HcyAC1rFUu3gdNwY=" + [mod."github.com/go-redis/redis/v8"] + version = "v8.7.1" + hash = "sha256-pHauD1/RzoHtIKPJCOp7mpxaJbhxVXLBwL1bsJcHDIs=" + [mod."github.com/go-sql-driver/mysql"] + version = "v1.5.0" + hash = "sha256-DDpwoQ/rAo3Eml3IZYZBu/2ohtGsAPBnxQsuZiKV4BU=" + [mod."github.com/go-stack/stack"] + version = "v1.8.0" + hash = "sha256-26RlTEcAkbewMUtmirKrDGQ1WJlNousp69v7HMopYnI=" + [mod."github.com/gobwas/httphead"] + version = "v0.0.0-20180130184737-2c6c146eadee" + hash = "sha256-Ws/x27D+/DKO5SKzMYIXWd+xDxMxJ3MVok6xdFym9kg=" + [mod."github.com/gobwas/pool"] + version = "v0.2.0" + hash = "sha256-8Rh94P7R/2JbI4JQgLiTF/DjpcxfcXU0JD7IchhSd6s=" + [mod."github.com/gobwas/ws"] + version = "v1.0.2" + hash = "sha256-w5HDb/cm1MwabqPQWPWVOo+Kro76RKwURG0Q0mxAOmY=" + [mod."github.com/godbus/dbus/v5"] + version = "v5.0.3" + hash = "sha256-B4TjaMvIFyrLpmjBEZywnB93E8Xi317HCtSEnABQeEs=" + [mod."github.com/gogo/googleapis"] + version = "v1.1.0" + hash = "sha256-yNc6PMrd72t+gdNb+ceUUMTXNN9GZyr/0zGJg0LdLcU=" + [mod."github.com/gogo/protobuf"] + version = "v1.3.2" + hash = "sha256-pogILFrrk+cAtb0ulqn9+gRZJ7sGnnLLdtqITvxvG6c=" + [mod."github.com/golang/freetype"] + version = "v0.0.0-20170609003504-e2365dfdc4a0" + hash = "sha256-AHAFBd20/tqxohkWyQkui2bUef9i1HWYgk9LOIFErvA=" + [mod."github.com/golang/geo"] + version = "v0.0.0-20200319012246-673a6f80352d" + hash = "sha256-A9IV55tUYWEDoPsABdkqPeE+5JsajQ7ikzCs4KccnKE=" + [mod."github.com/golang/glog"] + version = "v0.0.0-20160126235308-23def4e6c14b" + hash = "sha256-YDyL9TRikSXHSrYtITVA/ovYIYrdnZGym14XnslAYkk=" + [mod."github.com/golang/groupcache"] + version = "v0.0.0-20200121045136-8c9f03a8e57e" + hash = "sha256-0E3bzqOQk4xolVEGm0GXZ6tUpgCWF7DolyyKkdPJUm4=" + [mod."github.com/golang/lint"] + version = "v0.0.0-20180702182130-06c8688daad7" + hash = "sha256-hzB6hpOvURa3yzCs1ttltVQ/sXfpwoCXMQqUv3kjKXY=" + [mod."github.com/golang/mock"] + version = "v1.4.4" + hash = "sha256-13sT+TtOnOcjKXfrLwbLtlc1YrqMkY++R0plBl2aFAU=" + [mod."github.com/golang/protobuf"] + version = "v1.4.3" + hash = "sha256-GoytLjWoBKfZq3eBDa4rGQNP2la2IrpkFSWjsH/sPBI=" + [mod."github.com/golang/snappy"] + version = "v0.0.1" + hash = "sha256-OgJzsNwGEtOIq4kXHd/C8YD+B+54wfnmGZCPSv+c4z4=" + [mod."github.com/gomodule/redigo"] + version = "v1.7.1-0.20190724094224-574c33c3df38" + hash = "sha256-5hNHChYsk2Ghl0pDNSNOo0+uA0lbhaduhUHinnBF/OI=" + [mod."github.com/google/btree"] + version = "v1.0.0" + hash = "sha256-5gr0RMnlvrzCke3kwpkf92WvW3x5nnKZesoulyoYRC0=" + [mod."github.com/google/go-cmp"] + version = "v0.5.4" + hash = "sha256-kZWs4w9qj+za4xCz++Q9cSZ8aEhG3R9eOU8Iaha/qdE=" + [mod."github.com/google/go-github"] + version = "v17.0.0+incompatible" + hash = "sha256-5EGZnkefwLCEODLICIgaq39UoOzBJqpeLraoc2hJfM8=" + [mod."github.com/google/go-querystring"] + version = "v1.0.0" + hash = "sha256-n0ewWuB/JYt8bfrefQHRJ9uak9QzXeQs68TW7fESgXY=" + [mod."github.com/google/gofuzz"] + version = "v1.0.0" + hash = "sha256-ZvgcSQt4kMwS6nvPp3jrlCHSH3bky1oBD6kytnEa5GM=" + [mod."github.com/google/gopacket"] + version = "v1.1.18" + hash = "sha256-7uLqTn03J8C8k5AEZYR7zaUxIRmHRWYSLSzElhKavA4=" + [mod."github.com/google/martian"] + version = "v2.1.0+incompatible" + hash = "sha256-N3tPu89U5MQqmtFIqSEfqEXNgnHf883TAmXKvA2N8KQ=" + [mod."github.com/google/pprof"] + version = "v0.0.0-20200212024743-f11f1df84d12" + hash = "sha256-L8mufSQOkBFr/cSv1SZAayY0QJzAmuJavjXiuhps/Kg=" + [mod."github.com/google/renameio"] + version = "v0.1.0" + hash = "sha256-XQ5yI+LMfFQuK7+T3Xx5jiaRP7GmiQSsPkFmm1TpIs4=" + [mod."github.com/google/uuid"] + version = "v1.1.2" + hash = "sha256-DXttjObhEiMn5/OH+mYkJU6u03Gwsx5t08lTsIFyd+U=" + [mod."github.com/googleapis/gax-go"] + version = "v2.0.0+incompatible" + hash = "sha256-sAX+kv1TG/p8AuwjhRceRhk8g29NYKSmEzuvnU7pIkE=" + [mod."github.com/googleapis/gax-go/v2"] + version = "v2.0.5" + hash = "sha256-2ibpBbDxLVeYHd8gdszHb3w8rgKrChbUNlkaxW9lIhU=" + [mod."github.com/gopherjs/gopherjs"] + version = "v0.0.0-20190812055157-5d271430af9f" + hash = "sha256-trV26edBrEL82CcBy3toXYPE75MnQaU1BhxKSrnHg7w=" + [mod."github.com/gopherjs/gopherwasm"] + version = "v1.0.0" + hash = "sha256-MXMaPeTo1j8VzjT4ThQwllofeEWsWYk0YNnihwyNQGA=" + [mod."github.com/gorilla/context"] + version = "v1.1.1" + hash = "sha256-pA7z/VCUIHuoP4wOeeJx+tLUFx7G8HQBjK6yfZCF5A4=" + [mod."github.com/gorilla/mux"] + version = "v1.8.0" + hash = "sha256-s905hpzMH9bOLue09E2JmzPXfIS4HhAlgT7g13HCwKE=" + [mod."github.com/gorilla/websocket"] + version = "v1.4.2" + hash = "sha256-GhBLM/XTm2lFCyDvJbnCLAI2OyYXQV6W+jRPOQ1PdVY=" + [mod."github.com/gregjones/httpcache"] + version = "v0.0.0-20180305231024-9cad4c3443a7" + hash = "sha256-2ngFfFuSm8YSTNZWGQuN5yTpsXlwY2R8aaIzjDnjTXI=" + [mod."github.com/grpc-ecosystem/go-grpc-middleware"] + version = "v1.0.1-0.20190118093823-f849b5445de4" + hash = "sha256-qxUpPmUdsTGBRyX1PBCsVS6Jf8u0o8KCRuZNlheGo1A=" + [mod."github.com/grpc-ecosystem/go-grpc-prometheus"] + version = "v1.2.0" + hash = "sha256-XtdBJuUYTXEokPrUetjD6iEqxFTBgyrm1M0X7r+1Uys=" + [mod."github.com/grpc-ecosystem/grpc-gateway"] + version = "v1.9.5" + hash = "sha256-8vRk3cWgXBaq64feKhCcvA9T1J/kwr50AYhZyX2jZNA=" + [mod."github.com/gxed/hashland/keccakpg"] + version = "v0.0.1" + hash = "sha256-5L9cBwUjyZO/jukX24O6K8+L80zBvyIAvz4TXaF2HMA=" + [mod."github.com/gxed/hashland/murmur3"] + version = "v0.0.1" + hash = "sha256-4EtSRetMPT+/lnCOFXDd9R3GT2K8UoDOusx08ITNPZg=" + [mod."github.com/hajimehoshi/go-mp3"] + version = "v0.1.1" + hash = "sha256-X/vnN0VuK6yE54wHZB+tD4G3ACxzBh95/bL8mT1AMzc=" + [mod."github.com/hajimehoshi/oto"] + version = "v0.3.1" + hash = "sha256-H9Yh5b/+izrTGTKlBJ1jz7vjSXkpIe0J6Ov1j/74h3s=" + [mod."github.com/hannahhoward/cbor-gen-for"] + version = "v0.0.0-20200817222906-ea96cece81f1" + hash = "sha256-DkN0PQb6P+F0B7nQKMtWEyHbqT6G1WFTbXvMR+bjekI=" + [mod."github.com/hannahhoward/go-pubsub"] + version = "v0.0.0-20200423002714-8d62886cc36e" + hash = "sha256-JqoDIaztUDEl23C53r2+4RwmDvkosdzbJp/Lz+KLL5o=" + [mod."github.com/hashicorp/consul/api"] + version = "v1.3.0" + hash = "sha256-fMORNFAWK2GkRbBl/KzNHrvtCfwz/7P66HzDaE4GnuE=" + [mod."github.com/hashicorp/consul/sdk"] + version = "v0.3.0" + hash = "sha256-lF47JPGfmeGjpuQw9VSNs2Mi+G7FQLKrrHteX3iXfpU=" + [mod."github.com/hashicorp/errwrap"] + version = "v1.0.0" + hash = "sha256-LGSLrefkABG1kH1i+GUWiD2/ggJxiZEJ+D2YNbhZjmo=" + [mod."github.com/hashicorp/go-cleanhttp"] + version = "v0.5.1" + hash = "sha256-c54zcHr9THj3MQk7hrDQcpjOcQi1MvXZ4Kpin6EbfR4=" + [mod."github.com/hashicorp/go-hclog"] + version = "v0.15.0" + hash = "sha256-5Mxo+zSfjQnzckCPxKJzRllugdA8OaaU0zz+jAEQGvY=" + [mod."github.com/hashicorp/go-immutable-radix"] + version = "v1.0.0" + hash = "sha256-JmNxdGaJG63Ty/sVnPjqvTyA4/k5wkzZ/QvpMK2uduw=" + [mod."github.com/hashicorp/go-msgpack"] + version = "v0.5.3" + hash = "sha256-2OUYjD/Jt12TFBrtH0wRqg+lzRljDxSIhk2CqBLUczo=" + [mod."github.com/hashicorp/go-multierror"] + version = "v1.1.0" + hash = "sha256-c0zgZsrOoA1+j7N7uIU0ZAUAa7mM8t9nfJgele+/sl4=" + [mod."github.com/hashicorp/go-plugin"] + version = "v1.4.0" + hash = "sha256-PyW179J0Na97zBX1htsN3Xm8dxLtYCDm4t87Vy25DKo=" + [mod."github.com/hashicorp/go-rootcerts"] + version = "v1.0.0" + hash = "sha256-4NZJAT5/vocyto+dv6FmW4kFiYldmNvewowsYK/LiTI=" + [mod."github.com/hashicorp/go-sockaddr"] + version = "v1.0.0" + hash = "sha256-orG+SHVsp5lgNRCErmhMLABVFQ3ZWfYIJ/4LTFzlvao=" + [mod."github.com/hashicorp/go-syslog"] + version = "v1.0.0" + hash = "sha256-YRuq6oPMwAFVY7mvwpMDvZqGwNnb5CjBYyKI/x5mbCc=" + [mod."github.com/hashicorp/go-uuid"] + version = "v1.0.1" + hash = "sha256-s1wIvBu37z4U3qK9sdUR1CtbD39N6RwfX4HgDCpCa0s=" + [mod."github.com/hashicorp/go-version"] + version = "v1.2.0" + hash = "sha256-P0i5w1OAImpSMS2KBRMMtIRfWeAAy4k4R7iHEIw3ka8=" + [mod."github.com/hashicorp/go.net"] + version = "v0.0.1" + hash = "sha256-JKal3E+wPO+Hk838opKV4HHKB4O72Xy+77ncXlLkWRk=" + [mod."github.com/hashicorp/golang-lru"] + version = "v0.5.4" + hash = "sha256-1skUMZX+iIf66J1TBVYGWO1OWwQcaoXut3mne331q+k=" + [mod."github.com/hashicorp/hcl"] + version = "v1.0.0" + hash = "sha256-xsRCmYyBfglMxeWUvTZqkaRLSW+V2FvNodEDjTGg1WA=" + [mod."github.com/hashicorp/logutils"] + version = "v1.0.0" + hash = "sha256-e8t8Dm8sp/PzKClN1TOmFcrTAWNh4mZHSW7cAjVx3Bw=" + [mod."github.com/hashicorp/mdns"] + version = "v1.0.0" + hash = "sha256-ravx4tklQG43OEjPiJn68iJM9ODZ6hgU0idFCEOiJGM=" + [mod."github.com/hashicorp/memberlist"] + version = "v0.1.3" + hash = "sha256-IsxqevYulPt+2VGtlq068Jyq1YfIk4Ohh9TgakIGxnc=" + [mod."github.com/hashicorp/serf"] + version = "v0.8.2" + hash = "sha256-diRxWOouFLTO75f2E9NlrKgie/qsT+gOOrrbf4tACHw=" + [mod."github.com/hashicorp/yamux"] + version = "v0.0.0-20200609203250-aecfd211c9ce" + hash = "sha256-NVo7RATfhcrG6TFQMCVh2pPWLVKsqAwYzjHNEdG5eb8=" + [mod."github.com/hpcloud/tail"] + version = "v1.0.0" + hash = "sha256-7ByBr/RcOwIsGPCiCUpfNwUSvU18QAY+HMnCJr8uU1w=" + [mod."github.com/hudl/fargo"] + version = "v1.3.0" + hash = "sha256-iCTRPweBtUu6NT5rlaAA5W0MHhnoRzkAtqHckY7k97g=" + [mod."github.com/huin/goupnp"] + version = "v1.0.0" + hash = "sha256-Jp76asfqETscVB+R+TzKQRc5ezA64mBVgJ244F7Mx4k=" + [mod."github.com/huin/goutil"] + version = "v0.0.0-20170803182201-1ca381bf3150" + hash = "sha256-Irhe+oNPd4KmxBtm5Ou8hMrP09yPWOw7Fyxip5nykCo=" + [mod."github.com/ianlancetaylor/demangle"] + version = "v0.0.0-20181102032728-5e5cf60278f6" + hash = "sha256-5cS82VAt2PtDlx18XzvNwhp7zk/fryC9HCzdyEKYEro=" + [mod."github.com/imkira/go-interpol"] + version = "v1.1.0" + hash = "sha256-8NaipC19EEqREyLc0QZq9aDGz+SFOFyhgeyCK9wdEKA=" + [mod."github.com/inconshreveable/mousetrap"] + version = "v1.0.0" + hash = "sha256-ogTuLrV40FwS4ueo4hh6hi1wPywOI+LyIqfNjsibwNY=" + [mod."github.com/influxdata/influxdb1-client"] + version = "v0.0.0-20191209144304-8bf82d3c094d" + hash = "sha256-miivfmEqGGgXvGh+pZHADWRZFF1WxfxE96q7nu+JVDI=" + [mod."github.com/ipfs/bbloom"] + version = "v0.0.4" + hash = "sha256-4k778kBlNul2Rc4xuNQ9WA4kT0V7x5X9odZrT+2xjTU=" + [mod."github.com/ipfs/go-bitswap"] + version = "v0.3.3" + hash = "sha256-JqdZ5/COuGFVfZ5JQs4ux1sv8vrWlJbEHpPEI4lWj/E=" + [mod."github.com/ipfs/go-block-format"] + version = "v0.0.2" + hash = "sha256-bgYso07OxWcHQx0ZxjE/G80798DnhywUSvqBb0jK48g=" + [mod."github.com/ipfs/go-blockservice"] + version = "v0.1.4" + hash = "sha256-Ykrrdkfhkthyeys7GHjhN/vmGsvsDbjmZa5kSKx8aPE=" + [mod."github.com/ipfs/go-cid"] + version = "v0.0.7" + hash = "sha256-Hkdou57cagKg4fzDRNsu9e9Ji/NJuW7mvbT/yzTAAWg=" + [mod."github.com/ipfs/go-cidutil"] + version = "v0.0.2" + hash = "sha256-QGpax65+rzxhqORAIbbeBhCsdj1u7bTn9d6gECxK+nE=" + [mod."github.com/ipfs/go-datastore"] + version = "v0.4.5" + hash = "sha256-n2i+TGC8nqgNfhDIHmkVte0EEfuz5lvUf+GlZs08oDg=" + [mod."github.com/ipfs/go-detect-race"] + version = "v0.0.1" + hash = "sha256-ymK+c8hVHVR6JY8EwAlhKJnfigCZwlqkKOifZgwGC2c=" + [mod."github.com/ipfs/go-ds-badger"] + version = "v0.2.6" + hash = "sha256-MKHY8sqXnPsnGjgNUVV9l4vPLXUWrUbqf0lRv65X75M=" + [mod."github.com/ipfs/go-ds-flatfs"] + version = "v0.4.5" + hash = "sha256-vYCnzgnCBogmsR9Kc9c7Idw1woFqYHQIjvjlta2Kfzo=" + [mod."github.com/ipfs/go-ds-leveldb"] + version = "v0.4.2" + hash = "sha256-Pxr+nP5fLoeYEWwzZEWCdylh1adSYnVwqRjwnuqFvEU=" + [mod."github.com/ipfs/go-ds-measure"] + version = "v0.1.0" + hash = "sha256-tLDZkNauoo8mm+XcgsQRqvBp+gygVEkfv8Jlf/lnqaE=" + [mod."github.com/ipfs/go-filestore"] + version = "v0.0.3" + hash = "sha256-sj+mA+pV/0gVYpiKbbRsZXPC7YQbbT6k99rlOLrvW+U=" + [mod."github.com/ipfs/go-fs-lock"] + version = "v0.0.6" + hash = "sha256-cK+YqS1SEIwTWo8NntV9Km91yNsBRbxS6W7nuq62D8E=" + [mod."github.com/ipfs/go-graphsync"] + version = "v0.6.0" + hash = "sha256-HoPLXBGDYrWrr7bA0VCC36n9J55iQFfkryU3GcO3twM=" + [mod."github.com/ipfs/go-ipfs"] + version = "v0.8.0" + hash = "sha256-T2+NSEwIYlrEDEBgqUwGZwS3GX7CmUk4c1XwZ2uEu7w=" + [mod."github.com/ipfs/go-ipfs-api"] + version = "v0.2.0" + hash = "sha256-wjeqqDIVAaGTK9tBeiNWg9vm4EmPFOzEzoI0v39Rv1o=" + [mod."github.com/ipfs/go-ipfs-blockstore"] + version = "v0.1.4" + hash = "sha256-s0gB1RSxQfv3UHS868rPeBw5oskpZSSEpHj2/1lWTLY=" + [mod."github.com/ipfs/go-ipfs-blocksutil"] + version = "v0.0.1" + hash = "sha256-sR2YcBaGNiM0Rcak0MPQo8EJ92eKuAnBAxGc2VS6cRk=" + [mod."github.com/ipfs/go-ipfs-chunker"] + version = "v0.0.5" + hash = "sha256-EzCaQWfdFiKxHfGwRME49om6AlVc2wdd4QDOBRVlozs=" + [mod."github.com/ipfs/go-ipfs-cmds"] + version = "v0.6.0" + hash = "sha256-KgrDyltaMBxykiZTjV6C+NZDDiCbF0oZzdtnZnm7s0I=" + [mod."github.com/ipfs/go-ipfs-config"] + version = "v0.12.0" + hash = "sha256-nDmeVwbJzKbCUrapUHTmjHgMOYXfb/c4ZJMsNjLiUa4=" + [mod."github.com/ipfs/go-ipfs-delay"] + version = "v0.0.1" + hash = "sha256-PO6LIwGMEIITpBxY1YLX1iBIlK8jIWhXhGFqIYxkqig=" + [mod."github.com/ipfs/go-ipfs-ds-help"] + version = "v0.1.1" + hash = "sha256-BwK21JZAE1Fm1ZMNg9wR4tSp8bQK4Bi2QxexIznifa0=" + [mod."github.com/ipfs/go-ipfs-exchange-interface"] + version = "v0.0.1" + hash = "sha256-ltdMSx/EgQgDYufdUVnpoE+OHTnHPdTqKzK09Iq8BIo=" + [mod."github.com/ipfs/go-ipfs-exchange-offline"] + version = "v0.0.1" + hash = "sha256-Ebjjm0iJHUTLA9OM1gGpssw8RxcPy3KFVnImWSkti1o=" + [mod."github.com/ipfs/go-ipfs-files"] + version = "v0.0.8" + hash = "sha256-38CDT26MchY1tDT2PyzBUhpHNs94pdJTzIeqmyPkANU=" + [mod."github.com/ipfs/go-ipfs-pinner"] + version = "v0.1.1" + hash = "sha256-8eDFAlPTyWUP2nVOFyGoD8NFxtOR2JtTiaGfex5M56M=" + [mod."github.com/ipfs/go-ipfs-posinfo"] + version = "v0.0.1" + hash = "sha256-IvqFnazlQo9LJwXrsiiUIIPObu7cit7FHwWWqVNECEI=" + [mod."github.com/ipfs/go-ipfs-pq"] + version = "v0.0.2" + hash = "sha256-vD8IZ4dupT+ddproGHa6Qw7IzS84XeQSHUJ36/2YEgc=" + [mod."github.com/ipfs/go-ipfs-provider"] + version = "v0.4.3" + hash = "sha256-NZv9cR+zQzi6lJSjaKap/GvzUER7ZE+5SXMpof96Kqg=" + [mod."github.com/ipfs/go-ipfs-routing"] + version = "v0.1.0" + hash = "sha256-XTe/osQBA5gkYJB6Ejj69VF8tYvYr5FQ0GZ/2PbyMnM=" + [mod."github.com/ipfs/go-ipfs-util"] + version = "v0.0.2" + hash = "sha256-8b4gun6mgUiAReBYbrFjBHAyvdKkg41d1/JmwZhg9LQ=" + [mod."github.com/ipfs/go-ipld-cbor"] + version = "v0.0.5" + hash = "sha256-jJkEU8QEInm0xkFfRetza6X7vB+CL44kyJgqsxmFkRA=" + [mod."github.com/ipfs/go-ipld-format"] + version = "v0.2.0" + hash = "sha256-X362Fp6Xudm90EbiR4toiYi/qMqt2KlRNygn1W5rf7E=" + [mod."github.com/ipfs/go-ipld-git"] + version = "v0.0.3" + hash = "sha256-9vziRS7sEN2HMqa8ChOQ+84x5SPr4Y2Ucox5spovajo=" + [mod."github.com/ipfs/go-ipns"] + version = "v0.0.2" + hash = "sha256-Ztu9Sor3wOt3OcnFxtyopjELwQ5o5LM8NikwizLmSKg=" + [mod."github.com/ipfs/go-log"] + version = "v1.0.4" + hash = "sha256-WFBpnVxJ5OAXf+3s6xdbQyqcCdMNpi6v5PdZppNt6lk=" + [mod."github.com/ipfs/go-log/v2"] + version = "v2.1.1" + hash = "sha256-D7eG2PWk98skvuz4hDwj4tYqCx7U+J16XH0ll+J6l2Y=" + [mod."github.com/ipfs/go-merkledag"] + version = "v0.3.2" + hash = "sha256-oK7nEy4NJzrBzcEefWb/f8W9lcJzQ22O86G0jEZEb4w=" + [mod."github.com/ipfs/go-metrics-interface"] + version = "v0.0.1" + hash = "sha256-/vXCR/eiNvPMB0ToDWN6atmnpDGAr/kjxdbpckI4rCc=" + [mod."github.com/ipfs/go-metrics-prometheus"] + version = "v0.0.2" + hash = "sha256-1007Mm1hDyVAP35PLcfFus7xD51pFZGJ/v4NBaTkP/w=" + [mod."github.com/ipfs/go-mfs"] + version = "v0.1.2" + hash = "sha256-aFsnjvoEegKGhRmdUjqSc3VRiTPDiUwu67baHOKTL3o=" + [mod."github.com/ipfs/go-path"] + version = "v0.0.9" + hash = "sha256-jzDCjdAXyNTRjxnNurdauVySAnlHT0bcQWfoX3wVGvk=" + [mod."github.com/ipfs/go-peertaskqueue"] + version = "v0.2.0" + hash = "sha256-KbohhqPq3nQJkvGjC1KX8HKEjCskJ5UXAhNxLmsBuHo=" + [mod."github.com/ipfs/go-pinning-service-http-client"] + version = "v0.1.0" + hash = "sha256-m/siV1ABawHD2+enS1Q3mOh2u77+A9nYwJeKvzUX8Ps=" + [mod."github.com/ipfs/go-unixfs"] + version = "v0.2.4" + hash = "sha256-A3vGND5qs32/xPfGBNN/TQjGZI2AfDBp/ww3tOz9yAk=" + [mod."github.com/ipfs/go-verifcid"] + version = "v0.0.1" + hash = "sha256-CW45K43A4j0IearhE0W9xxjYYkui/02DTU0UTUZCMRo=" + [mod."github.com/ipfs/interface-go-ipfs-core"] + version = "v0.4.0" + hash = "sha256-EmdF9vdlDdIYTdk90drEerfce2jZ/LXK0cGGEjcG6Jc=" + [mod."github.com/ipld/go-car"] + version = "v0.1.1-0.20201015032735-ff6ccdc46acc" + hash = "sha256-3Y3ZliH1qYdWjsriHyMJJmiaXWuJflAQ/bC7szh7vaY=" + [mod."github.com/ipld/go-ipld-prime"] + version = "v0.5.1-0.20201021195245-109253e8a018" + hash = "sha256-ICyduXi6OTa8rhtMr29X4z6Z2BaU0+6fgMQGkPuVUDU=" + [mod."github.com/ipld/go-ipld-prime-proto"] + version = "v0.1.0" + hash = "sha256-zrrR7Y0xGi2M9naFa5Qo4X0bKE36PEiNpUpQNLAOcIk=" + [mod."github.com/iris-contrib/blackfriday"] + version = "v2.0.0+incompatible" + hash = "sha256-NY57AtaJ7YT8B5kn2PgemqYH4mImIxrTqb1iqbb6cb4=" + [mod."github.com/iris-contrib/go.uuid"] + version = "v2.0.0+incompatible" + hash = "sha256-ZehOVx9WMWSBkrwJBQQrpieEzB/d2shz42wZBex7gFk=" + [mod."github.com/iris-contrib/jade"] + version = "v1.1.3" + hash = "sha256-FTMzCiaWr8zutnBBLhhPeM/VkZ1ypQluO3dgc2WOd90=" + [mod."github.com/iris-contrib/pongo2"] + version = "v0.0.1" + hash = "sha256-8h07obq7x9GV5eYktRhDZ4KDhBTGswhb/op16Ytpd6g=" + [mod."github.com/iris-contrib/schema"] + version = "v0.0.1" + hash = "sha256-6TxQwAILQCgeYkb/huQ94nCMK8KEu+qcpGN3QamYNKg=" + [mod."github.com/jackpal/gateway"] + version = "v1.0.5" + hash = "sha256-gconsn92P1HEx9T+jraxLXC0XheaCNwGFcPIH2svLcc=" + [mod."github.com/jackpal/go-nat-pmp"] + version = "v1.0.2" + hash = "sha256-L1D4Yoxnzihs795GZ+Q3AZsFP5c4iqyjTeyrudzPXtw=" + [mod."github.com/jbenet/go-cienv"] + version = "v0.1.0" + hash = "sha256-u25QLTeUPX/uPm7RModuPFvVgGMpm/jLupAVi/KWzuM=" + [mod."github.com/jbenet/go-is-domain"] + version = "v1.0.5" + hash = "sha256-E+e2XI1ihXQ9FKN3Mz/vSDsJmQpFbksaHy9TdVuKJRQ=" + [mod."github.com/jbenet/go-random"] + version = "v0.0.0-20190219211222-123a90aedc0c" + hash = "sha256-gys4okqErwSnPP7jM3oLO7KmbpDGI41srNmci2oK/U0=" + [mod."github.com/jbenet/go-temp-err-catcher"] + version = "v0.1.0" + hash = "sha256-+SSoW7g/ADswuIS4AyVEp3+cH8KzByHlIJhLA6EUiFg=" + [mod."github.com/jbenet/goprocess"] + version = "v0.1.4" + hash = "sha256-U8K2bPDD8xkc+EcDMRpTaCcHN/jfsHvEYQLO1Kcuivw=" + [mod."github.com/jdeng/goheif"] + version = "v0.0.0-20200323230657-a0d6a8b3e68f" + hash = "sha256-qUqGMyzaz9sF2+ri7qgeVqGuuUeZMPHg1GED9w9JDOk=" + [mod."github.com/jehiah/go-strftime"] + version = "v0.0.0-20171201141054-1d33003b3869" + hash = "sha256-+4WOjV+F2BXgKmdfYvuSkfQAKOZlFo8eZrnCT+xT3xQ=" + [mod."github.com/jellevandenhooff/dkim"] + version = "v0.0.0-20150330215556-f50fe3d243e1" + hash = "sha256-oEIMb3uEs3GNrIWkAyq3kEuXiYhInA3kjpFd16+/xWE=" + [mod."github.com/jessevdk/go-flags"] + version = "v1.4.0" + hash = "sha256-5tg5rdiLEbI53DAwp3Yps1y/6e9m9AcgzX3No4wE9dY=" + [mod."github.com/jfreymuth/oggvorbis"] + version = "v1.0.0" + hash = "sha256-ylCTzeMqZEbigaKxYlygTGsHKkrZq7c3ogthcvUwGTA=" + [mod."github.com/jfreymuth/vorbis"] + version = "v1.0.0" + hash = "sha256-6kTol+g3NnZ3MazD786fvraw7ydUf0RWNBzHpzgN9Jk=" + [mod."github.com/jhump/protoreflect"] + version = "v1.6.0" + hash = "sha256-dERqwDuSk1Qq9OFHAsd8fvc277kcyyvi9E8l1IM1RWI=" + [mod."github.com/jmespath/go-jmespath"] + version = "v0.0.0-20180206201540-c2b33e8439af" + hash = "sha256-n5VGqJtkJxPhD3E8mWbUNjhT0dQfOj1m97l51Js/3OQ=" + [mod."github.com/jonboulle/clockwork"] + version = "v0.1.0" + hash = "sha256-dEV9aGzJRIrYfPpuJux3guJNvZGi+5dfseGurZqGHd8=" + [mod."github.com/jpillora/backoff"] + version = "v1.0.0" + hash = "sha256-uxHg68NN8hrwPCrPfLYYprZHf7dMyEoPoF46JFx0IHU=" + [mod."github.com/jrick/logrotate"] + version = "v1.0.0" + hash = "sha256-1JZrSgDekqwoWcHb9SnaBO56u0Z5nbvsiBdL/qIzNGs=" + [mod."github.com/json-iterator/go"] + version = "v1.1.10" + hash = "sha256-jdS2C0WsgsWREBSj+YUzSqdZofMfUMecaOQ/lB9Mu6k=" + [mod."github.com/jstemmer/go-junit-report"] + version = "v0.9.1" + hash = "sha256-fK6zLXQU8y+h+SqyeCUldA5OFPA/j0Wlbizk6AG60c4=" + [mod."github.com/jtolds/gls"] + version = "v4.20.0+incompatible" + hash = "sha256-Zu5naRjnwOYBzRv0CYhIZTizA0AajzOg7mJrL7Bo/cw=" + [mod."github.com/julienschmidt/httprouter"] + version = "v1.3.0" + hash = "sha256-YVbnyFLVZX1mtqcwM1SStQdhcQsPHyi1ltpOrD3w2qg=" + [mod."github.com/k0kubun/colorstring"] + version = "v0.0.0-20150214042306-9440f1994b88" + hash = "sha256-cmGwhftooSUXKypIpMV3nvcrmMusIJjtT5P4eZSfWkc=" + [mod."github.com/k3a/html2text"] + version = "v1.0.7" + hash = "sha256-DaaKEf9avkA7EmrDepdhmi9KX0LZvT2dnQbx0Rn5k7Y=" + [mod."github.com/kami-zh/go-capturer"] + version = "v0.0.0-20171211120116-e492ea43421d" + hash = "sha256-tiLO4M3CAOp+g9J9rEOOwj56a6OIEyTYO1o4x/3r2RY=" + [mod."github.com/kataras/golog"] + version = "v0.0.10" + hash = "sha256-/HMyYh68BdA23SsQVLRANeFRfncmrB6ctM/flbkyFZY=" + [mod."github.com/kataras/iris/v12"] + version = "v12.1.8" + hash = "sha256-fYRPtMCvFA/M5wDK8NZqOP8S8XTHEklSExZMK809ML0=" + [mod."github.com/kataras/neffos"] + version = "v0.0.14" + hash = "sha256-MQRj0UJwp6Qr3zgla4G6x8e3qG7wK1nNtZFGGzgVh3E=" + [mod."github.com/kataras/pio"] + version = "v0.0.2" + hash = "sha256-ZU9qUxKtJnYnwHPmRRbNXErHE9BC2qDYHrMfhTbadBE=" + [mod."github.com/kataras/sitemap"] + version = "v0.0.5" + hash = "sha256-CM1CjFd+XJyyUw5hhksNZJb0FoG8tGXWLI32wFu5VIk=" + [mod."github.com/kettek/apng"] + version = "v0.0.0-20191108220231-414630eed80f" + hash = "sha256-VPVAJt0RTGtLLzV5H5vgcSBQid1Y7pEf7U3raQgszZs=" + [mod."github.com/kisielk/errcheck"] + version = "v1.5.0" + hash = "sha256-ZmocFXtg+Thdup+RqDYC/Td3+m1nS0FydZecfsWXIzI=" + [mod."github.com/kisielk/gotool"] + version = "v1.0.0" + hash = "sha256-lsdQkue8gFz754PGqczUnvGiCQq87SruQtdrDdQVTpE=" + [mod."github.com/kkdai/bstream"] + version = "v0.0.0-20161212061736-f391b8402d23" + hash = "sha256-f8gCtCAFNARwPD9svGAGnHyUdeb4Ch7ZRHk4D75iqcE=" + [mod."github.com/klauspost/compress"] + version = "v1.9.7" + hash = "sha256-9rHx3bFYdGTeLWJUO2yn2mCN15gjhnP0uTa93f3ngDc=" + [mod."github.com/klauspost/cpuid"] + version = "v1.2.3" + hash = "sha256-1IBlONMxKVgudV/mzNrFZB60z8w4xFjVbEU2DoIAoeg=" + [mod."github.com/klauspost/cpuid/v2"] + version = "v2.0.4" + hash = "sha256-3Gwt/jjUixXAm/RvOVwxn7c3VuDIKGgiFt3ORQzKOa8=" + [mod."github.com/konsorten/go-windows-terminal-sequences"] + version = "v1.0.3" + hash = "sha256-9HojTXKv7b3HiEhYaKXDxraEfvU5vrg47FbCjTRpOvs=" + [mod."github.com/koron/go-ssdp"] + version = "v0.0.0-20191105050749-2e1c40ed0b5d" + hash = "sha256-Ewk3MaAzVJJ+46TfOupDhY+4DjSf5gc8GNO4tsSrQ0k=" + [mod."github.com/kr/logfmt"] + version = "v0.0.0-20140226030751-b84e30acd515" + hash = "sha256-CePQbqWGtS8qP/Av9pkLiqZwH6RaZQff/s1l+1//jQo=" + [mod."github.com/kr/pretty"] + version = "v0.2.0" + hash = "sha256-127gkrb5HVPOCp0sGZOmiJPaQuQ4zptRw0MNGP53i/s=" + [mod."github.com/kr/pty"] + version = "v1.1.3" + hash = "sha256-D4psQsJ1VbFwhTdaW8vF3htiLyvOPVCfuyF191ViJEw=" + [mod."github.com/kr/text"] + version = "v0.1.0" + hash = "sha256-QT65kTrNypS5GPWGvgnCpGLPlVbQAL4IYvuqAKhepb4=" + [mod."github.com/labstack/echo/v4"] + version = "v4.1.11" + hash = "sha256-BZD5+SVVY/Idj9IK4wc14UlOcG0dpSX958fa//nbJCw=" + [mod."github.com/labstack/gommon"] + version = "v0.3.0" + hash = "sha256-IDa2tl43cFAcLxEe8EHpO0ZSH54YLVKtMrec+v1U56M=" + [mod."github.com/lestrrat/go-envload"] + version = "v0.0.0-20180220120943-6ed08b54a570" + hash = "sha256-O+xFK7J0d+cgv9N4pI/Nunk89FVQ3Zmywn1QfBc8pH4=" + [mod."github.com/lestrrat/go-file-rotatelogs"] + version = "v0.0.0-20180223000712-d3151e2a480f" + hash = "sha256-A89P/ThMyvrYoj7Yhq/3PG8MM7KDQE+pWf4F3WHjuoo=" + [mod."github.com/lestrrat/go-strftime"] + version = "v0.0.0-20180220042222-ba3bf9c1d042" + hash = "sha256-Wd3GYo14taUxeZbqogdt6y8aPikCTyghK20WPamH5JU=" + [mod."github.com/lib/pq"] + version = "v1.10.0" + hash = "sha256-nVDAkYrV+F0c5lb7SpdURq9Z8LHKUvc//t968sLBIBg=" + [mod."github.com/libp2p/go-addr-util"] + version = "v0.0.2" + hash = "sha256-YKFwA2f8xYO1y+zA2vVdG7inQLAsqR5l0EHIuav5r6I=" + [mod."github.com/libp2p/go-buffer-pool"] + version = "v0.0.2" + hash = "sha256-dcgL4tAHDJsevnvwIAXZmtKqB9h4986go/Yn3IlfPAY=" + [mod."github.com/libp2p/go-cidranger"] + version = "v1.1.0" + hash = "sha256-aqk225oAthKAvCbtsLNH8CwMcmYBj2x/URafDsukHxY=" + [mod."github.com/libp2p/go-conn-security"] + version = "v0.0.1" + hash = "sha256-uWQhpdBOnirYI0eDSqc0zPz0vey/1MY20JPJghXgP3w=" + [mod."github.com/libp2p/go-conn-security-multistream"] + version = "v0.2.0" + hash = "sha256-56JLdOF5ZiHTvpmfz88zF9ZS9YBIlYR5eOWCUycg4O0=" + [mod."github.com/libp2p/go-eventbus"] + version = "v0.2.1" + hash = "sha256-tbQov7div/1xX69VxsaK9qutzpRNMFW+MtJOFxxRIg8=" + [mod."github.com/libp2p/go-flow-metrics"] + version = "v0.0.3" + hash = "sha256-HLAMxTWuN3nxl8VBiC+PywCd+/Zm+kTHDLICOVo2s54=" + [mod."github.com/libp2p/go-libp2p"] + version = "v0.13.0" + hash = "sha256-VJQW6ikDfnKhY5dRoyiFbUwFVhcFJupR/nrluNAW2oE=" + [mod."github.com/libp2p/go-libp2p-asn-util"] + version = "v0.0.0-20200825225859-85005c6cf052" + hash = "sha256-qF/YnzuB0OIaQ5umAKFF5twN/qQfqJ1Y0Py9PGRe4XQ=" + [mod."github.com/libp2p/go-libp2p-autonat"] + version = "v0.4.0" + hash = "sha256-7rSFC2Y17H/SxufxeyW+lc4IrrkOpMT3nsOPDGb7/Pw=" + [mod."github.com/libp2p/go-libp2p-blankhost"] + version = "v0.2.0" + hash = "sha256-LBF2x8N33dplrin6jATC8Cju/LOFwjLymHrqXZjm9lI=" + [mod."github.com/libp2p/go-libp2p-circuit"] + version = "v0.4.0" + hash = "sha256-Uqv8vVbgOB/PDjPE5WBIo7GxcRxML4lwUevwcHd+1xM=" + [mod."github.com/libp2p/go-libp2p-connmgr"] + version = "v0.2.4" + hash = "sha256-pKLwrD3zjFWliwEW1T6WOB5BjR0GO/+r+zvvniAdQTE=" + [mod."github.com/libp2p/go-libp2p-core"] + version = "v0.8.0" + hash = "sha256-7IZpap1hhznGVzxfH2Eifzu/qTA9Mxfa3pRxZ5bxqOs=" + [mod."github.com/libp2p/go-libp2p-crypto"] + version = "v0.1.0" + hash = "sha256-b9puUQVxgvDHnVuRgU+i7MXN0xiNUpSZ/ayqe+7cBnA=" + [mod."github.com/libp2p/go-libp2p-discovery"] + version = "v0.5.0" + hash = "sha256-mGt8NcaNyAqMGQ0imMA443Q5PCvrqFKRT166Kuyx3ow=" + [mod."github.com/libp2p/go-libp2p-gostream"] + version = "v0.3.0" + hash = "sha256-tzhWdFCeWqyqFnT3XYtFTggP/SPn+5cVugBJAsjK6dI=" + [mod."github.com/libp2p/go-libp2p-host"] + version = "v0.0.3" + hash = "sha256-1hc5qc2+XdRTHbRNjb705nt7Rw+w6r4t5nh28xI/MMM=" + [mod."github.com/libp2p/go-libp2p-http"] + version = "v0.2.0" + hash = "sha256-EN+CkLj+sXhwSBxPDbaDs5U0V8hL4u4sN4ss3Dv6Ar0=" + [mod."github.com/libp2p/go-libp2p-interface-connmgr"] + version = "v0.0.5" + hash = "sha256-fT7nOGYyn4mIvC0V9X+aPHa9nok+YjWq2D1EP2qLhu4=" + [mod."github.com/libp2p/go-libp2p-interface-pnet"] + version = "v0.0.1" + hash = "sha256-caU7Rd+7hL9FL/lrwHCR8pZnCef/DWadVEJrdjOpHc8=" + [mod."github.com/libp2p/go-libp2p-kad-dht"] + version = "v0.11.1" + hash = "sha256-Tc0a/pR8bfp1VewrzabPezEcnsp/ksyYBPXUOZ00820=" + [mod."github.com/libp2p/go-libp2p-kbucket"] + version = "v0.4.7" + hash = "sha256-StqZ8chkzXMCjxSdyzBZfkV7dEoGmWFK80WwFybCDwY=" + [mod."github.com/libp2p/go-libp2p-loggables"] + version = "v0.1.0" + hash = "sha256-5aFV5gkTANOXHV6K4hBYbozMISAffGdErObU556j2FA=" + [mod."github.com/libp2p/go-libp2p-metrics"] + version = "v0.0.1" + hash = "sha256-Pdgcxbg6QomVGF8Qh2Fm+TjHzFqscbfv4hGQzFm1m5M=" + [mod."github.com/libp2p/go-libp2p-mplex"] + version = "v0.4.1" + hash = "sha256-d2Wb9MBfnsRpe0/xeY9VnAAU6YBpH1rVVh5d7XJCqbw=" + [mod."github.com/libp2p/go-libp2p-nat"] + version = "v0.0.6" + hash = "sha256-S6xPea3qvutjtNpWEUjRs6/Kiofo+9IiEZv+YV2YscI=" + [mod."github.com/libp2p/go-libp2p-net"] + version = "v0.0.2" + hash = "sha256-U8nHbS62EyUmZLXDy/IPiSvrzhV3GG5FhN78ueEp0TE=" + [mod."github.com/libp2p/go-libp2p-netutil"] + version = "v0.1.0" + hash = "sha256-53zkCPoupfwJOY1RiUquLggD5InFMFFIx03g8l0aDj8=" + [mod."github.com/libp2p/go-libp2p-noise"] + version = "v0.1.2" + hash = "sha256-iUNwIboyPQ9KobwCGIfpsEdA1h4qC9SYLdPDRal4wJk=" + [mod."github.com/libp2p/go-libp2p-peer"] + version = "v0.2.0" + hash = "sha256-LPf7snkXXyw9zEkg/G57oY+2RoqgOXVCpA00vl9pw4Q=" + [mod."github.com/libp2p/go-libp2p-peerstore"] + version = "v0.2.6" + hash = "sha256-zxsl53bWXplRgQDrEFaOQ2VNtiCorwxiXlGAVJOzLew=" + [mod."github.com/libp2p/go-libp2p-pnet"] + version = "v0.2.0" + hash = "sha256-nzwzjP7jMlLWPQVFvqANHb3i0K0iraTLk/WvizehNTA=" + [mod."github.com/libp2p/go-libp2p-protocol"] + version = "v0.1.0" + hash = "sha256-EH1SHPuj96slRM6xiXlbv/5KTnVcx1tQvFtBTMpgsAc=" + [mod."github.com/libp2p/go-libp2p-pubsub"] + version = "v0.4.1" + hash = "sha256-+geS7yoYBP7Qyudf8vqGHmyrT/vr20PSdu6BHsXs5gw=" + [mod."github.com/libp2p/go-libp2p-pubsub-router"] + version = "v0.4.0" + hash = "sha256-0GZoJAzn4n8lY5GVadH+dovqRiBh86NvVzHhS/WoTYY=" + [mod."github.com/libp2p/go-libp2p-quic-transport"] + version = "v0.10.0" + hash = "sha256-BN3ZCZI6UFYDRZRgFKaNxT532ap/bYFbA1OQpYxMBTI=" + [mod."github.com/libp2p/go-libp2p-record"] + version = "v0.1.3" + hash = "sha256-mKMhjkYcEBXPmiIgIPLSM93K4WXeSPZM7Qgl7Th2aGs=" + [mod."github.com/libp2p/go-libp2p-routing"] + version = "v0.0.1" + hash = "sha256-4LYviUiYQr455/srKQrLig+OmNiox8FbmMb/tpQItSY=" + [mod."github.com/libp2p/go-libp2p-routing-helpers"] + version = "v0.2.3" + hash = "sha256-+kFqRKmJmFq7eh+BYf6SJ9WI0kwNmX0nxT8yYSvQ1fg=" + [mod."github.com/libp2p/go-libp2p-secio"] + version = "v0.2.2" + hash = "sha256-RAP+nzG850W/oImPAlBu/b2aqLpX22nnrTp3A8fS7tc=" + [mod."github.com/libp2p/go-libp2p-swarm"] + version = "v0.4.0" + hash = "sha256-n3B0s+eHMp3SrC5Q6yBhGXtc/aetaU8OhjBiDYs6aYY=" + [mod."github.com/libp2p/go-libp2p-testing"] + version = "v0.4.0" + hash = "sha256-GodC5+wGhKsIEwS0AesnmyK+7sAqjf7PnoWy5WaHDL8=" + [mod."github.com/libp2p/go-libp2p-tls"] + version = "v0.1.3" + hash = "sha256-YDmRtr/ILSdbdkgnOZPixknefFEMUCejfaPjMKsCkjU=" + [mod."github.com/libp2p/go-libp2p-transport"] + version = "v0.0.5" + hash = "sha256-OlRW7yD9CpzLFYYtK9KmOizU8HmvmVoniAWS3v5ya1A=" + [mod."github.com/libp2p/go-libp2p-transport-upgrader"] + version = "v0.4.0" + hash = "sha256-1jeBhwQovxT6ORV2AWsZqZbRlOjahv0mKGgO+06ZqHA=" + [mod."github.com/libp2p/go-libp2p-yamux"] + version = "v0.5.1" + hash = "sha256-N3AfWQlNx4Xslu7d5D1srFreaVBtzIPuDTiKHX1Tkk0=" + [mod."github.com/libp2p/go-maddr-filter"] + version = "v0.1.0" + hash = "sha256-8mSH3OtgUrMiXUWqwdtDvXCGdxuF1ZwnXCE/aqfBLcQ=" + [mod."github.com/libp2p/go-mplex"] + version = "v0.3.0" + hash = "sha256-MZLaZPvUd6EDoK/Zv3XZBkmdOEdtny8MVPlM3HFboIc=" + [mod."github.com/libp2p/go-msgio"] + version = "v0.0.6" + hash = "sha256-wAO7Lhai8Dp5mmgJtrXB9/hCMlEUGv7TYCc5+nIBiRY=" + [mod."github.com/libp2p/go-nat"] + version = "v0.0.5" + hash = "sha256-UR20n6c8zNY9tBZq4Ahvg98VHmc3bNJZvHC+Z+A2Tuk=" + [mod."github.com/libp2p/go-netroute"] + version = "v0.1.3" + hash = "sha256-8PlVTZrAwjJeyOCrrl2vhDG3QIi3V4MfbQuGl3J531g=" + [mod."github.com/libp2p/go-openssl"] + version = "v0.0.7" + hash = "sha256-AOgs8JLzDh57N7Mmzj6DVtdKSRN9Uo1fjPOTsxx18hs=" + [mod."github.com/libp2p/go-reuseport"] + version = "v0.0.2" + hash = "sha256-lSonGY4LUYwrEcwEOMn1FmD33163Rw0TNyc2mEINLxQ=" + [mod."github.com/libp2p/go-reuseport-transport"] + version = "v0.0.4" + hash = "sha256-xTOaq/b6F74lkMw13piBfxkICka8KE8Ar2+NMERkhDc=" + [mod."github.com/libp2p/go-sockaddr"] + version = "v0.0.2" + hash = "sha256-7nQUV/ZFacPnZALSBnb0QR4bvGfO85HPTpsdHTIl/Qg=" + [mod."github.com/libp2p/go-socket-activation"] + version = "v0.0.2" + hash = "sha256-8D+WnkCRuDGyQ2Sp2o7oAf/+/AhNYTOKAo4CeSJYGuY=" + [mod."github.com/libp2p/go-stream-muxer"] + version = "v0.1.0" + hash = "sha256-LbeBQKlluF9ejrcCjseBl2KbkrU7ny7OhS8CDGLH5i0=" + [mod."github.com/libp2p/go-stream-muxer-multistream"] + version = "v0.3.0" + hash = "sha256-X09jQCPvysJgSC/w4kOLeP+CjsQlna7e1iDwb2Pv82U=" + [mod."github.com/libp2p/go-tcp-transport"] + version = "v0.2.1" + hash = "sha256-UGuMJdF1N2HYNTkX7836HoLQSOj4zs+nd/Wcj5b1dJY=" + [mod."github.com/libp2p/go-testutil"] + version = "v0.1.0" + hash = "sha256-NNjldPxn7or0ZFkC2U/3GXKat7/sCVYupPCk5YOfAAE=" + [mod."github.com/libp2p/go-ws-transport"] + version = "v0.4.0" + hash = "sha256-XKz1MPijMXLHRVvOGSGgCQWay0T43ZxVeaRhw4Yn0WQ=" + [mod."github.com/libp2p/go-yamux"] + version = "v1.4.1" + hash = "sha256-1RZ7NkYmEV7SqJRZWaWKSyg1KAkEXSWP0+DrLPS0kJ0=" + [mod."github.com/libp2p/go-yamux/v2"] + version = "v2.0.0" + hash = "sha256-YrVDRbB1ZoQ39mz0Gl4cimjtkS0iOt41WLhUWzDt2l8=" + [mod."github.com/lightstep/lightstep-tracer-common/golang/gogo"] + version = "v0.0.0-20190605223551-bc2310a04743" + hash = "sha256-Nb8mdhONwjpQusNOQRN+qGWKNcxEWI5vK6bGX21xDmM=" + [mod."github.com/lightstep/lightstep-tracer-go"] + version = "v0.18.1" + hash = "sha256-ckmJCf+x/Ad/ADm+nDbvgLKnkkEU/3qH1pT5XmgQKWA=" + [mod."github.com/lucas-clemente/quic-go"] + version = "v0.19.3" + hash = "sha256-ME+cVO89utYtbJrDYBqo19FAXn1XCjvfm5q+7yhJKnM=" + [mod."github.com/lucasb-eyer/go-colorful"] + version = "v0.0.0-20181028223441-12d3b2882a08" + hash = "sha256-/AEoHg9/EmM2fQDWkz2erab8bDxHz9zD+NmoYF1XJfE=" + [mod."github.com/lunixbochs/vtclean"] + version = "v1.0.0" + hash = "sha256-qMFvDEEogp8p+IjBmjQZ781H8/l9r2/MbMT/GegYFks=" + [mod."github.com/lyft/protoc-gen-validate"] + version = "v0.0.13" + hash = "sha256-JhFMmEaP1amtJJBLWFVqjjHeHuAHRP0qwLMMFX2b3FM=" + [mod."github.com/magefile/mage"] + version = "v1.11.0" + hash = "sha256-7X+f+bXgVTQ5DMuNULQXYd6W1s7b+xdV6GnuUCRF8sI=" + [mod."github.com/magiconair/properties"] + version = "v1.8.0" + hash = "sha256-tkt1yGEPbRjQvhsCkiD7jyLyhX2eo4AWx0ihzYUZIKg=" + [mod."github.com/mailru/easyjson"] + version = "v0.0.0-20190312143242-1de009706dbe" + hash = "sha256-5ebTirYcLZdNlF9h1TGjmUK3hm9E5gMSurGsZJ9izww=" + [mod."github.com/marten-seemann/qpack"] + version = "v0.2.1" + hash = "sha256-FMWYbeOBc0TKdUe9B2XI1N2q1e7/Vta5VhOMpra9TuQ=" + [mod."github.com/marten-seemann/qtls"] + version = "v0.10.0" + hash = "sha256-aKTlE6fo8Gtw/6VOR2kFNt9X0UrAdywoE6LeE9o2Sp8=" + [mod."github.com/marten-seemann/qtls-go1-15"] + version = "v0.1.1" + hash = "sha256-3BYuwsXAR9xFFIvcXgzcd2fGdQxbtq+irIm4c4cv4sA=" + [mod."github.com/mattn/go-colorable"] + version = "v0.1.8" + hash = "sha256-TBXc2n5tRebabjt0HipS8wCdRml0kM0JjpppUbdx1XQ=" + [mod."github.com/mattn/go-isatty"] + version = "v0.0.12" + hash = "sha256-noBpx3K4sa7tJcPpSUh+h7wJ8CRfrObaraKC2dE6VWU=" + [mod."github.com/mattn/go-runewidth"] + version = "v0.0.9" + hash = "sha256-dK/kIPe1tcxEubwI4CWfov/HWRBgD/fqlPC3d5i30CY=" + [mod."github.com/mattn/go-sqlite3"] + version = "v2.0.3+incompatible" + hash = "sha256-+zdGqThUb7if9JAiO+6s6KXBeuT322JhfcityvdrxD4=" + [mod."github.com/mattn/goveralls"] + version = "v0.0.2" + hash = "sha256-l2rntbH5TtEUuv1aOXmOJ099UCUpQp9reCQVtmdszo0=" + [mod."github.com/matttproud/golang_protobuf_extensions"] + version = "v1.0.1" + hash = "sha256-ystDNStxR90j4CK+AMcEQ5oyYFRgWoGdvWlS0XQMDLQ=" + [mod."github.com/mediocregopher/radix/v3"] + version = "v3.4.2" + hash = "sha256-uGUKSrC2H9yD+oYh8Zl/dEO8hQcgGGfjiffy8IP2xtc=" + [mod."github.com/mewkiz/flac"] + version = "v1.0.5" + hash = "sha256-x2c2eYny+gdTiG+a8GEp0ERjiavflBSRaZ9PwS9l9UM=" + [mod."github.com/mgutz/ansi"] + version = "v0.0.0-20170206155736-9520e82c474b" + hash = "sha256-MnBed2XD418sSMjuE2hVrqWWvCQYuMDNOEZIEoYQfwE=" + [mod."github.com/microcosm-cc/bluemonday"] + version = "v1.0.2" + hash = "sha256-Isf006ItnLdSyyzXsup5+1KJ1a0MwXt4IpJJ3DX1Ckg=" + [mod."github.com/miekg/dns"] + version = "v1.1.31" + hash = "sha256-QWB1m5CQ5aHjfI1EzcumyyhZW0DH8hNr2XxQqUfPqcc=" + [mod."github.com/minio/blake2b-simd"] + version = "v0.0.0-20160723061019-3f5f724cb5b1" + hash = "sha256-rc7ozPwT59tTjs/7ERxAN4C3OoK1fdJcrQ8wYaRd0iw=" + [mod."github.com/minio/md5-simd"] + version = "v1.1.2" + hash = "sha256-vykcXvy2VBBAXnJott/XsGTT0gk2UL36JzZKfJ1KAUY=" + [mod."github.com/minio/minio-go/v6"] + version = "v6.0.57" + hash = "sha256-edGdCSO6vhpYsP8v6DAWPIzQlqGybHOM9lSy/1PsHhk=" + [mod."github.com/minio/sha256-simd"] + version = "v1.0.0" + hash = "sha256-oEo/BoMqSLdwSjrhHTiFjl5Om4MVLNQXDJINk6Z110Y=" + [mod."github.com/mitchellh/cli"] + version = "v1.0.0" + hash = "sha256-4nG7AhRcjTRCwUCdnaNaFrAKDxEEoiihaCA4lk+uM8U=" + [mod."github.com/mitchellh/go-homedir"] + version = "v1.1.0" + hash = "sha256-oduBKXHAQG8X6aqLEpqZHs5DOKe84u6WkBwi4W6cv3k=" + [mod."github.com/mitchellh/go-testing-interface"] + version = "v1.14.1" + hash = "sha256-TMGi38D13BEVN5cpeKDzKRIgLclm4ErOG+JEyqJrN/c=" + [mod."github.com/mitchellh/gox"] + version = "v0.4.0" + hash = "sha256-GV3LYxzJt8YVbnSac2orlj2QR3MX/YIDrLkSkPhsjuA=" + [mod."github.com/mitchellh/iochan"] + version = "v1.0.0" + hash = "sha256-b5Tp7cw/e8mL++IjsebbmKWXtb9Hrzu4Fc6M4tZKFhU=" + [mod."github.com/mitchellh/mapstructure"] + version = "v1.1.2" + hash = "sha256-OU9HZYHtl0qaqMFd84w7snkkRuRY6UMSsfCnL5HYdw0=" + [mod."github.com/modern-go/concurrent"] + version = "v0.0.0-20180306012644-bacd9c7ef1dd" + hash = "sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo=" + [mod."github.com/modern-go/reflect2"] + version = "v1.0.1" + hash = "sha256-5D1HGVBc/REwPVdlPYcXsbZM80OIh7V5uiyKAbMA5qo=" + [mod."github.com/moul/http2curl"] + version = "v1.0.0" + hash = "sha256-1ZP4V71g1K3oTvz5nGWUBD5h84hXga/RUQwWTpSnphM=" + [mod."github.com/mr-tron/base58"] + version = "v1.2.0" + hash = "sha256-8FzMu3kHUbBX10pUdtGf59Ag7BNupx8ZHeUaodR1/Vk=" + [mod."github.com/multiformats/go-base32"] + version = "v0.0.3" + hash = "sha256-L18a2v2c5XenmJcwB1BmN0XzDFY45H0ougcZwrGVl7g=" + [mod."github.com/multiformats/go-base36"] + version = "v0.1.0" + hash = "sha256-QGoZm4HrdKWwmbJNbaTW0PvDdvPYrhx10znwhIFnFNM=" + [mod."github.com/multiformats/go-multiaddr"] + version = "v0.3.1" + hash = "sha256-aKa2MXWFcTNopB8UdWSX5Ps5nAZ1zJwld7I5xdrwM1s=" + [mod."github.com/multiformats/go-multiaddr-dns"] + version = "v0.2.0" + hash = "sha256-VVFKnmmdMDaDUtmH0+yJNWjfeMJh7osJt/JeOkyohG8=" + [mod."github.com/multiformats/go-multiaddr-fmt"] + version = "v0.1.0" + hash = "sha256-1SbQXGliO7tAaFoBD8mROaffxNaaKiRIjWmxD23GOIU=" + [mod."github.com/multiformats/go-multiaddr-net"] + version = "v0.2.0" + hash = "sha256-nALVMumJW0d0j3T0TxJH4CO3z3h6pGbtMgRBEbAt480=" + [mod."github.com/multiformats/go-multibase"] + version = "v0.0.3" + hash = "sha256-yH1bl+jSJlAvPSqg9Z7xF4JS2fpoNUqH8wCDbU87ZDA=" + [mod."github.com/multiformats/go-multihash"] + version = "v0.0.14" + hash = "sha256-eTL5Nj37yxgnZnjjNCJaDC+HkfCkI88qKsOeO738G9g=" + [mod."github.com/multiformats/go-multistream"] + version = "v0.2.0" + hash = "sha256-HE9fvbfeHJ1gCN4p+vuiG5HSVL7Shslp2x/YSdONmt4=" + [mod."github.com/multiformats/go-varint"] + version = "v0.0.6" + hash = "sha256-QlY6AzrSB/8IrlINPi8J8uw1J0SOa2UMTtlo79fg9gM=" + [mod."github.com/mwitkow/go-conntrack"] + version = "v0.0.0-20190716064945-2f068394615f" + hash = "sha256-h6tgygomf/oVKMa2MO8sPLUD3CxK81z5q/roKYKvsno=" + [mod."github.com/nats-io/jwt"] + version = "v0.3.2" + hash = "sha256-JFC1U3Oq+pli+P2Ot6F2Yoe+GFYbiUDYuvPoJFtlvnY=" + [mod."github.com/nats-io/nats-server/v2"] + version = "v2.1.2" + hash = "sha256-WkLk1r9U+6zC/dbp1vvuUmckJEJSmxIqTGXE09olDXg=" + [mod."github.com/nats-io/nats.go"] + version = "v1.9.1" + hash = "sha256-O2ueDi/tVnjiony4uYgZ8XJZr067jLL7d6/7OeC31+8=" + [mod."github.com/nats-io/nkeys"] + version = "v0.1.3" + hash = "sha256-FxLfFz3CRw/ZTIkfaC+PWxLRro12HXP3VjUcouQCN7o=" + [mod."github.com/nats-io/nuid"] + version = "v1.0.1" + hash = "sha256-7wddxVz3hnFg/Pf+61+MtQJJL/l8EaC8brHoNsmD64c=" + [mod."github.com/neelance/astrewrite"] + version = "v0.0.0-20160511093645-99348263ae86" + hash = "sha256-sAJM5k19YxqqoKdKlI5xF4jy00H0bf7XOnqTB8JZuIY=" + [mod."github.com/neelance/sourcemap"] + version = "v0.0.0-20151028013722-8c68805598ab" + hash = "sha256-8+AK1S2vsYl6WVvJ5Mw/I+iBBLzRT8Hmyx3i2uEA4Gk=" + [mod."github.com/nxadm/tail"] + version = "v1.4.4" + hash = "sha256-S336Q+5j2uVmwLOfEUpU0iFBEEDH+UtdQO0NWPsc9OY=" + [mod."github.com/oklog/oklog"] + version = "v0.3.2" + hash = "sha256-qlnPX0uYC0pIA44MvacLIDxEcl/n4KPoIHMFmCWkurY=" + [mod."github.com/oklog/run"] + version = "v1.1.0" + hash = "sha256-U4IS0keJa4BSBSeEBqtIV1Zg6N4b0zFiKfzN9ua4pWQ=" + [mod."github.com/olebedev/emitter"] + version = "v0.0.0-20190110104742-e8d1457e6aee" + hash = "sha256-hY8Cy3+zu+ONxriJ1OrNcL1RGPLDSXvkfk571CTzELM=" + [mod."github.com/olekukonko/tablewriter"] + version = "v0.0.0-20170122224234-a0225b3f23b5" + hash = "sha256-ARnzbCFVz0npfCrsnhi64+bhi8i7SijouaMZ/7vJ6S4=" + [mod."github.com/onsi/ginkgo"] + version = "v1.15.0" + hash = "sha256-kMfmdLSHmXJweKQQ242072iyDdr6LpGm4Cv7UvCRNZM=" + [mod."github.com/onsi/gomega"] + version = "v1.10.5" + hash = "sha256-EMndgbr6d5yYPLTMNOufNR+sUvSfeuIhpCYWoQVRO1c=" + [mod."github.com/op/go-logging"] + version = "v0.0.0-20160315200505-970db520ece7" + hash = "sha256-kk1wY0YgUzB7OvV0LzX/Dak5243/TJt3+OEAWrpQ9rI=" + [mod."github.com/opentracing-contrib/go-observer"] + version = "v0.0.0-20170622124052-a52f23424492" + hash = "sha256-Yx4crdNKvA+ojqv5+JgMFjunrqg7dULrXwNuUVEh/+A=" + [mod."github.com/opentracing/basictracer-go"] + version = "v1.0.0" + hash = "sha256-QLEXYXQGg5It+zp8o5fcOIrvF8i/lDOLxJ6sqFUySUM=" + [mod."github.com/opentracing/opentracing-go"] + version = "v1.2.0" + hash = "sha256-kKTKFGXOsCF6QdVzI++GgaRzv2W+kWq5uDXOJChvLxM=" + [mod."github.com/openzipkin-contrib/zipkin-go-opentracing"] + version = "v0.4.5" + hash = "sha256-+OTH7Ih9TSHjpQ0qbLcEEG1SPnpyQpiNSOwEXkHpu1U=" + [mod."github.com/openzipkin/zipkin-go"] + version = "v0.2.2" + hash = "sha256-WiTZzEPwv4KZO7PcztgY2PNDxGsZei4rVPMCbBVBiKE=" + [mod."github.com/pact-foundation/pact-go"] + version = "v1.0.4" + hash = "sha256-4w92Zo53qmhuIxTmnfo9llSTPvkJsU5mRLnfit/lReg=" + [mod."github.com/pascaldekloe/goe"] + version = "v0.0.0-20180627143212-57f6aae5913c" + hash = "sha256-2KUjqrEC/BwkTZRxImazcI/C3H7QmXfNrlt8slwdDbc=" + [mod."github.com/patrickmn/go-cache"] + version = "v2.1.0+incompatible" + hash = "sha256-+i3/Cd9byb1q926jszLjadiUMUeux0VyGKnmP20EAoA=" + [mod."github.com/pborman/uuid"] + version = "v1.2.0" + hash = "sha256-zz0hvDdrajoUaOCXvI/2EIGGoWQa0QlCyFV0jqU3JDg=" + [mod."github.com/pelletier/go-toml"] + version = "v1.2.0" + hash = "sha256-Yt9MGTbIaU/1FhE7SO5UCQbTLxe+2vsypTdf38i3kFY=" + [mod."github.com/performancecopilot/speed"] + version = "v3.0.0+incompatible" + hash = "sha256-epw3iYvcfLf4cbsH90B1lKOUVFFsp+T72XThsLWodZM=" + [mod."github.com/peterbourgon/g2s"] + version = "v0.0.0-20170223122336-d4e7ad98afea" + hash = "sha256-NIVsrq1z2UEvuVTHVIptWDn0MYx4jMyk707K7QNLiq8=" + [mod."github.com/pierrec/lz4"] + version = "v2.0.5+incompatible" + hash = "sha256-R2UoyN7wUKVbYMPwH7DL8mIJIMzx/cOndvklKSjbQ6o=" + [mod."github.com/pingcap/errors"] + version = "v0.11.4" + hash = "sha256-9rHewclIZPLFniKSrTwSEGWC1R2dWzfMUV4JUsFYZgo=" + [mod."github.com/pkg/errors"] + version = "v0.9.1" + hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" + [mod."github.com/pkg/profile"] + version = "v1.2.1" + hash = "sha256-2WJi+BJnWA0k5Ml/kDPUDgeeWG/upusGrHi1jd+umC4=" + [mod."github.com/pmezard/go-difflib"] + version = "v1.0.0" + hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA=" + [mod."github.com/polydawn/refmt"] + version = "v0.0.0-20190809202753-05966cbd336a" + hash = "sha256-33kZwZk+ioZOsCs727xT3tm5uYAWuM350T9/erXiVuk=" + [mod."github.com/posener/complete"] + version = "v1.1.1" + hash = "sha256-heyPMSBzVlx7ZKgTyzl/xmUfZw3EZCcvGFGrRMIbIr8=" + [mod."github.com/prometheus/client_golang"] + version = "v1.9.0" + hash = "sha256-GF+KJ3arE4GbCabcJlxM7+zRRKVBEVjLKdP4dWA4gDo=" + [mod."github.com/prometheus/client_model"] + version = "v0.2.0" + hash = "sha256-LTHxYPRgoggl+v89ly2/RkyPIuJlmZRdGs6ZRtK3zkk=" + [mod."github.com/prometheus/common"] + version = "v0.15.0" + hash = "sha256-2LfZKSNG8cSHxLAJSyQIAs87yd5DMaeHYn8+w4PcrcM=" + [mod."github.com/prometheus/procfs"] + version = "v0.2.0" + hash = "sha256-Ev8tX7rPvrnNhcphKHesCNmI3Nzsatd/XX2mEq1rqzA=" + [mod."github.com/prometheus/statsd_exporter"] + version = "v0.15.0" + hash = "sha256-Gd3/eLFN/FP1E388/gX8f9d8QSBel1ToXeXBgIMlY50=" + [mod."github.com/rcrowley/go-metrics"] + version = "v0.0.0-20181016184325-3113b8401b8a" + hash = "sha256-QvEExHYVtsd3SH2jH3Yr41LI3JpjLfwqs5AzTeKd+6E=" + [mod."github.com/rifflock/lfshook"] + version = "v0.0.0-20180920164130-b9218ef580f5" + hash = "sha256-LHemSy/AaUcajEm9mdPjw6+nJht81dcqnYCh5ySTuHM=" + [mod."github.com/rogpeppe/fastuuid"] + version = "v0.0.0-20150106093220-6724a57986af" + hash = "sha256-n4HjQqPQwAH49y6AoG6vxa38pkJylgU2kR2a7uAtRos=" + [mod."github.com/rogpeppe/go-internal"] + version = "v1.3.0" + hash = "sha256-JgiasZeXDy10syy7wmXtqRffDY7CJ1o5VNY+FmmAjVU=" + [mod."github.com/rs/cors"] + version = "v1.7.0" + hash = "sha256-8fmvap36M+KvxjBDBrQhbF4t45QqffY05wyuc7s0f6k=" + [mod."github.com/rubyist/circuitbreaker"] + version = "v2.2.1+incompatible" + hash = "sha256-6qlPpfrp0grghKbwnRBh3azjyJSjS2e2FPhgz3Q76DU=" + [mod."github.com/russross/blackfriday"] + version = "v1.5.2" + hash = "sha256-7MjJB7KZoNFTBo5Qzc3LL9QKrzWf9keqt5lh7tl360s=" + [mod."github.com/russross/blackfriday/v2"] + version = "v2.0.1" + hash = "sha256-smS2RGP+eOAlWkCJKSQZv7PIKUyJIKM/ty+T1nQ8n1o=" + [mod."github.com/rwcarlsen/goexif"] + version = "v0.0.0-20190401172101-9e8deecbddbd" + hash = "sha256-AiY2T9hXj6jnfldYDoe4WNr3FldpVTxc3lScR++HOLc=" + [mod."github.com/ryanuber/columnize"] + version = "v2.1.0+incompatible" + hash = "sha256-5ion0we/ruidQwfcQxteI96dXOvmRNWY+4TMsJ6CMlU=" + [mod."github.com/ryanuber/go-glob"] + version = "v1.0.0" + hash = "sha256-YkMl1utwUhi3E0sHK23ISpAsPyj4+KeXyXKoFYGXGVY=" + [mod."github.com/saintfish/chardet"] + version = "v0.0.0-20120816061221-3af4cd4741ca" + hash = "sha256-i12UWnfQA2Jg7t8jtLrS5ISRo1YAe0XpomkS0yoo8DM=" + [mod."github.com/samuel/go-zookeeper"] + version = "v0.0.0-20190923202752-2cc03de413da" + hash = "sha256-/UFD4nSHZIIHqKUVEEBuGrvFTusNzl+H72lig8fJ4oc=" + [mod."github.com/schollz/closestmatch"] + version = "v2.1.0+incompatible" + hash = "sha256-SpWqGfqlMkZPQ6TSf7NTaYMbQllBaBgPM8oxTBOTn7w=" + [mod."github.com/sean-/seed"] + version = "v0.0.0-20170313163322-e2103e2c3529" + hash = "sha256-RQQTjvf8Y91jP5FGOyEnGMFw7zCrcSnUU4eH2CXKkT4=" + [mod."github.com/sebest/xff"] + version = "v0.0.0-20210106013422-671bd2870b3a" + hash = "sha256-t7Gdp7S71Koej5Njg3jOo5vwyj02tJCbJjrq/vZGOho=" + [mod."github.com/sergi/go-diff"] + version = "v1.0.0" + hash = "sha256-I8rbJFKm44u/wS/gz+2yX9882xXcBdb9mKEKq5OoJRU=" + [mod."github.com/shurcooL/component"] + version = "v0.0.0-20170202220835-f88ec8f54cc4" + hash = "sha256-a9k68+DDAOivFE6+w6PLtY7jP7tBhRJ0HpWqPctXRH0=" + [mod."github.com/shurcooL/events"] + version = "v0.0.0-20181021180414-410e4ca65f48" + hash = "sha256-doJ8stiMuz8GxoqSSkn4C2i0d8ldWtnKPTVhtYuJ/nU=" + [mod."github.com/shurcooL/github_flavored_markdown"] + version = "v0.0.0-20181002035957-2122de532470" + hash = "sha256-f2JjGSD1ZLRKOUOXyKm/bjgG+/Qs5CmdDI/WSbM3BH4=" + [mod."github.com/shurcooL/go"] + version = "v0.0.0-20180423040247-9e1955d9fb6e" + hash = "sha256-Es8aOKHjj9/JEq/jBeYpgAmWxklBfceCsVqWo/dKTdE=" + [mod."github.com/shurcooL/go-goon"] + version = "v0.0.0-20170922171312-37c2f522c041" + hash = "sha256-G3f/tdgytwRSsjQy09ZBK43xC4f9GgxdXZ01XY00TJ0=" + [mod."github.com/shurcooL/gofontwoff"] + version = "v0.0.0-20180329035133-29b52fc0a18d" + hash = "sha256-4GjYbep1rhy1d9JWIGKrXNq3KU2EYgvgFAmfrZr4ZdQ=" + [mod."github.com/shurcooL/gopherjslib"] + version = "v0.0.0-20160914041154-feb6d3990c2c" + hash = "sha256-se6fbps3O7pR2/7QL8U2HZL+IQRPzkuSJ+5TIgsoiP8=" + [mod."github.com/shurcooL/highlight_diff"] + version = "v0.0.0-20170515013008-09bb4053de1b" + hash = "sha256-IbiL6KDehzZL7ezTZNe4RtkHMYMHOBzApy5NUlaIIIA=" + [mod."github.com/shurcooL/highlight_go"] + version = "v0.0.0-20181028180052-98c3abbbae20" + hash = "sha256-rfuaW3yyOVo4WwOdOkADQj0oMl6Ol5ROn832L6xrLyU=" + [mod."github.com/shurcooL/home"] + version = "v0.0.0-20181020052607-80b7ffcb30f9" + hash = "sha256-tWABrK9+JMevjA7pY/JYACRttqK+4F8lGNd5Iy8/7iQ=" + [mod."github.com/shurcooL/htmlg"] + version = "v0.0.0-20170918183704-d01228ac9e50" + hash = "sha256-8ojFDF1jY5tLR7gM2nSedOmNndfIm7iwLw0j2dTadM0=" + [mod."github.com/shurcooL/httperror"] + version = "v0.0.0-20170206035902-86b7830d14cc" + hash = "sha256-Ax2w2RK8OQeT/9oS/jcvYSMLTEviyhkUh1mIKhlmKW4=" + [mod."github.com/shurcooL/httpfs"] + version = "v0.0.0-20171119174359-809beceb2371" + hash = "sha256-gwtJ8AVVlNPRYEIyIfE9+rrzHHYD+HPc+QNxOQsucsM=" + [mod."github.com/shurcooL/httpgzip"] + version = "v0.0.0-20180522190206-b1c53ac65af9" + hash = "sha256-xCYeIhRIkuz14fCTWDrnjr6QlVebA1BZVPOz4FLZCGw=" + [mod."github.com/shurcooL/issues"] + version = "v0.0.0-20181008053335-6292fdc1e191" + hash = "sha256-CrpA2SWZfAedcjwRhXD1+9oSmhYuewnd2GD/mTKvRMM=" + [mod."github.com/shurcooL/issuesapp"] + version = "v0.0.0-20180602232740-048589ce2241" + hash = "sha256-kgkvS1UYQ6LvaCpgM1FDar2Pe3LFeT5PE9BDIwCC1hM=" + [mod."github.com/shurcooL/notifications"] + version = "v0.0.0-20181007000457-627ab5aea122" + hash = "sha256-z6p5qL45G6vfOoyaETxud+nFcU0dpxakwzbhq7HN45k=" + [mod."github.com/shurcooL/octicon"] + version = "v0.0.0-20181028054416-fa4f57f9efb2" + hash = "sha256-NaIzinqI6MUvlrLXuesyYsdo2uXpa+7eqfwfbBGCOvk=" + [mod."github.com/shurcooL/reactions"] + version = "v0.0.0-20181006231557-f2e0b4ca5b82" + hash = "sha256-IYh1YHNMNBSo/P/NOttlk3buI9G5dwAvMxDdacpw7oQ=" + [mod."github.com/shurcooL/sanitized_anchor_name"] + version = "v1.0.0" + hash = "sha256-DtFSzeLmD1fAl103ncgwab7Vv2F0aulsA+gbkq24ab8=" + [mod."github.com/shurcooL/users"] + version = "v0.0.0-20180125191416-49c67e49c537" + hash = "sha256-q8tUPY+8zZYu5VaCem6aPcoJxTypSWlXDqvm6RejQ4g=" + [mod."github.com/shurcooL/webdavfs"] + version = "v0.0.0-20170829043945-18c3829fa133" + hash = "sha256-JaSaBUeMJQHFCEtK2zG3IdYrQntKyd8ZZhmILcIJAxE=" + [mod."github.com/sirupsen/logrus"] + version = "v1.8.0" + hash = "sha256-Z47GL42du12DnwzclnolPgSHd0wjbX8pxHVxmH9yJ1Y=" + [mod."github.com/smartystreets/assertions"] + version = "v1.0.1" + hash = "sha256-lLGPZvd0vMx/6VRaJ/dy8JtPlNTgK52dg6NDd1p+jDQ=" + [mod."github.com/smartystreets/goconvey"] + version = "v1.6.4" + hash = "sha256-gDEvwEBgCVYi6daVRlQ2DUXFFlpybM1h4HyvvHphmM4=" + [mod."github.com/smola/gocompat"] + version = "v0.2.0" + hash = "sha256-O1g9DDSymRoRJx9FQVvtr1gCVOdJhHXT8qPJZQ4I3HI=" + [mod."github.com/soheilhy/cmux"] + version = "v0.1.4" + hash = "sha256-EGyOVbQFq4k+A2M61ZMZ5aAM8uwOPLOcp3ynhswz47g=" + [mod."github.com/sony/gobreaker"] + version = "v0.4.1" + hash = "sha256-ABy1A/HYvhLjGdAaVBpSHEhn/1yJa3lSuqAJPipdWUU=" + [mod."github.com/sourcegraph/annotate"] + version = "v0.0.0-20160123013949-f4cad6c6324d" + hash = "sha256-bsu85jFOThQa5/6EDKdz0R3/9AiirXwxGR/sjltXJoI=" + [mod."github.com/sourcegraph/syntaxhighlight"] + version = "v0.0.0-20170531221838-bd320f5d308e" + hash = "sha256-HWnE9MHUdI4CoM1DTgkiKwqez3jLYCvPHcZtnZfFYGQ=" + [mod."github.com/spacemonkeygo/openssl"] + version = "v0.0.0-20181017203307-c2dcc5cca94a" + hash = "sha256-SzIKPfYmYc/EFfq8rPlKMrCPM83PVuobtFI1creF1AQ=" + [mod."github.com/spacemonkeygo/spacelog"] + version = "v0.0.0-20180420211403-2296661a0572" + hash = "sha256-3q+BPKhaohGhT2CcsnbyDd8/Nhi9NI7FESUdwt3MbEQ=" + [mod."github.com/spaolacci/murmur3"] + version = "v1.1.0" + hash = "sha256-RWD4PPrlAsZZ8Xy356MBxpj+/NZI7w2XOU14Ob7/Y9M=" + [mod."github.com/spf13/afero"] + version = "v1.1.2" + hash = "sha256-00yWOvw9GosWm6QkogM8MxpnVFRm/7BcdBLG4pQjO1Y=" + [mod."github.com/spf13/cast"] + version = "v1.3.0" + hash = "sha256-hbVF7F0YsgSybYEJa7W+Rz0As6OpgmpZOxB5JLFzAXc=" + [mod."github.com/spf13/cobra"] + version = "v0.0.5" + hash = "sha256-YovRLduyDxoYoz1tNVgh9rnebjFIaeNeeBzWYrREnXw=" + [mod."github.com/spf13/jwalterweatherman"] + version = "v1.0.0" + hash = "sha256-KLftz+gaA5wSkvLqvQ7CuboB79kKEoTJvgTtrXatbiQ=" + [mod."github.com/spf13/pflag"] + version = "v1.0.3" + hash = "sha256-Vu3dUmDZASu8/sAVAXaBXawtbZhsL9nMo43vANOdNMU=" + [mod."github.com/spf13/viper"] + version = "v1.3.2" + hash = "sha256-8I/LyWr7cOKg+0NokEbewJ8WNz8hp0KLUW0WgNyGSaA=" + [mod."github.com/src-d/envconfig"] + version = "v1.0.0" + hash = "sha256-g4N9s4vnvLjy+BR8oWrcI+yoUw2mRF1rrSoLkJ8xWfQ=" + [mod."github.com/streadway/amqp"] + version = "v0.0.0-20190827072141-edfb9018d271" + hash = "sha256-KmrYNdmuBxGj5b+7w27z7qrf76N8gfVI5c7BqSWBHJY=" + [mod."github.com/streadway/handy"] + version = "v0.0.0-20190108123426-d5acb3125c2a" + hash = "sha256-GYyndQNB7ewajGHgVPq1iUrtYYkG0ml1gFRIBxVVXAo=" + [mod."github.com/stretchr/objx"] + version = "v0.1.1" + hash = "sha256-HdGVZCuy7VprC5W9UxGbDmXqsKADMjpEDht7ilGVLco=" + [mod."github.com/stretchr/testify"] + version = "v1.7.0" + hash = "sha256-t1I9uCrn9vSUu/z5IZuNyGShmbOcJ6UGc2f75ZBrHzE=" + [mod."github.com/syndtr/goleveldb"] + version = "v1.0.0" + hash = "sha256-rW7SW6nehede0oMZo4NBatM6Eizbnlb7xYoX/dcDUxA=" + [mod."github.com/tarm/serial"] + version = "v0.0.0-20180830185346-98f6abe2eb07" + hash = "sha256-646ngos1o2K+T+wxZpfuaQKrWqWZuta5iqMPJ3aURPo=" + [mod."github.com/tebeka/strftime"] + version = "v0.1.3" + hash = "sha256-ahLbzsDylxmyGMzcUGePJCCR/qjtNPDQ2R21C38ydi8=" + [mod."github.com/texttheater/golang-levenshtein"] + version = "v0.0.0-20180516184445-d188e65d659e" + hash = "sha256-LIlCO9LMoWFVJqg+tAdWVwEjPmdXLg9D2aJv8XntqjY=" + [mod."github.com/tmc/grpc-websocket-proxy"] + version = "v0.0.0-20170815181823-89b8d40f7ca8" + hash = "sha256-U9vCalLqZTqRmh0xFiMC62+aIrRr/nIC57p45hmo5q0=" + [mod."github.com/tv42/httpunix"] + version = "v0.0.0-20191220191345-2ba4b9c3382c" + hash = "sha256-POmmc6hl9dGJgu9RVEyKwSPabLESHdSmaNBpKG68fHU=" + [mod."github.com/ugorji/go"] + version = "v1.1.7" + hash = "sha256-k9HKvzLh9r6Q4l0q5kyeDgc0rnH1VxqmY4EPiFyNL40=" + [mod."github.com/ugorji/go/codec"] + version = "v1.1.7" + hash = "sha256-fulAoEEqegVZP4qtPJAD6/vw/AeI00i27tslP2c/7ko=" + [mod."github.com/urfave/cli"] + version = "v1.22.1" + hash = "sha256-sx4cCoJIH3Yd+ahTrWe/TZYfDrPqOaWeLLGfn/KJNqk=" + [mod."github.com/urfave/cli/v2"] + version = "v2.0.0" + hash = "sha256-Xg+HW9ZmPAv9DiZ2M9ZhJD1EJIWwk6z2w2po1jA6upk=" + [mod."github.com/urfave/negroni"] + version = "v1.0.0" + hash = "sha256-l7ExYayxsfYdqYYcYQd5n1AOP/187IIdsizEpsiR5r4=" + [mod."github.com/valyala/bytebufferpool"] + version = "v1.0.0" + hash = "sha256-I9FPZ3kCNRB+o0dpMwBnwZ35Fj9+ThvITn8a3Jr8mAY=" + [mod."github.com/valyala/fasthttp"] + version = "v1.6.0" + hash = "sha256-xYYoISGsO3XhVynQCM4RbQpYfnG5H+jnxl7PbfleJPQ=" + [mod."github.com/valyala/fasttemplate"] + version = "v1.0.1" + hash = "sha256-21QSS1ifAq75mzwXxcWu3wT3VXEknudAMIqrHae36T0=" + [mod."github.com/valyala/tcplisten"] + version = "v0.0.0-20161114210144-ceec8f93295a" + hash = "sha256-ztY4IPsJ5XwBoN7eDzhZcR0QGOOBF0+hXVbhpl+QS08=" + [mod."github.com/viant/assertly"] + version = "v0.4.8" + hash = "sha256-5rGa38W/uINh98ayk5rGnPWt57HWOR94/IWYs8Lw0BA=" + [mod."github.com/viant/toolbox"] + version = "v0.24.0" + hash = "sha256-4tJYWRDDbstA8bxlFaP0XKL1kS+f9lg3itEzexl6vY8=" + [mod."github.com/warpfork/go-wish"] + version = "v0.0.0-20200122115046-b9ea61034e4a" + hash = "sha256-MONWCjfywUgv4BJo0q44yH9SiI25OoglIOqnaBx13Q8=" + [mod."github.com/whyrusleeping/base32"] + version = "v0.0.0-20170828182744-c30ac30633cc" + hash = "sha256-DlJl5zgWr2EY3OkGu30ekC3fWvpOnr0PqaPanCSSEhg=" + [mod."github.com/whyrusleeping/cbor-gen"] + version = "v0.0.0-20200710004633-5379fc63235d" + hash = "sha256-/BDUNsTxhYC0x0fZqlqgE0sAm+7Cd7N96ZJXPi0yF9E=" + [mod."github.com/whyrusleeping/chunker"] + version = "v0.0.0-20181014151217-fe64bd25879f" + hash = "sha256-IkucTGx1aVXB2xQLUYfLIxxBoEEnK/wjiJ7zmC51BI8=" + [mod."github.com/whyrusleeping/go-keyspace"] + version = "v0.0.0-20160322163242-5b898ac5add1" + hash = "sha256-a2V0vuPSQh6d9yoxz07JNJllo1Gm1iDMC3/xjk88czo=" + [mod."github.com/whyrusleeping/go-logging"] + version = "v0.0.1" + hash = "sha256-cz1RDHJCkPpM3Cc0835puioHVDfKxOXWcPq48WScLB0=" + [mod."github.com/whyrusleeping/go-notifier"] + version = "v0.0.0-20170827234753-097c5d47330f" + hash = "sha256-Ck6AVzhmE4o6CPnMvmUXJOcgXg1+jQJpBXYAM4YiMCA=" + [mod."github.com/whyrusleeping/go-sysinfo"] + version = "v0.0.0-20190219211824-4a357d4b90b1" + hash = "sha256-OMo0PoyOZKA8SDTBLiTaVjEI8B5DvbV4OoUxG9OV3mg=" + [mod."github.com/whyrusleeping/mafmt"] + version = "v1.2.8" + hash = "sha256-mzGZ6k+4SRkCwtH+ReZ4OB0VmnwNbNQcs6PFvq4AJms=" + [mod."github.com/whyrusleeping/mdns"] + version = "v0.0.0-20190826153040-b9b60ed33aa9" + hash = "sha256-g3dbADmNEz68KiJfmRXze1zgKY77bbAuPXik2mn+YAI=" + [mod."github.com/whyrusleeping/multiaddr-filter"] + version = "v0.0.0-20160516205228-e903e4adabd7" + hash = "sha256-gBiRLiZAbneTwjcwbx0AyUUkG+VfZVjh3e0Ace1GTU8=" + [mod."github.com/whyrusleeping/tar-utils"] + version = "v0.0.0-20201201191210-20a61371de5b" + hash = "sha256-/+boTjPUUT7kr863GnjNL6OvsauakHNXF0380L/JarQ=" + [mod."github.com/whyrusleeping/timecache"] + version = "v0.0.0-20160911033111-cfcb2f1abfee" + hash = "sha256-Wkjdw0c2Org1Cv14GHLVY8bb3INoRSEzGZIdvONR2Vo=" + [mod."github.com/x-cray/logrus-prefixed-formatter"] + version = "v0.5.2" + hash = "sha256-yob8w9upAT+A279x0oek69tXM7E+6umNhIAv0GNsDFc=" + [mod."github.com/xeipuuv/gojsonpointer"] + version = "v0.0.0-20180127040702-4e3ac2762d5f" + hash = "sha256-OEW9nOR3EeMzvqvqpdAgowpZlbXPLWM0JT+5bwWOxo8=" + [mod."github.com/xeipuuv/gojsonreference"] + version = "v0.0.0-20180127040603-bd5ef7bd5415" + hash = "sha256-ZbXA+ASQrTgBQzasUKC9vznrOGpquYyWr+uwpm46fvU=" + [mod."github.com/xeipuuv/gojsonschema"] + version = "v1.2.0" + hash = "sha256-1ERBEvxj3pvHkMS2mvmvmYRi8jgAaTquo5hwjDLAEdc=" + [mod."github.com/xiang90/probing"] + version = "v0.0.0-20190116061207-43a291ad63a2" + hash = "sha256-sXyLzdjys2YAQBxz1ELmV3RulY5huFrOEUQWaYKuQvw=" + [mod."github.com/xordataexchange/crypt"] + version = "v0.0.3-0.20170626215501-b2862e3d0a77" + hash = "sha256-HuXuIK/V5iNuF7j68acNQ3SW7rrn1efaI/Rfq0xBAxM=" + [mod."github.com/yalp/jsonpath"] + version = "v0.0.0-20180802001716-5cc68e5049a0" + hash = "sha256-i7iWzS6hR5IwvrJ8kcjqxEYpRnj9cwiL726Ox8Ltfk4=" + [mod."github.com/yudai/gojsondiff"] + version = "v1.0.0" + hash = "sha256-9nVgqa9z/jdnusUcrVN+HsbkNJvSd3C4Bp3wr6Xw814=" + [mod."github.com/yudai/golcs"] + version = "v0.0.0-20170316035057-ecda9a501e82" + hash = "sha256-+CaxcEHjkNZjhQ6lZ+0mvBa2RtJ37wHehr6A7wrjplc=" + [mod."github.com/yudai/pp"] + version = "v2.0.1+incompatible" + hash = "sha256-8xXrFy0IFrl1ZO3K1Br+f51rAXVOYrgvD1zap+Rha6M=" + [mod."github.com/yuin/goldmark"] + version = "v1.2.1" + hash = "sha256-vrL87IsRgYTTHvCH2fodVu+ECk9UCu4kuCy3Ypy2Oos=" + [mod."go.etcd.io/bbolt"] + version = "v1.3.3" + hash = "sha256-DM/GTsa/Oi+i+lVLgj4xFL5xXAhprJwz+LEnPZ/9wDY=" + [mod."go.etcd.io/etcd"] + version = "v0.0.0-20191023171146-3cf2f69b5738" + hash = "sha256-+ak7iGjlT3FLqy3IXYu2wh1WyRWZnfU+QqrsPlit8Cs=" + [mod."go.opencensus.io"] + version = "v0.22.5" + hash = "sha256-1EhPgCDtRoeU1gYXud7cEUxZNaC6z1k8rpYbS8OeTBU=" + [mod."go.opentelemetry.io/otel"] + version = "v0.18.0" + hash = "sha256-zGTZjVFVKxX1EAMYnpzLhe3jFhZ8yo1ryMtXckZ3NFM=" + [mod."go.opentelemetry.io/otel/metric"] + version = "v0.18.0" + hash = "sha256-y3qy8KRcDIoBh4XarxrIP2lGFSrY+m0aMxN4jGZUMNM=" + [mod."go.opentelemetry.io/otel/oteltest"] + version = "v0.18.0" + hash = "sha256-et6Gb5Snp6Wp1Qfba6giNyx6JsvkV2P7bPEoifR3QCA=" + [mod."go.opentelemetry.io/otel/trace"] + version = "v0.18.0" + hash = "sha256-hVr0ikQwYdRdy1ataFO8AdhY2U57c9DeMEb69c2K3pk=" + [mod."go.uber.org/atomic"] + version = "v1.6.0" + hash = "sha256-BR42nmQCrvUSK1qWUcVaP+pYAEJOg5kJgE6q8DKEml0=" + [mod."go.uber.org/dig"] + version = "v1.10.0" + hash = "sha256-yEMI8kOVp4mKsLH1kjRGGAAVpEMYKxq+lYAF7x6n/SI=" + [mod."go.uber.org/fx"] + version = "v1.13.1" + hash = "sha256-UeLwx2d1/ClQG1NLKgdKWZtIPfcUW5ACc8PI0hKBhKk=" + [mod."go.uber.org/goleak"] + version = "v1.0.0" + hash = "sha256-uevfpNPCE2LE3GU4VMMTPOt/zUEVJbTZCE9lHT+0Z+0=" + [mod."go.uber.org/multierr"] + version = "v1.5.0" + hash = "sha256-vMCPfQVr5zYI5+9rlZjA64YeJDSPCDDiA3Rkx7+v7nU=" + [mod."go.uber.org/tools"] + version = "v0.0.0-20190618225709-2cfd321de3ee" + hash = "sha256-vLL9lT4iMxODR5+I6ZS14V4WcEd7REPNYZt0pCdNKLM=" + [mod."go.uber.org/zap"] + version = "v1.16.0" + hash = "sha256-sQSj+Cx++tz78WezoiiSqtGMDXdYdhCoGJELCnwLeB8=" + [mod."go4.org"] + version = "v0.0.0-20200411211856-f5505b9728dd" + hash = "sha256-UxbUjyr/bArM+3XAQfQ58XBbePvUdZ31EiQkCfXl/i0=" + [mod."golang.org/x/build"] + version = "v0.0.0-20190111050920-041ab4dc3f9d" + hash = "sha256-eNhyzCbiAMVm8WHRkK/zEkQUgwvXDAwLoQ7Kr5aFaIo=" + [mod."golang.org/x/crypto"] + version = "v0.0.0-20210220033148-5ea612d1eb83" + hash = "sha256-ZacGMV1CFBAmShBQ/dN+C8Ls5ECHXXZdUiI1hcu4cFU=" + [mod."golang.org/x/exp"] + version = "v0.0.0-20200207192155-f17229e696bd" + hash = "sha256-J5Tk8vk6YUtzZ/1DpCCDTah5O1GOOgOyXoXZu/514MQ=" + [mod."golang.org/x/image"] + version = "v0.0.0-20210220032944-ac19c3e999fb" + hash = "sha256-V3hwNVeqOvBVR1mp7p8+xAlh8TwOrJDaCXM0hgOZjcY=" + [mod."golang.org/x/lint"] + version = "v0.0.0-20200302205851-738671d3881b" + hash = "sha256-LNkJ9QCzsDgFjrLI+hYNISu9jrsu9tX9tFKm4i/5cUo=" + [mod."golang.org/x/mobile"] + version = "v0.0.0-20190719004257-d2bd2a29d028" + hash = "sha256-At0uE2mTr/GHCyF4U8Z+AiU2jlvBVQuX25tooo2ll6M=" + [mod."golang.org/x/mod"] + version = "v0.3.0" + hash = "sha256-c+KKzeDUDxrKIx8un1DpETlTK+DmHP+zUjRZrgs0ejo=" + [mod."golang.org/x/net"] + version = "v0.0.0-20210226172049-e18ecbb05110" + hash = "sha256-4u7XpPV+Ersntau6zUiLuNsZQZCIIZs3RouHYl/I02o=" + [mod."golang.org/x/oauth2"] + version = "v0.0.0-20200107190931-bf48bf16ab8d" + hash = "sha256-r+VK6vgr8pMOmLXonG6YhBSUQ+kZJzdHgpV/YFZsOeo=" + [mod."golang.org/x/perf"] + version = "v0.0.0-20180704124530-6e6d33e29852" + hash = "sha256-/ExiBWIazyLr5+jDL/O00Fek+JBnGqBGWaiRXyGC0Jc=" + [mod."golang.org/x/sync"] + version = "v0.0.0-20201207232520-09787c993a3a" + hash = "sha256-Phh5d0Ba21YQXkkdw4JjArr3UJa5V04P83NKmyKvZNs=" + [mod."golang.org/x/sys"] + version = "v0.0.0-20210305230114-8fe3ee5dd75b" + hash = "sha256-OXbqn4SoBt9sS20YcPilzJGfSIXTJoDhsBOaO5QdCLs=" + [mod."golang.org/x/term"] + version = "v0.0.0-20201126162022-7de9c90e9dd1" + hash = "sha256-ykpqi1F7Yzo1BVwuG0nbQOZnK0qevcCD2xqbXbsoQq0=" + [mod."golang.org/x/text"] + version = "v0.3.5" + hash = "sha256-wObZsr3SvLWITdBBxb5tFdpWCR5OF+RRN6DJl6WQpzE=" + [mod."golang.org/x/time"] + version = "v0.0.0-20210220033141-f8bda1e9f3ba" + hash = "sha256-EXcg0EH7WIgc2raopkjaOX3uPORJPM6PKzvJQy5QazQ=" + [mod."golang.org/x/tools"] + version = "v0.0.0-20210106214847-113979e3529a" + hash = "sha256-VdoV0LIBWehslesNW1ETJ1WmO4KsGojC2HDdNAjGzsI=" + [mod."golang.org/x/xerrors"] + version = "v0.0.0-20200804184101-5ec99f83aff1" + hash = "sha256-62f++IO8Ia32CYy+xX8XDxCcT9r1sbPvVwoKV99gf7U=" + [mod."google.golang.org/api"] + version = "v0.17.0" + hash = "sha256-uq4UQu+21RMJbg1wY946dstvyZPWIOvaeuZStc21W/w=" + [mod."google.golang.org/appengine"] + version = "v1.6.5" + hash = "sha256-cE9jZUiPSk7GMhhpdcl4NS6OkGqwh9IU3exKiqs+3ns=" + [mod."google.golang.org/genproto"] + version = "v0.0.0-20210303154014-9728d6b83eeb" + hash = "sha256-vFTs4XNg4Wd0G93aOoqxqoadAXZofRguntZ7BBNTm6s=" + [mod."google.golang.org/grpc"] + version = "v1.36.0" + hash = "sha256-6ThDzMLXhuTrQlp8DVjKilh0NxAPZgF/ynYEqfFksSg=" + [mod."google.golang.org/protobuf"] + version = "v1.25.0" + hash = "sha256-3sf57K5A0nmA1UmDe+6FUNJI6UR+SfVyZWNv+2TGHT4=" + [mod."gopkg.in/DATA-DOG/go-sqlmock.v1"] + version = "v1.3.0" + hash = "sha256-G2MsxKln2XVMVImzqzfA+NYiT5uDnLx5R8MYVaNpBJk=" + [mod."gopkg.in/alecthomas/kingpin.v2"] + version = "v2.2.6" + hash = "sha256-uViE2kPj7tMrGYVjjdLOl2jFDmmu+3P7GvnZBse2zVY=" + [mod."gopkg.in/check.v1"] + version = "v1.0.0-20190902080502-41f04d3bba15" + hash = "sha256-Xl5gjoqU26M+Yxm6Xok5VHVpYT5hItwsN7d2Wj9L020=" + [mod."gopkg.in/cheggaaa/pb.v1"] + version = "v1.0.25" + hash = "sha256-tw2ZjiPI6xoxFIlftyGI6AP1kdOTkjf8B9v34QyPuG8=" + [mod."gopkg.in/errgo.v2"] + version = "v2.1.0" + hash = "sha256-Ir/MuxQFxvVJEciovGOZbM8ZfKJ/AYotPwYfH2FctRg=" + [mod."gopkg.in/fsnotify.v1"] + version = "v1.4.7" + hash = "sha256-j/Ts92oXa3k1MFU7Yd8/AqafRTsFn7V2pDKCyDJLah8=" + [mod."gopkg.in/gcfg.v1"] + version = "v1.2.3" + hash = "sha256-+viy8UzF1dvwI53s4vcjE1UCGXGhmo4uXdNyZiNPrpg=" + [mod."gopkg.in/go-playground/assert.v1"] + version = "v1.2.1" + hash = "sha256-9SYLM6GItl90ggSFWIGK5dxS3siUpmAilw2oO/2risA=" + [mod."gopkg.in/go-playground/validator.v8"] + version = "v8.18.2" + hash = "sha256-paiXWSGghOoy/RQK3ViE7GwCIupZC05t4nOoAi8iUdQ=" + [mod."gopkg.in/inf.v0"] + version = "v0.9.1" + hash = "sha256-z84XlyeWLcoYOvWLxPkPFgLkpjyb2Y4pdeGMyySOZQI=" + [mod."gopkg.in/ini.v1"] + version = "v1.62.0" + hash = "sha256-u9T6wgmbmG+hw8qiGLkWdxo9DgdrChFpuVpR53HzqbY=" + [mod."gopkg.in/mgo.v2"] + version = "v2.0.0-20180705113604-9856a29383ce" + hash = "sha256-oIMWi+uKxazK0KOtGMalGQkvpiwVV1/NQq/JANvlZpI=" + [mod."gopkg.in/resty.v1"] + version = "v1.12.0" + hash = "sha256-t9KTjlm1K1WdPAZ0L6rLv0ME/iP/gKeKgvDjXMaxVRg=" + [mod."gopkg.in/src-d/go-cli.v0"] + version = "v0.0.0-20181105080154-d492247bbc0d" + hash = "sha256-LEaSkBfgHqWRSYIi4nrl8YFTxvMoxxFe5DHP9OFEEe4=" + [mod."gopkg.in/src-d/go-log.v1"] + version = "v1.0.1" + hash = "sha256-UeXQVu8c5JrbsK8+K4GytM5z8FUpodRFB8EDihDxIlM=" + [mod."gopkg.in/tomb.v1"] + version = "v1.0.0-20141024135613-dd632973f1e7" + hash = "sha256-W/4wBAvuaBFHhowB67SZZfXCRDp5tzbYG4vo81TAFdM=" + [mod."gopkg.in/warnings.v0"] + version = "v0.1.2" + hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8=" + [mod."gopkg.in/yaml.v2"] + version = "v2.4.0" + hash = "sha256-uVEGglIedjOIGZzHW4YwN1VoRSTK8o0eGZqzd+TNdd0=" + [mod."gopkg.in/yaml.v3"] + version = "v3.0.0-20200313102051-9f266ea9e77c" + hash = "sha256-ZXiVLum4UY7Xg2LUMJOk3m248lOrab5FBxWU9emIaq0=" + [mod."grpc.go4.org"] + version = "v0.0.0-20170609214715-11d0a25b4919" + hash = "sha256-jqrYvDHRhwKMz/aK+/ndovBWMyJ0jULc4r/UJe7LnE4=" + [mod."honnef.co/go/tools"] + version = "v0.0.1-2019.2.3" + hash = "sha256-jpCzv1UG8xGB44IA+kcAXDULYQlJWqa816GYP+BQoMs=" + [mod."rsc.io/binaryregexp"] + version = "v0.2.0" + hash = "sha256-izALTmzybQe67BNXliqQ3xCEOo+b6o8C4YoX5H0FWc0=" + [mod."rsc.io/quote/v3"] + version = "v3.1.0" + hash = "sha256-sF7lOq/bInDPtLI+j610WJRAQ09Cxc5lmPzzytuE6DI=" + [mod."rsc.io/sampler"] + version = "v1.3.0" + hash = "sha256-UPbUO3GOGn6/fz1EBEYONBX45V6bzQKQv6CoZb2Y3S8=" + [mod."sigs.k8s.io/yaml"] + version = "v1.1.0" + hash = "sha256-awYwA5r3OlWQbtBEIIY12g9nX73hBe3tmV7Lkpvc8Nw=" + [mod."sourcegraph.com/sourcegraph/appdash"] + version = "v0.0.0-20190731080439-ebfcffb1b5c0" + hash = "sha256-0qD4VP3zQw3yRnN3FqwSyaid4zxJGJRfygX44JPcd8k=" + [mod."sourcegraph.com/sourcegraph/go-diff"] + version = "v0.5.0" + hash = "sha256-UAjCnRCObNQ8I8SREesPLsxyBLj1fBuPdz47RFmMMJY=" + [mod."sourcegraph.com/sqs/pbtypes"] + version = "v0.0.0-20180604144634-d3ebe8f20ae4" + hash = "sha256-OfuzshdNsyjvGY7aTQ+QjnUcyu4NIyQgD1sKJgnGnm0=" diff --git a/matrix/matrix-media-repo/update.sh b/matrix/matrix-media-repo/update.sh new file mode 100755 index 0000000..3fdebda --- /dev/null +++ b/matrix/matrix-media-repo/update.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env nix-shell +#! nix-shell -i bash -p nix-prefetch-git jq +set -e + +WORK_DIR=$(mktemp -d) +URL=https://github.com/turt2live/matrix-media-repo +REVISION=$(jq -r '.nodes."matrix-media-repo".locked.rev' ../../flake.lock) +TARGET_DIR="$PWD" + +function cleanup { + grep "fatal" $WORK_DIR/nix-prefetch-git.out >/dev/stderr || true + rm -rf "$WORK_DIR" +} +trap cleanup EXIT + +echo "Fetching source code $REVISION from $URL" +JSON=$(nix-prefetch-git --url "$URL" --rev "$REVISION" 2> $WORK_DIR/nix-prefetch-git.out) +SHA=$(echo $JSON | jq -r .sha256) +SOURCE_DIR=$(grep '^path is' $WORK_DIR/nix-prefetch-git.out | sed 's/^path is //') + +echo "Creating gomod2nix.toml" +nix run github:tweag/gomod2nix -- -dir $SOURCE_DIR -outdir $TARGET_DIR