├── .env.example ├── common ├── middleware │ ├── config.go │ ├── zapdriver.go │ └── auth.go ├── response │ └── response.go ├── helpers │ └── response.go ├── database │ ├── testconfig.go │ ├── context.go │ ├── migrations_test.go │ ├── migrations.go │ └── postgres.go └── logging │ └── zapDriver.go ├── model └── user.go ├── service ├── config.go ├── panic.go ├── status.go ├── routes.go └── user.go ├── .gitignore ├── README.md ├── repository └── user.go ├── handler.go ├── docs ├── swagger.yaml ├── swagger.json └── docs.go ├── main.go ├── go.mod └── go.sum /.env.example: -------------------------------------------------------------------------------- 1 | ENV="" 2 | SERVICENAME="" 3 | SERVICEPORT="" 4 | VERSION="" -------------------------------------------------------------------------------- /common/middleware/config.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | type MiddlewareConfig struct { 4 | Auth AuthMiddlewareConfig 5 | } 6 | -------------------------------------------------------------------------------- /model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "github.com/gofrs/uuid" 5 | ) 6 | 7 | type User struct { 8 | ID uuid.UUID `json:"id"` 9 | FirstName string `json:"first_name"` 10 | LastName string `json:"last_name"` 11 | } 12 | -------------------------------------------------------------------------------- /common/response/response.go: -------------------------------------------------------------------------------- 1 | package response 2 | 3 | type NoContent struct { 4 | } 5 | 6 | type StatusResponse struct { 7 | Status string `json:"status"` 8 | } 9 | 10 | type ErrorResponse struct { 11 | Code int `json:"code"` 12 | Cause string `json:"cause"` 13 | } 14 | -------------------------------------------------------------------------------- /common/helpers/response.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | 6 | "golang-program-structure/common/response" 7 | ) 8 | 9 | func RespondWithError(c *gin.Context, code int, cause string) { 10 | c.JSON(code, response.ErrorResponse{ 11 | Code: code, 12 | Cause: cause, 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /service/config.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | 6 | "golang-program-structure/common/middleware" 7 | ) 8 | 9 | type Config struct { 10 | Env string `required:"true"` 11 | ServiceName string `required:"true"` 12 | ServicePort string `required:"true"` 13 | Version string `required:"true"` 14 | 15 | Mw middleware.MiddlewareConfig `required:"true"` 16 | 17 | Logger *zap.SugaredLogger `ignored:"true"` 18 | } 19 | -------------------------------------------------------------------------------- /common/database/testconfig.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "log" 5 | 6 | "github.com/joho/godotenv" 7 | "github.com/kelseyhightower/envconfig" 8 | ) 9 | 10 | func TestDbConfigFromEnv() DbConfig { 11 | err := godotenv.Load() 12 | if err != nil { 13 | log.Fatal(err.Error()) 14 | } 15 | 16 | var dbConfig DbConfig 17 | err = envconfig.Process("test_db", &dbConfig) 18 | if err != nil { 19 | log.Fatal(err.Error()) 20 | } 21 | 22 | return dbConfig 23 | } 24 | -------------------------------------------------------------------------------- /service/panic.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | 8 | "golang-program-structure/common/response" 9 | ) 10 | 11 | func (config *Config) PanicRecovery(c *gin.Context, recovered interface{}) { 12 | if err, ok := recovered.(string); ok { 13 | config.Logger.Error(err) 14 | c.JSON(http.StatusInternalServerError, response.ErrorResponse{Code: http.StatusInternalServerError, Cause: "Something went wrong"}) 15 | return 16 | } 17 | c.AbortWithStatus(http.StatusInternalServerError) 18 | } 19 | -------------------------------------------------------------------------------- /service/status.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/gin-gonic/gin" 7 | 8 | "golang-program-structure/common/response" 9 | ) 10 | 11 | // Status godoc 12 | // @Summary Status 13 | // @Description service status 14 | // @Tags system 15 | // @Produce json 16 | // @Success 200 {object} response.StatusResponse 17 | // @Failure 500 {object} response.ErrorResponse 18 | // @Router /v2/products/status [get] 19 | func (config *Config) Status(c *gin.Context) { 20 | c.JSON(http.StatusOK, response.StatusResponse{Status: "ok"}) 21 | } 22 | -------------------------------------------------------------------------------- /common/database/context.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "context" 5 | "time" 6 | ) 7 | 8 | const ( 9 | DefaultContextSeconds = 60 10 | ) 11 | 12 | func DefaultTimeoutContext() (context.Context, context.CancelFunc) { 13 | ctx, cancel := context.WithTimeout(context.Background(), DefaultContextSeconds*time.Second) 14 | return ctx, cancel 15 | } 16 | 17 | func CustomTimeoutContext(seconds int) (context.Context, context.CancelFunc) { 18 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(seconds)*time.Second) 19 | return ctx, cancel 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Test reports 12 | test-results/ 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | target/ 19 | vendor/ 20 | 21 | # Static resources for self hosting swagger docs 22 | statik 23 | **/swaggerui/swagger.json 24 | 25 | # IDEs 26 | .idea 27 | *.iml 28 | 29 | # Env files 30 | .env 31 | 32 | # air build 33 | **/air-tmp/ 34 | .air.conf 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang-Program-Structure 2 | This is a Project structure for developers to kick-start their journey of developing golang project. 3 | 4 | ## 🙇 Application Requirement 5 | 6 | 1. Install Go version - 1.19.2 via 7 | * https://www.digitalocean.com/community/tutorial_collections/how-to-install-go OR https://golang.org/dl 8 | 9 | 2. Once installed, Please check via below command 10 | ```bash 11 | go version 12 | ``` 13 | 14 | ## 🛠️ Start the application locally 15 | 1. Clone the repository 16 | 17 | 2. Create an .env file at root directory of project and copy the keys from .env.example file and update its values 18 | 19 | 3. Run `go get .` to install all the required dependencies 20 | 21 | 4. From go-program-structure directory, open a terminal and run 22 | ```bash 23 | go run . 24 | ``` 25 | 26 | 5. If any error comes related to any dependency, then install dependency individually as like below command 27 | ```bash 28 | go get 29 | ``` 30 | 31 | ## Run Swagger 32 | - Swagger doc URL - http://xxxxxxxxxx:PORT/vVERSION/SERVICENAME/docs 33 | 34 | 🌟 You are all set! 35 | -------------------------------------------------------------------------------- /repository/user.go: -------------------------------------------------------------------------------- 1 | package repository 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/gofrs/uuid" 7 | "github.com/jackc/pgx/v4" 8 | 9 | "golang-program-structure/common/database" 10 | ) 11 | 12 | type GetUserResponse struct { 13 | ID uuid.UUID `json:"id"` 14 | FirstName string `json:"first_name"` 15 | LastName string `json:"last_name"` 16 | } 17 | 18 | func GetUserById(ctx context.Context, userId *uuid.UUID) (GetUserResponse, error) { 19 | var user GetUserResponse 20 | 21 | p, err := database.GetConnectionPool() 22 | if err != nil { 23 | return user, err 24 | } 25 | 26 | c, err := p.Acquire(ctx) 27 | if err != nil { 28 | return user, err 29 | } 30 | defer c.Release() 31 | 32 | tx, err := c.BeginTx(ctx, pgx.TxOptions{}) 33 | if err != nil { 34 | return user, err 35 | } 36 | 37 | rows, err := tx.Query(ctx, ` 38 | SELECT * 39 | FROM users 40 | WHERE user_id=$1 41 | `, userId) 42 | if err != nil { 43 | return user, err 44 | } 45 | 46 | err = rows.Scan(&user) 47 | if err != nil { 48 | tx.Rollback(ctx) 49 | return user, err 50 | } 51 | 52 | return user, nil 53 | } 54 | -------------------------------------------------------------------------------- /common/middleware/zapdriver.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/blendle/zapdriver" 8 | "github.com/gin-gonic/gin" 9 | "go.uber.org/zap" 10 | 11 | "golang-program-structure/common/logging" 12 | ) 13 | 14 | type RequestLogger struct { 15 | logger *zap.SugaredLogger 16 | } 17 | 18 | // The request logger takes the preconfigured logger used by the app logging 19 | func NewRequestLogger(logger *zap.SugaredLogger) *RequestLogger { 20 | if logger == nil { 21 | logger = zap.NewNop().Sugar() 22 | } 23 | 24 | return &RequestLogger{ 25 | logger, 26 | } 27 | } 28 | 29 | func (requestLogger *RequestLogger) Middleware(c *gin.Context) { 30 | start := time.Now() 31 | c.Next() 32 | 33 | sdReq := zapdriver.NewHTTP(c.Request, nil) 34 | 35 | sdReq.Status = c.Writer.Status() 36 | sdReq.Latency = fmt.Sprintf("%fs", time.Since(start).Seconds()) 37 | 38 | l := requestLogger.logger 39 | if ctxRqId, ok := c.Value(logging.RequestIDKey).(string); ok { 40 | l = requestLogger.logger.With(zap.String(logging.LogRequestIDKey, ctxRqId)) 41 | } 42 | l.Infow("Request ", zapdriver.HTTP(sdReq)) 43 | } 44 | -------------------------------------------------------------------------------- /service/routes.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | swaggerFiles "github.com/swaggo/files" 9 | ginSwagger "github.com/swaggo/gin-swagger" 10 | 11 | "golang-program-structure/common/middleware" 12 | ) 13 | 14 | func AddRoutes(r *gin.Engine, config *Config) { 15 | requestAuth := middleware.NewRequestAuth(config.Logger) 16 | 17 | userGroup := r.Group(fmt.Sprintf("/v%s", config.Version)) 18 | userGroup.Use(requestAuth.Middleware) 19 | userGroup.GET("/user", config.GetUser) 20 | r.GET("/users", func(c *gin.Context) { 21 | c.JSON(200, "Success") 22 | }) 23 | } 24 | 25 | func SetupDefaultEndpoints(r *gin.Engine, config *Config) { 26 | r.GET("/", func(c *gin.Context) { 27 | htmlString := "Welcome to Golang-Program-Structure!" 28 | c.Writer.WriteHeader(http.StatusOK) 29 | _, err := c.Writer.Write([]byte(htmlString)) 30 | if err != nil { 31 | return 32 | } 33 | }) 34 | r.GET("/ping", func(c *gin.Context) { 35 | var msg string 36 | if config.Env == "production" { 37 | msg = fmt.Sprintf("Pong! I am %s. Version is %s.", config.ServiceName, config.Version) 38 | } else { 39 | msg = "pong" 40 | } 41 | c.JSON(200, gin.H{"message": msg}) 42 | }) 43 | if config.Env == "development" || config.Env == "staging" { 44 | r.GET("/docs/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/logging/zapDriver.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | import ( 4 | "github.com/blendle/zapdriver" 5 | "github.com/gin-gonic/gin" 6 | "go.uber.org/zap" 7 | ) 8 | 9 | const ( 10 | RequestIDKey = "X-Request-ID" 11 | LogRequestIDKey = "req-id" 12 | ) 13 | 14 | // See: https://github.com/evry/go-negroni-zap-middleware 15 | 16 | func GetLogger() *zap.SugaredLogger { 17 | // The sugared logger allows untyped arguments, similar to "fmt.Printf" 18 | return zap.S() 19 | } 20 | 21 | func GetRequestLogger(c *gin.Context) *zap.SugaredLogger { 22 | // The sugared logger allows untyped arguments, similar to "fmt.Printf" 23 | l := zap.S() 24 | if c != nil { 25 | if ctxRqId, ok := c.Value(RequestIDKey).(string); ok { 26 | l = l.With(zap.String(LogRequestIDKey, ctxRqId)) 27 | } 28 | } 29 | return l 30 | } 31 | 32 | func SetupLogger(environment string) { 33 | // By default, use the kubernetes specific production StackDriver logger 34 | logger, err := zapdriver.NewProduction() 35 | 36 | // In local mode, use the console logger 37 | if environment == "local" { 38 | logger, err = zap.NewDevelopment() 39 | } 40 | // In test mode, don't output warnings 41 | if environment == "test" { 42 | testConfig := zap.NewDevelopmentConfig() 43 | testConfig.Level = zap.NewAtomicLevelAt(zap.ErrorLevel) 44 | logger, err = testConfig.Build() 45 | } 46 | if err != nil { 47 | panic(err) 48 | } 49 | 50 | // Replace the global Zap logger with the logger we just configured 51 | zap.ReplaceGlobals(logger) 52 | 53 | GetLogger().Info("Logger configured") 54 | } 55 | -------------------------------------------------------------------------------- /service/user.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "context" 5 | "net/http" 6 | 7 | "github.com/gin-gonic/gin" 8 | "github.com/gofrs/uuid" 9 | "github.com/opencontainers/runc/libcontainer/utils" 10 | 11 | "golang-program-structure/common/helpers" 12 | "golang-program-structure/repository" 13 | ) 14 | 15 | // GetUser godoc 16 | // @Summary Get a user 17 | // @Description get user by user id 18 | // @Tags user 19 | // @Param userId path string true "User ID" 20 | // @Accept json 21 | // @Produce json 22 | // @Success 200 {object} GetUserResponse 23 | // @Failure 400 {object} response.ErrorResponse 24 | // @Failure 404 {object} response.ErrorResponse 25 | // @Failure 500 {object} response.ErrorResponse 26 | // @Router /user [get] 27 | func (config *Config) GetUser(c *gin.Context) { 28 | 29 | userId, err := uuid.FromString(c.Param("userId")) 30 | if err != nil { 31 | helpers.RespondWithError(c, http.StatusBadRequest, "invalid user id") 32 | return 33 | } 34 | 35 | user, err := repository.GetUserById(context.Background(), &userId) 36 | if err != nil { 37 | config.Logger.Errorf("Error while searching: %s", err) 38 | helpers.RespondWithError(c, http.StatusInternalServerError, "internal server error") 39 | return 40 | } 41 | if user.ID.IsNil() { 42 | helpers.RespondWithError(c, http.StatusNotFound, "user not found") 43 | return 44 | } 45 | 46 | err = utils.WriteJSON(c.Writer, c) 47 | if err != nil { 48 | helpers.RespondWithError(c, http.StatusInternalServerError, "internal server error") 49 | return 50 | } 51 | 52 | c.JSON(http.StatusOK, user) 53 | } 54 | -------------------------------------------------------------------------------- /common/database/migrations_test.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "sort" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestMigrations_Sort(t *testing.T) { 11 | migrations := Migrations{ 12 | {Path: "/foo/bar/baz/V20__create_things.sql"}, 13 | {Path: "/foo/bar/baz/V5__create_things.sql"}, 14 | {Path: "/foo/bar/baz/V123__create_things.sql"}, 15 | } 16 | 17 | sort.Sort(migrations) 18 | 19 | assert.Equal(t, 5, migrations[0].Version()) 20 | assert.Equal(t, 20, migrations[1].Version()) 21 | assert.Equal(t, 123, migrations[2].Version()) 22 | } 23 | 24 | func TestMigration_Filename(t *testing.T) { 25 | m := Migration{Path: "/foo/bar/baz/V1__create_things.sql"} 26 | assert.Equal(t, "V1__create_things.sql", m.Filename()) 27 | } 28 | 29 | func TestMigration_Name(t *testing.T) { 30 | m := Migration{Path: "/foo/bar/baz/V1__create_things.sql"} 31 | assert.Equal(t, "create_things", m.Name()) 32 | } 33 | 34 | func TestMigration_SQL(t *testing.T) { 35 | sql := "CREATE TABLE things;" 36 | m := Migration{Data: []byte(sql)} 37 | assert.Equal(t, sql, m.SQL()) 38 | } 39 | 40 | func TestMigration_Version(t *testing.T) { 41 | tests := []struct { 42 | expected int 43 | path string 44 | }{ 45 | {-1, "/foo/bar/baz/no_number.sql"}, 46 | {1, "/foo/bar/baz/V1__create_things.sql"}, 47 | {10, "/foo/bar/baz/V10__create_things.sql"}, 48 | {123, "/foo/bar/baz/V123__create_things.sql"}, 49 | } 50 | 51 | for _, tt := range tests { 52 | t.Run(tt.path, func(t *testing.T) { 53 | migration := &Migration{Path: tt.path} 54 | assert.Equal(t, tt.expected, migration.Version()) 55 | }) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/gin-contrib/cors" 8 | "github.com/gin-gonic/gin" 9 | "github.com/mvrilo/go-redoc" 10 | ginredoc "github.com/mvrilo/go-redoc/gin" 11 | 12 | "golang-program-structure/common/middleware" 13 | "golang-program-structure/service" 14 | ) 15 | 16 | func NewHandler(config *service.Config) *gin.Engine { 17 | h := gin.New() 18 | 19 | // Header preservation during redirect differs between Google and Apple 20 | // To be safe, do no automatic redirects 21 | h.RedirectTrailingSlash = false 22 | h.RedirectFixedPath = false 23 | 24 | // The status route is open 25 | h.GET("/status", config.Status) 26 | 27 | // Add a CORS middleware handler 28 | corsConfig := cors.DefaultConfig() 29 | corsConfig.AllowAllOrigins = true 30 | h.Use(cors.New(corsConfig)) 31 | 32 | // Add the fallback handler to catch any panic and return a 500 to the client 33 | h.Use(gin.CustomRecovery(config.PanicRecovery)) 34 | 35 | // Add the request logging middleware handler to all service routes 36 | requestLogger := middleware.NewRequestLogger(config.Logger) 37 | h.Use(requestLogger.Middleware) 38 | 39 | // Setup default routes 40 | service.SetupDefaultEndpoints(h, config) 41 | // Setup custom routes 42 | service.AddRoutes(h, config) 43 | 44 | // Add the handler to serve the redoc 45 | specFile := "./docs/swagger.json" 46 | if _, err := os.Stat(specFile); err == nil { 47 | docs := redoc.Redoc{ 48 | Title: "Docs", 49 | Description: "Documentation", 50 | SpecFile: "./docs/swagger.json", 51 | SpecPath: fmt.Sprintf("/v%s/%s/docs/openapi.json", config.Version, config.ServiceName), 52 | DocsPath: fmt.Sprintf("/v%s/%s/docs", config.Version, config.ServiceName), 53 | } 54 | h.Use(ginredoc.New(docs)) 55 | } else { 56 | config.Logger.Warnf("Swagger file not found at %s, skipping redoc init", specFile) 57 | } 58 | 59 | return h 60 | } 61 | -------------------------------------------------------------------------------- /common/middleware/auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | 7 | "github.com/gin-gonic/gin" 8 | "github.com/gofrs/uuid" 9 | "go.uber.org/zap" 10 | ) 11 | 12 | const bearerPrefix = "Bearer " 13 | 14 | type UserTokenData struct { 15 | Id uuid.UUID `json:"id" bson:"id"` 16 | Email string `json:"email" bson:"email"` 17 | UserType string `json:"user_type" bson:"user_type"` 18 | Scope string `json:"scope"` 19 | } 20 | 21 | type AdminTokenData struct { 22 | Id uuid.UUID `json:"id" bson:"id"` 23 | Type string `json:"type" bson:"type"` 24 | } 25 | 26 | type AuthMiddlewareConfig struct { 27 | RequestAuth 28 | } 29 | 30 | type RequestAuth struct { 31 | logger *zap.SugaredLogger 32 | } 33 | 34 | func abortAuthenticationFailed(c *gin.Context) { 35 | // Send back the Unauthorized message 36 | c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "cause": "Unauthorized"}) 37 | // Don't go any further down the request chain 38 | c.Abort() 39 | } 40 | 41 | // The request logger takes the preconfigured logger used by the app logging 42 | func NewRequestAuth(logger *zap.SugaredLogger) *RequestAuth { 43 | return &RequestAuth{ 44 | logger, 45 | } 46 | } 47 | 48 | func (ra *RequestAuth) Middleware(c *gin.Context) { 49 | 50 | // check if the user is authenticated 51 | authPassed := ra.BearerAuth(c) 52 | 53 | // not authenticated, no access 54 | if !authPassed { 55 | abortAuthenticationFailed(c) 56 | return 57 | } 58 | c.Next() 59 | } 60 | 61 | func (ra *RequestAuth) BearerAuth(c *gin.Context) bool { 62 | 63 | authHeaderValue := c.Request.Header.Get("Authorization") 64 | 65 | if !strings.HasPrefix(authHeaderValue, bearerPrefix) { 66 | ra.logger.Errorf("No bearer token found in Authorization header") 67 | return false 68 | } 69 | 70 | token := strings.TrimPrefix(authHeaderValue, bearerPrefix) 71 | if len(token) == 0 { 72 | ra.logger.Error("No bearer token found in Authorization header") 73 | return false 74 | } 75 | 76 | return true 77 | } 78 | -------------------------------------------------------------------------------- /docs/swagger.yaml: -------------------------------------------------------------------------------- 1 | basePath: / 2 | definitions: 3 | response.ErrorResponse: 4 | properties: 5 | cause: 6 | type: string 7 | code: 8 | type: integer 9 | type: object 10 | response.StatusResponse: 11 | properties: 12 | status: 13 | type: string 14 | type: object 15 | info: 16 | contact: 17 | name: Golang-Program-Structure Support 18 | url: http://www.mindinventory.com 19 | description: Golang-Program-Structure 20 | license: 21 | name: Apache 2.0 22 | url: http://www.apache.org/licenses/LICENSE-2.0.html 23 | title: Golang-Program-Structure 24 | version: "1.0" 25 | paths: 26 | /v2/golang/user: 27 | get: 28 | consumes: 29 | - application/json 30 | description: get user by user id 31 | parameters: 32 | - description: User ID 33 | in: path 34 | name: userId 35 | required: true 36 | type: string 37 | produces: 38 | - application/json 39 | responses: 40 | "200": 41 | description: OK 42 | schema: 43 | $ref: '#/definitions/response.ErrorResponse' 44 | "400": 45 | description: Bad Request 46 | schema: 47 | $ref: '#/definitions/response.ErrorResponse' 48 | "404": 49 | description: Not Found 50 | schema: 51 | $ref: '#/definitions/response.ErrorResponse' 52 | "500": 53 | description: Internal Server Error 54 | schema: 55 | $ref: '#/definitions/response.ErrorResponse' 56 | summary: Get a user 57 | tags: 58 | - user 59 | /v2/products/status: 60 | get: 61 | description: service status 62 | produces: 63 | - application/json 64 | responses: 65 | "200": 66 | description: OK 67 | schema: 68 | $ref: '#/definitions/response.StatusResponse' 69 | "500": 70 | description: Internal Server Error 71 | schema: 72 | $ref: '#/definitions/response.ErrorResponse' 73 | summary: Status 74 | tags: 75 | - system 76 | schemes: 77 | - http 78 | swagger: "2.0" 79 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "sort" 8 | 9 | "github.com/gin-gonic/gin" 10 | "github.com/joho/godotenv" 11 | "github.com/kelseyhightower/envconfig" 12 | 13 | "golang.org/x/net/http2" 14 | "golang.org/x/net/http2/h2c" 15 | 16 | "golang-program-structure/common/logging" 17 | _ "golang-program-structure/docs" 18 | "golang-program-structure/service" 19 | ) 20 | 21 | /* 22 | @title Golang-Program-Structure 23 | @version 1.0 24 | @description Golang-Program-Structure 25 | @contact.name Golang-Program-Structure Support 26 | @contact.url http://www.mindinventory.com 27 | @license.name Apache 2.0 28 | @license.url http://www.apache.org/licenses/LICENSE-2.0.html 29 | @BasePath / 30 | @schemes http 31 | */ 32 | func main() { 33 | // Load the environment vars from a .env file if present 34 | err := godotenv.Load() 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | 39 | // Output the environment, sorted by var, for debug purposes 40 | var envVars map[string]string 41 | envVars, _ = godotenv.Read() 42 | keys := make([]string, 0, len(envVars)) 43 | for key := range envVars { 44 | keys = append(keys, key) 45 | } 46 | sort.Strings(keys) 47 | 48 | // Load the config struct with values from the environment without any prefix (i.e. "") 49 | var config service.Config 50 | err = envconfig.Process("", &config) 51 | if err != nil { 52 | log.Fatal(err) 53 | } 54 | 55 | // Set up the logger and attach to the config struct 56 | logging.SetupLogger(config.Env) 57 | logger := logging.GetLogger() 58 | config.Logger = logger 59 | 60 | // Output the config for debugging 61 | logger.Infof("%+v\n", config) 62 | 63 | // Set the router/handler environment level and initialize 64 | mode := gin.ReleaseMode 65 | if config.Env == "local" { 66 | mode = gin.DebugMode 67 | } 68 | gin.SetMode(mode) 69 | 70 | // Service HTTP/2 requests using unencrypted method, H2C 71 | address := fmt.Sprintf(":%v", config.ServicePort) 72 | h := NewHandler(&config) 73 | 74 | server := &http.Server{ 75 | Addr: address, 76 | Handler: h2c.NewHandler(h, &http2.Server{}), 77 | } 78 | 79 | logger.Infof("Listening on %s", address) 80 | logger.Fatal(server.ListenAndServe()) 81 | } 82 | -------------------------------------------------------------------------------- /common/database/migrations.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "io/fs" 5 | "os" 6 | "path/filepath" 7 | "regexp" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | var filenameRegexp = regexp.MustCompile(`V(\d+)__(.*).sql$`) 13 | 14 | // Migration is a Flyway migration file read from disk. 15 | type Migration struct { 16 | Path string 17 | Data []byte 18 | } 19 | 20 | // Migrations is a sortable collection of migrations. 21 | type Migrations []*Migration 22 | 23 | func (s Migrations) Len() int { return len(s) } 24 | func (s Migrations) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 25 | func (s Migrations) Less(i, j int) bool { 26 | return s[i].Version() < s[j].Version() 27 | } 28 | 29 | // Filename is the base name of the migration path with the directory removed. 30 | func (m *Migration) Filename() string { 31 | return filepath.Base(m.Path) 32 | } 33 | 34 | // Name is the name of the migration. 35 | func (m *Migration) Name() string { 36 | matches := filenameRegexp.FindStringSubmatch(m.Filename()) 37 | 38 | if len(matches) < 3 { 39 | return "" 40 | } 41 | return matches[2] 42 | } 43 | 44 | // Version is the sortable number of the migration. 45 | func (m *Migration) Version() int { 46 | name := m.Filename() 47 | 48 | matches := filenameRegexp.FindStringSubmatch(name) 49 | 50 | if len(matches) < 3 { 51 | return -1 52 | } 53 | 54 | i, err := strconv.Atoi(matches[1]) 55 | if err != nil { 56 | return -1 57 | } 58 | 59 | return i 60 | } 61 | 62 | // SQL returns the string SQL for passing to (*sql.DB).Exec(). 63 | func (m *Migration) SQL() string { 64 | return string(m.Data) 65 | } 66 | 67 | func LoadMigrations(path string) (Migrations, error) { 68 | var migrations []*Migration 69 | 70 | err := filepath.Walk(path, func(path string, info fs.FileInfo, err error) error { 71 | if err != nil { 72 | return err 73 | } 74 | 75 | if info.IsDir() { 76 | return nil 77 | } 78 | 79 | if strings.HasPrefix(info.Name(), ".") { 80 | return nil 81 | } 82 | 83 | b, err := os.ReadFile(path) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | migrations = append(migrations, &Migration{ 89 | Path: path, 90 | Data: b, 91 | }) 92 | 93 | return nil 94 | }) 95 | 96 | return migrations, err 97 | } 98 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module golang-program-structure 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/avast/retry-go/v3 v3.1.1 7 | github.com/blendle/zapdriver v1.3.1 8 | github.com/gin-contrib/cors v1.4.0 9 | github.com/gin-gonic/gin v1.9.0 10 | github.com/gofrs/uuid v4.4.0+incompatible 11 | github.com/jackc/pgx/v4 v4.18.1 12 | github.com/joho/godotenv v1.5.1 13 | github.com/kelseyhightower/envconfig v1.4.0 14 | github.com/mvrilo/go-redoc v0.1.2 15 | github.com/opencontainers/runc v1.1.6 16 | github.com/stretchr/testify v1.8.2 17 | github.com/swaggo/swag v1.16.1 18 | go.uber.org/zap v1.24.0 19 | golang.org/x/net v0.9.0 20 | ) 21 | 22 | require github.com/swaggo/files v1.0.1 23 | 24 | require ( 25 | github.com/bytedance/sonic v1.8.7 // indirect 26 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 27 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 28 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 29 | golang.org/x/arch v0.3.0 // indirect 30 | ) 31 | 32 | require ( 33 | github.com/KyleBanks/depth v1.2.1 // indirect 34 | github.com/cyphar/filepath-securejoin v0.2.3 // indirect 35 | github.com/davecgh/go-spew v1.1.1 // indirect 36 | github.com/gin-contrib/sse v0.1.0 // indirect 37 | github.com/go-openapi/jsonpointer v0.19.6 // indirect 38 | github.com/go-openapi/jsonreference v0.20.2 // indirect 39 | github.com/go-openapi/spec v0.20.9 // indirect 40 | github.com/go-openapi/swag v0.22.3 // indirect 41 | github.com/go-playground/locales v0.14.1 // indirect 42 | github.com/go-playground/universal-translator v0.18.1 // indirect 43 | github.com/go-playground/validator/v10 v10.12.0 // indirect 44 | github.com/goccy/go-json v0.10.2 // indirect 45 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 46 | github.com/jackc/pgconn v1.14.0 // indirect 47 | github.com/jackc/pgio v1.0.0 // indirect 48 | github.com/jackc/pgpassfile v1.0.0 // indirect 49 | github.com/jackc/pgproto3/v2 v2.3.2 // indirect 50 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 51 | github.com/jackc/pgtype v1.14.0 // indirect 52 | github.com/jackc/puddle v1.3.0 // indirect 53 | github.com/josharian/intern v1.0.0 // indirect 54 | github.com/json-iterator/go v1.1.12 // indirect 55 | github.com/leodido/go-urn v1.2.3 // indirect 56 | github.com/mailru/easyjson v0.7.7 // indirect 57 | github.com/mattn/go-isatty v0.0.18 // indirect 58 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 59 | github.com/modern-go/reflect2 v1.0.2 // indirect 60 | github.com/pelletier/go-toml/v2 v2.0.7 // indirect 61 | github.com/pmezard/go-difflib v1.0.0 // indirect 62 | github.com/swaggo/gin-swagger v1.6.0 63 | github.com/ugorji/go/codec v1.2.11 // indirect 64 | go.uber.org/atomic v1.10.0 // indirect 65 | go.uber.org/multierr v1.11.0 // indirect 66 | golang.org/x/crypto v0.8.0 // indirect 67 | golang.org/x/sys v0.7.0 // indirect 68 | golang.org/x/text v0.9.0 // indirect 69 | golang.org/x/tools v0.8.0 // indirect 70 | google.golang.org/protobuf v1.30.0 // indirect 71 | gopkg.in/yaml.v3 v3.0.1 // indirect 72 | ) 73 | -------------------------------------------------------------------------------- /docs/swagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemes": [ 3 | "http" 4 | ], 5 | "swagger": "2.0", 6 | "info": { 7 | "description": "Golang-Program-Structure", 8 | "title": "Golang-Program-Structure", 9 | "contact": { 10 | "name": "Golang-Program-Structure Support", 11 | "url": "http://www.mindinventory.com" 12 | }, 13 | "license": { 14 | "name": "Apache 2.0", 15 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 16 | }, 17 | "version": "1.0" 18 | }, 19 | "basePath": "/", 20 | "paths": { 21 | "/v2/golang/user": { 22 | "get": { 23 | "description": "get user by user id", 24 | "consumes": [ 25 | "application/json" 26 | ], 27 | "produces": [ 28 | "application/json" 29 | ], 30 | "tags": [ 31 | "user" 32 | ], 33 | "summary": "Get a user", 34 | "parameters": [ 35 | { 36 | "type": "string", 37 | "description": "User ID", 38 | "name": "userId", 39 | "in": "path", 40 | "required": true 41 | } 42 | ], 43 | "responses": { 44 | "200": { 45 | "description": "OK", 46 | "schema": { 47 | "$ref": "#/definitions/response.ErrorResponse" 48 | } 49 | }, 50 | "400": { 51 | "description": "Bad Request", 52 | "schema": { 53 | "$ref": "#/definitions/response.ErrorResponse" 54 | } 55 | }, 56 | "404": { 57 | "description": "Not Found", 58 | "schema": { 59 | "$ref": "#/definitions/response.ErrorResponse" 60 | } 61 | }, 62 | "500": { 63 | "description": "Internal Server Error", 64 | "schema": { 65 | "$ref": "#/definitions/response.ErrorResponse" 66 | } 67 | } 68 | } 69 | } 70 | }, 71 | "/v2/products/status": { 72 | "get": { 73 | "description": "service status", 74 | "produces": [ 75 | "application/json" 76 | ], 77 | "tags": [ 78 | "system" 79 | ], 80 | "summary": "Status", 81 | "responses": { 82 | "200": { 83 | "description": "OK", 84 | "schema": { 85 | "$ref": "#/definitions/response.StatusResponse" 86 | } 87 | }, 88 | "500": { 89 | "description": "Internal Server Error", 90 | "schema": { 91 | "$ref": "#/definitions/response.ErrorResponse" 92 | } 93 | } 94 | } 95 | } 96 | } 97 | }, 98 | "definitions": { 99 | "response.ErrorResponse": { 100 | "type": "object", 101 | "properties": { 102 | "cause": { 103 | "type": "string" 104 | }, 105 | "code": { 106 | "type": "integer" 107 | } 108 | } 109 | }, 110 | "response.StatusResponse": { 111 | "type": "object", 112 | "properties": { 113 | "status": { 114 | "type": "string" 115 | } 116 | } 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /docs/docs.go: -------------------------------------------------------------------------------- 1 | // Package docs GENERATED BY SWAG; DO NOT EDIT 2 | // This file was generated by swaggo/swag 3 | package docs 4 | 5 | import "github.com/swaggo/swag" 6 | 7 | const docTemplate = `{ 8 | "schemes": {{ marshal .Schemes }}, 9 | "swagger": "2.0", 10 | "info": { 11 | "description": "{{escape .Description}}", 12 | "title": "{{.Title}}", 13 | "contact": { 14 | "name": "Golang-Program-Structure Support", 15 | "url": "http://www.mindinventory.com" 16 | }, 17 | "license": { 18 | "name": "Apache 2.0", 19 | "url": "http://www.apache.org/licenses/LICENSE-2.0.html" 20 | }, 21 | "version": "{{.Version}}" 22 | }, 23 | "host": "{{.Host}}", 24 | "basePath": "{{.BasePath}}", 25 | "paths": { 26 | "/v2/golang/user": { 27 | "get": { 28 | "description": "get user by user id", 29 | "consumes": [ 30 | "application/json" 31 | ], 32 | "produces": [ 33 | "application/json" 34 | ], 35 | "tags": [ 36 | "user" 37 | ], 38 | "summary": "Get a user", 39 | "parameters": [ 40 | { 41 | "type": "string", 42 | "description": "User ID", 43 | "name": "userId", 44 | "in": "path", 45 | "required": true 46 | } 47 | ], 48 | "responses": { 49 | "200": { 50 | "description": "OK", 51 | "schema": { 52 | "$ref": "#/definitions/response.ErrorResponse" 53 | } 54 | }, 55 | "400": { 56 | "description": "Bad Request", 57 | "schema": { 58 | "$ref": "#/definitions/response.ErrorResponse" 59 | } 60 | }, 61 | "404": { 62 | "description": "Not Found", 63 | "schema": { 64 | "$ref": "#/definitions/response.ErrorResponse" 65 | } 66 | }, 67 | "500": { 68 | "description": "Internal Server Error", 69 | "schema": { 70 | "$ref": "#/definitions/response.ErrorResponse" 71 | } 72 | } 73 | } 74 | } 75 | }, 76 | "/v2/products/status": { 77 | "get": { 78 | "description": "service status", 79 | "produces": [ 80 | "application/json" 81 | ], 82 | "tags": [ 83 | "system" 84 | ], 85 | "summary": "Status", 86 | "responses": { 87 | "200": { 88 | "description": "OK", 89 | "schema": { 90 | "$ref": "#/definitions/response.StatusResponse" 91 | } 92 | }, 93 | "500": { 94 | "description": "Internal Server Error", 95 | "schema": { 96 | "$ref": "#/definitions/response.ErrorResponse" 97 | } 98 | } 99 | } 100 | } 101 | } 102 | }, 103 | "definitions": { 104 | "response.ErrorResponse": { 105 | "type": "object", 106 | "properties": { 107 | "cause": { 108 | "type": "string" 109 | }, 110 | "code": { 111 | "type": "integer" 112 | } 113 | } 114 | }, 115 | "response.StatusResponse": { 116 | "type": "object", 117 | "properties": { 118 | "status": { 119 | "type": "string" 120 | } 121 | } 122 | } 123 | } 124 | }` 125 | 126 | // SwaggerInfo holds exported Swagger Info so clients can modify it 127 | var SwaggerInfo = &swag.Spec{ 128 | Version: "1.0", 129 | Host: "", 130 | BasePath: "/", 131 | Schemes: []string{"http"}, 132 | Title: "Golang-Program-Structure", 133 | Description: "Golang-Program-Structure", 134 | InfoInstanceName: "swagger", 135 | SwaggerTemplate: docTemplate, 136 | } 137 | 138 | func init() { 139 | swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) 140 | } 141 | -------------------------------------------------------------------------------- /common/database/postgres.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "sync" 9 | "time" 10 | 11 | "github.com/avast/retry-go/v3" 12 | "github.com/gofrs/uuid" 13 | "github.com/jackc/pgx/v4" 14 | "github.com/jackc/pgx/v4/pgxpool" 15 | ) 16 | 17 | type DbConfig struct { 18 | User string `required:"true" split_words:"true"` 19 | Password string `required:"true" split_words:"true"` 20 | Host string `required:"true" split_words:"true"` 21 | Port int `required:"true" split_words:"true"` 22 | Name string `required:"true" split_words:"true"` 23 | 24 | disableSSL bool 25 | } 26 | 27 | type RowsAndCount struct { 28 | c int 29 | id *uuid.UUID 30 | err error 31 | } 32 | 33 | var ( 34 | pool *pgxpool.Pool 35 | ponce sync.Once 36 | ) 37 | 38 | func (dbConfig *DbConfig) URL() string { 39 | url := fmt.Sprintf( 40 | "postgres://%s:%s@%s:%d/%s", 41 | dbConfig.User, 42 | dbConfig.Password, 43 | dbConfig.Host, 44 | dbConfig.Port, 45 | dbConfig.Name, 46 | ) 47 | 48 | if dbConfig.disableSSL { 49 | url = fmt.Sprintf("%s?sslmode=disable", url) 50 | } 51 | 52 | return url 53 | } 54 | 55 | func getConfig(dbConfig DbConfig) (*pgxpool.Config, error) { 56 | config, err := pgxpool.ParseConfig(dbConfig.URL()) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | config.ConnConfig.LogLevel = pgx.LogLevelDebug 62 | 63 | return config, nil 64 | } 65 | 66 | func resetPool() { 67 | pool = nil 68 | ponce = sync.Once{} 69 | } 70 | 71 | func CreateConnectionPoolWithConnectionLimit(dbConfig DbConfig, maxConnections int) (*pgxpool.Pool, error) { 72 | config, err := getConfig(dbConfig) 73 | if err != nil { 74 | return nil, err 75 | } 76 | config.MaxConns = int32(maxConnections) 77 | return createConnectionPool(config) 78 | } 79 | 80 | func CreateConnectionPool(dbConfig DbConfig) (*pgxpool.Pool, error) { 81 | config, err := getConfig(dbConfig) 82 | if err != nil { 83 | return nil, err 84 | } 85 | // well make our default pool size 10. The pacakge default is 4... ouch! 86 | config.MaxConns = int32(10) 87 | return createConnectionPool(config) 88 | } 89 | 90 | func createConnectionPool(config *pgxpool.Config) (*pgxpool.Pool, error) { 91 | var err error 92 | ponce.Do(func() { 93 | err = retry.Do(func() error { 94 | p, err := pgxpool.ConnectConfig(context.Background(), config) 95 | if err != nil { 96 | return err 97 | } 98 | pool = p 99 | return nil 100 | }, 101 | retry.Delay(1*time.Second)) 102 | if err != nil { 103 | log.Fatal(err.Error()) 104 | } 105 | }) 106 | 107 | return pool, err 108 | } 109 | 110 | func GetConnectionPool() (*pgxpool.Pool, error) { 111 | if pool == nil { 112 | return nil, errors.New("connection Pool has not been created") 113 | } 114 | return pool, nil 115 | } 116 | 117 | func ClosePool() error { 118 | if pool == nil { 119 | return errors.New("connection Pool has not been created") 120 | } 121 | pool.Close() 122 | return nil 123 | } 124 | 125 | func CountRowsAndLastId(ctx context.Context, table string, descending bool, ch chan RowsAndCount) error { 126 | if pool == nil { 127 | return errors.New("connection Pool has not been created") 128 | } 129 | idc := table[:len(table)-1] 130 | 131 | batch := pgx.Batch{} 132 | batch.Queue(fmt.Sprintf("select count(%vid) from assets.%v", idc, table)) 133 | if descending { 134 | batch.Queue(fmt.Sprintf("select %vid from assets.%v order by %vid asc limit 1", idc, table, idc)) 135 | } else { 136 | batch.Queue(fmt.Sprintf("select %vid from assets.%v order by %vid desc limit 1", idc, table, idc)) 137 | } 138 | 139 | con, err := pool.Acquire(ctx) 140 | if err != nil { 141 | ch <- RowsAndCount{c: 0, id: nil, err: err} 142 | return nil 143 | } 144 | defer con.Release() 145 | 146 | br := con.SendBatch(ctx, &batch) 147 | 148 | c := 0 149 | err = br.QueryRow().Scan(&c) 150 | 151 | switch err { 152 | case pgx.ErrNoRows: 153 | ch <- RowsAndCount{c: 0, id: nil, err: nil} 154 | return nil 155 | case nil: 156 | default: 157 | ch <- RowsAndCount{c: 0, id: nil, err: err} 158 | return nil 159 | } 160 | 161 | u := new(uuid.UUID) 162 | err = br.QueryRow().Scan(u) 163 | 164 | switch err { 165 | case pgx.ErrNoRows: 166 | ch <- RowsAndCount{c: 0, id: nil, err: nil} 167 | return nil 168 | case nil: 169 | default: 170 | ch <- RowsAndCount{c: 0, id: nil, err: err} 171 | return nil 172 | } 173 | 174 | ch <- RowsAndCount{c: c, id: u, err: nil} 175 | return nil 176 | } 177 | 178 | func InsertBatch(ctx context.Context, batch *pgx.Batch) error { 179 | return ExecuteBatch(ctx, batch, "inserted", true) 180 | } 181 | 182 | func UpdateBatch(ctx context.Context, batch *pgx.Batch) error { 183 | return ExecuteBatch(ctx, batch, "updated", true) 184 | } 185 | 186 | func DeleteBatch(ctx context.Context, batch *pgx.Batch) error { 187 | return ExecuteBatch(ctx, batch, "deleted", false) 188 | } 189 | 190 | func ExecuteBatch(ctx context.Context, batch *pgx.Batch, action string, verify bool) error { 191 | if pool == nil { 192 | return errors.New("connection Pool has not been created") 193 | } 194 | c, err := pool.Acquire(ctx) 195 | if err != nil { 196 | return err 197 | } 198 | defer c.Release() 199 | 200 | tx, err := c.Begin(ctx) 201 | if err != nil { 202 | return err 203 | } 204 | 205 | br := tx.SendBatch(ctx, batch) 206 | 207 | for i := 0; i < batch.Len(); i++ { 208 | ct, err := br.Exec() 209 | if err != nil { 210 | 211 | if er := tx.Rollback(ctx); er != nil { 212 | } 213 | 214 | return err 215 | } 216 | 217 | if ct.RowsAffected() != 1 { 218 | msg := fmt.Sprintf("no row %v", action) 219 | 220 | if verify { 221 | if err := br.Close(); err != nil { 222 | } 223 | if er := tx.Rollback(ctx); er != nil { 224 | } 225 | 226 | return errors.New(msg) 227 | } 228 | } 229 | } 230 | 231 | if err := br.Close(); err != nil { 232 | } 233 | 234 | if err := tx.Commit(ctx); err != nil { 235 | return err 236 | } 237 | 238 | return nil 239 | } 240 | 241 | // https://www.starkandwayne.com/blog/uuid-primary-keys-in-postgresql/ 242 | // https://wiki.postgresql.org/images/3/35/Pagination_Done_the_PostgreSQL_Way.pdf 243 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= 3 | github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= 4 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 5 | github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 6 | github.com/avast/retry-go/v3 v3.1.1 h1:49Scxf4v8PmiQ/nY0aY3p0hDueqSmc7++cBbtiDGu2g= 7 | github.com/avast/retry-go/v3 v3.1.1/go.mod h1:6cXRK369RpzFL3UQGqIUp9Q7GDrams+KsYWrfNA1/nQ= 8 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 9 | github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= 10 | github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= 11 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 12 | github.com/bytedance/sonic v1.8.7 h1:d3sry5vGgVq/OpgozRUNP6xBsSo0mtNdwliApw+SAMQ= 13 | github.com/bytedance/sonic v1.8.7/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 14 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 15 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 16 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 17 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= 18 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 19 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 20 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 21 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 22 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 23 | github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= 24 | github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= 25 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 26 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 27 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 28 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 29 | github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= 30 | github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= 31 | github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= 32 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 33 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 34 | github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 35 | github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= 36 | github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= 37 | github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= 38 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 39 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 40 | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 41 | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 42 | github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= 43 | github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= 44 | github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= 45 | github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= 46 | github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= 47 | github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= 48 | github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= 49 | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= 50 | github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= 51 | github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= 52 | github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= 53 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 54 | github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 55 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 56 | github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= 57 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 58 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 59 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 60 | github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= 61 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 62 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 63 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 64 | github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= 65 | github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI= 66 | github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA= 67 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 68 | github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 69 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 70 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 71 | github.com/gofiber/adaptor/v2 v2.1.22/go.mod h1:3EMReMfZxfHG0/+I/DHG+h9utIO3a9M59O+V0bYHF8o= 72 | github.com/gofiber/fiber/v2 v2.31.0/go.mod h1:1Ega6O199a3Y7yDGuM9FyXDPYQfv+7/y48wl6WCwUF4= 73 | github.com/gofiber/utils v0.1.2/go.mod h1:pacRFtghAE3UoknMOUiXh2Io/nLWSUHtQCi/3QASsOc= 74 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 75 | github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= 76 | github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 77 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 78 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 79 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 80 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 81 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 82 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 83 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 84 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 85 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 86 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= 87 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 88 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 89 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 90 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 91 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 92 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 93 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 94 | github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q= 95 | github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= 96 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= 97 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 98 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 99 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 100 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= 101 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 102 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 103 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 104 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 105 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 106 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 107 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 108 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 109 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 110 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 111 | github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= 112 | github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 113 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 114 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= 115 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 116 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 117 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 118 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 119 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 120 | github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= 121 | github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 122 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 123 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 124 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 125 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 126 | github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= 127 | github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= 128 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 129 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 130 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 131 | github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= 132 | github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 133 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 134 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 135 | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= 136 | github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= 137 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 138 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 139 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 140 | github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= 141 | github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 142 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 143 | github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 144 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 145 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 146 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 147 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 148 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 149 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 150 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 151 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 152 | github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 153 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 154 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 155 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 156 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 157 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 158 | github.com/labstack/echo/v4 v4.1.17/go.mod h1:Tn2yRQL/UclUalpb5rPdXDevbkJ+lp/2svdyFBg6CHQ= 159 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 160 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 161 | github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= 162 | github.com/leodido/go-urn v1.2.3 h1:6BE2vPT0lqoz3fmOesHZiaiFh7889ssCo2GMvLCfiuA= 163 | github.com/leodido/go-urn v1.2.3/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 164 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 165 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 166 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 167 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 168 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 169 | github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 170 | github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= 171 | github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 172 | github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= 173 | github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 174 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 175 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 176 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 177 | github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 178 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 179 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 180 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 181 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 182 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 183 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 184 | github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= 185 | github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 186 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 187 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 188 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 189 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 190 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 191 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 192 | github.com/mvrilo/go-redoc v0.1.2 h1:qQWTa9YPbE3jcq9XwYRVy0rOUSSskO0cteVyN9tIUYA= 193 | github.com/mvrilo/go-redoc v0.1.2/go.mod h1:GIPJDv4/44PLH8WGb8o5/6xS10hoa4tF6eTUJTd2uTo= 194 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 195 | github.com/opencontainers/runc v1.1.6 h1:XbhB8IfG/EsnhNvZtNdLB0GBw92GYEFvKlhaJk9jUgA= 196 | github.com/opencontainers/runc v1.1.6/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50= 197 | github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= 198 | github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= 199 | github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= 200 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 201 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 202 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 203 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 204 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 205 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 206 | github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 207 | github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= 208 | github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= 209 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 210 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 211 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 212 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 213 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 214 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 215 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 216 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 217 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 218 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 219 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 220 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 221 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 222 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 223 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 224 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 225 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 226 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 227 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 228 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 229 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 230 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 231 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 232 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 233 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 234 | github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= 235 | github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= 236 | github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= 237 | github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= 238 | github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= 239 | github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= 240 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 241 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 242 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 243 | github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= 244 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 245 | github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 246 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 247 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 248 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 249 | github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= 250 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 251 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 252 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 253 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 254 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 255 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 256 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 257 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 258 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 259 | go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= 260 | go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 261 | go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= 262 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 263 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 264 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 265 | go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= 266 | go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= 267 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 268 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 269 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 270 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 271 | go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= 272 | go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= 273 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 274 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= 275 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 276 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 277 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 278 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 279 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 280 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 281 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 282 | golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 283 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 284 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 285 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 286 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 287 | golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 288 | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 289 | golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= 290 | golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= 291 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 292 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 293 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 294 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 295 | golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= 296 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 297 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 298 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 299 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 300 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 301 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 302 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 303 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 304 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 305 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 306 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 307 | golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= 308 | golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= 309 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 310 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 311 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 312 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 313 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 314 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 315 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 316 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 317 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 318 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 319 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 320 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 321 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 322 | golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 323 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 324 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 325 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 326 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 327 | golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 328 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 329 | golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 330 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 331 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 332 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 333 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 334 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 335 | golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= 336 | golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 337 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 338 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 339 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 340 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 341 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 342 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 343 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 344 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 345 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 346 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 347 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 348 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= 349 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 350 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 351 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 352 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 353 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 354 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 355 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 356 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 357 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 358 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 359 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 360 | golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y= 361 | golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= 362 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 363 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 364 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 365 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 366 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 367 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 368 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 369 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 370 | google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 371 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 372 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 373 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 374 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 375 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 376 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 377 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 378 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 379 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 380 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 381 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 382 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 383 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 384 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 385 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 386 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 387 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 388 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 389 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 390 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 391 | --------------------------------------------------------------------------------