├── README.md ├── build-version ├── Makefile ├── main.go └── version.go ├── configmap └── main.go ├── exiting-gracefully ├── app │ └── app.go ├── grpc │ └── server.go ├── http │ └── server.go └── main.go ├── go.mod └── go.sum /README.md: -------------------------------------------------------------------------------- 1 | # golang-best-practices 2 | -------------------------------------------------------------------------------- /build-version/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=$(shell git describe --tags --always) 2 | BRANCH=$(shell git symbolic-ref -q --short HEAD) 3 | REVISION=$(shell git rev-parse --short HEAD) 4 | BUILD_DATE=$(shell date +%FT%T%Z) 5 | 6 | build: 7 | go build -ldflags "-X main.Version=$(VERSION) -X main.Branch=$(BRANCH) -X main.Revision=$(REVISION) -X main.BuildDate=$(BUILD_DATE)" 8 | 9 | all: build 10 | -------------------------------------------------------------------------------- /build-version/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println("version:", Version) 9 | fmt.Println("branch:", Branch) 10 | fmt.Println("revision:", Revision) 11 | fmt.Println("build_date:", BuildDate) 12 | } 13 | -------------------------------------------------------------------------------- /build-version/version.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // go build -ldflags "-X main.Version=x.y.yz" 4 | var ( 5 | // Version is the version of the compiled software. 6 | Version string 7 | // Branch is current branch name the code is built off 8 | Branch string 9 | // Revision is the short commit hash of source tree 10 | Revision string 11 | // BuildDate is the date when the binary was built. 12 | BuildDate string 13 | ) 14 | -------------------------------------------------------------------------------- /configmap/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "strings" 7 | 8 | simplejson "github.com/bitly/go-simplejson" 9 | "github.com/ghodss/yaml" 10 | ) 11 | 12 | type Map struct { 13 | raw *simplejson.Json 14 | } 15 | 16 | func NewMap(data []byte) (*Map, error) { 17 | raw, err := simplejson.NewJson(data) 18 | if err != nil { 19 | return nil, err 20 | } 21 | return &Map{ 22 | raw: raw, 23 | }, nil 24 | } 25 | 26 | func (m *Map) Value(key string) *simplejson.Json { 27 | return m.raw.GetPath(strings.Split(key, ".")...) 28 | } 29 | 30 | func (m *Map) Scan(key string, v interface{}) error { 31 | data, err := m.Value(key).MarshalJSON() 32 | if err != nil { 33 | return err 34 | } 35 | return json.Unmarshal(data, v) 36 | } 37 | 38 | func main() { 39 | yml := ` 40 | test: 41 | settings: 42 | int_key: 100 43 | float_key: 1000.1 44 | string_key: string_value 45 | server: 46 | addr: 127.0.0.1 47 | port: 8000 48 | ` 49 | text, err := yaml.YAMLToJSON([]byte(yml)) 50 | if err != nil { 51 | panic(err) 52 | } 53 | fmt.Println(string(text)) 54 | m, err := NewMap([]byte(text)) 55 | if err != nil { 56 | panic(err) 57 | } 58 | var settings struct { 59 | IntKey int `json:"int_key"` 60 | FloatKey float32 `json:"float_key"` 61 | StringKey string `json:"string_key"` 62 | } 63 | fmt.Println("source:", m) 64 | fmt.Println(m.Scan("test.settings", &settings), settings) 65 | fmt.Println(m.Value("test.settings.int_key")) 66 | fmt.Println(m.Value("test.settings.float_key")) 67 | fmt.Println(m.Value("test.settings.string_key")) 68 | fmt.Println(m.Value("test.server.addr")) 69 | fmt.Println(m.Value("test.server.port")) 70 | } 71 | -------------------------------------------------------------------------------- /exiting-gracefully/app/app.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | "time" 9 | 10 | "github.com/pkg/errors" 11 | ) 12 | 13 | // Hook is a pair of start and stop callbacks. 14 | type Hook struct { 15 | OnStart func(context.Context) error 16 | OnStop func(context.Context) error 17 | } 18 | 19 | // Option is a life cycle option. 20 | type Option func(o *Options) 21 | 22 | // Options is a life cycle options. 23 | type Options struct { 24 | startTimeout time.Duration 25 | stopTimeout time.Duration 26 | exitSignals []os.Signal 27 | } 28 | 29 | // WithStartTimeout with the start timeout. 30 | func WithStartTimeout(timeout time.Duration) Option { 31 | return func(o *Options) { 32 | o.startTimeout = timeout 33 | } 34 | } 35 | 36 | // WithStopTimeout with the stop timeout. 37 | func WithStopTimeout(timeout time.Duration) Option { 38 | return func(o *Options) { 39 | o.stopTimeout = timeout 40 | } 41 | } 42 | 43 | // WithExitSignal with the exit signals. 44 | func WithExitSignal(sigs ...os.Signal) Option { 45 | return func(o *Options) { 46 | o.exitSignals = sigs 47 | } 48 | } 49 | 50 | // App is manage the application component life cycle. 51 | type App struct { 52 | opts Options 53 | hooks []Hook 54 | started int 55 | } 56 | 57 | // New new a application manage. 58 | func New(opts ...Option) *App { 59 | options := Options{ 60 | startTimeout: time.Second * 30, 61 | stopTimeout: time.Second * 30, 62 | exitSignals: []os.Signal{ 63 | syscall.SIGTERM, 64 | syscall.SIGQUIT, 65 | syscall.SIGINT, 66 | }, 67 | } 68 | for _, o := range opts { 69 | o(&options) 70 | } 71 | return &App{opts: options} 72 | } 73 | 74 | // Append register callbacks that are executed on application start and stop. 75 | func (a *App) Append(hook Hook) { 76 | a.hooks = append(a.hooks, hook) 77 | } 78 | 79 | // Run starts the application, blocks on the signals channel, and then gracefully shuts the application down. 80 | func (a *App) Run() error { 81 | startCtx, startCancel := context.WithTimeout(context.Background(), a.opts.startTimeout) 82 | defer startCancel() 83 | if err := a.Start(startCtx); err != nil { 84 | return err 85 | } 86 | 87 | <-a.Signal() 88 | 89 | stopCtx, stopCancel := context.WithTimeout(context.Background(), a.opts.stopTimeout) 90 | defer stopCancel() 91 | return a.Stop(stopCtx) 92 | } 93 | 94 | // Start executes all OnStart hooks registered with the application's Lifecycle. 95 | func (a *App) Start(ctx context.Context) error { 96 | for _, hook := range a.hooks { 97 | if hook.OnStart != nil { 98 | if err := hook.OnStart(ctx); err != nil { 99 | return err 100 | } 101 | } 102 | a.started++ 103 | } 104 | return nil 105 | } 106 | 107 | // Stop gracefully stops the application. 108 | func (a *App) Stop(ctx context.Context) error { 109 | var errs error 110 | for ; a.started > 0; a.started-- { 111 | if hook := a.hooks[a.started-1]; hook.OnStop != nil { 112 | if err := hook.OnStop(ctx); err != nil { 113 | errs = errors.Wrapf(err, "OnStop error: %v", errs) 114 | } 115 | } 116 | } 117 | return errs 118 | } 119 | 120 | // Signal returns a stop channel to wait on exit signals. 121 | func (a *App) Signal() <-chan os.Signal { 122 | sig := make(chan os.Signal, len(a.opts.exitSignals)) 123 | signal.Notify(sig, a.opts.exitSignals...) 124 | return sig 125 | } 126 | -------------------------------------------------------------------------------- /exiting-gracefully/grpc/server.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "net" 7 | 8 | "google.golang.org/grpc" 9 | ) 10 | 11 | // Server is a grpc server wrapped. 12 | type Server struct { 13 | srv *grpc.Server 14 | } 15 | 16 | // NewServer new a gRPC server.. 17 | func NewServer() *Server { 18 | return &Server{srv: grpc.NewServer()} 19 | } 20 | 21 | // Start start the gRPC server. 22 | func (s *Server) Start(ctx context.Context) error { 23 | log.Println("[GRPC] Listening on: :9000") 24 | 25 | lis, err := net.Listen("tcp", ":9000") 26 | if err != nil { 27 | return err 28 | } 29 | go func() { 30 | if err := s.srv.Serve(lis); err != nil { 31 | log.Fatal(err) 32 | } 33 | }() 34 | return nil 35 | } 36 | 37 | // Stop stop the gRPC server. 38 | func (s *Server) Stop(ctx context.Context) error { 39 | log.Println("[GRPC] Stopping") 40 | 41 | s.srv.GracefulStop() 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /exiting-gracefully/http/server.go: -------------------------------------------------------------------------------- 1 | package http 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "log" 7 | "net" 8 | "net/http" 9 | ) 10 | 11 | // Server is a HTTP server. 12 | type Server struct { 13 | srv *http.Server 14 | } 15 | 16 | // NewServer new a HTTP server. 17 | func NewServer() *Server { 18 | mux := http.NewServeMux() 19 | mux.Handle("/", http.HandlerFunc( 20 | func(w http.ResponseWriter, r *http.Request) { 21 | fmt.Fprintf(w, "okay") 22 | }, 23 | )) 24 | srv := &http.Server{ 25 | Addr: ":8000", 26 | Handler: mux, 27 | } 28 | return &Server{srv: srv} 29 | } 30 | 31 | // Start start the HTTP server. 32 | func (s *Server) Start(context.Context) error { 33 | log.Printf("[HTTP] Listening on: %s\n", s.srv.Addr) 34 | 35 | ln, err := net.Listen("tcp", s.srv.Addr) 36 | if err != nil { 37 | return err 38 | } 39 | go func() { 40 | if err := s.srv.Serve(ln); err != http.ErrServerClosed { 41 | log.Fatal(err) 42 | } 43 | }() 44 | return nil 45 | } 46 | 47 | // Stop stop the HTTP server. 48 | func (s *Server) Stop(ctx context.Context) error { 49 | log.Printf("[HTTP] Stopping\n") 50 | 51 | return s.srv.Shutdown(ctx) 52 | } 53 | -------------------------------------------------------------------------------- /exiting-gracefully/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/tonybase/golang-best-practices/exiting-gracefully/app" 7 | "github.com/tonybase/golang-best-practices/exiting-gracefully/grpc" 8 | "github.com/tonybase/golang-best-practices/exiting-gracefully/http" 9 | ) 10 | 11 | func main() { 12 | httpSrv := http.NewServer() 13 | grpcSrv := grpc.NewServer() 14 | 15 | a := app.New() 16 | a.Append(app.Hook{OnStart: httpSrv.Start, OnStop: httpSrv.Stop}) 17 | a.Append(app.Hook{OnStart: grpcSrv.Start, OnStop: grpcSrv.Stop}) 18 | 19 | if err := a.Run(); err != nil { 20 | log.Fatal(err) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tonybase/golang-best-practices 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/bitly/go-simplejson v0.5.0 7 | github.com/ghodss/yaml v1.0.0 8 | github.com/pkg/errors v0.9.1 9 | google.golang.org/grpc v1.34.0 10 | ) 11 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= 4 | github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= 5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 6 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 7 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 10 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 11 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 12 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 13 | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= 14 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 15 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 16 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 17 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 18 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 19 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 20 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 21 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 22 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 23 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 24 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 25 | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= 26 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 27 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 28 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 29 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 30 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 31 | github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= 32 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 33 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 34 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 35 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 36 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 37 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 38 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 39 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 40 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 41 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 42 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 43 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 44 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 45 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 46 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 47 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 48 | golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= 49 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 50 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 51 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 52 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 53 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 54 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 55 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= 56 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 57 | golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= 58 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 59 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 60 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 61 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 62 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 63 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 64 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 65 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 66 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 67 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 68 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 69 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= 70 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 71 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 72 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 73 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 74 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 75 | google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI= 76 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 77 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 78 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 79 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 80 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 81 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 82 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 83 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 84 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 85 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 86 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 87 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 88 | gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= 89 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 90 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 91 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 92 | --------------------------------------------------------------------------------