aboutsummaryrefslogtreecommitdiff
path: root/echo
diff options
context:
space:
mode:
authorMike Crute <mike@crute.us>2023-08-01 17:19:17 -0700
committerMike Crute <mike@crute.us>2023-08-01 17:19:17 -0700
commit058e4faba9c1531661234a5adaa7a6c3791f92d4 (patch)
treebf7cc7879e1ad41f8dc1cbbaae74dad632556af8 /echo
parent14a8d74efed00c13bd59e2ff9adc0b743803535d (diff)
downloadgolib-058e4faba9c1531661234a5adaa7a6c3791f92d4.tar.bz2
golib-058e4faba9c1531661234a5adaa7a6c3791f92d4.tar.xz
golib-058e4faba9c1531661234a5adaa7a6c3791f92d4.zip
echo: add new content type negotiatorecho/v0.10.0
Diffstat (limited to 'echo')
-rw-r--r--echo/controller/content_type_negotiator_v2.go196
-rw-r--r--echo/controller/content_type_negotiator_v2_test.go72
-rw-r--r--echo/go.mod8
-rw-r--r--echo/go.sum18
4 files changed, 284 insertions, 10 deletions
diff --git a/echo/controller/content_type_negotiator_v2.go b/echo/controller/content_type_negotiator_v2.go
new file mode 100644
index 0000000..63d7fd3
--- /dev/null
+++ b/echo/controller/content_type_negotiator_v2.go
@@ -0,0 +1,196 @@
1package controller
2
3import (
4 "errors"
5 "net/http"
6
7 "github.com/labstack/echo/v4"
8
9 glecho "code.crute.us/mcrute/golib/echo"
10 glhttp "code.crute.us/mcrute/golib/net/http"
11)
12
13const (
14 ContextMediaTypeParameters = "__golib_echo_negotiator_media_type_params"
15 DefaultContentType = "*/*"
16)
17
18type ContentTypeHandlerMap map[string]ErrorHandler
19
20type ErrorHandler interface {
21 HandleError(echo.Context, int, error) error
22}
23
24type GetableHandler interface{ HandleGet(echo.Context) error }
25type HeadableHandler interface{ HandleHead(echo.Context) error }
26type PostableHandler interface{ HandlePost(echo.Context) error }
27type PutableHandler interface{ HandlePut(echo.Context) error }
28type PatchableHandler interface{ HandlePatch(echo.Context) error }
29type DeleteableHandler interface{ HandleDelete(echo.Context) error }
30type ConnectableHandler interface{ HandleConnect(echo.Context) error }
31type OptionableHandler interface{ HandleOptions(echo.Context) error }
32type TraceableHandler interface{ HandleTrace(echo.Context) error }
33
34type ContentTypeNegotiatingHandlerV2 struct {
35 handlers map[string]map[string]echo.HandlerFunc // Content-Type -> HTTP Method -> Handler
36 errorHandlers map[string]ErrorHandler
37 mediaTypes glhttp.AcceptableTypes
38}
39
40func NewContentTypeNegotiatingHandlerV2() *ContentTypeNegotiatingHandlerV2 {
41 return &ContentTypeNegotiatingHandlerV2{
42 handlers: map[string]map[string]echo.HandlerFunc{},
43 mediaTypes: glhttp.AcceptableTypes{},
44 errorHandlers: map[string]ErrorHandler{},
45 }
46}
47
48func buildMethodMap(hnd ErrorHandler) map[string]echo.HandlerFunc {
49 methods := map[string]echo.HandlerFunc{}
50
51 if h, ok := hnd.(GetableHandler); ok {
52 methods[http.MethodGet] = h.HandleGet
53 }
54
55 if h, ok := hnd.(HeadableHandler); ok {
56 methods[http.MethodHead] = h.HandleHead
57 }
58
59 if h, ok := hnd.(PostableHandler); ok {
60 methods[http.MethodPost] = h.HandlePost
61 }
62
63 if h, ok := hnd.(PutableHandler); ok {
64 methods[http.MethodPut] = h.HandlePut
65 }
66
67 if h, ok := hnd.(PatchableHandler); ok {
68 methods[http.MethodPatch] = h.HandlePatch
69 }
70
71 if h, ok := hnd.(DeleteableHandler); ok {
72 methods[http.MethodDelete] = h.HandleDelete
73 }
74
75 if h, ok := hnd.(ConnectableHandler); ok {
76 methods[http.MethodConnect] = h.HandleConnect
77 }
78
79 if h, ok := hnd.(OptionableHandler); ok {
80 methods[http.MethodOptions] = h.HandleOptions
81 }
82
83 if h, ok := hnd.(TraceableHandler); ok {
84 methods[http.MethodTrace] = h.HandleTrace
85 }
86
87 return methods
88}
89
90// RegisterHandler registers a handler for a content type and method. It
91// will return an error if registration fails.
92func (h *ContentTypeNegotiatingHandlerV2) RegisterHandler(ct string, hnd ErrorHandler) error {
93 mt, err := glhttp.ParseMediaType(ct)
94 if err != nil {
95 return err
96 }
97
98 h.mediaTypes = append(h.mediaTypes, mt)
99 h.mediaTypes.Sorted()
100
101 h.handlers[mt.String()] = buildMethodMap(hnd)
102 h.errorHandlers[mt.String()] = hnd
103 return nil
104}
105
106func (h *ContentTypeNegotiatingHandlerV2) Default(hnd ErrorHandler) *ContentTypeNegotiatingHandlerV2 {
107 return h.Handles(DefaultContentType, hnd)
108}
109
110// Handles is a fluent builder that panics on error
111func (h *ContentTypeNegotiatingHandlerV2) Handles(ct string, hnd ErrorHandler) *ContentTypeNegotiatingHandlerV2 {
112 if err := h.RegisterHandler(ct, hnd); err != nil {
113 panic(err)
114 }
115 return h
116}
117
118func (h *ContentTypeNegotiatingHandlerV2) HandlesAll(hnds ContentTypeHandlerMap) *ContentTypeNegotiatingHandlerV2 {
119 for ct, hnd := range hnds {
120 h.Handles(ct, hnd)
121 }
122 return h
123}
124
125func (h *ContentTypeNegotiatingHandlerV2) handleDefaultError(c echo.Context, code int, status string) error {
126 if hnd, ok := h.errorHandlers[DefaultContentType]; ok {
127 return hnd.HandleError(c, code, errors.New(status))
128 }
129
130 return c.JSON(code, map[string]any{
131 "error": map[string]any{
132 "code": code,
133 "message": status,
134 },
135 })
136}
137
138func (h *ContentTypeNegotiatingHandlerV2) Handle(c echo.Context) error {
139 accept, err := glhttp.ParseAccept(c.Request().Header.Values("Accept"))
140 if err != nil {
141 return err
142 }
143
144 match, matcher := h.mediaTypes.FindMatch(accept)
145 if match == nil {
146 code := http.StatusNotAcceptable
147 return h.handleDefaultError(c, code, http.StatusText(code))
148 }
149
150 c.Set(ContextMediaTypeParameters, matcher.Parameters)
151
152 ctHandlers := h.handlers[match.String()]
153 handler, ok := ctHandlers[c.Request().Method]
154 if !ok {
155 code := http.StatusMethodNotAllowed
156 return h.errorHandlers[match.String()].HandleError(c, code, errors.New(http.StatusText(code)))
157 }
158
159 c.Response().Header().Set("Content-Type", match.String())
160
161 return handler(c)
162}
163
164func (h *ContentTypeNegotiatingHandlerV2) Connect(path string, r glecho.URLRouter, mw ...echo.MiddlewareFunc) *ContentTypeNegotiatingHandlerV2 {
165 allMethods := map[string]*int{}
166 for _, v := range h.handlers {
167 for k, _ := range v {
168 allMethods[k] = nil
169 }
170 }
171
172 for k, _ := range allMethods {
173 switch k {
174 case http.MethodGet:
175 r.GET(path, h.Handle, mw...)
176 case http.MethodHead:
177 r.HEAD(path, h.Handle, mw...)
178 case http.MethodPost:
179 r.POST(path, h.Handle, mw...)
180 case http.MethodPut:
181 r.PUT(path, h.Handle, mw...)
182 case http.MethodPatch:
183 r.PATCH(path, h.Handle, mw...)
184 case http.MethodDelete:
185 r.DELETE(path, h.Handle, mw...)
186 case http.MethodConnect:
187 r.Add(http.MethodConnect, path, h.Handle, mw...)
188 case http.MethodOptions:
189 r.OPTIONS(path, h.Handle, mw...)
190 case http.MethodTrace:
191 r.Add(http.MethodTrace, path, h.Handle, mw...)
192 }
193 }
194
195 return h
196}
diff --git a/echo/controller/content_type_negotiator_v2_test.go b/echo/controller/content_type_negotiator_v2_test.go
new file mode 100644
index 0000000..689003a
--- /dev/null
+++ b/echo/controller/content_type_negotiator_v2_test.go
@@ -0,0 +1,72 @@
1package controller
2
3import (
4 "fmt"
5 "io"
6 "net/http"
7 "net/http/httptest"
8 "testing"
9
10 "github.com/labstack/echo/v4"
11 "github.com/stretchr/testify/assert"
12)
13
14// TODO
15// Not Acceptable Error
16// Bad Request Error
17// Other error
18// Error with default handler
19// Error without default handler
20
21// Check context params
22// No handler for method
23// Check content-type return header
24// Handler runs
25
26type GetOnlyHandler struct{}
27
28func (h *GetOnlyHandler) HandleError(c echo.Context, code int, err error) error {
29 return c.String(code, fmt.Sprintf("%s -- default", err))
30}
31
32func (h *GetOnlyHandler) HandleGet(c echo.Context) error {
33 return c.String(http.StatusOK, "GET OK -- default")
34}
35
36type GetPostHandler struct{ Name string }
37
38func (h *GetPostHandler) HandleError(c echo.Context, code int, err error) error {
39 return c.String(code, fmt.Sprintf("%s %s", h.Name, err))
40}
41
42func (h *GetPostHandler) HandleGet(c echo.Context) error {
43 return c.String(http.StatusOK, fmt.Sprintf("%s GET OK", h.Name))
44}
45
46func (h *GetPostHandler) HandlePost(c echo.Context) error {
47 return c.String(http.StatusOK, fmt.Sprintf("%s POST OK", h.Name))
48}
49
50func TestHandlerSuccess(t *testing.T) {
51 hnd := NewContentTypeNegotiatingHandlerV2().
52 HandlesAll(ContentTypeHandlerMap{
53 "*/*": &GetOnlyHandler{},
54 "text/xml": &GetPostHandler{"xml"},
55 "text/*": &GetPostHandler{"html"},
56 "text/plain": &GetPostHandler{"plain"},
57 })
58
59 e := echo.New()
60 req := httptest.NewRequest(http.MethodPost, "/", nil)
61 req.Header.Set("Accept", "text/*,*/*;q=0.8")
62 //"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
63 rec := httptest.NewRecorder()
64 c := e.NewContext(req, rec)
65
66 assert.NoError(t, hnd.Handle(c))
67
68 res := rec.Result()
69 o, _ := io.ReadAll(res.Body)
70 fmt.Printf("%s\n", o)
71 assert.False(t, true)
72}
diff --git a/echo/go.mod b/echo/go.mod
index 39501c2..fcedf30 100644
--- a/echo/go.mod
+++ b/echo/go.mod
@@ -2,16 +2,18 @@ module code.crute.us/mcrute/golib/echo
2 2
3go 1.18 3go 1.18
4 4
5replace code.crute.us/mcrute/golib => ../
6
5require ( 7require (
6 code.crute.us/mcrute/golib v0.4.2 8 code.crute.us/mcrute/golib v0.4.2
7 code.crute.us/mcrute/golib/clients/netbox v0.1.0 9 code.crute.us/mcrute/golib/clients/netbox v0.1.0
8 code.crute.us/mcrute/golib/secrets v0.1.0 10 code.crute.us/mcrute/golib/secrets v0.1.0
9 code.crute.us/mcrute/golib/vault v0.2.4 11 code.crute.us/mcrute/golib/vault v0.2.4
10 github.com/elnormous/contenttype v1.0.0 12 github.com/elnormous/contenttype v1.0.3
11 github.com/labstack/echo/v4 v4.6.1 13 github.com/labstack/echo/v4 v4.6.1
12 github.com/labstack/gommon v0.3.1 14 github.com/labstack/gommon v0.3.1
13 github.com/prometheus/client_golang v1.11.0 15 github.com/prometheus/client_golang v1.11.0
14 github.com/stretchr/testify v1.7.0 16 github.com/stretchr/testify v1.8.1
15 gopkg.in/square/go-jose.v2 v2.5.1 17 gopkg.in/square/go-jose.v2 v2.5.1
16) 18)
17 19
@@ -72,5 +74,5 @@ require (
72 google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 // indirect 74 google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 // indirect
73 google.golang.org/grpc v1.41.0 // indirect 75 google.golang.org/grpc v1.41.0 // indirect
74 google.golang.org/protobuf v1.26.0 // indirect 76 google.golang.org/protobuf v1.26.0 // indirect
75 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 77 gopkg.in/yaml.v3 v3.0.1 // indirect
76) 78)
diff --git a/echo/go.sum b/echo/go.sum
index 0c48b3b..fe3ba40 100644
--- a/echo/go.sum
+++ b/echo/go.sum
@@ -30,8 +30,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
30cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 30cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
31cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 31cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
32cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 32cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
33code.crute.us/mcrute/golib v0.4.2 h1:WeZyBMRFOiIkdNhsXx3kMgRGDUdUshzHS/J4OIPThlY=
34code.crute.us/mcrute/golib v0.4.2/go.mod h1:dukLPhs1H8dxtkhXtpJZYo/bMzefLRbdRj9Tj67wdaQ=
35code.crute.us/mcrute/golib/clients/netbox v0.1.0 h1:7ae676WtINm2oSLoUw1ERIZ2ndLD5gi7cvv2iZZd1XI= 33code.crute.us/mcrute/golib/clients/netbox v0.1.0 h1:7ae676WtINm2oSLoUw1ERIZ2ndLD5gi7cvv2iZZd1XI=
36code.crute.us/mcrute/golib/clients/netbox v0.1.0/go.mod h1:csRsnmAwenAz8Pbo7CcQTWzn6uaXadELIdB81JxsacY= 34code.crute.us/mcrute/golib/clients/netbox v0.1.0/go.mod h1:csRsnmAwenAz8Pbo7CcQTWzn6uaXadELIdB81JxsacY=
37code.crute.us/mcrute/golib/secrets v0.1.0 h1:22W0rLhE5jvIQlsUDQt1soGBEoBn4rl4a883f1yBybI= 35code.crute.us/mcrute/golib/secrets v0.1.0 h1:22W0rLhE5jvIQlsUDQt1soGBEoBn4rl4a883f1yBybI=
@@ -76,8 +74,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
76github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 74github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
77github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 75github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
78github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 76github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
79github.com/elnormous/contenttype v1.0.0 h1:cTLou7K7uQMsPEmRiTJosAznsPcYuoBmXMrFAf86t2A= 77github.com/elnormous/contenttype v1.0.3 h1:5DrD4LGO3ohab+jPplwE/LlY9JqmkYdssz4Zu7xl8Cs=
80github.com/elnormous/contenttype v1.0.0/go.mod h1:ngVcyGGU8pnn4QJ5sL4StrNgc/wmXZXy5IQSBuHOFPg= 78github.com/elnormous/contenttype v1.0.3/go.mod h1:ngVcyGGU8pnn4QJ5sL4StrNgc/wmXZXy5IQSBuHOFPg=
81github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 79github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
82github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 80github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
83github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 81github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -334,14 +332,19 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
334github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 332github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
335github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 333github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
336github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 334github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
337github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
338github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 335github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
336github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
337github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
338github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
339github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 339github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
340github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 340github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
341github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 341github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
342github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 342github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
343github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
344github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 343github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
344github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
345github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
346github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
347github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
345github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= 348github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
346github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 349github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
347github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 350github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
@@ -653,8 +656,9 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
653gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 656gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
654gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 657gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
655gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 658gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
656gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
657gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 659gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
660gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
661gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
658honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 662honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
659honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 663honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
660honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 664honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=