├── README.md ├── docker-compose.yml ├── random.go ├── go.mod ├── LICENSE ├── config.go ├── poolurl.go ├── example_test.go ├── package_test.go ├── testpool.go └── go.sum /README.md: -------------------------------------------------------------------------------- 1 | [![Go Reference](https://pkg.go.dev/badge/github.com/go-pa/pgxtesting.svg)](https://pkg.go.dev/github.com/go-pa/pgxtesting) 2 | 3 | # pgxtesting 4 | 5 | A Go package to give each test it's own database when testing projects that use 6 | [pgx](https://github.com/jackc/pgx). 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | postgres: 4 | image: postgres:13 5 | ports: 6 | - "45432:5432" 7 | command: postgres -c 'max_connections=1000' 8 | environment: 9 | POSTGRES_USER: test 10 | POSTGRES_PASSWORD: test 11 | POSTGRES_DB: test 12 | 13 | 14 | -------------------------------------------------------------------------------- /random.go: -------------------------------------------------------------------------------- 1 | package pgxtesting 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | var ( 11 | random = rand.New(rand.NewSource(time.Now().UTC().UnixNano())) 12 | randomMu sync.Mutex 13 | ) 14 | 15 | func getRandomDBName() string { 16 | randomMu.Lock() 17 | defer randomMu.Unlock() 18 | return fmt.Sprintf("pgxtesting_%v", random.Int63()) 19 | } 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/go-pa/pgxtesting 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/jackc/pgconn v1.10.1 7 | github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 8 | github.com/jackc/pgx/v4 v4.14.1 9 | ) 10 | 11 | require ( 12 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 13 | github.com/jackc/pgio v1.0.0 // indirect 14 | github.com/jackc/pgpassfile v1.0.0 // indirect 15 | github.com/jackc/pgproto3/v2 v2.2.0 // indirect 16 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect 17 | github.com/jackc/pgtype v1.9.1 // indirect 18 | github.com/jackc/puddle v1.2.1 // indirect 19 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect 20 | golang.org/x/text v0.3.7 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Thomas Frössman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package pgxtesting 2 | 3 | import ( 4 | "net/url" 5 | "os" 6 | "sync" 7 | ) 8 | 9 | var ( 10 | configMu sync.Mutex 11 | defaultURL = "postgres://test:test@localhost:5432/test?sslmode=disable&pool_max_conns=500" 12 | envName = "PGURL" 13 | ) 14 | 15 | // SetDefaultURL sets the default URL for postgres tests, panics if the url is invalid 16 | func SetDefaultURL(pgxurl string) { 17 | _, err := url.Parse(pgxurl) 18 | if err != nil { 19 | panic(err) 20 | } 21 | configMu.Lock() 22 | defaultURL = pgxurl 23 | configMu.Unlock() 24 | } 25 | 26 | // SetDefaultURL returns the default URL used to connect to the postgres server 27 | // while creating and destorying test databases. 28 | func GetDefaultURL() string { 29 | configMu.Lock() 30 | defer configMu.Unlock() 31 | return defaultURL 32 | } 33 | 34 | // SetEnvName sets the enviroment variable name used to fetch the pgxpool URL, 35 | // defaults name is PGURL. 36 | func SetEnvName(name string) { 37 | configMu.Lock() 38 | envName = name 39 | configMu.Unlock() 40 | } 41 | 42 | // GetEnvName gets the enviroment variable name used to fetch the pgxpool URL, 43 | // defaults name is PGURL. 44 | func GetEnvName() string { 45 | configMu.Lock() 46 | defer configMu.Unlock() 47 | return envName 48 | } 49 | 50 | // GetURL returns the pgx pool URL from environment or the default value. 51 | func GetURL() string { 52 | v := os.Getenv(GetEnvName()) 53 | if v != "" { 54 | return v 55 | } 56 | return GetDefaultURL() 57 | } 58 | -------------------------------------------------------------------------------- /poolurl.go: -------------------------------------------------------------------------------- 1 | package pgxtesting 2 | 3 | import ( 4 | "net/url" 5 | "strings" 6 | ) 7 | 8 | // PoolURL makes for quick manipulation of some paramets that are important for 9 | // tests. The url is expected to always be a valid URL, utility functions will 10 | // panic if it's not. 11 | type PoolURL string 12 | 13 | // NewPoolURL validates the input yurl 14 | func NewPoolURL(poolURL string) (PoolURL, error) { 15 | _, err := url.Parse(poolURL) 16 | if err != nil { 17 | return "", err 18 | } 19 | return PoolURL(poolURL), nil 20 | } 21 | 22 | func (pu PoolURL) String() string { 23 | return string(pu) 24 | } 25 | 26 | // SetName sets the database name 27 | func (pu PoolURL) SetName(dbName string) PoolURL { 28 | u, err := url.Parse(string(pu)) 29 | if err != nil { 30 | panic(err) 31 | } 32 | u.Path = dbName 33 | return PoolURL(u.String()) 34 | } 35 | 36 | // Name returns the database name 37 | func (pu PoolURL) Name() string { 38 | u, err := url.Parse(string(pu)) 39 | if err != nil { 40 | panic(err) 41 | } 42 | return strings.TrimPrefix(u.Path, "/") 43 | } 44 | 45 | // ConnURL returns a valid non pool connection url (can be used with go-migrate 46 | // or sql.db) 47 | func (pu PoolURL) ConnURL() PoolURL { 48 | u, err := url.Parse(string(pu)) 49 | if err != nil { 50 | panic(err) 51 | } 52 | q := u.Query() 53 | for _, k := range []string{ 54 | "pool_max_conns", 55 | "pool_min_conns", 56 | "pool_max_conn_lifetime", 57 | "pool_max_conn_idle_time", 58 | "pool_health_check_period", 59 | } { 60 | q.Del(k) 61 | } 62 | u.RawQuery = q.Encode() 63 | return PoolURL(u.String()) 64 | } 65 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package pgxtesting_test 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "testing" 7 | 8 | "github.com/go-pa/pgxtesting" 9 | ) 10 | 11 | func Example() { 12 | var t *testing.T // the t argument in your test function 13 | 14 | pool := pgxtesting.CreateTestDatabaseEnv(t) 15 | 16 | // And you can ten do something with the database... 17 | row := pool.QueryRow(context.Background(), "SELECT current_database()") 18 | var v string 19 | err := row.Scan(&v) 20 | if err != nil { 21 | t.Error(err) 22 | return 23 | } 24 | log.Println("the test database name if", v) 25 | 26 | // example using go-migrate, commented out to not depend on go-migrate: 27 | 28 | // // If you need an URL for the postgres test database you use pool.URL. 29 | // // If you need to strip pgxpool specific parameters from it to use it 30 | // // with the std library sql package or go-migrate, use the ConnURL() 31 | // // method. 32 | // m, _ := migrate.New( 33 | // "file://migrations", 34 | // pool.URL.ConnURL().String()) 35 | 36 | // if err := m.Up(); err != nil { 37 | // t.Error(err) 38 | // return 39 | // } 40 | 41 | } 42 | 43 | func ExampleCreateTestDatabase() { 44 | var t *testing.T // the t argument in your test function 45 | 46 | // You can create a test database from a database url. 47 | // It will automatically clean up (drop the database) after the test has been run. 48 | // The CreateTestDatabase function will fatal the test if the 49 | // connection/creation to the datavbase fails there are no errors to 50 | // handle. 51 | pool := pgxtesting.CreateTestDatabase(t, 52 | "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable&pool_max_conns=500") 53 | 54 | // You can close the pool early if you want to free up database 55 | // connections before the test has run and the testing package does it 56 | // automatically for you. Close() drops the database and closes the 57 | // connection. 58 | // If you have a lot of subtests and each creates it's own test 59 | // database this might be a good idea because the testing package does 60 | // not clean up before all sub tests are done so you might exceed 61 | // maximum number of connections if you have many subtests. 62 | pool.Close() 63 | } 64 | 65 | func ExampleCreateTestDatabaseEnv() { 66 | var t *testing.T // the t argument in your test function 67 | 68 | // You set the pgxtesting default postgres url in a 69 | // init() function in one of your test files. 70 | pgxtesting.SetDefaultURL( 71 | "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable&pool_max_conns=500") 72 | 73 | // and then only use this function to get a new pool for each test. 74 | _ = pgxtesting.CreateTestDatabaseEnv(t) 75 | } 76 | -------------------------------------------------------------------------------- /package_test.go: -------------------------------------------------------------------------------- 1 | package pgxtesting 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "os" 7 | "strings" 8 | "testing" 9 | 10 | "github.com/jackc/pgconn" 11 | "github.com/jackc/pgerrcode" 12 | ) 13 | 14 | var testURL = "postgres://test:test@localhost:45432/test?sslmode=disable&pool_max_conns=1000" 15 | 16 | func TestPoolURL(t *testing.T) { 17 | const testu = "postgres://user:pass@host:500/dbname?pool_max_conns=100" 18 | u, err := NewPoolURL(testu) 19 | if err != nil { 20 | t.Error(err) 21 | } 22 | 23 | equal := func(a, b string) { 24 | t.Helper() 25 | if a != b { 26 | t.Errorf("not equal: '%v' '%v'", a, b) 27 | } 28 | } 29 | 30 | equal(u.Name(), "dbname") 31 | equal(u.String(), testu) 32 | equal(u.ConnURL().String(), "postgres://user:pass@host:500/dbname") 33 | } 34 | 35 | func TestCreateTestDB(t *testing.T) { 36 | pool := CreateTestDatabase(t, testURL) 37 | 38 | row := pool.QueryRow(context.Background(), "SELECT current_database()") 39 | var v string 40 | err := row.Scan(&v) 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | if !strings.HasPrefix(v, "pgxtesting_") { 45 | t.Errorf("%s does not start with pgxtesting_", v) 46 | } 47 | if v != pool.URL.Name() { 48 | t.Errorf("'%s' != '%s'", v, pool.URL.Name()) 49 | } 50 | } 51 | 52 | func TestClosePool(t *testing.T) { 53 | t.Parallel() 54 | pool := CreateTestDatabase(t, testURL) 55 | 56 | // this should not generate any logs 57 | defer pool.Close() 58 | if pool.closed { 59 | t.Error("pool is closed") 60 | } 61 | pool.Close() 62 | if !pool.closed { 63 | t.Error("pool is not closed") 64 | } 65 | pool.Close() 66 | if !pool.closed { 67 | t.Error("pool is not closed") 68 | } 69 | } 70 | 71 | func TestClosePoolStillOpenConnections(t *testing.T) { 72 | if testing.Short() { 73 | t.Skip() 74 | return 75 | } 76 | t.Parallel() 77 | 78 | pool := CreateTestDatabase(t, testURL) 79 | 80 | pool2, err := connectPostgres(pool.URL) 81 | if err != nil { 82 | t.Fatal(err) 83 | } 84 | 85 | pool.Pool.Close() 86 | pool.closed = true 87 | 88 | err = pool.dropTestDB() // this takes some time to run 89 | 90 | pool2.Close() 91 | if err == nil { 92 | t.Fatal("expected error due to connection still being open") 93 | } 94 | 95 | if perr := PgErr(err); err == nil { 96 | t.Fatalf("error is not a pgconn error: %v", err) 97 | } else { 98 | if perr.Code != pgerrcode.ObjectInUse { 99 | t.Fatalf("got wrong error message: %v", err) 100 | } 101 | } 102 | 103 | err = pool.dropTestDB() 104 | if err != nil { 105 | t.Fatal(err) 106 | } 107 | 108 | pool.Close() 109 | pool.Close() 110 | } 111 | 112 | func TestGlobalConfig(t *testing.T) { 113 | t.Parallel() 114 | equal := func(a, b string) { 115 | t.Helper() 116 | if a != b { 117 | t.Errorf("not equal: '%v' '%v'", a, b) 118 | } 119 | } 120 | os.Setenv("PGURL", "") 121 | equal(defaultURL, GetDefaultURL()) 122 | equal(GetURL(), GetDefaultURL()) 123 | os.Setenv("PGURL", "postgres://foo") 124 | equal(GetURL(), "postgres://foo") 125 | SetDefaultURL("postgres://foo") 126 | equal(GetURL(), "postgres://foo") 127 | equal(defaultURL, GetDefaultURL()) 128 | 129 | SetEnvName("DBURL") 130 | os.Setenv("DBURL", "") 131 | equal(GetURL(), GetDefaultURL()) 132 | os.Setenv("DBURL", "postgres://bar") 133 | equal(GetURL(), "postgres://bar") 134 | SetEnvName("PGURL") 135 | } 136 | 137 | // PgErr returns a *pgconn.PgError or nil if there are no PgErrors in the error 138 | // chain. 139 | func PgErr(err error) *pgconn.PgError { 140 | var e *pgconn.PgError 141 | if errors.As(err, &e) { 142 | return e 143 | } 144 | return nil 145 | } 146 | -------------------------------------------------------------------------------- /testpool.go: -------------------------------------------------------------------------------- 1 | package pgxtesting 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/jackc/pgconn" 8 | "github.com/jackc/pgx/v4/pgxpool" 9 | ) 10 | 11 | type TB interface { 12 | Cleanup(func()) 13 | Error(args ...interface{}) 14 | Errorf(format string, args ...interface{}) 15 | Fail() 16 | FailNow() 17 | Failed() bool 18 | Fatal(args ...interface{}) 19 | Fatalf(format string, args ...interface{}) 20 | Helper() 21 | Log(args ...interface{}) 22 | Logf(format string, args ...interface{}) 23 | Name() string 24 | Skip(args ...interface{}) 25 | SkipNow() 26 | Skipf(format string, args ...interface{}) 27 | Skipped() bool 28 | TempDir() string 29 | } 30 | 31 | // TestPool . 32 | type TestPool struct { 33 | *pgxpool.Pool 34 | Name string // database name 35 | URL PoolURL 36 | originalURL PoolURL 37 | closed bool 38 | } 39 | 40 | // Close closes the test pool and deletes the testing database. 41 | func (t *TestPool) Close() { 42 | if t.Pool != nil && !t.closed { 43 | t.closed = true 44 | t.Pool.Close() 45 | } 46 | 47 | err := t.dropTestDB() 48 | if err != nil { 49 | fmt.Println(err) 50 | } 51 | } 52 | 53 | func (t *TestPool) dropTestDB() error { 54 | ctx := context.Background() 55 | pool, err := connectPostgres(t.originalURL) 56 | if err != nil { 57 | return fmt.Errorf("pgxtesting.Pool.Cleanup error: %w", err) 58 | } 59 | defer pool.Close() 60 | 61 | conn, err := pool.Acquire(ctx) 62 | if err != nil { 63 | return fmt.Errorf("pgxtesting.Pool.Cleanup error: %w", err) 64 | } 65 | defer conn.Release() 66 | 67 | sql := fmt.Sprintf("drop database %s", t.URL.Name()) 68 | _, err = conn.Exec(ctx, sql) 69 | if err != nil { 70 | if err, ok := err.(*pgconn.PgError); ok { 71 | if err.Code != "3D000" { 72 | return fmt.Errorf("pgxtesting.Pool.Cleanup error running '%s': %w\n", sql, err) 73 | } 74 | } else { 75 | return fmt.Errorf("pgxtesting.Pool.Cleanup error running '%s': %w\n", sql, err) 76 | } 77 | } 78 | 79 | return nil 80 | } 81 | 82 | func CreateTestDatabaseEnv(tb TB) *TestPool { 83 | tb.Helper() 84 | return CreateTestDatabase(tb, GetURL()) 85 | } 86 | 87 | func CreateTestDatabase(tb TB, pgxPoolURL string) *TestPool { 88 | tb.Helper() 89 | pu, err := NewPoolURL(pgxPoolURL) 90 | if err != nil { 91 | tb.Fatal(err) 92 | } 93 | 94 | dbName := getRandomDBName() 95 | 96 | if err := createDB(pu, dbName); err != nil { 97 | tb.Fatalf("error creating database %v: %w", dbName, err) 98 | } 99 | 100 | URL := pu.SetName(dbName) 101 | 102 | pool, err := connectPostgres(URL) 103 | if err != nil { 104 | tb.Fatal(err) 105 | } 106 | 107 | tp := &TestPool{ 108 | Pool: pool, 109 | Name: dbName, 110 | URL: URL, 111 | originalURL: pu, 112 | } 113 | tb.Cleanup(tp.Close) 114 | return tp 115 | } 116 | 117 | func createDB(pu PoolURL, dbName string) error { 118 | ctx := context.Background() 119 | pool, err := connectPostgres(pu) 120 | if err != nil { 121 | return fmt.Errorf("cannot connect to dburl %s: %w", pu, err) 122 | } 123 | defer pool.Close() 124 | 125 | conn, err := pool.Acquire(ctx) 126 | if err != nil { 127 | return fmt.Errorf("error: %w", err) 128 | } 129 | defer conn.Release() 130 | 131 | _, err = conn.Exec(ctx, fmt.Sprintf("create database %s", dbName)) 132 | if err != nil { 133 | return fmt.Errorf("error %w", err) 134 | } 135 | 136 | return nil 137 | } 138 | 139 | func connectPostgres(pu PoolURL) (*pgxpool.Pool, error) { 140 | ctx := context.Background() 141 | config, err := pgxpool.ParseConfig(pu.String()) 142 | if err != nil { 143 | return nil, err 144 | } 145 | 146 | pool, err := pgxpool.ConnectConfig(ctx, config) 147 | return pool, err 148 | } 149 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 3 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= 4 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 5 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 6 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 7 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 11 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 12 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 13 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 14 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 15 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 16 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 17 | github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= 18 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 19 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 20 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= 21 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 22 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 23 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 24 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 25 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 26 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 27 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 28 | github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= 29 | github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 30 | github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 h1:WAvSpGf7MsFuzAtK4Vk7R4EVe+liW4x83r4oWu0WHKw= 31 | github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= 32 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= 33 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 34 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 35 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 36 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= 37 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 38 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 39 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 40 | github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= 41 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 42 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 43 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 44 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 45 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 46 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 47 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 48 | github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= 49 | github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 50 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= 51 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 52 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 53 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 54 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 55 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 56 | github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0= 57 | github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 58 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 59 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 60 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 61 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 62 | github.com/jackc/pgx/v4 v4.14.1 h1:71oo1KAGI6mXhLiTMn6iDFcp3e7+zon/capWjl2OEFU= 63 | github.com/jackc/pgx/v4 v4.14.1/go.mod h1:RgDuE4Z34o7XE92RpLsvFiOEfrAUT0Xt2KxvX73W06M= 64 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 65 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 66 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 67 | github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 68 | github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= 69 | github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 70 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 71 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 72 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 73 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 74 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 75 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 76 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 77 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 78 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 79 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 80 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 81 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 82 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 83 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 84 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 85 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 86 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 87 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 88 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 89 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 90 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 91 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 92 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 93 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 94 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 95 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 96 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 97 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 98 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 99 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 100 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 101 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 102 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 103 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 104 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 105 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 106 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 107 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 108 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 109 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 110 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 111 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 112 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 113 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 114 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 115 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 116 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 117 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 118 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 119 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 120 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 121 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 122 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 123 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 124 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 125 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 126 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 127 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 128 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 129 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 130 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 131 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= 132 | golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 133 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 134 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 135 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 136 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 137 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 138 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 139 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 140 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 141 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 142 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 143 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 144 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 145 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 146 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 147 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 148 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 149 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 150 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 151 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 152 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 153 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 154 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 155 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 156 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 157 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 158 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 159 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 160 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 161 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 162 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 163 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 164 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 165 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 166 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 167 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 168 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 169 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 170 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 171 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 172 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 173 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 174 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 175 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 176 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 177 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 178 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 179 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 180 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 181 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 182 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 183 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 184 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 185 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 186 | --------------------------------------------------------------------------------