diff --git a/assignment-2/Dockerfile b/assignment-2/Dockerfile
new file mode 100644
index 0000000..4c63ebc
--- /dev/null
+++ b/assignment-2/Dockerfile
@@ -0,0 +1,13 @@
+FROM golang:1.20 AS builder
+WORKDIR /app
+COPY . .
+
+FROM alpine:3.13
+WORKDIR /app
+COPY --from=builder /app/deploy/hacktiv-assignment-2 .
+COPY --from=builder /app/template /app/template/.
+RUN ls
+EXPOSE 8080
+
+ENV APP_NAME=hacktiv-assignment-2
+CMD ["./hacktiv-assignment-2"]
diff --git a/assignment-2/Makefile b/assignment-2/Makefile
new file mode 100644
index 0000000..ad1430d
--- /dev/null
+++ b/assignment-2/Makefile
@@ -0,0 +1,34 @@
+.PHONY: migration
+migration:
+ migrate create -ext sql -dir db/migrations/$(module) $(name)
+
+.PHONY: migrate
+migrate:
+ migrate -path db/migrations/$(module) -database "postgres://postgresuser:postgrespassword@127.0.0.1:5432/postgres?sslmode=disable&search_path=public" -verbose up
+
+.PHONY: rollback
+rollback:
+ migrate -path db/migrations/$(module) -database "postgres://postgresuser:postgrespassword@127.0.0.1:5432/postgres?sslmode=disable&search_path=public" -verbose down 1
+
+.PHONY: rollback-all
+rollback-all:
+ migrate -path db/migrations/$(module) -database "postgres://postgresuser:postgrespassword@127.0.0.1:5432/postgres?sslmode=disable&search_path=public" -verbose down -all
+
+.PHONY: force-migrate
+force-migrate:
+ migrate -path db/migrations/$(module) -database "postgres://postgresuser:postgrespassword@127.0.0.1:5432/postgres?sslmode=disable&search_path=public" -verbose force $(version)
+
+.PHONY: compile-server
+compile-server:
+ GO111MODULE=on CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o deploy/hacktiv-assignment-2 main.go
+
+.PHONY: docker-build-server
+docker-build-server:
+ docker build --no-cache -t hacktiv-assignment-2:latest -f Dockerfile .
+
+.PHONY: run
+run:
+ docker-compose up
+
+.PHONY: compile-build-run
+compile-build-run: compile-server docker-build-server run
\ No newline at end of file
diff --git a/assignment-2/README.md b/assignment-2/README.md
new file mode 100644
index 0000000..960ff51
--- /dev/null
+++ b/assignment-2/README.md
@@ -0,0 +1,12 @@
+# Assignment 2 Hacktiv
+Simple login-logout page with gorilla session stored on postgres db
+
+# Dependencies
+- [Docker](https://docs.docker.com/engine/install/ubuntu/)
+- [Docker-compose](https://docs.docker.com/compose/install/)
+
+# How To Run
+1. Compile server to generate executable file `make compile-server`
+2. Build docker image `make docker-build-server`
+3. Run docker image `make run`
+4. Alternatively, you can use this shortcut to automatically run 3 above steps `make compile-build-run`
diff --git a/assignment-2/db/migrations/users/20221114032114_create_table_user.down.sql b/assignment-2/db/migrations/users/20221114032114_create_table_user.down.sql
new file mode 100644
index 0000000..1dac82b
--- /dev/null
+++ b/assignment-2/db/migrations/users/20221114032114_create_table_user.down.sql
@@ -0,0 +1,5 @@
+BEGIN;
+
+DROP TABLE users;
+
+COMMIT;
\ No newline at end of file
diff --git a/assignment-2/db/migrations/users/20221114032114_create_table_user.up.sql b/assignment-2/db/migrations/users/20221114032114_create_table_user.up.sql
new file mode 100644
index 0000000..a08b7e3
--- /dev/null
+++ b/assignment-2/db/migrations/users/20221114032114_create_table_user.up.sql
@@ -0,0 +1,11 @@
+BEGIN;
+
+CREATE TABLE users (
+ id serial not null,
+ username varchar(50) unique not null,
+ first_name varchar(200) not null,
+ last_name varchar(200) not null,
+ password varchar(120) not null
+);
+
+COMMIT;
\ No newline at end of file
diff --git a/assignment-2/deploy/hacktiv-assignment-2 b/assignment-2/deploy/hacktiv-assignment-2
new file mode 100755
index 0000000..830f74f
Binary files /dev/null and b/assignment-2/deploy/hacktiv-assignment-2 differ
diff --git a/assignment-2/docker-compose.yaml b/assignment-2/docker-compose.yaml
new file mode 100644
index 0000000..28d99db
--- /dev/null
+++ b/assignment-2/docker-compose.yaml
@@ -0,0 +1,24 @@
+version: '3'
+
+services:
+ postgres:
+ image: postgres:13.2-alpine
+ environment:
+ - POSTGRES_USER=postgresuser
+ - POSTGRES_PASSWORD=postgrespassword
+ - POSTGRES_DB=postgres
+ ports:
+ - 5432:5432
+ networks:
+ - assignment-2
+ server:
+ image: hacktiv-assignment-2:latest
+ ports:
+ - 8080:8080
+ depends_on:
+ - postgres
+ networks:
+ - assignment-2
+
+networks:
+ assignment-2:
\ No newline at end of file
diff --git a/assignment-2/driver/pgx.go b/assignment-2/driver/pgx.go
new file mode 100644
index 0000000..7d958a8
--- /dev/null
+++ b/assignment-2/driver/pgx.go
@@ -0,0 +1,11 @@
+package driver
+
+import (
+ "context"
+
+ "github.com/jackc/pgx/v4"
+)
+
+func NewPostgresConn(ctx context.Context) (*pgx.Conn, error) {
+ return pgx.Connect(ctx, POSTGRES_URL)
+}
diff --git a/assignment-2/driver/renderer.go b/assignment-2/driver/renderer.go
new file mode 100644
index 0000000..5e790d8
--- /dev/null
+++ b/assignment-2/driver/renderer.go
@@ -0,0 +1,41 @@
+package driver
+
+import (
+ "html/template"
+ "io"
+
+ "github.com/labstack/echo"
+)
+
+type Renderer struct {
+ template *template.Template
+ debug bool
+ location string
+}
+
+func NewRenderer(location string, debug bool) *Renderer {
+ tpl := new(Renderer)
+ tpl.location = location
+ tpl.debug = debug
+
+ tpl.ReloadTemplates()
+
+ return tpl
+}
+
+func (t *Renderer) ReloadTemplates() {
+ t.template = template.Must(template.ParseGlob(t.location))
+}
+
+func (t *Renderer) Render(
+ w io.Writer,
+ name string,
+ data interface{},
+ c echo.Context,
+) error {
+ if t.debug {
+ t.ReloadTemplates()
+ }
+
+ return t.template.ExecuteTemplate(w, name, data)
+}
diff --git a/assignment-2/driver/session_store.go b/assignment-2/driver/session_store.go
new file mode 100644
index 0000000..3f09b62
--- /dev/null
+++ b/assignment-2/driver/session_store.go
@@ -0,0 +1,36 @@
+package driver
+
+import (
+ "log"
+
+ "github.com/antonlindstrom/pgstore"
+ "github.com/gorilla/sessions"
+)
+
+const (
+ SESSION_ID = "test-id"
+ POSTGRES_URL = "postgres://postgresuser:postgrespassword@postgres:5432/postgres?sslmode=disable"
+)
+
+var (
+ SESSION_AUTH_KEY = []byte("my-auth-key-very-secret")
+ SESSION_ENCRYPTION_KEY = []byte("my-encryption-key-very-secret123")
+)
+
+func NewPostgresStore() *pgstore.PGStore {
+ store, err := pgstore.NewPGStore(POSTGRES_URL, SESSION_AUTH_KEY, SESSION_ENCRYPTION_KEY)
+ if err != nil {
+ log.Fatalln("ERROR", err)
+ }
+
+ return store
+}
+
+func NewCookieStore() *sessions.CookieStore {
+ store := sessions.NewCookieStore(SESSION_AUTH_KEY, SESSION_ENCRYPTION_KEY)
+ store.Options.Path = "/"
+ store.Options.MaxAge = 86400 * 7
+ store.Options.HttpOnly = true
+
+ return store
+}
diff --git a/assignment-2/entity/user.go b/assignment-2/entity/user.go
new file mode 100644
index 0000000..4213de3
--- /dev/null
+++ b/assignment-2/entity/user.go
@@ -0,0 +1,9 @@
+package entity
+
+type User struct {
+ ID int `json:"id"`
+ Username string `json:"username"`
+ FirstName string `json:"first_name"`
+ LastName string `json:"last_name"`
+ Password string `json:"password"`
+}
diff --git a/assignment-2/handler/common.go b/assignment-2/handler/common.go
new file mode 100644
index 0000000..ce37eb2
--- /dev/null
+++ b/assignment-2/handler/common.go
@@ -0,0 +1,21 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/antonlindstrom/pgstore"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/driver"
+ "github.com/labstack/echo"
+)
+
+func storeSessionHelper(c echo.Context, pgs *pgstore.PGStore, username string) error {
+ session, err := pgs.Get(c.Request(), driver.SESSION_ID)
+ if err != nil {
+ return c.String(http.StatusInternalServerError, err.Error())
+ }
+ session.Values["username"] = username
+ if err = session.Save(c.Request(), c.Response()); err != nil {
+ return c.String(http.StatusInternalServerError, err.Error())
+ }
+ return nil
+}
diff --git a/assignment-2/handler/login_handler.go b/assignment-2/handler/login_handler.go
new file mode 100644
index 0000000..ecb80e1
--- /dev/null
+++ b/assignment-2/handler/login_handler.go
@@ -0,0 +1,87 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/antonlindstrom/pgstore"
+ "github.com/gorilla/sessions"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/driver"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/entity"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/repository"
+ "github.com/labstack/echo"
+ log "github.com/sirupsen/logrus"
+)
+
+type HTMLTemplate struct {
+ User entity.User
+ Err string
+}
+
+type Login struct {
+ cs *sessions.CookieStore
+ pgStore *pgstore.PGStore
+ ur *repository.User
+}
+
+func NewLoginHandler(cs *sessions.CookieStore, pgs *pgstore.PGStore, ur *repository.User) *Login {
+ return &Login{
+ cs: cs,
+ pgStore: pgs,
+ ur: ur,
+ }
+}
+
+func (l *Login) LoginHandler(c echo.Context) error {
+ log.Info("Start Login Handler")
+ // authenticate in db
+ user, err := l.ur.GetByUsernamePassword(c.Request().Context(), c.FormValue("username"), c.FormValue("password"))
+ if err != nil {
+ log.Warn(err)
+ return c.Render(http.StatusOK, "login.html", HTMLTemplate{
+ User: entity.User{},
+ Err: "Error when login",
+ })
+ }
+ log.Info("Successfully authenticate user", user)
+
+ // store username in session
+ if err = storeSessionHelper(c, l.pgStore, user.Username); err != nil {
+ log.Warn("error when store session")
+ return c.Render(http.StatusOK, "login.html", HTMLTemplate{
+ User: entity.User{},
+ Err: "Error when store session",
+ })
+ }
+
+ return c.Redirect(http.StatusTemporaryRedirect, "/home")
+}
+
+func (l *Login) HomeHandler(c echo.Context) error {
+ log.Info("Start Home Handler")
+
+ session, err := l.pgStore.Get(c.Request(), driver.SESSION_ID)
+ if err != nil {
+ log.WithError(err).Warn("error when retrieve session")
+ return c.Redirect(http.StatusTemporaryRedirect, "/login")
+ }
+
+ if len(session.Values) == 0 {
+ log.Info("no session values available")
+ return c.Redirect(http.StatusTemporaryRedirect, "/login")
+ }
+
+ log.Info("Session exists, render html")
+ return c.Render(http.StatusOK, "home.html", HTMLTemplate{
+ User: entity.User{Username: session.Values["username"].(string)},
+ Err: "",
+ })
+}
+
+func (l *Login) LogoutHandler(c echo.Context) error {
+ log.Info("Start Logout Handler")
+ session, _ := l.pgStore.Get(c.Request(), driver.SESSION_ID)
+ session.Options.MaxAge = -1
+ session.Save(c.Request(), c.Response())
+
+ return c.Redirect(http.StatusTemporaryRedirect, "/home")
+}
diff --git a/assignment-2/handler/register_handler.go b/assignment-2/handler/register_handler.go
new file mode 100644
index 0000000..43a3eb0
--- /dev/null
+++ b/assignment-2/handler/register_handler.go
@@ -0,0 +1,51 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/antonlindstrom/pgstore"
+ "github.com/gorilla/sessions"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/entity"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/repository"
+ "github.com/labstack/echo"
+ log "github.com/sirupsen/logrus"
+)
+
+type Register struct {
+ cs *sessions.CookieStore
+ pgs *pgstore.PGStore
+ ur *repository.User
+}
+
+func NewRegisterHandler(cs *sessions.CookieStore, pgs *pgstore.PGStore, ur *repository.User) *Register {
+ return &Register{
+ cs: cs,
+ pgs: pgs,
+ ur: ur,
+ }
+}
+
+func (r *Register) RegisterHandler(c echo.Context) error {
+ data := "Hello from /html"
+ u := &entity.User{
+ Username: c.FormValue("username"),
+ FirstName: c.FormValue("firstname"),
+ LastName: c.FormValue("lastname"),
+ Password: c.FormValue("password"),
+ }
+ log.Info("user", u)
+ if u.Username == "" || u.Password == "" {
+ log.Warn("username password cannot be empty")
+ return c.Redirect(http.StatusTemporaryRedirect, "/home")
+ }
+ if err := r.ur.Insert(c.Request().Context(), u); err != nil {
+ return c.Render(http.StatusOK, "login.html", data)
+ }
+
+ // store username in session
+ if err := storeSessionHelper(c, r.pgs, u.Username); err != nil {
+ return c.String(http.StatusInternalServerError, err.Error())
+ }
+
+ return c.Redirect(http.StatusTemporaryRedirect, "/home")
+}
diff --git a/assignment-2/main.go b/assignment-2/main.go
new file mode 100644
index 0000000..a1afdce
--- /dev/null
+++ b/assignment-2/main.go
@@ -0,0 +1,44 @@
+package main
+
+import (
+ "context"
+ "log"
+ "net/http"
+
+ "github.com/ibrahimker/golang-intermediate/assignment-2/driver"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/handler"
+ "github.com/ibrahimker/golang-intermediate/assignment-2/repository"
+ "github.com/labstack/echo"
+)
+
+func main() {
+ e := echo.New()
+ e.Renderer = driver.NewRenderer("template/*.html", true)
+ ctx := context.Background()
+ store := driver.NewPostgresStore()
+ pgPool, err := driver.NewPostgresConn(ctx)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ userRepo := repository.NewUser(pgPool)
+
+ loginHandler := handler.NewLoginHandler(nil, store, userRepo)
+ registerHandler := handler.NewRegisterHandler(nil, store, userRepo)
+
+ e.GET("/", func(ctx echo.Context) error {
+ return ctx.Redirect(http.StatusTemporaryRedirect, "/home")
+ })
+
+ e.GET("/login", loginHandler.LoginHandler)
+ e.POST("/login", loginHandler.LoginHandler)
+
+ e.GET("/home", loginHandler.HomeHandler)
+ e.POST("/home", loginHandler.HomeHandler)
+
+ e.POST("/register", registerHandler.RegisterHandler)
+
+ e.POST("/logout", loginHandler.LogoutHandler)
+
+ e.Start(":8080")
+}
diff --git a/assignment-2/repository/common.go b/assignment-2/repository/common.go
new file mode 100644
index 0000000..26484ce
--- /dev/null
+++ b/assignment-2/repository/common.go
@@ -0,0 +1,18 @@
+package repository
+
+import (
+ "context"
+
+ "github.com/jackc/pgconn"
+ "github.com/jackc/pgx/v4"
+)
+
+// PgxPoolIface defines a little interface for pgxpool functionality.
+// Since in the real implementation we can use pgxpool.Pool,
+// this interface exists mostly for testing purpose.
+type PgxPoolIface interface {
+ Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error)
+ Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error)
+ QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row
+ Ping(ctx context.Context) error
+}
diff --git a/assignment-2/repository/users.go b/assignment-2/repository/users.go
new file mode 100644
index 0000000..3d60d7a
--- /dev/null
+++ b/assignment-2/repository/users.go
@@ -0,0 +1,59 @@
+package repository
+
+import (
+ "context"
+
+ "github.com/ibrahimker/golang-intermediate/assignment-2/entity"
+ log "github.com/sirupsen/logrus"
+)
+
+// User is responsible to connect user entity with users table in PostgreSQL.
+type User struct {
+ pool PgxPoolIface
+}
+
+// NewUser creates an instance of User.
+func NewUser(pool PgxPoolIface) *User {
+ return &User{pool: pool}
+}
+
+// Insert inserts the user into the users table and return the user id.
+func (u *User) Insert(ctx context.Context, user *entity.User) error {
+ query := "INSERT INTO " +
+ "users (username, first_name, last_name, password) " +
+ "VALUES ($1, $2, $3, $4) " +
+ "RETURNING id"
+
+ row := u.pool.QueryRow(ctx, query,
+ user.Username,
+ user.FirstName,
+ user.LastName,
+ user.Password,
+ )
+
+ if err := row.Scan(&user.ID); err != nil {
+ log.Warn("Error when scan rows")
+ return err
+ }
+
+ return nil
+}
+
+// GetByUsernamePassword gets a user from PostgreSQL.
+// If there isn't any data, it returns error.
+func (u *User) GetByUsernamePassword(ctx context.Context, username, password string) (*entity.User, error) {
+ log.Info("Start GetByUsernamePassword", username, password)
+ query := "SELECT id,username,first_name,last_name,password " +
+ "FROM users WHERE username = $1 AND password = $2"
+
+ row := u.pool.QueryRow(ctx, query, username, password)
+
+ user := entity.User{}
+ err := row.Scan(&user.ID, &user.Username, &user.FirstName, &user.LastName, &user.Password)
+ if err != nil {
+ log.WithError(err).Warn("Error when scan rows")
+ return nil, err
+ }
+ log.Infof("Success retrieve user %+v\n", user)
+ return &user, nil
+}
diff --git a/assignment-2/template/home.html b/assignment-2/template/home.html
new file mode 100644
index 0000000..6cc869a
--- /dev/null
+++ b/assignment-2/template/home.html
@@ -0,0 +1,18 @@
+
+
+ Assignment 2 - Home
+
+
+
+
+
+
+
Halo, {{.User.Username}}
+
...
+
+
+
+
+
\ No newline at end of file
diff --git a/assignment-2/template/login.html b/assignment-2/template/login.html
new file mode 100644
index 0000000..7c68a81
--- /dev/null
+++ b/assignment-2/template/login.html
@@ -0,0 +1,51 @@
+
+
+ Assignment 2 - Login
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/final-project/index.html b/final-project/index.html
new file mode 100644
index 0000000..ffd825b
--- /dev/null
+++ b/final-project/index.html
@@ -0,0 +1,125 @@
+
+
+
+ WebSocket
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/final-project/main.go b/final-project/main.go
new file mode 100644
index 0000000..438524b
--- /dev/null
+++ b/final-project/main.go
@@ -0,0 +1,115 @@
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "strings"
+
+ "github.com/gorilla/websocket"
+)
+
+type M map[string]interface{}
+
+const MESSAGE_NEW_USER = "New User"
+const MESSAGE_CHAT = "Chat"
+const MESSAGE_LEAVE = "Leave"
+
+var connections = make([]*WebSocketConnection, 0)
+
+type SocketPayload struct {
+ Message string
+}
+
+type SocketResponse struct {
+ From string
+ Type string
+ Message string
+}
+
+type WebSocketConnection struct {
+ *websocket.Conn
+ Username string
+ Age string
+}
+
+func main() {
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ content, err := ioutil.ReadFile("index.html")
+ if err != nil {
+ http.Error(w, "Could not open requested file", http.StatusInternalServerError)
+ return
+ }
+
+ fmt.Fprintf(w, "%s", content)
+ })
+
+ http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
+ currentGorillaConn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
+ if err != nil {
+ http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
+ }
+
+ username := r.URL.Query().Get("username")
+ age := r.URL.Query().Get("age")
+ currentConn := WebSocketConnection{Conn: currentGorillaConn, Username: username, Age: age}
+ connections = append(connections, ¤tConn)
+
+ go handleIO(¤tConn, connections)
+ })
+
+ fmt.Println("Server starting at :8080")
+ http.ListenAndServe(":8080", nil)
+}
+
+func handleIO(currentConn *WebSocketConnection, connections []*WebSocketConnection) {
+ defer func() {
+ if r := recover(); r != nil {
+ log.Println("ERROR", fmt.Sprintf("%v", r))
+ }
+ }()
+
+ broadcastMessage(currentConn, MESSAGE_NEW_USER, "")
+
+ for {
+ payload := SocketPayload{}
+ err := currentConn.ReadJSON(&payload)
+ if err != nil {
+ if strings.Contains(err.Error(), "websocket: close") {
+ broadcastMessage(currentConn, MESSAGE_LEAVE, "")
+ ejectConnection(currentConn)
+ return
+ }
+
+ log.Println("ERROR", err.Error())
+ continue
+ }
+
+ broadcastMessage(currentConn, MESSAGE_CHAT, payload.Message)
+ }
+}
+
+func ejectConnection(currentConn *WebSocketConnection) {
+ var newConn []*WebSocketConnection
+ for _, conn := range connections {
+ if conn != currentConn {
+ newConn = append(newConn, conn)
+ }
+ }
+ connections = newConn
+}
+
+func broadcastMessage(currentConn *WebSocketConnection, kind, message string) {
+ for _, eachConn := range connections {
+ if eachConn == currentConn {
+ continue
+ }
+
+ eachConn.WriteJSON(SocketResponse{
+ From: fmt.Sprintf(currentConn.Username + " Age: " + currentConn.Age),
+ Type: kind,
+ Message: message,
+ })
+ }
+}
diff --git a/go.mod b/go.mod
index dd19778..ecc4607 100644
--- a/go.mod
+++ b/go.mod
@@ -1,33 +1,85 @@
module github.com/ibrahimker/golang-intermediate
-go 1.18
+go 1.20
require (
+ github.com/antonlindstrom/pgstore v0.0.0-20220421113606-e3a6e3fed12a
+ github.com/crewjam/saml v0.4.12
+ github.com/go-ldap/ldap v3.0.3+incompatible
+ github.com/go-playground/validator v9.31.0+incompatible
github.com/golang/protobuf v1.5.2
github.com/gorilla/mux v1.8.0
+ github.com/gorilla/sessions v1.2.1
+ github.com/gorilla/websocket v1.5.0
+ github.com/grpc-ecosystem/grpc-gateway/v2 v2.13.0
+ github.com/jackc/pgconn v1.13.0
+ github.com/jackc/pgx/v4 v4.17.2
+ github.com/labstack/echo v3.3.10+incompatible
+ github.com/pkg/sftp v1.13.5
+ github.com/sirupsen/logrus v1.9.0
+ github.com/spf13/viper v1.15.0
+ github.com/stretchr/testify v1.8.1
github.com/swaggo/http-swagger v1.3.3
github.com/swaggo/swag v1.8.7
- google.golang.org/grpc v1.50.1
+ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
+ google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef
+ google.golang.org/grpc v1.52.0
google.golang.org/protobuf v1.28.1
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
- github.com/go-ldap/ldap v3.0.3+incompatible // indirect
+ github.com/beevik/etree v1.1.0 // indirect
+ github.com/crewjam/httperr v0.2.0 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
+ github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
- github.com/go-openapi/spec v0.20.7 // indirect
- github.com/go-openapi/swag v0.22.3 // indirect
- github.com/grpc-ecosystem/grpc-gateway/v2 v2.13.0 // indirect
+ github.com/go-openapi/spec v0.20.6 // indirect
+ github.com/go-openapi/swag v0.19.15 // indirect
+ github.com/go-playground/locales v0.14.1 // indirect
+ github.com/go-playground/universal-translator v0.18.0 // indirect
+ github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
+ github.com/gorilla/securecookie v1.1.1 // indirect
+ github.com/hashicorp/hcl v1.0.0 // indirect
+ github.com/jackc/chunkreader/v2 v2.0.1 // indirect
+ github.com/jackc/pgio v1.0.0 // indirect
+ github.com/jackc/pgpassfile v1.0.0 // indirect
+ github.com/jackc/pgproto3/v2 v2.3.1 // indirect
+ github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
+ github.com/jackc/pgtype v1.12.0 // indirect
+ github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/sirupsen/logrus v1.9.0 // indirect
- github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect
- golang.org/x/net v0.1.0 // indirect
- golang.org/x/sys v0.1.0 // indirect
- golang.org/x/text v0.4.0 // indirect
- golang.org/x/tools v0.2.0 // indirect
- google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c // indirect
+ github.com/kr/fs v0.1.0 // indirect
+ github.com/labstack/gommon v0.4.0 // indirect
+ github.com/leodido/go-urn v1.2.1 // indirect
+ github.com/lib/pq v1.10.5 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
+ github.com/mailru/easyjson v0.7.6 // indirect
+ github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
+ github.com/mattn/go-colorable v0.1.12 // indirect
+ github.com/mattn/go-isatty v0.0.14 // indirect
+ github.com/mitchellh/mapstructure v1.5.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.6 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/russellhaering/goxmldsig v1.2.0 // indirect
+ github.com/spf13/afero v1.9.3 // indirect
+ github.com/spf13/cast v1.5.0 // indirect
+ github.com/spf13/jwalterweatherman v1.1.0 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ github.com/subosito/gotenv v1.4.2 // indirect
+ github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
+ golang.org/x/net v0.4.0 // indirect
+ golang.org/x/sys v0.3.0 // indirect
+ golang.org/x/text v0.5.0 // indirect
+ golang.org/x/tools v0.1.12 // indirect
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
+ gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
+ gopkg.in/ini.v1 v1.67.0 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 0bf8aab..d120b97 100644
--- a/go.sum
+++ b/go.sum
@@ -1,83 +1,704 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
+cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
+cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
+cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
+cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
+cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
+cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
+cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
+cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
+cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
+cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
+cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
+cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
+cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
+cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
+cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
+cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/antonlindstrom/pgstore v0.0.0-20220421113606-e3a6e3fed12a h1:dIdcLbck6W67B5JFMewU5Dba1yKZA3MsT67i4No/zh0=
+github.com/antonlindstrom/pgstore v0.0.0-20220421113606-e3a6e3fed12a/go.mod h1:Sdr/tmSOLEnncCuXS5TwZRxuk7deH1WXVY8cve3eVBM=
+github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
+github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo=
+github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
+github.com/crewjam/saml v0.4.12 h1:66Gsd+9iA/8ZGl8W+7DDTlJGWe3RneBFo+Uu/gvlB0w=
+github.com/crewjam/saml v0.4.12/go.mod h1:igEejV+fihTIlHXYP8zOec3V5A8y3lws5bQBFsTm4gA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
+github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
+github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk=
github.com/go-ldap/ldap v3.0.3+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA=
github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo=
-github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI=
-github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
+github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ=
+github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
-github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
-github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
+github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
+github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
+github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
+github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
+github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA=
+github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
+github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
+github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
+github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
+github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
+github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
+github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
+github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.13.0 h1:fi9bGIUJOGzzrHBbP8NWbTfNC5fKO6X7kFw40TOqGB8=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.13.0/go.mod h1:uY3Aurq+SxwQCpdX91xZ9CgxIMT1EsYtcidljXufYIY=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
+github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
+github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
+github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
+github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
+github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
+github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
+github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
+github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
+github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
+github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
+github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
+github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
+github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
+github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
+github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
+github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
+github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
+github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
+github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
+github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
+github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
+github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU=
+github.com/mattermost/xml-roundtrip-validator v0.1.0/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
+github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
+github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
+github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
+github.com/pkg/sftp v1.13.5 h1:a3RLUqkyjYRtBTZJZ1VRrKbN3zhuPLlUc3sphVz81go=
+github.com/pkg/sftp v1.13.5/go.mod h1:wHDZ0IZX6JcBYRK1TH9bcVq8G7TLpVHYIGJRFnmPfxg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/russellhaering/goxmldsig v1.2.0 h1:Y6GTTc9Un5hCxSzVz4UIWQ/zuVwDvzJk80guqzwx6Vg=
+github.com/russellhaering/goxmldsig v1.2.0/go.mod h1:gM4MDENBQf7M+V824SGfyIUVFWydB7n0KkEubVJl+Tw=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
+github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
+github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
+github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
+github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
+github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
+github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
-github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a h1:kAe4YSu0O0UFn1DowNo2MY5p6xzqtJ/wQ7LZynSvGaY=
-github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
+github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc=
+github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc=
github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo=
github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU=
github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk=
-golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220128200615-198e4374d7ed/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
+golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
-golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
+golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
+golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
-golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
+golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
+golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo=
-google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
-google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
-google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
+google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
+google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
+google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
+google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
+google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef h1:uQ2vjV/sHTsWSqdKeLqmwitzgvjMl7o4IdtHwUDXSJY=
+google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
+google.golang.org/grpc v1.52.0 h1:kd48UiU7EHsV4rnLyOJRuP/Il/UHE7gdDAQ+SZI7nZk=
+google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
@@ -88,10 +709,30 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
+gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
+gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
+rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
diff --git a/session-10/config.go b/session-10/config.go
new file mode 100644
index 0000000..800d4ca
--- /dev/null
+++ b/session-10/config.go
@@ -0,0 +1,12 @@
+package main
+
+import "fmt"
+
+var (
+ samlCertificatePath = "./myservice.cert"
+ samlPrivateKeyPath = "./myservice.key"
+ samlIDPMetadata = "https://samltest.id/saml/idp"
+
+ webserverPort = 9000
+ webserverRootURL = fmt.Sprintf("http://localhost:%d", webserverPort)
+)
diff --git a/session-10/main.go b/session-10/main.go
new file mode 100644
index 0000000..a1a5736
--- /dev/null
+++ b/session-10/main.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+
+ "github.com/crewjam/saml/samlsp"
+)
+
+func landingHandler(w http.ResponseWriter, r *http.Request) {
+ name := samlsp.AttributeFromContext(r.Context(), "displayName")
+ w.Write([]byte(fmt.Sprintf("Welcome, %s!", name)))
+}
+func helloHandler(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("Hello!"))
+}
+
+func main() {
+ sp, err := newSamlMiddleware()
+ if err != nil {
+ log.Fatal(err.Error())
+ }
+ http.Handle("/saml/", sp)
+
+ http.Handle("/index", sp.RequireAccount(
+ http.HandlerFunc(landingHandler),
+ ))
+ http.Handle("/hello", sp.RequireAccount(
+ http.HandlerFunc(helloHandler),
+ ))
+
+ portString := fmt.Sprintf(":%d", webserverPort)
+ fmt.Println("server started at", portString)
+ http.ListenAndServe(portString, nil)
+}
diff --git a/session-10/metadata b/session-10/metadata
new file mode 100644
index 0000000..64a0cd2
--- /dev/null
+++ b/session-10/metadata
@@ -0,0 +1,19 @@
+
+
+
+
+
+ MIIDCTCCAfGgAwIBAgIUfYfQd8O9qWWnhhBO7yFjWlm6sbIwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMTEzMDAyMTkzNFoXDTIzMTEzMDAyMTkzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxWk3irjmg2J5GatxVCBbq8CI5WThzUqncV22mANlxGJin89zS9Anf2E6yzlE+li1EL8bv9ndrRTkXN+HTImhU+62/83OXAz5PJAxq22eMVMmAcRxVxq7zKqcEwk5uPe2wdKclhIfE1/hca3042LR1p+l3/PMv7IaUUlIiqLQxMDeb+nhB3z7afwUQhL4NQt21fz1G5NPrzIXzj+baCdyrvtugO10haWOvtu5YsKj/bAYi90lsgawgmonf3/sfNwUMWiD0esL1Mq2YclDgC72j84Yb8zhGxaQJkbeq1BSofsax2GiIPMjEGMVefZas6zaa7knTwa71vL6lu/tPq7cgwIDAQABo1MwUTAdBgNVHQ4EFgQUP0j91usGpXqmwgbKRd1Knd1PuRowHwYDVR0jBBgwFoAUP0j91usGpXqmwgbKRd1Knd1PuRowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYpx/dwBWbOo1TbnXv1xgQrYD4HVoqsKd5kWNDZB79BtOQ4XdHUWBAySvDrYTC83UO7vWtAJRW3UI6CrbgOpzSJFcRiwv8/Noj7N8WXiq+UuVtaUdMpHNStt57NfgGlJ8Bf9EnhFhRcfgkTuIIwPb4W/4+6yF0AS6b+VUERYPSVig2ZveUsldt2ZHjOGmi55NUTGdtVX3H4QFfMcWNGaESGdohqn2t3AfEk83boiSBXBtC9gv9hRBZa9i89Qd0H12T0cx0UJYQYRni2Zy3rfT0AKtQtY0fIkigt24c8hDUePKBezx3Qilq3q+bnON6MUdi80+GvJutl1GtevGrGXlvw==
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/session-10/myservice.cert b/session-10/myservice.cert
new file mode 100644
index 0000000..724a95f
--- /dev/null
+++ b/session-10/myservice.cert
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCTCCAfGgAwIBAgIUfYfQd8O9qWWnhhBO7yFjWlm6sbIwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMTEzMDAyMTkzNFoXDTIzMTEz
+MDAyMTkzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAxWk3irjmg2J5GatxVCBbq8CI5WThzUqncV22mANlxGJi
+n89zS9Anf2E6yzlE+li1EL8bv9ndrRTkXN+HTImhU+62/83OXAz5PJAxq22eMVMm
+AcRxVxq7zKqcEwk5uPe2wdKclhIfE1/hca3042LR1p+l3/PMv7IaUUlIiqLQxMDe
+b+nhB3z7afwUQhL4NQt21fz1G5NPrzIXzj+baCdyrvtugO10haWOvtu5YsKj/bAY
+i90lsgawgmonf3/sfNwUMWiD0esL1Mq2YclDgC72j84Yb8zhGxaQJkbeq1BSofsa
+x2GiIPMjEGMVefZas6zaa7knTwa71vL6lu/tPq7cgwIDAQABo1MwUTAdBgNVHQ4E
+FgQUP0j91usGpXqmwgbKRd1Knd1PuRowHwYDVR0jBBgwFoAUP0j91usGpXqmwgbK
+Rd1Knd1PuRowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYpx/
+dwBWbOo1TbnXv1xgQrYD4HVoqsKd5kWNDZB79BtOQ4XdHUWBAySvDrYTC83UO7vW
+tAJRW3UI6CrbgOpzSJFcRiwv8/Noj7N8WXiq+UuVtaUdMpHNStt57NfgGlJ8Bf9E
+nhFhRcfgkTuIIwPb4W/4+6yF0AS6b+VUERYPSVig2ZveUsldt2ZHjOGmi55NUTGd
+tVX3H4QFfMcWNGaESGdohqn2t3AfEk83boiSBXBtC9gv9hRBZa9i89Qd0H12T0cx
+0UJYQYRni2Zy3rfT0AKtQtY0fIkigt24c8hDUePKBezx3Qilq3q+bnON6MUdi80+
+GvJutl1GtevGrGXlvw==
+-----END CERTIFICATE-----
diff --git a/session-10/myservice.key b/session-10/myservice.key
new file mode 100644
index 0000000..b40ef89
--- /dev/null
+++ b/session-10/myservice.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFaTeKuOaDYnkZ
+q3FUIFurwIjlZOHNSqdxXbaYA2XEYmKfz3NL0Cd/YTrLOUT6WLUQvxu/2d2tFORc
+34dMiaFT7rb/zc5cDPk8kDGrbZ4xUyYBxHFXGrvMqpwTCTm497bB0pyWEh8TX+Fx
+rfTjYtHWn6Xf88y/shpRSUiKotDEwN5v6eEHfPtp/BRCEvg1C3bV/PUbk0+vMhfO
+P5toJ3Ku+26A7XSFpY6+27liwqP9sBiL3SWyBrCCaid/f+x83BQxaIPR6wvUyrZh
+yUOALvaPzhhvzOEbFpAmRt6rUFKh+xrHYaIg8yMQYxV59lqzrNpruSdPBrvW8vqW
+7+0+rtyDAgMBAAECggEAEfMiOLvdQd8HUd0z3clfbHuCNxF4MplyJi22N5Y/f57O
+hudu/Vq87Kkjlmzrp7O/KvmlhUlDDcTTitpMTBpLj/0pqJLHC7mmQ+p8ibDa7HM6
+BnkdMSVeJBrzPAvfssDbXj5PPJoDN1jFf/eoR7CpkdFMXNOnL1r7Z565ONnbD7is
+mVJf6VIlBf1hgbfohh/SJY+P9qJyK6ZxepZ6Z16fFGsq2njyWSzzOb02PfNrezr5
+RNWpeyZOOV55T8iEUX4Dm1g5c/2y1EN9plwLlk7dP+8yw0mE3DZrTIYrS68d95Pn
+4K9YRheAcrNEEJ8gmAdSa0Ov5hVs6f9ONzzXyUbY4QKBgQD8W+xqHPu2MCsOpxNj
+KiyWYZr3/Fs3XOML1SxTLRcPl7AigXhRRDZZy6RBeBLcA3TDMvF18gY9+5v1cITu
+A0Je750HkFZa/N2Dn78qzjfcaJXoH6PB4u6pix+EYJ6Rti0leIp6/JNPxJGPgO8A
+fZMwssA1yrhNUeTv7+BTHfx20wKBgQDIQlhmu60IN2+yFiXDcCfww1sts5YOsb1y
+8oEWv0BltbiIdVlZo1Pz6/AGwKSiyffHST4+FdhvcoqMAZWPgiKeNwTjkPb91G7b
+ICKsCJi8zyy7OcQouaBA3jHMvn9VUaAvn2GdkI7M+OrhRKFmBMkX4+2YTFu03tUR
+M8DP3abVkQKBgQDvzF2rO51IMx9HDiYTDelOgLMkQE1hH0e0X7190BPgwjAhqctt
+1Zab3zFW8MVjAXm7XrYpcHDUBznckS4PiVNRKPmbTWFxlmTbhTm/cDOOomcIKsCO
+JZjJzKSHQtSK+4SM3a0hTs6gdtYmecsiOTFbjg+tTdOxzUbxZIxSDuVu9wKBgExQ
+tD2aQcuCzMcSF5wODrp6yDF3YbUB2Q+ICNexVIouIT+ncMBvNJwdCqCYI2WCEDHa
+4KRqUMvP26qVI/jHgAfJMczDPszmesR4z529vO8fCI3k6rMWYlK2GkZLRl0uORxM
+4bdZEoJcTa5BKDynkDbRfobuenhH/uyKS20rq9txAoGBAOx23uUCsf10udtLNeQL
+x1k3nKEBXQzHzO26AoD0J8dhf9ilnzqtOoAM8br2Z8dw8KUWEu8w7iNo9AiAMUp0
+Wb/MuGJh1Cqsd4bcVbmaIh2s3aN6rUc403NIUFcl2WC4TljYPewn5hdEe1BWjsoz
+ocWQKoHw9qiqpjv0CbvLfnFT
+-----END PRIVATE KEY-----
diff --git a/session-10/saml_middleware.go b/session-10/saml_middleware.go
new file mode 100644
index 0000000..1e85822
--- /dev/null
+++ b/session-10/saml_middleware.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "context"
+ "crypto/rsa"
+ "crypto/tls"
+ "crypto/x509"
+ "net/http"
+ "net/url"
+
+ "github.com/crewjam/saml/samlsp"
+)
+
+func newSamlMiddleware() (*samlsp.Middleware, error) {
+ keyPair, err := tls.LoadX509KeyPair(samlCertificatePath, samlPrivateKeyPath)
+ if err != nil {
+ return nil, err
+ }
+ keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
+ if err != nil {
+ return nil, err
+ }
+
+ idpMetadataURL, err := url.Parse(samlIDPMetadata)
+ if err != nil {
+ return nil, err
+ }
+ idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient,
+ *idpMetadataURL)
+ if err != nil {
+ return nil, err
+ }
+
+ rootURL, err := url.Parse(webserverRootURL)
+ if err != nil {
+ return nil, err
+ }
+
+ sp, err := samlsp.New(samlsp.Options{
+ URL: *rootURL,
+ Key: keyPair.PrivateKey.(*rsa.PrivateKey),
+ Certificate: keyPair.Leaf,
+ IDPMetadata: idpMetadata,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return sp, nil
+}
diff --git a/session-11/main.go b/session-11/main.go
new file mode 100644
index 0000000..382c771
--- /dev/null
+++ b/session-11/main.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+)
+
+func main() {
+ fmt.Println(LuasPersegi(4))
+}
+
+func LuasPersegi(sisi int) int {
+ return sisi * sisi
+}
+
+func Register(username, password string) error {
+ if username == "" {
+ return errors.New("username tidak boleh kosong")
+ }
+ if password == "" {
+ return errors.New("password tidak boleh kosong")
+ }
+
+ // ceritanya masukin ke db
+
+ // kalo sukses return nil
+ return nil
+}
diff --git a/session-11/main_test.go b/session-11/main_test.go
new file mode 100644
index 0000000..a8e06bc
--- /dev/null
+++ b/session-11/main_test.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestLuasPersegi(t *testing.T) {
+ t.Run("case sisi 4", func(t *testing.T) {
+ luas := LuasPersegi(4)
+ require.Equal(t, 16, luas)
+ })
+ t.Run("case sisi 6", func(t *testing.T) {
+ luas := LuasPersegi(6)
+ require.Equal(t, 36, luas)
+ })
+}
+
+func TestRegister(t *testing.T) {
+ t.Run("case username kosong", func(t *testing.T) {
+ err := Register("", "password")
+ require.Error(t, err)
+ })
+ t.Run("case password kosong", func(t *testing.T) {
+ err := Register("username", "")
+ require.Error(t, err)
+ })
+ t.Run("case sukses", func(t *testing.T) {
+ err := Register("username", "password")
+ require.NoError(t, err)
+ })
+}
diff --git a/session-3/clientserver/Makefile b/session-3/clientserver/Makefile
index 6dd183f..871b465 100644
--- a/session-3/clientserver/Makefile
+++ b/session-3/clientserver/Makefile
@@ -1,3 +1,3 @@
.PHONY: generate-proto
generate-proto:
- protoc --proto_path=common/model --go_out=plugins=grpc:common/model/. --go_opt=paths=source_relative common/model/*.proto
\ No newline at end of file
+ protoc -I common/model/google/api --proto_path=common/model --go_out=plugins=grpc:common/model/. --go_opt=paths=source_relative common/model/*.proto
\ No newline at end of file
diff --git a/session-3/clientserver/common/model/user.pb.go b/session-3/clientserver/common/model/user.pb.go
index 0fbcbca..91b43a7 100644
--- a/session-3/clientserver/common/model/user.pb.go
+++ b/session-3/clientserver/common/model/user.pb.go
@@ -220,8 +220,8 @@ var file_common_model_user_proto_rawDesc = []byte{
0x6e, 0x33, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2e,
0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
- 0x74, 0x79, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x22, 0x09, 0x2f, 0x76, 0x31, 0x2f,
- 0x75, 0x73, 0x65, 0x72, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x58, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74,
+ 0x74, 0x79, 0x22, 0x14, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0e, 0x3a, 0x01, 0x2a, 0x22, 0x09, 0x2f,
+ 0x76, 0x31, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x58, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74,
0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69,
0x6f, 0x6e, 0x33, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
diff --git a/session-3/todo/buf.gen.yaml b/session-3/todo/buf.gen.yaml
new file mode 100644
index 0000000..abced21
--- /dev/null
+++ b/session-3/todo/buf.gen.yaml
@@ -0,0 +1,16 @@
+version: v1
+plugins:
+ - name: go
+ out: .
+ opt:
+ - paths=source_relative
+ - name: go-grpc
+ out: .
+ opt:
+ - paths=source_relative
+ - name: grpc-gateway
+ out: .
+ opt:
+ - paths=source_relative
+ - name: openapiv2
+ out: docs/openapiv2
\ No newline at end of file
diff --git a/session-3/todo/buf.lock b/session-3/todo/buf.lock
new file mode 100644
index 0000000..f5c25d7
--- /dev/null
+++ b/session-3/todo/buf.lock
@@ -0,0 +1,7 @@
+# Generated by buf. DO NOT EDIT.
+version: v1
+deps:
+ - remote: buf.build
+ owner: googleapis
+ repository: googleapis
+ commit: 783e4b5374fa488ab068d08af9658438
diff --git a/session-3/todo/buf.yaml b/session-3/todo/buf.yaml
new file mode 100644
index 0000000..8134aa3
--- /dev/null
+++ b/session-3/todo/buf.yaml
@@ -0,0 +1,4 @@
+version: v1
+name: buf.build/yourorg/myprotos
+deps:
+ - buf.build/googleapis/googleapis
\ No newline at end of file
diff --git a/session-3/todo/common/model/todo.pb.go b/session-3/todo/common/model/todo.pb.go
new file mode 100644
index 0000000..2c0bde8
--- /dev/null
+++ b/session-3/todo/common/model/todo.pb.go
@@ -0,0 +1,657 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.28.1
+// protoc (unknown)
+// source: common/model/todo.proto
+
+package model
+
+import (
+ _ "google.golang.org/genproto/googleapis/api/annotations"
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Todo struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *Todo) Reset() {
+ *x = Todo{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *Todo) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Todo) ProtoMessage() {}
+
+func (x *Todo) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Todo.ProtoReflect.Descriptor instead.
+func (*Todo) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Todo) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *Todo) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type GetAllResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data []*Todo `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *GetAllResponse) Reset() {
+ *x = GetAllResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetAllResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetAllResponse) ProtoMessage() {}
+
+func (x *GetAllResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetAllResponse.ProtoReflect.Descriptor instead.
+func (*GetAllResponse) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *GetAllResponse) GetData() []*Todo {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+type GetAllRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data []*Todo `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *GetAllRequest) Reset() {
+ *x = GetAllRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[2]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetAllRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetAllRequest) ProtoMessage() {}
+
+func (x *GetAllRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[2]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetAllRequest.ProtoReflect.Descriptor instead.
+func (*GetAllRequest) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *GetAllRequest) GetData() []*Todo {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+type GetByIDRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *GetByIDRequest) Reset() {
+ *x = GetByIDRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[3]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetByIDRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetByIDRequest) ProtoMessage() {}
+
+func (x *GetByIDRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[3]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetByIDRequest.ProtoReflect.Descriptor instead.
+func (*GetByIDRequest) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *GetByIDRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+type GetByIDResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Data *Todo `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
+}
+
+func (x *GetByIDResponse) Reset() {
+ *x = GetByIDResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[4]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *GetByIDResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*GetByIDResponse) ProtoMessage() {}
+
+func (x *GetByIDResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[4]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use GetByIDResponse.ProtoReflect.Descriptor instead.
+func (*GetByIDResponse) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *GetByIDResponse) GetData() *Todo {
+ if x != nil {
+ return x.Data
+ }
+ return nil
+}
+
+type MutationResponse struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Success string `protobuf:"bytes,1,opt,name=success,proto3" json:"success,omitempty"`
+}
+
+func (x *MutationResponse) Reset() {
+ *x = MutationResponse{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[5]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *MutationResponse) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MutationResponse) ProtoMessage() {}
+
+func (x *MutationResponse) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[5]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use MutationResponse.ProtoReflect.Descriptor instead.
+func (*MutationResponse) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *MutationResponse) GetSuccess() string {
+ if x != nil {
+ return x.Success
+ }
+ return ""
+}
+
+type UpdateRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+ Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
+}
+
+func (x *UpdateRequest) Reset() {
+ *x = UpdateRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[6]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *UpdateRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*UpdateRequest) ProtoMessage() {}
+
+func (x *UpdateRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[6]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use UpdateRequest.ProtoReflect.Descriptor instead.
+func (*UpdateRequest) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *UpdateRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+func (x *UpdateRequest) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+type DeleteRequest struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
+}
+
+func (x *DeleteRequest) Reset() {
+ *x = DeleteRequest{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_common_model_todo_proto_msgTypes[7]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *DeleteRequest) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*DeleteRequest) ProtoMessage() {}
+
+func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
+ mi := &file_common_model_todo_proto_msgTypes[7]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead.
+func (*DeleteRequest) Descriptor() ([]byte, []int) {
+ return file_common_model_todo_proto_rawDescGZIP(), []int{7}
+}
+
+func (x *DeleteRequest) GetId() string {
+ if x != nil {
+ return x.Id
+ }
+ return ""
+}
+
+var File_common_model_todo_proto protoreflect.FileDescriptor
+
+var file_common_model_todo_proto_rawDesc = []byte{
+ 0x0a, 0x17, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2f, 0x74,
+ 0x6f, 0x64, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x73, 0x65, 0x73, 0x73, 0x69,
+ 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0x1c,
+ 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f,
+ 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d,
+ 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2a, 0x0a, 0x04, 0x54, 0x6f, 0x64,
+ 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
+ 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3f, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x52,
+ 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33,
+ 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x54, 0x6f, 0x64, 0x6f,
+ 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c,
+ 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33,
+ 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x54, 0x6f, 0x64, 0x6f,
+ 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x20, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49,
+ 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
+ 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x40, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x42,
+ 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x64,
+ 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x65, 0x73, 0x73,
+ 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e,
+ 0x54, 0x6f, 0x64, 0x6f, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2c, 0x0a, 0x10, 0x4d, 0x75,
+ 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18,
+ 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+ 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x33, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61,
+ 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
+ 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x1f, 0x0a,
+ 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e,
+ 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x85,
+ 0x04, 0x0a, 0x0b, 0x54, 0x6f, 0x64, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x55,
+ 0x0a, 0x06, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
+ 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
+ 0x1a, 0x23, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f,
+ 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x6c, 0x52, 0x65, 0x73,
+ 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f,
+ 0x74, 0x6f, 0x64, 0x6f, 0x73, 0x12, 0x69, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x44,
+ 0x12, 0x23, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f,
+ 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65,
+ 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33,
+ 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x47, 0x65, 0x74, 0x42,
+ 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4,
+ 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d,
+ 0x12, 0x5d, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x73,
+ 0x73, 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
+ 0x2e, 0x54, 0x6f, 0x64, 0x6f, 0x1a, 0x25, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33,
+ 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4d, 0x75, 0x74, 0x61,
+ 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3,
+ 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x73, 0x12,
+ 0x6b, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x65, 0x73, 0x73,
+ 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e,
+ 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e,
+ 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f,
+ 0x64, 0x65, 0x6c, 0x2e, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
+ 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x16, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x3a, 0x01, 0x2a, 0x1a,
+ 0x0b, 0x2f, 0x74, 0x6f, 0x64, 0x6f, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x68, 0x0a, 0x06,
+ 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x22, 0x2e, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x44, 0x65, 0x6c,
+ 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x73, 0x65, 0x73,
+ 0x73, 0x69, 0x6f, 0x6e, 0x33, 0x2e, 0x74, 0x6f, 0x64, 0x6f, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c,
+ 0x2e, 0x4d, 0x75, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
+ 0x65, 0x22, 0x13, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x2a, 0x0b, 0x2f, 0x74, 0x6f, 0x64, 0x6f,
+ 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x42, 0x40, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x69, 0x62, 0x72, 0x61, 0x68, 0x69, 0x6d, 0x6b, 0x65, 0x72, 0x2f,
+ 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2d, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69,
+ 0x61, 0x74, 0x65, 0x2f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x2d, 0x33, 0x2f, 0x74, 0x6f,
+ 0x64, 0x6f, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_common_model_todo_proto_rawDescOnce sync.Once
+ file_common_model_todo_proto_rawDescData = file_common_model_todo_proto_rawDesc
+)
+
+func file_common_model_todo_proto_rawDescGZIP() []byte {
+ file_common_model_todo_proto_rawDescOnce.Do(func() {
+ file_common_model_todo_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_model_todo_proto_rawDescData)
+ })
+ return file_common_model_todo_proto_rawDescData
+}
+
+var file_common_model_todo_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
+var file_common_model_todo_proto_goTypes = []interface{}{
+ (*Todo)(nil), // 0: session3.todo.model.Todo
+ (*GetAllResponse)(nil), // 1: session3.todo.model.GetAllResponse
+ (*GetAllRequest)(nil), // 2: session3.todo.model.GetAllRequest
+ (*GetByIDRequest)(nil), // 3: session3.todo.model.GetByIDRequest
+ (*GetByIDResponse)(nil), // 4: session3.todo.model.GetByIDResponse
+ (*MutationResponse)(nil), // 5: session3.todo.model.MutationResponse
+ (*UpdateRequest)(nil), // 6: session3.todo.model.UpdateRequest
+ (*DeleteRequest)(nil), // 7: session3.todo.model.DeleteRequest
+ (*emptypb.Empty)(nil), // 8: google.protobuf.Empty
+}
+var file_common_model_todo_proto_depIdxs = []int32{
+ 0, // 0: session3.todo.model.GetAllResponse.data:type_name -> session3.todo.model.Todo
+ 0, // 1: session3.todo.model.GetAllRequest.data:type_name -> session3.todo.model.Todo
+ 0, // 2: session3.todo.model.GetByIDResponse.data:type_name -> session3.todo.model.Todo
+ 8, // 3: session3.todo.model.TodoService.GetAll:input_type -> google.protobuf.Empty
+ 3, // 4: session3.todo.model.TodoService.GetByID:input_type -> session3.todo.model.GetByIDRequest
+ 0, // 5: session3.todo.model.TodoService.Create:input_type -> session3.todo.model.Todo
+ 6, // 6: session3.todo.model.TodoService.Update:input_type -> session3.todo.model.UpdateRequest
+ 7, // 7: session3.todo.model.TodoService.Delete:input_type -> session3.todo.model.DeleteRequest
+ 1, // 8: session3.todo.model.TodoService.GetAll:output_type -> session3.todo.model.GetAllResponse
+ 4, // 9: session3.todo.model.TodoService.GetByID:output_type -> session3.todo.model.GetByIDResponse
+ 5, // 10: session3.todo.model.TodoService.Create:output_type -> session3.todo.model.MutationResponse
+ 5, // 11: session3.todo.model.TodoService.Update:output_type -> session3.todo.model.MutationResponse
+ 5, // 12: session3.todo.model.TodoService.Delete:output_type -> session3.todo.model.MutationResponse
+ 8, // [8:13] is the sub-list for method output_type
+ 3, // [3:8] is the sub-list for method input_type
+ 3, // [3:3] is the sub-list for extension type_name
+ 3, // [3:3] is the sub-list for extension extendee
+ 0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_common_model_todo_proto_init() }
+func file_common_model_todo_proto_init() {
+ if File_common_model_todo_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_common_model_todo_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*Todo); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetAllResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetAllRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetByIDRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*GetByIDResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*MutationResponse); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*UpdateRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_common_model_todo_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*DeleteRequest); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_common_model_todo_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 8,
+ NumExtensions: 0,
+ NumServices: 1,
+ },
+ GoTypes: file_common_model_todo_proto_goTypes,
+ DependencyIndexes: file_common_model_todo_proto_depIdxs,
+ MessageInfos: file_common_model_todo_proto_msgTypes,
+ }.Build()
+ File_common_model_todo_proto = out.File
+ file_common_model_todo_proto_rawDesc = nil
+ file_common_model_todo_proto_goTypes = nil
+ file_common_model_todo_proto_depIdxs = nil
+}
diff --git a/session-3/todo/common/model/todo.pb.gw.go b/session-3/todo/common/model/todo.pb.gw.go
new file mode 100644
index 0000000..e3dd037
--- /dev/null
+++ b/session-3/todo/common/model/todo.pb.gw.go
@@ -0,0 +1,566 @@
+// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
+// source: common/model/todo.proto
+
+/*
+Package model is a reverse proxy.
+
+It translates gRPC into RESTful JSON APIs.
+*/
+package model
+
+import (
+ "context"
+ "io"
+ "net/http"
+
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/codes"
+ "google.golang.org/grpc/grpclog"
+ "google.golang.org/grpc/metadata"
+ "google.golang.org/grpc/status"
+ "google.golang.org/protobuf/proto"
+ "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// Suppress "imported and not used" errors
+var _ codes.Code
+var _ io.Reader
+var _ status.Status
+var _ = runtime.String
+var _ = utilities.NewDoubleArray
+var _ = metadata.Join
+
+func request_TodoService_GetAll_0(ctx context.Context, marshaler runtime.Marshaler, client TodoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq emptypb.Empty
+ var metadata runtime.ServerMetadata
+
+ msg, err := client.GetAll(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_TodoService_GetAll_0(ctx context.Context, marshaler runtime.Marshaler, server TodoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq emptypb.Empty
+ var metadata runtime.ServerMetadata
+
+ msg, err := server.GetAll(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+func request_TodoService_GetByID_0(ctx context.Context, marshaler runtime.Marshaler, client TodoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq GetByIDRequest
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.String(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := client.GetByID(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_TodoService_GetByID_0(ctx context.Context, marshaler runtime.Marshaler, server TodoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq GetByIDRequest
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.String(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := server.GetByID(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+func request_TodoService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client TodoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq Todo
+ var metadata runtime.ServerMetadata
+
+ newReader, berr := utilities.IOReaderFactory(req.Body)
+ if berr != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+ }
+ if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_TodoService_Create_0(ctx context.Context, marshaler runtime.Marshaler, server TodoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq Todo
+ var metadata runtime.ServerMetadata
+
+ newReader, berr := utilities.IOReaderFactory(req.Body)
+ if berr != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+ }
+ if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ msg, err := server.Create(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+func request_TodoService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client TodoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq UpdateRequest
+ var metadata runtime.ServerMetadata
+
+ newReader, berr := utilities.IOReaderFactory(req.Body)
+ if berr != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+ }
+ if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.String(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_TodoService_Update_0(ctx context.Context, marshaler runtime.Marshaler, server TodoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq UpdateRequest
+ var metadata runtime.ServerMetadata
+
+ newReader, berr := utilities.IOReaderFactory(req.Body)
+ if berr != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
+ }
+ if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
+ }
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.String(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := server.Update(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+func request_TodoService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client TodoServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq DeleteRequest
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.String(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+ return msg, metadata, err
+
+}
+
+func local_request_TodoService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, server TodoServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+ var protoReq DeleteRequest
+ var metadata runtime.ServerMetadata
+
+ var (
+ val string
+ ok bool
+ err error
+ _ = err
+ )
+
+ val, ok = pathParams["id"]
+ if !ok {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
+ }
+
+ protoReq.Id, err = runtime.String(val)
+ if err != nil {
+ return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
+ }
+
+ msg, err := server.Delete(ctx, &protoReq)
+ return msg, metadata, err
+
+}
+
+// RegisterTodoServiceHandlerServer registers the http handlers for service TodoService to "mux".
+// UnaryRPC :call TodoServiceServer directly.
+// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
+// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterTodoServiceHandlerFromEndpoint instead.
+func RegisterTodoServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server TodoServiceServer) error {
+
+ mux.Handle("GET", pattern_TodoService_GetAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/session3.todo.model.TodoService/GetAll", runtime.WithHTTPPathPattern("/todos"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_TodoService_GetAll_0(annotatedContext, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_GetAll_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("GET", pattern_TodoService_GetByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/session3.todo.model.TodoService/GetByID", runtime.WithHTTPPathPattern("/todos/{id}"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_TodoService_GetByID_0(annotatedContext, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_GetByID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("POST", pattern_TodoService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/session3.todo.model.TodoService/Create", runtime.WithHTTPPathPattern("/todos"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_TodoService_Create_0(annotatedContext, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_Create_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("PUT", pattern_TodoService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/session3.todo.model.TodoService/Update", runtime.WithHTTPPathPattern("/todos/{id}"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_TodoService_Update_0(annotatedContext, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_Update_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("DELETE", pattern_TodoService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ var stream runtime.ServerTransportStream
+ ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/session3.todo.model.TodoService/Delete", runtime.WithHTTPPathPattern("/todos/{id}"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := local_request_TodoService_Delete_0(annotatedContext, inboundMarshaler, server, req, pathParams)
+ md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_Delete_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+// RegisterTodoServiceHandlerFromEndpoint is same as RegisterTodoServiceHandler but
+// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
+func RegisterTodoServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
+ conn, err := grpc.Dial(endpoint, opts...)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ if err != nil {
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ return
+ }
+ go func() {
+ <-ctx.Done()
+ if cerr := conn.Close(); cerr != nil {
+ grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
+ }
+ }()
+ }()
+
+ return RegisterTodoServiceHandler(ctx, mux, conn)
+}
+
+// RegisterTodoServiceHandler registers the http handlers for service TodoService to "mux".
+// The handlers forward requests to the grpc endpoint over "conn".
+func RegisterTodoServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
+ return RegisterTodoServiceHandlerClient(ctx, mux, NewTodoServiceClient(conn))
+}
+
+// RegisterTodoServiceHandlerClient registers the http handlers for service TodoService
+// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "TodoServiceClient".
+// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "TodoServiceClient"
+// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
+// "TodoServiceClient" to call the correct interceptors.
+func RegisterTodoServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client TodoServiceClient) error {
+
+ mux.Handle("GET", pattern_TodoService_GetAll_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/session3.todo.model.TodoService/GetAll", runtime.WithHTTPPathPattern("/todos"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_TodoService_GetAll_0(annotatedContext, inboundMarshaler, client, req, pathParams)
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_GetAll_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("GET", pattern_TodoService_GetByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/session3.todo.model.TodoService/GetByID", runtime.WithHTTPPathPattern("/todos/{id}"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_TodoService_GetByID_0(annotatedContext, inboundMarshaler, client, req, pathParams)
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_GetByID_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("POST", pattern_TodoService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/session3.todo.model.TodoService/Create", runtime.WithHTTPPathPattern("/todos"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_TodoService_Create_0(annotatedContext, inboundMarshaler, client, req, pathParams)
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_Create_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("PUT", pattern_TodoService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/session3.todo.model.TodoService/Update", runtime.WithHTTPPathPattern("/todos/{id}"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_TodoService_Update_0(annotatedContext, inboundMarshaler, client, req, pathParams)
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_Update_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ mux.Handle("DELETE", pattern_TodoService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+ ctx, cancel := context.WithCancel(req.Context())
+ defer cancel()
+ inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+ var err error
+ var annotatedContext context.Context
+ annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/session3.todo.model.TodoService/Delete", runtime.WithHTTPPathPattern("/todos/{id}"))
+ if err != nil {
+ runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+ return
+ }
+ resp, md, err := request_TodoService_Delete_0(annotatedContext, inboundMarshaler, client, req, pathParams)
+ annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
+ if err != nil {
+ runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
+ return
+ }
+
+ forward_TodoService_Delete_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+ })
+
+ return nil
+}
+
+var (
+ pattern_TodoService_GetAll_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"todos"}, ""))
+
+ pattern_TodoService_GetByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"todos", "id"}, ""))
+
+ pattern_TodoService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"todos"}, ""))
+
+ pattern_TodoService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"todos", "id"}, ""))
+
+ pattern_TodoService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"todos", "id"}, ""))
+)
+
+var (
+ forward_TodoService_GetAll_0 = runtime.ForwardResponseMessage
+
+ forward_TodoService_GetByID_0 = runtime.ForwardResponseMessage
+
+ forward_TodoService_Create_0 = runtime.ForwardResponseMessage
+
+ forward_TodoService_Update_0 = runtime.ForwardResponseMessage
+
+ forward_TodoService_Delete_0 = runtime.ForwardResponseMessage
+)
diff --git a/session-3/todo/common/model/todo.proto b/session-3/todo/common/model/todo.proto
new file mode 100644
index 0000000..5bfea0b
--- /dev/null
+++ b/session-3/todo/common/model/todo.proto
@@ -0,0 +1,76 @@
+syntax = "proto3";
+
+package session3.todo.model;
+
+option go_package = "github.com/ibrahimker/golang-intermediate/session-3/todo/model";
+
+import "google/api/annotations.proto";
+import "google/protobuf/empty.proto";
+
+service TodoService {
+ rpc GetAll(google.protobuf.Empty) returns (GetAllResponse) {
+ option (google.api.http) = {
+ get : "/todos",
+ };
+ }
+
+ rpc GetByID(GetByIDRequest) returns (GetByIDResponse) {
+ option (google.api.http) = {
+ get : "/todos/{id}",
+ };
+ }
+
+ rpc Create(Todo) returns (MutationResponse) {
+ option (google.api.http) = {
+ post : "/todos",
+ body : "*",
+ };
+ }
+
+ rpc Update(UpdateRequest) returns (MutationResponse) {
+ option (google.api.http) = {
+ put : "/todos/{id}",
+ body : "*",
+ };
+ }
+
+ rpc Delete(DeleteRequest) returns (MutationResponse) {
+ option (google.api.http) = {
+ delete : "/todos/{id}",
+ };
+ }
+}
+
+message Todo {
+ string id = 1;
+ string name = 2;
+}
+
+message GetAllResponse {
+ repeated Todo data = 1;
+}
+
+message GetAllRequest {
+ repeated Todo data = 1;
+}
+
+message GetByIDRequest {
+ string id = 1;
+}
+
+message GetByIDResponse {
+ Todo data = 1;
+}
+
+message MutationResponse {
+ string success = 1;
+}
+
+message UpdateRequest {
+ string id = 1;
+ string name = 2;
+}
+
+message DeleteRequest {
+ string id = 1;
+}
\ No newline at end of file
diff --git a/session-3/todo/common/model/todo_grpc.pb.go b/session-3/todo/common/model/todo_grpc.pb.go
new file mode 100644
index 0000000..d67867b
--- /dev/null
+++ b/session-3/todo/common/model/todo_grpc.pb.go
@@ -0,0 +1,250 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.2.0
+// - protoc (unknown)
+// source: common/model/todo.proto
+
+package model
+
+import (
+ context "context"
+ grpc "google.golang.org/grpc"
+ codes "google.golang.org/grpc/codes"
+ status "google.golang.org/grpc/status"
+ emptypb "google.golang.org/protobuf/types/known/emptypb"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+// TodoServiceClient is the client API for TodoService service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type TodoServiceClient interface {
+ GetAll(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetAllResponse, error)
+ GetByID(ctx context.Context, in *GetByIDRequest, opts ...grpc.CallOption) (*GetByIDResponse, error)
+ Create(ctx context.Context, in *Todo, opts ...grpc.CallOption) (*MutationResponse, error)
+ Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*MutationResponse, error)
+ Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*MutationResponse, error)
+}
+
+type todoServiceClient struct {
+ cc grpc.ClientConnInterface
+}
+
+func NewTodoServiceClient(cc grpc.ClientConnInterface) TodoServiceClient {
+ return &todoServiceClient{cc}
+}
+
+func (c *todoServiceClient) GetAll(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetAllResponse, error) {
+ out := new(GetAllResponse)
+ err := c.cc.Invoke(ctx, "/session3.todo.model.TodoService/GetAll", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *todoServiceClient) GetByID(ctx context.Context, in *GetByIDRequest, opts ...grpc.CallOption) (*GetByIDResponse, error) {
+ out := new(GetByIDResponse)
+ err := c.cc.Invoke(ctx, "/session3.todo.model.TodoService/GetByID", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *todoServiceClient) Create(ctx context.Context, in *Todo, opts ...grpc.CallOption) (*MutationResponse, error) {
+ out := new(MutationResponse)
+ err := c.cc.Invoke(ctx, "/session3.todo.model.TodoService/Create", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *todoServiceClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*MutationResponse, error) {
+ out := new(MutationResponse)
+ err := c.cc.Invoke(ctx, "/session3.todo.model.TodoService/Update", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func (c *todoServiceClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*MutationResponse, error) {
+ out := new(MutationResponse)
+ err := c.cc.Invoke(ctx, "/session3.todo.model.TodoService/Delete", in, out, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// TodoServiceServer is the server API for TodoService service.
+// All implementations must embed UnimplementedTodoServiceServer
+// for forward compatibility
+type TodoServiceServer interface {
+ GetAll(context.Context, *emptypb.Empty) (*GetAllResponse, error)
+ GetByID(context.Context, *GetByIDRequest) (*GetByIDResponse, error)
+ Create(context.Context, *Todo) (*MutationResponse, error)
+ Update(context.Context, *UpdateRequest) (*MutationResponse, error)
+ Delete(context.Context, *DeleteRequest) (*MutationResponse, error)
+ mustEmbedUnimplementedTodoServiceServer()
+}
+
+// UnimplementedTodoServiceServer must be embedded to have forward compatible implementations.
+type UnimplementedTodoServiceServer struct {
+}
+
+func (UnimplementedTodoServiceServer) GetAll(context.Context, *emptypb.Empty) (*GetAllResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetAll not implemented")
+}
+func (UnimplementedTodoServiceServer) GetByID(context.Context, *GetByIDRequest) (*GetByIDResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method GetByID not implemented")
+}
+func (UnimplementedTodoServiceServer) Create(context.Context, *Todo) (*MutationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Create not implemented")
+}
+func (UnimplementedTodoServiceServer) Update(context.Context, *UpdateRequest) (*MutationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Update not implemented")
+}
+func (UnimplementedTodoServiceServer) Delete(context.Context, *DeleteRequest) (*MutationResponse, error) {
+ return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
+}
+func (UnimplementedTodoServiceServer) mustEmbedUnimplementedTodoServiceServer() {}
+
+// UnsafeTodoServiceServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to TodoServiceServer will
+// result in compilation errors.
+type UnsafeTodoServiceServer interface {
+ mustEmbedUnimplementedTodoServiceServer()
+}
+
+func RegisterTodoServiceServer(s grpc.ServiceRegistrar, srv TodoServiceServer) {
+ s.RegisterService(&TodoService_ServiceDesc, srv)
+}
+
+func _TodoService_GetAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(emptypb.Empty)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TodoServiceServer).GetAll(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/session3.todo.model.TodoService/GetAll",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TodoServiceServer).GetAll(ctx, req.(*emptypb.Empty))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _TodoService_GetByID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(GetByIDRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TodoServiceServer).GetByID(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/session3.todo.model.TodoService/GetByID",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TodoServiceServer).GetByID(ctx, req.(*GetByIDRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _TodoService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(Todo)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TodoServiceServer).Create(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/session3.todo.model.TodoService/Create",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TodoServiceServer).Create(ctx, req.(*Todo))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _TodoService_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(UpdateRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TodoServiceServer).Update(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/session3.todo.model.TodoService/Update",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TodoServiceServer).Update(ctx, req.(*UpdateRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+func _TodoService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+ in := new(DeleteRequest)
+ if err := dec(in); err != nil {
+ return nil, err
+ }
+ if interceptor == nil {
+ return srv.(TodoServiceServer).Delete(ctx, in)
+ }
+ info := &grpc.UnaryServerInfo{
+ Server: srv,
+ FullMethod: "/session3.todo.model.TodoService/Delete",
+ }
+ handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+ return srv.(TodoServiceServer).Delete(ctx, req.(*DeleteRequest))
+ }
+ return interceptor(ctx, in, info, handler)
+}
+
+// TodoService_ServiceDesc is the grpc.ServiceDesc for TodoService service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var TodoService_ServiceDesc = grpc.ServiceDesc{
+ ServiceName: "session3.todo.model.TodoService",
+ HandlerType: (*TodoServiceServer)(nil),
+ Methods: []grpc.MethodDesc{
+ {
+ MethodName: "GetAll",
+ Handler: _TodoService_GetAll_Handler,
+ },
+ {
+ MethodName: "GetByID",
+ Handler: _TodoService_GetByID_Handler,
+ },
+ {
+ MethodName: "Create",
+ Handler: _TodoService_Create_Handler,
+ },
+ {
+ MethodName: "Update",
+ Handler: _TodoService_Update_Handler,
+ },
+ {
+ MethodName: "Delete",
+ Handler: _TodoService_Delete_Handler,
+ },
+ },
+ Streams: []grpc.StreamDesc{},
+ Metadata: "common/model/todo.proto",
+}
diff --git a/session-3/todo/docs/openapiv2/common/model/todo.swagger.json b/session-3/todo/docs/openapiv2/common/model/todo.swagger.json
new file mode 100644
index 0000000..746bc05
--- /dev/null
+++ b/session-3/todo/docs/openapiv2/common/model/todo.swagger.json
@@ -0,0 +1,238 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "title": "common/model/todo.proto",
+ "version": "version not set"
+ },
+ "tags": [
+ {
+ "name": "TodoService"
+ }
+ ],
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "paths": {
+ "/todos": {
+ "get": {
+ "operationId": "TodoService_GetAll",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/modelGetAllResponse"
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "schema": {
+ "$ref": "#/definitions/rpcStatus"
+ }
+ }
+ },
+ "tags": [
+ "TodoService"
+ ]
+ },
+ "post": {
+ "operationId": "TodoService_Create",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/modelMutationResponse"
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "schema": {
+ "$ref": "#/definitions/rpcStatus"
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/modelTodo"
+ }
+ }
+ ],
+ "tags": [
+ "TodoService"
+ ]
+ }
+ },
+ "/todos/{id}": {
+ "get": {
+ "operationId": "TodoService_GetByID",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/modelGetByIDResponse"
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "schema": {
+ "$ref": "#/definitions/rpcStatus"
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "tags": [
+ "TodoService"
+ ]
+ },
+ "delete": {
+ "operationId": "TodoService_Delete",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/modelMutationResponse"
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "schema": {
+ "$ref": "#/definitions/rpcStatus"
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "tags": [
+ "TodoService"
+ ]
+ },
+ "put": {
+ "operationId": "TodoService_Update",
+ "responses": {
+ "200": {
+ "description": "A successful response.",
+ "schema": {
+ "$ref": "#/definitions/modelMutationResponse"
+ }
+ },
+ "default": {
+ "description": "An unexpected error response.",
+ "schema": {
+ "$ref": "#/definitions/rpcStatus"
+ }
+ }
+ },
+ "parameters": [
+ {
+ "name": "id",
+ "in": "path",
+ "required": true,
+ "type": "string"
+ },
+ {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ ],
+ "tags": [
+ "TodoService"
+ ]
+ }
+ }
+ },
+ "definitions": {
+ "modelGetAllResponse": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/modelTodo"
+ }
+ }
+ }
+ },
+ "modelGetByIDResponse": {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/definitions/modelTodo"
+ }
+ }
+ },
+ "modelMutationResponse": {
+ "type": "object",
+ "properties": {
+ "success": {
+ "type": "string"
+ }
+ }
+ },
+ "modelTodo": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "protobufAny": {
+ "type": "object",
+ "properties": {
+ "@type": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": {}
+ },
+ "rpcStatus": {
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "message": {
+ "type": "string"
+ },
+ "details": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/protobufAny"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/session-3/todo/main.go b/session-3/todo/main.go
new file mode 100644
index 0000000..8b56773
--- /dev/null
+++ b/session-3/todo/main.go
@@ -0,0 +1,87 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "flag"
+ "net"
+ "net/http"
+
+ "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
+ "github.com/ibrahimker/golang-intermediate/session-3/todo/common/config"
+ "github.com/ibrahimker/golang-intermediate/session-3/todo/common/model"
+ log "github.com/sirupsen/logrus"
+ "google.golang.org/grpc"
+ "google.golang.org/grpc/credentials/insecure"
+ "google.golang.org/protobuf/types/known/emptypb"
+)
+
+type TodoServer struct {
+ model.UnimplementedTodoServiceServer
+}
+
+var Todos = make(map[string]*model.Todo)
+
+func main() {
+ srv := grpc.NewServer()
+ userSrv := new(TodoServer)
+ model.RegisterTodoServiceServer(srv, userSrv)
+
+ log.Println("Starting Todo Server at ", config.SERVICE_TODO_PORT)
+
+ listener, err := net.Listen("tcp", config.SERVICE_TODO_PORT)
+ if err != nil {
+ log.Fatalf("could not listen. Err: %+v\n", err)
+ }
+
+ // setup http proxy
+ go func() {
+ mux := runtime.NewServeMux()
+ opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
+ grpcServerEndpoint := flag.String("grpc-server-endpoint", "localhost"+config.SERVICE_TODO_PORT, "gRPC server endpoint")
+ _ = model.RegisterTodoServiceHandlerFromEndpoint(context.Background(), r, *grpcServerEndpoint, opts)
+ log.Println("Starting Todo Server HTTP at 9001 ")
+ http.ListenAndServe(":9001", mux)
+ }()
+
+ log.Fatalln(srv.Serve(listener))
+}
+
+func (t *TodoServer) GetAll(ctx context.Context, req *emptypb.Empty) (*model.GetAllResponse, error) {
+ var todos []*model.Todo
+ for _, v := range Todos {
+ todos = append(todos, &model.Todo{
+ Id: v.GetId(),
+ Name: v.GetName(),
+ })
+ }
+ return &model.GetAllResponse{Data: todos}, nil
+}
+func (t *TodoServer) GetByID(ctx context.Context, req *model.GetByIDRequest) (*model.GetByIDResponse, error) {
+ todo, ok := Todos[req.GetId()]
+ if !ok {
+ return nil, errors.New("not found")
+ }
+ return &model.GetByIDResponse{Data: todo}, nil
+}
+func (t *TodoServer) Create(ctx context.Context, req *model.Todo) (*model.MutationResponse, error) {
+ Todos[req.GetId()] = &model.Todo{
+ Id: req.GetId(),
+ Name: req.GetName(),
+ }
+ msg := req.GetId() + "successfully appended"
+ return &model.MutationResponse{Success: msg}, nil
+}
+func (t *TodoServer) Update(ctx context.Context, req *model.UpdateRequest) (*model.MutationResponse, error) {
+ Todos[req.GetId()] = &model.Todo{
+ Id: req.GetId(),
+ Name: req.GetName(),
+ }
+ msg := req.GetId() + "successfully appended"
+ return &model.MutationResponse{Success: msg}, nil
+}
+func (t *TodoServer) Delete(ctx context.Context, req *model.DeleteRequest) (*model.MutationResponse, error) {
+ delete(Todos, req.GetId())
+ msg := req.GetId() + "successfully deleted"
+ return &model.MutationResponse{Success: msg}, nil
+}
diff --git a/session-4/login.html b/session-4/login.html
new file mode 100644
index 0000000..2834e67
--- /dev/null
+++ b/session-4/login.html
@@ -0,0 +1,18 @@
+
+
+ Template
+
+
+
+
+
\ No newline at end of file
diff --git a/session-4/main.go b/session-4/main.go
index 3b159e3..f0799c8 100644
--- a/session-4/main.go
+++ b/session-4/main.go
@@ -2,79 +2,45 @@ package main
import (
"fmt"
- "html/template"
"net/http"
+ "github.com/go-ldap/ldap"
+ "github.com/ibrahimker/golang-intermediate/session-4/config"
+ "github.com/ibrahimker/golang-intermediate/session-4/repository"
+ "github.com/ibrahimker/golang-intermediate/session-4/router"
+ "github.com/ibrahimker/golang-intermediate/session-4/service"
log "github.com/sirupsen/logrus"
"github.com/gorilla/mux"
- "github.com/ibrahimker/golang-intermediate/session-4/ldap"
)
const (
port = "9000"
baseURL = "0.0.0.0:" + port
- view = `
-
-
- Template
-
-
-
-
-
- `
)
func main() {
log.SetReportCaller(true)
- r := mux.NewRouter()
- r.HandleFunc("/", handleRoute)
- r.HandleFunc("/login", handleLogin)
- log.Infoln("Listening at ", baseURL)
- log.Fatal(http.ListenAndServe(baseURL, r))
-}
-
-func handleRoute(w http.ResponseWriter, r *http.Request) {
- tmpl := template.Must(template.New("main-template").Parse(view))
- if err := tmpl.Execute(w, nil); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ // init ldap connection
+ ldapConn, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", config.LdapServer, config.LdapPort))
+ if err != nil {
+ panic(err)
}
-}
-
-func handleLogin(w http.ResponseWriter, r *http.Request) {
- if err := r.ParseForm(); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ defer ldapConn.Close()
+ // bind to ldap server
+ if err = ldapConn.Bind(config.LdapBindDN, config.LdapPassword); err != nil {
+ panic(err)
}
- username := r.PostFormValue("username")
- password := r.PostFormValue("password")
+ ldapRepo := repository.NewLDAPRepo(ldapConn)
+ loginService := service.NewLoginService(ldapRepo)
- ok, data, err := ldap.AuthUsingLDAP(username, password)
- if !ok {
- log.Error("auth using ldap not ok")
- http.Error(w, "invalid username/password", http.StatusUnauthorized)
- return
- }
- if err != nil {
- log.Error(err)
- http.Error(w, err.Error(), http.StatusUnauthorized)
- return
- }
+ r := mux.NewRouter()
+ routerHandler := router.NewRouterHandler(loginService)
+ r.HandleFunc("/", routerHandler.ServeHTML)
+ r.HandleFunc("/login", routerHandler.HandleLogin)
- message := fmt.Sprintf("Welcome %s\n", data.FullName)
- w.Write([]byte(message))
+ log.Infoln("Listening at ", baseURL)
+ log.Fatal(http.ListenAndServe(baseURL, r))
}
diff --git a/session-4/ldap/ldap.go b/session-4/repository/ldap.go
similarity index 57%
rename from session-4/ldap/ldap.go
rename to session-4/repository/ldap.go
index 980c027..11dcbbd 100644
--- a/session-4/ldap/ldap.go
+++ b/session-4/repository/ldap.go
@@ -1,22 +1,15 @@
-package ldap
+package repository
import (
"errors"
"fmt"
+ "github.com/ibrahimker/golang-intermediate/session-4/config"
log "github.com/sirupsen/logrus"
"github.com/go-ldap/ldap"
)
-const (
- ldapServer = "ldap.forumsys.com"
- ldapPort = 389
- ldapBindDN = "cn=read-only-admin,dc=example,dc=com"
- ldapPassword = "password"
- ldapSearchDN = "dc=example,dc=com"
-)
-
type UserLDAPData struct {
ID string
Email string
@@ -24,23 +17,17 @@ type UserLDAPData struct {
FullName string
}
-func AuthUsingLDAP(username, password string) (bool, *UserLDAPData, error) {
-
- // init ldap connection
- l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
- if err != nil {
- log.Error(err)
- return false, nil, err
- }
- defer l.Close()
+type LDAPRepo struct {
+ conn *ldap.Conn
+}
- // bind to ldap server
- if err = l.Bind(ldapBindDN, ldapPassword); err != nil {
- return false, nil, err
- }
+func NewLDAPRepo(conn *ldap.Conn) *LDAPRepo {
+ return &LDAPRepo{conn: conn}
+}
+func (r *LDAPRepo) AuthUsingLDAP(username, password string) (bool, *UserLDAPData, error) {
searchRequest := ldap.NewSearchRequest(
- ldapSearchDN,
+ config.LdapSearchDN,
ldap.ScopeWholeSubtree,
ldap.NeverDerefAliases,
0,
@@ -51,7 +38,7 @@ func AuthUsingLDAP(username, password string) (bool, *UserLDAPData, error) {
nil,
)
- sr, err := l.Search(searchRequest)
+ sr, err := r.conn.Search(searchRequest)
if err != nil {
log.Error(err)
return false, nil, err
@@ -62,7 +49,7 @@ func AuthUsingLDAP(username, password string) (bool, *UserLDAPData, error) {
}
entry := sr.Entries[0]
- if err = l.Bind(entry.DN, password); err != nil {
+ if err = r.conn.Bind(entry.DN, password); err != nil {
log.Error(err)
return false, nil, err
}
diff --git a/session-4/router/router.go b/session-4/router/router.go
new file mode 100644
index 0000000..6219081
--- /dev/null
+++ b/session-4/router/router.go
@@ -0,0 +1,44 @@
+package router
+
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+
+ "github.com/ibrahimker/golang-intermediate/session-4/service"
+)
+
+type RouterHandler struct {
+ loginService *service.LoginSvc
+}
+
+func NewRouterHandler(loginService *service.LoginSvc) *RouterHandler {
+ return &RouterHandler{loginService: loginService}
+}
+
+func (rh *RouterHandler) ServeHTML(w http.ResponseWriter, r *http.Request) {
+ parsedTemplate, _ := template.ParseFiles("login.html")
+ if err := parsedTemplate.Execute(w, nil); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
+func (rh *RouterHandler) HandleLogin(w http.ResponseWriter, r *http.Request) {
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ username := r.PostFormValue("username")
+ password := r.PostFormValue("password")
+
+ data, err := rh.loginService.Authenticate(username, password)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusUnauthorized)
+ return
+ }
+
+ message := fmt.Sprintf("Welcome Name: %s, FullName: %s, Email: %s\n", data.Name, data.FullName, data.Email)
+ w.Write([]byte(message))
+}
diff --git a/session-4/service/login.go b/session-4/service/login.go
new file mode 100644
index 0000000..82358af
--- /dev/null
+++ b/session-4/service/login.go
@@ -0,0 +1,31 @@
+package service
+
+import (
+ "errors"
+
+ "github.com/ibrahimker/golang-intermediate/session-4/repository"
+ log "github.com/sirupsen/logrus"
+)
+
+type LoginSvc struct {
+ loginRepo *repository.LDAPRepo
+}
+
+func NewLoginService(loginRepo *repository.LDAPRepo) *LoginSvc {
+ return &LoginSvc{loginRepo: loginRepo}
+}
+
+func (s *LoginSvc) Authenticate(username, password string) (*repository.UserLDAPData, error) {
+ ok, data, err := s.loginRepo.AuthUsingLDAP(username, password)
+ if !ok {
+ err := errors.New("auth using ldap not ok")
+ log.Error("auth using ldap not ok")
+ return nil, err
+ }
+ if err != nil {
+ log.Error(err)
+ return nil, err
+ }
+
+ return data, nil
+}
diff --git a/session-5/main.go b/session-5/main.go
new file mode 100644
index 0000000..1d60855
--- /dev/null
+++ b/session-5/main.go
@@ -0,0 +1,106 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/go-playground/validator"
+ "github.com/labstack/echo"
+)
+
+type M map[string]interface{}
+
+type User struct {
+ Name string `json:"name" form:"name" query:"name" validate:"required"`
+ Email string `json:"email" form:"email" query:"email" validate:"required,email"`
+}
+
+type CustomValidator struct {
+ validator *validator.Validate
+}
+
+func (cv *CustomValidator) Validate(i interface{}) error {
+ return cv.validator.Struct(i)
+}
+
+func main() {
+ r := echo.New()
+ r.Validator = &CustomValidator{validator: validator.New()}
+
+ r.GET("/", func(ctx echo.Context) error {
+ data := "Hello from /index"
+ return ctx.String(http.StatusOK, data)
+ })
+
+ r.GET("/index", func(ctx echo.Context) error {
+ data := "Hello from /index"
+ return ctx.String(http.StatusOK, data)
+ })
+
+ r.GET("/html", func(ctx echo.Context) error {
+ data := "Hello from /html"
+ return ctx.HTML(http.StatusOK, data)
+ })
+
+ r.GET("/index", func(ctx echo.Context) error {
+ return ctx.Redirect(http.StatusTemporaryRedirect, "/")
+ })
+
+ r.GET("/json", func(ctx echo.Context) error {
+ data := M{"Message": "Hello", "Counter": 2}
+ return ctx.JSON(http.StatusOK, data)
+ })
+
+ r.GET("/page1", func(ctx echo.Context) error {
+ name := ctx.QueryParam("name")
+ data := fmt.Sprintf("Hello %s", name)
+
+ return ctx.String(http.StatusOK, data)
+ })
+
+ r.GET("/page2/:name", func(ctx echo.Context) error {
+ name := ctx.Param("name")
+ data := fmt.Sprintf("Hello %s", name)
+
+ return ctx.String(http.StatusOK, data)
+ })
+
+ r.GET("/page3/:name/*", func(ctx echo.Context) error {
+ name := ctx.Param("name")
+ message := ctx.Param("*")
+
+ data := fmt.Sprintf("Hello %s, I have message for you: %s", name, message)
+
+ return ctx.String(http.StatusOK, data)
+ })
+
+ r.POST("/page4", func(ctx echo.Context) error {
+ name := ctx.FormValue("name")
+ message := ctx.FormValue("message")
+
+ data := fmt.Sprintf(
+ "Hello %s, I have message for you: %s",
+ name,
+ strings.Replace(message, "/", "", 1),
+ )
+
+ return ctx.String(http.StatusOK, data)
+ })
+
+ r.POST("/user", func(ctx echo.Context) error {
+ u := new(User)
+
+ if err := ctx.Bind(u); err != nil {
+ return ctx.String(http.StatusInternalServerError, err.Error())
+ }
+
+ if err := ctx.Validate(u); err != nil {
+ return ctx.String(http.StatusBadRequest, err.Error())
+ }
+
+ return ctx.JSON(http.StatusOK, u)
+ })
+
+ r.Start(":9000")
+}
diff --git a/session-6/docker-compose.yaml b/session-6/docker-compose.yaml
new file mode 100644
index 0000000..165a29a
--- /dev/null
+++ b/session-6/docker-compose.yaml
@@ -0,0 +1,11 @@
+version: '3'
+
+services:
+ postgres:
+ image: postgres:13.2-alpine
+ environment:
+ - POSTGRES_USER=postgresuser
+ - POSTGRES_PASSWORD=postgrespassword
+ - POSTGRES_DB=postgres
+ ports:
+ - 5432:5432
diff --git a/session-6/main.go b/session-6/main.go
new file mode 100644
index 0000000..7d513f4
--- /dev/null
+++ b/session-6/main.go
@@ -0,0 +1,88 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+
+ "github.com/antonlindstrom/pgstore"
+ "github.com/gorilla/sessions"
+ "github.com/labstack/echo"
+)
+
+const SESSION_ID = "test-session-id"
+
+func newPostgresStore() *pgstore.PGStore {
+ url := "postgres://postgresuser:postgrespassword@127.0.0.1:5432/postgres?sslmode=disable"
+ authKey := []byte("my-auth-key-very-secret")
+ encryptionKey := []byte("my-encryption-key-very-secret123")
+
+ store, err := pgstore.NewPGStore(url, authKey, encryptionKey)
+ if err != nil {
+ log.Println("ERROR", err)
+ os.Exit(0)
+ }
+
+ return store
+}
+
+func newCookieStore() *sessions.CookieStore {
+ authKey := []byte("my-auth-key-very-secret")
+ encryptionKey := []byte("my-encryption-key-very-secret123")
+
+ store := sessions.NewCookieStore(authKey, encryptionKey)
+ store.Options.Path = "/"
+ store.Options.MaxAge = 86400 * 7
+ store.Options.HttpOnly = true
+
+ return store
+}
+
+func main() {
+ e := echo.New()
+ store := newPostgresStore()
+
+ e.GET("/", func(ctx echo.Context) error {
+ data := "Hello from /index"
+ return ctx.String(http.StatusOK, data)
+ })
+
+ e.GET("/set", func(c echo.Context) error {
+ session, err := store.Get(c.Request(), SESSION_ID)
+ if err != nil {
+ return c.String(http.StatusInternalServerError, err.Error())
+ }
+ session.Values["message1"] = "hello"
+ session.Values["message2"] = "world"
+ if err := session.Save(c.Request(), c.Response()); err != nil {
+ return c.String(http.StatusInternalServerError, err.Error())
+ }
+
+ return c.Redirect(http.StatusTemporaryRedirect, "/get")
+ })
+
+ e.GET("/get", func(c echo.Context) error {
+ session, _ := store.Get(c.Request(), SESSION_ID)
+
+ if len(session.Values) == 0 {
+ return c.String(http.StatusOK, "empty result")
+ }
+
+ return c.String(http.StatusOK, fmt.Sprintf(
+ "%s %s",
+ session.Values["message1"],
+ session.Values["message2"],
+ ))
+ })
+
+ e.GET("/delete", func(c echo.Context) error {
+ session, _ := store.Get(c.Request(), SESSION_ID)
+ session.Options.MaxAge = -1
+ session.Save(c.Request(), c.Response())
+
+ return c.Redirect(http.StatusTemporaryRedirect, "/get")
+ })
+
+ e.Start(":9000")
+}
diff --git a/session-7/main.go b/session-7/main.go
new file mode 100644
index 0000000..a6a5bd2
--- /dev/null
+++ b/session-7/main.go
@@ -0,0 +1,124 @@
+package main
+
+import (
+ "io"
+ "log"
+ "os"
+
+ "github.com/pkg/sftp"
+ "golang.org/x/crypto/ssh"
+)
+
+func main() {
+ const SSH_ADDRESS = "0.0.0.0:22"
+ const SSH_USERNAME = "user"
+ const SSH_PASSWORD = "password"
+
+ sshConfig := &ssh.ClientConfig{
+ User: SSH_USERNAME,
+ HostKeyCallback: ssh.InsecureIgnoreHostKey(),
+ Auth: []ssh.AuthMethod{
+ ssh.Password(SSH_PASSWORD),
+ },
+ }
+
+ // dial ssh
+ client, err := ssh.Dial("tcp", SSH_ADDRESS, sshConfig)
+ if client != nil {
+ defer client.Close()
+ }
+ if err != nil {
+ log.Fatal("Failed to dial. " + err.Error())
+ }
+
+ // create session
+ session, err := client.NewSession()
+ if err != nil {
+ log.Fatal("Failed to create session. " + err.Error())
+ }
+ //session.Stdin = os.Stdin
+ session.Stdout = os.Stdout
+ session.Stderr = os.Stderr
+
+ // test session
+ stdinBuf, _ := session.StdinPipe()
+ if err := session.Shell(); err != nil {
+ panic(err)
+ }
+ stdinBuf.Write([]byte("echo hello\n"))
+ stdinBuf.Write([]byte("ls -l ~/\n"))
+ //err = session.Run("ls -l ~/")
+ //if err != nil {
+ // log.Fatal("Command execution error. " + err.Error())
+ //}
+
+ // test StdinPipe
+ //var stdout, stderr bytes.Buffer
+ //session.Stdout = &stdout
+ //session.Stderr = &stderr
+ //
+ //stdin, err := session.StdinPipe()
+ //if err != nil {
+ // log.Fatal("Error getting stdin pipe. " + err.Error())
+ //}
+ //
+ //err = session.Start("/bin/bash")
+ //if err != nil {
+ // log.Fatal("Error starting bash. " + err.Error())
+ //}
+ //
+ //commands := []string{
+ // "cd /where/is/the/path",
+ // "cd src/myproject",
+ // "ls",
+ // "exit",
+ //}
+ //for _, cmd := range commands {
+ // if _, err = fmt.Fprintln(stdin, cmd); err != nil {
+ // log.Fatal(err)
+ // }
+ //}
+ //
+ //err = session.Wait()
+ //if err != nil {
+ // log.Fatal(err)
+ //}
+ //
+ //outputErr := stderr.String()
+ //fmt.Println("============== ERROR")
+ //fmt.Println(strings.TrimSpace(outputErr))
+ //
+ //outputString := stdout.String()
+ //fmt.Println("============== OUTPUT")
+ //fmt.Println(strings.TrimSpace(outputString))
+
+ // test sftp
+ sftpClient, err := sftp.NewClient(client)
+ if err != nil {
+ log.Fatal("Failed create client sftp client. " + err.Error())
+ }
+
+ //err = session.Run("touch ~/test-file.txt")
+ //if err != nil {
+ // log.Fatal("Command execution error. " + err.Error())
+ //}
+ //session.Close()
+ fDestination, err := sftpClient.Create("/home/user/test-file.txt")
+ if err != nil {
+ log.Fatal("Failed to create destination file. " + err.Error())
+ }
+
+ fSource, err := os.Open("/home/ibam/Documents/code/golang-intermediate/session-7/test-file.txt")
+ if err != nil {
+ log.Fatal("Failed to read source file. " + err.Error())
+ }
+
+ _, err = io.Copy(fDestination, fSource)
+ if err != nil {
+ log.Fatal("Failed copy source file into destination file. " + err.Error())
+ }
+
+ log.Println("File copied.")
+
+ // create new session
+}
diff --git a/session-7/test-file.txt b/session-7/test-file.txt
new file mode 100644
index 0000000..9f6398f
--- /dev/null
+++ b/session-7/test-file.txt
@@ -0,0 +1 @@
+hai
\ No newline at end of file
diff --git a/session-8/main.go b/session-8/main.go
new file mode 100644
index 0000000..3705a20
--- /dev/null
+++ b/session-8/main.go
@@ -0,0 +1,107 @@
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/ibrahimker/golang-intermediate/session-8/middleware"
+ "github.com/labstack/echo"
+ echoMiddleware "github.com/labstack/echo/middleware"
+ "github.com/sirupsen/logrus"
+ "github.com/spf13/viper"
+)
+
+func main() {
+ viper.AddConfigPath("./config")
+ viper.SetConfigName("config.yaml")
+ viper.SetConfigType("yaml")
+ if err := viper.ReadInConfig(); err != nil {
+ panic(err)
+ }
+
+ e := echo.New()
+ e.Use(middlewareOne)
+ e.Use(middlewareTwo)
+ e.Use(echo.WrapMiddleware(middlewareSomething))
+ //e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
+ // Format: "method=${method}, uri=${uri}, status=${status}\n",
+ //}))
+
+ // with logrus
+ e.Use(middlewareLogging)
+ e.HTTPErrorHandler = errorHandler
+
+ // middleware here
+
+ e.GET("/index", func(c echo.Context) (err error) {
+ fmt.Println("threeeeee!")
+
+ return c.JSON(http.StatusOK, true)
+ })
+
+ private := e.Group("/private")
+ private.Use(echoMiddleware.BasicAuth(middleware.BasicAuthMiddleware))
+ private.GET("/index", func(c echo.Context) (err error) {
+ fmt.Println("threeeeee!")
+
+ return c.JSON(http.StatusOK, true)
+ })
+
+ e.Logger.Fatal(e.Start(":9000"))
+}
+
+func middlewareOne(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ fmt.Println("from middleware one")
+ return next(c)
+ }
+}
+
+func middlewareTwo(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ fmt.Println("from middleware two")
+ return next(c)
+ }
+}
+
+func middlewareSomething(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Println("from middleware something")
+ next.ServeHTTP(w, r)
+ })
+}
+
+func makeLogEntry(c echo.Context) *logrus.Entry {
+ if c == nil {
+ return logrus.WithFields(logrus.Fields{
+ "at": time.Now().Format("2006-01-02 15:04:05"),
+ })
+ }
+
+ return logrus.WithFields(logrus.Fields{
+ "at": time.Now().Format("2006-01-02 15:04:05"),
+ "method": c.Request().Method,
+ "uri": c.Request().URL.String(),
+ "ip": c.Request().RemoteAddr,
+ })
+}
+
+func middlewareLogging(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ makeLogEntry(c).Info("incoming request")
+ return next(c)
+ }
+}
+
+func errorHandler(err error, c echo.Context) {
+ report, ok := err.(*echo.HTTPError)
+ if ok {
+ report.Message = fmt.Sprintf("http error %d - %v", report.Code, report.Message)
+ } else {
+ report = echo.NewHTTPError(http.StatusInternalServerError, err.Error())
+ }
+
+ makeLogEntry(c).Error(report.Message)
+ c.HTML(report.Code, report.Message.(string))
+}
diff --git a/session-8/middleware/basicauth.go b/session-8/middleware/basicauth.go
new file mode 100644
index 0000000..26feac9
--- /dev/null
+++ b/session-8/middleware/basicauth.go
@@ -0,0 +1,14 @@
+package middleware
+
+import (
+ "github.com/labstack/echo"
+ "github.com/spf13/viper"
+)
+
+func BasicAuthMiddleware(username, password string, c echo.Context) (bool, error) {
+ // Be careful to use constant time comparison to prevent timing attacks
+ if username == viper.GetString("BasicAuthUser") && password == viper.GetString("BasicAuthPass") {
+ return true, nil
+ }
+ return false, nil
+}
diff --git a/session-9/main.go b/session-9/main.go
new file mode 100644
index 0000000..96ad28d
--- /dev/null
+++ b/session-9/main.go
@@ -0,0 +1,47 @@
+package main
+
+import (
+ "fmt"
+ "html/template"
+ "net/http"
+
+ "github.com/labstack/echo"
+ "github.com/labstack/echo/middleware"
+)
+
+type M map[string]interface{}
+
+const (
+ CSRFTokenHeader = "X-CSRF-Token"
+ CSRFKey = "csrf"
+)
+
+func main() {
+ tmpl := template.Must(template.ParseGlob("./*.html"))
+
+ e := echo.New()
+
+ e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{
+ TokenLookup: "header:" + CSRFTokenHeader,
+ ContextKey: CSRFKey,
+ CookieMaxAge: 60,
+ }))
+
+ e.GET("/index", func(c echo.Context) error {
+ data := make(M)
+ data[CSRFKey] = c.Get(CSRFKey)
+ return tmpl.Execute(c.Response(), data)
+ })
+
+ e.POST("/sayhello", func(c echo.Context) error {
+ data := make(M)
+ if err := c.Bind(&data); err != nil {
+ return err
+ }
+
+ message := fmt.Sprintf("hello %s", data["name"])
+ return c.JSON(http.StatusOK, message)
+ })
+
+ e.Logger.Fatal(e.Start(":9000"))
+}
diff --git a/session-9/view.html b/session-9/view.html
new file mode 100644
index 0000000..5a5ff93
--- /dev/null
+++ b/session-9/view.html
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file