├── frontend ├── dist │ └── asoul ├── babel.config.js ├── vue.config.js ├── embed.go ├── src │ ├── plugins │ │ └── vuetify.js │ ├── main.js │ ├── router │ │ └── index.js │ ├── App.vue │ └── views │ │ └── Index.vue ├── .gitignore ├── public │ └── index.html └── package.json ├── .github ├── FUNDING.yml └── workflows │ ├── lsif.yml │ ├── go.yml │ ├── deploy.yml │ └── codeql-analysis.yml ├── migrations ├── 3_create_video_list_view.down.sql ├── 9_create_comments_table.down.sql ├── 1_init.down.sql ├── 10_create_face_points_column.down.sql ├── 5_create_video_updated_at_column.down.sql ├── 10_create_face_points_column.up.sql ├── 5_create_video_updated_at_column.up.sql ├── 11_create_cover_size_column.down.sql ├── 11_create_cover_size_column.up.sql ├── 2_create_url_videos_table.down.sql ├── embed.go ├── 2_create_url_videos_table.up.sql ├── 9_create_comments_table.up.sql ├── 3_create_video_list_view.up.sql ├── 6_create_statistics_table.down.sql ├── 4_create_vid_column.up.sql ├── 4_create_vid_column.down.sql ├── 1_init.up.sql ├── 8_set_view_default_value.down.sql ├── 7_create_is_dynamic_cover_column.down.sql ├── 7_create_is_dynamic_cover_column.up.sql ├── 8_set_view_default_value.up.sql └── 6_create_statistics_table.up.sql ├── assets └── templates │ ├── embed.go │ └── index.html ├── .deepsource.toml ├── .gitignore ├── SECURITY.md ├── Dockerfile ├── dev └── db │ ├── migrate.sh │ └── add_migration.sh ├── internal ├── dbutil │ ├── syntax.go │ ├── error.go │ ├── migrate.go │ └── type.go ├── route │ ├── landing.go │ ├── member.go │ ├── video.go │ └── source.go ├── db │ ├── db.go │ ├── statistics.go │ ├── comments.go │ ├── members.go │ ├── video_urls.go │ └── videos.go └── context │ └── context.go ├── systemd └── asoulvideo.service ├── LICENSE ├── pkg └── model │ ├── const.go │ └── model.go ├── go.mod ├── main.go ├── README.md └── go.sum /frontend/dist/asoul: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: wuhan005 2 | -------------------------------------------------------------------------------- /migrations/3_create_video_list_view.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP VIEW IF EXISTS video_list; 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /migrations/9_create_comments_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP TABLE IF EXISTS comments; 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transpileDependencies: [ 3 | 'vuetify' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /migrations/1_init.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP TABLE IF EXISTS members; 4 | DROP TABLE IF EXISTS videos; 5 | 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /migrations/10_create_face_points_column.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | DROP COLUMN IF EXISTS face_points; 5 | 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /migrations/5_create_video_updated_at_column.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | DROP COLUMN IF EXISTS updated_at; 5 | 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /migrations/10_create_face_points_column.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | ADD COLUMN face_points jsonb DEFAULT '[]'::jsonb NOT NULL; 5 | 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /migrations/5_create_video_updated_at_column.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | ADD COLUMN updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(); 5 | 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /migrations/11_create_cover_size_column.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | DROP COLUMN IF EXISTS cover_width; 5 | 6 | ALTER TABLE videos 7 | DROP COLUMN IF EXISTS cover_height; 8 | 9 | COMMIT; 10 | -------------------------------------------------------------------------------- /migrations/11_create_cover_size_column.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | ADD COLUMN cover_width INT DEFAULT 0 NOT NULL; 5 | 6 | ALTER TABLE videos 7 | ADD COLUMN cover_height INT DEFAULT 0 NOT NULL; 8 | 9 | COMMIT; 10 | -------------------------------------------------------------------------------- /migrations/2_create_url_videos_table.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP TABLE IF EXISTS video_urls; 4 | 5 | ALTER TABLE videos 6 | ADD COLUMN video_urls TEXT[] NOT NULL; 7 | 8 | ALTER TABLE videos 9 | ADD COLUMN video_cdn_url TEXT NOT NULL; 10 | 11 | COMMIT; 12 | -------------------------------------------------------------------------------- /frontend/embed.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package frontend 6 | 7 | import ( 8 | "embed" 9 | ) 10 | 11 | //go:embed dist/* 12 | var FS embed.FS 13 | -------------------------------------------------------------------------------- /assets/templates/embed.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package templates 6 | 7 | import ( 8 | "embed" 9 | ) 10 | 11 | //go:embed *.html 12 | var FS embed.FS 13 | -------------------------------------------------------------------------------- /migrations/embed.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package migrations 6 | 7 | import ( 8 | "embed" 9 | ) 10 | 11 | //go:embed *.sql 12 | var Migrations embed.FS 13 | -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "shell" 5 | enabled = true 6 | 7 | [[analyzers]] 8 | name = "go" 9 | enabled = true 10 | 11 | [analyzers.meta] 12 | import_root = "github.com/asoul-sig/asoul-video" 13 | 14 | [[analyzers]] 15 | name = "javascript" 16 | enabled = true 17 | 18 | [analyzers.meta] 19 | plugins = ["vue"] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .idea/ 18 | .bin/ 19 | .task 20 | .envrc -------------------------------------------------------------------------------- /frontend/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | import Vuetify from 'vuetify/lib'; 4 | import colors from 'vuetify/lib/util/colors' 5 | 6 | Vue.use(Vuetify); 7 | 8 | export default new Vuetify({ 9 | theme: { 10 | themes: { 11 | light: { 12 | primary: colors.red.lighten2, 13 | }, 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # 安全策略 2 | 3 | ## 支持版本 4 | 5 | 我们只接收当前 `master` 分支最新 commit 版本存在的漏洞情报。 6 | 7 | ## 漏洞报告及处理流程 8 | 9 | 1. 请发送详细的漏洞说明,复现流程至邮箱 i@github.red,我们将在三个工作日给予回复。 10 | 11 | 2. 在本仓库创建一个占位的 issue,用于保持对该漏洞的跟踪。 12 | 13 | 3. 我们将会查看你提交的报告,并确认或忽略报告。 14 | 15 | 4. 一旦报告被确认,报告提交者可选择自行提交修复代码或等待项目维护者对漏洞进行修复。 16 | 17 | 5. 漏洞被修复,并部署至线上环境。 18 | 19 | 6. 我们将对外披露漏洞相关情况,并发布 GitHub Security Advisory 通知。 20 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import vuetify from './plugins/vuetify' 5 | import 'typeface-roboto/index.css'; 6 | import '@mdi/font/css/materialdesignicons.css' 7 | 8 | Vue.config.productionTip = false 9 | 10 | new Vue({ 11 | vuetify, 12 | router, 13 | render: h => h(App) 14 | }).$mount('#app') 15 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist/css 4 | /dist/js 5 | /dist/fonts 6 | /dist/index.html 7 | 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | pnpm-debug.log* 18 | 19 | # Editor directories and files 20 | .idea 21 | .vscode 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /frontend/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | Vue.use(VueRouter) 5 | 6 | const routes = [ 7 | { 8 | path: '/', 9 | name: 'Index', 10 | component: () => import('@/views/Index.vue') 11 | }, 12 | ] 13 | 14 | let router = new VueRouter({ 15 | mode: 'hash', 16 | base: process.env.BASE_URL, 17 | routes 18 | }) 19 | 20 | export default router 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* 4 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 5 | RUN echo 'Asia/Shanghai' > /etc/timezone 6 | 7 | RUN mkdir /etc/asoul-video 8 | WORKDIR /etc/asoul-video 9 | 10 | ADD asoul-video /etc/asoul-video 11 | 12 | RUN chmod 655 /etc/asoul-video/asoul-video 13 | 14 | ENTRYPOINT ["/etc/asoul-video/asoul-video"] 15 | EXPOSE 2830 16 | -------------------------------------------------------------------------------- /dev/db/migrate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | cd "$(dirname "${BASH_SOURCE[0]}")/../.." 6 | 7 | hash migrate 2>/dev/null || { 8 | if [[ $(uname) == "Darwin" ]]; then 9 | brew install golang-migrate 10 | else 11 | echo "You need to install the 'migrate' tool: https://github.com/golang-migrate/migrate" 12 | exit 1 13 | fi 14 | } 15 | 16 | migrate -database "postgres://${PGHOST}:${PGPORT}/${PGDATABASE}" -path ./assets/migrations "$@" 17 | -------------------------------------------------------------------------------- /internal/dbutil/syntax.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package dbutil 6 | 7 | import ( 8 | "strings" 9 | ) 10 | 11 | // QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be 12 | // used as part of an SQL statement. 13 | func QuoteIdentifier(s string) string { 14 | return `"` + strings.ReplaceAll(s, `"`, `""`) + `"` 15 | } 16 | -------------------------------------------------------------------------------- /internal/dbutil/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package dbutil 6 | 7 | import ( 8 | "github.com/Shyp/go-dberror" 9 | ) 10 | 11 | func IsUniqueViolation(err error, constraint string) bool { 12 | switch e := dberror.GetError(err).(type) { 13 | case *dberror.Error: 14 | return e.Constraint == constraint 15 | default: 16 | return false 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /internal/route/landing.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package route 6 | 7 | import ( 8 | "net/http" 9 | 10 | "github.com/flamego/template" 11 | ) 12 | 13 | type Landing struct{} 14 | 15 | // NewLandingHandler creates a new Landing router. 16 | func NewLandingHandler() *Landing { 17 | return &Landing{} 18 | } 19 | 20 | func (l *Landing) Home(t template.Template) { 21 | t.HTML(http.StatusOK, "index") 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/lsif.yml: -------------------------------------------------------------------------------- 1 | name: LSIF 2 | on: 3 | push: 4 | paths: 5 | - '**.go' 6 | - '.github/workflows/lsif.yml' 7 | jobs: 8 | lsif-go: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Generate LSIF data 13 | uses: sourcegraph/lsif-go-action@master 14 | - name: Upload LSIF data to sourcegraph.com 15 | continue-on-error: true 16 | uses: docker://sourcegraph/src-cli:latest 17 | with: 18 | args: lsif upload -github-token=${{ secrets.GITHUB_TOKEN }} 19 | -------------------------------------------------------------------------------- /dev/db/add_migration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname "${BASH_SOURCE[0]}")"/../../migrations 4 | set -e 5 | 6 | if [ -z "$1" ]; then 7 | echo "USAGE: $0 " 8 | exit 1 9 | fi 10 | 11 | awkcmd=$( 12 | cat <<-EOF 13 | BEGIN { FS="[_/]" } 14 | { n=\$2 } 15 | END { 16 | gsub(/[^A-Za-z0-9]/, "_", name); 17 | printf("%s_%s.up.sql\n", n + 1, name); 18 | printf("%s_%s.down.sql\n", n + 1, name); 19 | } 20 | EOF 21 | ) 22 | 23 | files=$(find -s . -type f -name '[0-9]*.sql' | sort -n -t '/' -k 2 | awk -v name="$1" "$awkcmd") 24 | 25 | for f in $files; do 26 | cat >"$f" < 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A-SOUL Video 10 | 11 | 12 | 23 | 24 | 25 | 29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /internal/dbutil/migrate.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package dbutil 6 | 7 | import ( 8 | "database/sql" 9 | "embed" 10 | "net/http" 11 | 12 | "github.com/golang-migrate/migrate/v4" 13 | "github.com/golang-migrate/migrate/v4/database/postgres" 14 | "github.com/golang-migrate/migrate/v4/source/httpfs" 15 | "github.com/pkg/errors" 16 | ) 17 | 18 | func Migrate(db *sql.DB, migrations embed.FS) (func() error, error) { 19 | var cfg postgres.Config 20 | dbDriver, err := postgres.WithInstance(db, &cfg) 21 | if err != nil { 22 | return nil, errors.Wrap(err, "new database driver") 23 | } 24 | 25 | srcDriver, err := httpfs.New(http.FS(migrations), ".") 26 | if err != nil { 27 | return nil, errors.Wrap(err, "new source driver") 28 | } 29 | 30 | m, err := migrate.NewWithInstance("httpfs", srcDriver, "postgres", dbDriver) 31 | if err != nil { 32 | return nil, errors.Wrap(err, "new migrate instance") 33 | } 34 | 35 | err = m.Up() 36 | if err == nil || err == migrate.ErrNoChange { 37 | return dbDriver.Close, nil 38 | } 39 | return nil, errors.Wrap(err, "migrate up") 40 | } 41 | -------------------------------------------------------------------------------- /internal/db/db.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package db 6 | 7 | import ( 8 | "database/sql" 9 | "os" 10 | 11 | "github.com/pkg/errors" 12 | "upper.io/db.v3/postgresql" 13 | 14 | "github.com/asoul-sig/asoul-video/internal/dbutil" 15 | "github.com/asoul-sig/asoul-video/migrations" 16 | ) 17 | 18 | // Init connects to the database and migrate tables. 19 | func Init() error { 20 | db, err := postgresql.Open(postgresql.ConnectionURL{ 21 | Host: os.Getenv("PGHOST"), 22 | User: os.Getenv("PGUSER"), 23 | Password: os.Getenv("PGPASSWORD"), 24 | Database: os.Getenv("PGDATABASE"), 25 | Options: map[string]string{ 26 | "sslmode": os.Getenv("PGSSLMODE"), 27 | }, 28 | }) 29 | if err != nil { 30 | return errors.Wrap(err, "open database") 31 | } 32 | 33 | _, err = dbutil.Migrate(db.Driver().(*sql.DB), migrations.Migrations) 34 | if err != nil { 35 | return errors.Wrap(err, "migrate") 36 | } 37 | 38 | Members = NewMembersStore(db) 39 | Videos = NewVideosStore(db) 40 | VideoURLs = NewVideoURLsStore(db) 41 | Statistics = NewStatisticsStore(db) 42 | Comments = NewCommentsStore(db) 43 | 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /pkg/model/const.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package model 6 | 7 | type MemberSecUID string 8 | 9 | const ( 10 | MemberSecUIDAva = MemberSecUID("MS4wLjABAAAAxOXMMwlShWjp4DONMwfEEfloRYiC1rXwQ64eydoZ0ORPFVGysZEd4zMt8AjsTbyt") 11 | MemberSecUIDBella = MemberSecUID("MS4wLjABAAAAlpnJ0bXVDV6BNgbHUYVWnnIagRqeeZyNyXB84JXTqAS5tgGjAtw0ZZkv0KSHYyhP") 12 | MemberSecUIDCarol = MemberSecUID("MS4wLjABAAAAuZHC7vwqRhPzdeTb24HS7So91u9ucl9c8JjpOS2CPK-9Kg2D32Sj7-mZYvUCJCya") 13 | MemberSecUIDDiana = MemberSecUID("MS4wLjABAAAA5ZrIrbgva_HMeHuNn64goOD2XYnk4ItSypgRHlbSh1c") 14 | MemberSecUIDEileen = MemberSecUID("MS4wLjABAAAAxCiIYlaaKaMz_J1QaIAmHGgc3bTerIpgTzZjm0na8w5t2KTPrCz4bm_5M5EMPy92") 15 | MemberSecUIDAcao = MemberSecUID("MS4wLjABAAAAflgvVQ5O1K4RfgUu3k0A2erAZSK7RsdiqPAvxcObn93x2vk4SKk1eUb6l_D4MX-n") 16 | ) 17 | 18 | type ReportType string 19 | 20 | const ( 21 | ReportTypeUpdateMember ReportType = "update_member" 22 | ReportTypeCreateVideo ReportType = "create_video" 23 | ReportTypeUpdateVideoMeta ReportType = "update_video_meta" 24 | ReportTypeComment ReportType = "comment" 25 | ReportTypeFacePoint ReportType = "face_point" 26 | ) 27 | -------------------------------------------------------------------------------- /internal/dbutil/type.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package dbutil 6 | 7 | import ( 8 | "database/sql" 9 | "database/sql/driver" 10 | "encoding/json" 11 | 12 | "github.com/pkg/errors" 13 | ) 14 | 15 | type JSON json.RawMessage 16 | 17 | func (j *JSON) Scan(value interface{}) error { 18 | if value == nil { 19 | return nil 20 | } 21 | 22 | bytes, ok := value.([]byte) 23 | if !ok { 24 | return errors.Errorf("dbutil.JSON: Scan wants []byte but got %T", value) 25 | } 26 | 27 | *j = bytes 28 | return nil 29 | } 30 | 31 | func (j JSON) Value() (driver.Value, error) { 32 | if len(j) == 0 { 33 | return nil, nil 34 | } 35 | return json.RawMessage(j), nil 36 | } 37 | 38 | func (j JSON) MarshalJSON() ([]byte, error) { 39 | if j == nil { 40 | return []byte("null"), nil 41 | } 42 | return j, nil 43 | } 44 | 45 | func (j *JSON) UnmarshalJSON(data []byte) error { 46 | if j == nil { 47 | return errors.New("dbutil.JSON: UnmarshalJSON on nil pointer") 48 | } 49 | *j = append((*j)[0:0], data...) 50 | return nil 51 | } 52 | 53 | var _ sql.Scanner = (*JSON)(nil) 54 | var _ driver.Valuer = (*JSON)(nil) 55 | var _ json.Marshaler = (*JSON)(nil) 56 | var _ json.Unmarshaler = (*JSON)(nil) 57 | -------------------------------------------------------------------------------- /internal/route/member.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package route 6 | 7 | import ( 8 | "net/http" 9 | 10 | log "unknwon.dev/clog/v2" 11 | 12 | "github.com/asoul-sig/asoul-video/internal/context" 13 | "github.com/asoul-sig/asoul-video/internal/db" 14 | "github.com/asoul-sig/asoul-video/pkg/model" 15 | ) 16 | 17 | type Member struct{} 18 | 19 | // NewMemberHandler creates a new Member router. 20 | func NewMemberHandler() *Member { 21 | return &Member{} 22 | } 23 | 24 | func (*Member) List(ctx context.Context) { 25 | members, err := db.Members.List(ctx.Request().Context()) 26 | if err != nil { 27 | log.Error("Failed to get member list: %v", err) 28 | ctx.ServerError() 29 | return 30 | } 31 | 32 | ctx.Success(members) 33 | } 34 | 35 | func (*Member) GetBySecUID(ctx context.Context) { 36 | secUID := ctx.Param("secUID") 37 | 38 | member, err := db.Members.GetBySecID(ctx.Request().Context(), model.MemberSecUID(secUID)) 39 | if err != nil { 40 | if err == db.ErrMemberNotFound { 41 | ctx.Error(http.StatusNotFound, err) 42 | return 43 | } 44 | 45 | log.Error("Failed to get member by sec_uid: %v", err) 46 | ctx.ServerError() 47 | return 48 | } 49 | 50 | ctx.Success(member) 51 | } 52 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/asoul-sig/asoul-video 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/Shyp/go-dberror v0.0.0-20180123195207-36ecba57721e 7 | github.com/flamego/flamego v0.0.0-20210913073131-adc6656c34a1 8 | github.com/flamego/template v0.0.0-20210914144450-be182d441b73 9 | github.com/golang-migrate/migrate/v4 v4.14.1 10 | github.com/json-iterator/go v1.1.12 11 | github.com/pkg/errors v0.9.1 12 | unknwon.dev/clog/v2 v2.2.0 13 | upper.io/db.v3 v3.8.0+incompatible 14 | ) 15 | 16 | require ( 17 | github.com/alecthomas/participle/v2 v2.0.0-alpha7 // indirect 18 | github.com/fatih/color v1.10.0 // indirect 19 | github.com/google/uuid v1.2.0 // indirect 20 | github.com/hashicorp/errwrap v1.0.0 // indirect 21 | github.com/hashicorp/go-multierror v1.1.0 // indirect 22 | github.com/lib/pq v1.8.0 // indirect 23 | github.com/mattn/go-colorable v0.1.8 // indirect 24 | github.com/mattn/go-isatty v0.0.12 // indirect 25 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 26 | github.com/modern-go/reflect2 v1.0.2 // indirect 27 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect 28 | ) 29 | 30 | require ( 31 | github.com/letsencrypt/boulder v0.0.0-20210917202203-e27634717069 // indirect 32 | github.com/robfig/cron/v3 v3.0.1 33 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect 34 | ) 35 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asoul-video", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^0.21.4", 12 | "core-js": "^3.6.5", 13 | "qs": "^6.10.1", 14 | "typeface-roboto": "^1.1.13", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.5.2", 17 | "vue-video-player": "^5.0.2", 18 | "vuetify": "^2.4.0" 19 | }, 20 | "devDependencies": { 21 | "@mdi/font": "^6.6.96", 22 | "@vue/cli-plugin-babel": "~4.5.0", 23 | "@vue/cli-plugin-eslint": "~4.5.0", 24 | "@vue/cli-service": "~4.5.0", 25 | "babel-eslint": "^10.1.0", 26 | "eslint": "^6.7.2", 27 | "eslint-plugin-vue": "^6.2.2", 28 | "sass": "~1.32.0", 29 | "sass-loader": "^10.0.0", 30 | "vue-cli-plugin-vuetify": "~2.4.2", 31 | "vue-template-compiler": "^2.6.11", 32 | "vuetify-loader": "^1.7.0" 33 | }, 34 | "eslintConfig": { 35 | "root": true, 36 | "env": { 37 | "node": true 38 | }, 39 | "extends": [ 40 | "plugin:vue/essential", 41 | "eslint:recommended" 42 | ], 43 | "parserOptions": { 44 | "parser": "babel-eslint" 45 | }, 46 | "rules": {} 47 | }, 48 | "browserslist": [ 49 | "> 1%", 50 | "last 2 versions", 51 | "not dead" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: 3 | push: 4 | branches: [ master ] 5 | paths: 6 | - '**.go' 7 | - 'go.mod' 8 | - '.github/workflows/go.yml' 9 | pull_request: 10 | paths: 11 | - '**.go' 12 | - 'go.mod' 13 | - '.github/workflows/go.yml' 14 | env: 15 | GOPROXY: "https://proxy.golang.org" 16 | 17 | jobs: 18 | lint: 19 | name: Lint 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v2 24 | - name: Run golangci-lint 25 | uses: golangci/golangci-lint-action@v2 26 | with: 27 | version: latest 28 | args: --timeout=30m 29 | 30 | test: 31 | name: Test 32 | runs-on: ubuntu-latest 33 | services: 34 | postgres: 35 | image: postgres:12 36 | env: 37 | POSTGRES_PASSWORD: postgres 38 | options: >- 39 | --health-cmd pg_isready 40 | --health-interval 10s 41 | --health-timeout 5s 42 | --health-retries 5 43 | ports: 44 | - 5432:5432 45 | steps: 46 | - name: Install Go 47 | uses: actions/setup-go@v2 48 | with: 49 | go-version: 1.18.x 50 | - name: Checkout code 51 | uses: actions/checkout@v2 52 | - name: Run tests 53 | run: go test -v -race ./... 54 | env: 55 | PGPORT: 5432 56 | PGHOST: localhost 57 | PGUSER: postgres 58 | PGPASSWORD: postgres 59 | PGSSLMODE: disable 60 | 61 | -------------------------------------------------------------------------------- /migrations/1_init.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | CREATE TABLE IF NOT EXISTS members ( 4 | sec_uid TEXT NOT NULL, 5 | uid TEXT NOT NULL, 6 | unique_id TEXT NOT NULL, 7 | short_id TEXT NOT NULL, 8 | name TEXT NOT NULL, 9 | avatar_url TEXT NOT NULL, 10 | signature TEXT NOT NULL, 11 | created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() 12 | ); 13 | 14 | CREATE INDEX idx_member_sec_uid ON members( sec_uid ); 15 | 16 | CREATE TABLE IF NOT EXISTS videos ( 17 | id TEXT NOT NULL, 18 | author_sec_id TEXT NOT NULL, 19 | description TEXT NOT NULL, 20 | text_extra TEXT[] NOT NULL, 21 | origin_cover_urls TEXT[] NOT NULL, 22 | dynamic_cover_urls TEXT[] NOT NULL, 23 | video_height INT NOT NULL, 24 | video_width INT NOT NULL, 25 | video_duration BIGINT NOT NULL, 26 | video_ratio TEXT NOT NULL, 27 | video_urls TEXT[] NOT NULL, 28 | video_cdn_url TEXT NOT NULL, 29 | created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() 30 | ); 31 | 32 | ALTER TABLE ONLY videos 33 | ADD CONSTRAINT videos_pkey PRIMARY KEY ( id ); 34 | 35 | COMMIT; 36 | -------------------------------------------------------------------------------- /internal/context/context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package context 6 | 7 | import ( 8 | "net/http" 9 | 10 | "github.com/flamego/flamego" 11 | jsoniter "github.com/json-iterator/go" 12 | "github.com/pkg/errors" 13 | log "unknwon.dev/clog/v2" 14 | ) 15 | 16 | // Context represents context of a request. 17 | type Context struct { 18 | flamego.Context 19 | } 20 | 21 | func (c *Context) Success(data interface{}) { 22 | c.ResponseWriter().Header().Set("Content-Type", "application/json") 23 | c.ResponseWriter().WriteHeader(http.StatusOK) 24 | 25 | err := jsoniter.NewEncoder(c.ResponseWriter()).Encode( 26 | map[string]interface{}{ 27 | "data": data, 28 | }, 29 | ) 30 | if err != nil { 31 | log.Error("Failed to encode: %v", err) 32 | } 33 | } 34 | 35 | func (c *Context) ServerError() { 36 | c.Error(http.StatusInternalServerError, errors.New("internal server error")) 37 | } 38 | 39 | func (c *Context) Error(statusCode int, error error) { 40 | c.ResponseWriter().Header().Set("Content-Type", "application/json") 41 | c.ResponseWriter().WriteHeader(statusCode) 42 | 43 | err := jsoniter.NewEncoder(c.ResponseWriter()).Encode( 44 | map[string]interface{}{ 45 | "msg": error.Error(), 46 | }, 47 | ) 48 | if err != nil { 49 | log.Error("Failed to encode: %v", err) 50 | } 51 | } 52 | 53 | // Contexter initializes a classic context for a request. 54 | func Contexter() flamego.Handler { 55 | return func(ctx flamego.Context) { 56 | c := Context{ 57 | Context: ctx, 58 | } 59 | c.Map(c) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | on: 3 | push: 4 | branches: [ master ] 5 | 6 | jobs: 7 | deploy: 8 | name: Deploy to production 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Install Go 12 | uses: actions/setup-go@v2 13 | with: 14 | go-version: 1.18.x 15 | 16 | - name: Install NodeJS 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: '12' 20 | 21 | - name: Install Yarn 22 | run: npm install -g yarn 23 | 24 | - name: Checkout code 25 | uses: actions/checkout@v2 26 | 27 | - name: Build frontend 28 | run: cd frontend && yarn install && yarn build 29 | 30 | - name: Get current date 31 | id: date 32 | run: echo "::set-output name=date::$(date -u '+%Y-%m-%d %I:%M:%S %Z')" 33 | 34 | - name: Build binary 35 | run: | 36 | CGO_ENABLED=0 go build -v -ldflags " -X \"main.BuildTime=${{ steps.date.outputs.date }}\" -X \"main.BuildCommit=$GITHUB_SHA\"" -trimpath 37 | 38 | - name: Build & Publish to Registry 39 | uses: wuhan005/publish-docker-action@master 40 | with: 41 | username: ${{ secrets.DOCKER_USERNAME }} 42 | password: ${{ secrets.DOCKER_PASSWORD }} 43 | registry: registry.cn-hangzhou.aliyuncs.com 44 | repository: registry.cn-hangzhou.aliyuncs.com/eggplant/asoul-video 45 | tag_format: "%YYYY%_%MM%_%DD%_%H%%m%%s%" 46 | auto_tag: true 47 | 48 | - name: Send notification to Discrod 49 | env: 50 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} 51 | uses: Ilshidur/action-discord@master 52 | with: 53 | args: 'The asoul-video backend has been deployed. https://github.com/asoul-video/asoul-video/commit/{{ GITHUB_SHA }}' 54 | -------------------------------------------------------------------------------- /migrations/8_set_view_default_value.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP VIEW IF EXISTS video_list; 4 | 5 | CREATE VIEW video_list AS ( 6 | SELECT v.*, 7 | members.sec_uid, 8 | members.uid, 9 | members.unique_id, 10 | members.short_id, 11 | members."name", 12 | members.avatar_url, 13 | members.signature, 14 | statistics.share, 15 | statistics.forward, 16 | statistics.digg, 17 | statistics.play, 18 | statistics.comment 19 | FROM (SELECT videos.*, array_agg(DISTINCT video_urls.url) AS video_urls 20 | FROM videos JOIN video_urls ON video_urls.video_id = videos.id 21 | GROUP BY videos.id) AS v 22 | JOIN members ON members.sec_uid = v.author_sec_id 23 | LEFT JOIN (SELECT * 24 | FROM statistics JOIN (SELECT id AS statistic_id, MAX(created_at) AS created_at 25 | FROM statistics 26 | GROUP BY id) AS latest_s 27 | ON "statistics".id = latest_s.statistic_id AND 28 | "statistics".created_at = 29 | latest_s.created_at) AS statistics 30 | ON statistics.id = v.id ); 31 | 32 | COMMIT; 33 | -------------------------------------------------------------------------------- /internal/route/video.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package route 6 | 7 | import ( 8 | "net/http" 9 | 10 | log "unknwon.dev/clog/v2" 11 | 12 | "github.com/asoul-sig/asoul-video/internal/context" 13 | "github.com/asoul-sig/asoul-video/internal/db" 14 | ) 15 | 16 | type Video struct{} 17 | 18 | // NewVideoHandler creates a new Video router. 19 | func NewVideoHandler() *Video { 20 | return &Video{} 21 | } 22 | 23 | func (*Video) List(ctx context.Context) { 24 | secUIDs := ctx.QueryStrings("secUID") 25 | keyword := ctx.Query("keyword") 26 | orderBy := "created_at" 27 | if ctx.Query("orderBy") != "" { 28 | orderBy = ctx.Query("orderBy") 29 | } 30 | order := ctx.Query("order") 31 | 32 | page := ctx.QueryInt("page") 33 | pageSize := ctx.QueryInt("pageSize") 34 | 35 | videos, err := db.Videos.List(ctx.Request().Context(), db.ListVideoOptions{ 36 | SecUIDs: secUIDs, 37 | Keyword: keyword, 38 | OrderBy: orderBy, 39 | Order: order, 40 | Page: page, 41 | PageSize: pageSize, 42 | }) 43 | if err != nil { 44 | log.Error("Failed to list video: %v", err) 45 | ctx.ServerError() 46 | return 47 | } 48 | 49 | ctx.Success(videos) 50 | } 51 | 52 | func (*Video) GetByID(ctx context.Context) { 53 | id := ctx.Param("id") 54 | video, err := db.Videos.GetByID(ctx.Request().Context(), id) 55 | if err != nil { 56 | if err == db.ErrVideoNotFound { 57 | ctx.Error(http.StatusNotFound, err) 58 | return 59 | } 60 | log.Error("Failed to get video by ID: %v", err) 61 | ctx.ServerError() 62 | return 63 | } 64 | 65 | ctx.Success(video) 66 | } 67 | 68 | func (*Video) Random(ctx context.Context) { 69 | video, err := db.Videos.Random(ctx.Request().Context()) 70 | if err != nil { 71 | log.Error("Failed to get video randomly: %v", err) 72 | ctx.ServerError() 73 | return 74 | } 75 | 76 | ctx.Success(video) 77 | } 78 | -------------------------------------------------------------------------------- /migrations/7_create_is_dynamic_cover_column.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP VIEW IF EXISTS video_list; 4 | 5 | ALTER TABLE videos 6 | DROP COLUMN IF EXISTS is_dynamic_cover; 7 | 8 | CREATE VIEW video_list AS ( 9 | SELECT v.*, 10 | members.sec_uid, 11 | members.uid, 12 | members.unique_id, 13 | members.short_id, 14 | members."name", 15 | members.avatar_url, 16 | members.signature, 17 | statistics.share, 18 | statistics.forward, 19 | statistics.digg, 20 | statistics.play, 21 | statistics.comment 22 | FROM (SELECT videos.*, array_agg(DISTINCT video_urls.url) AS video_urls 23 | FROM videos JOIN video_urls ON video_urls.video_id = videos.id 24 | GROUP BY videos.id) AS v 25 | JOIN members ON members.sec_uid = v.author_sec_id 26 | LEFT JOIN (SELECT * 27 | FROM statistics JOIN (SELECT id AS statistic_id, MAX(created_at) AS created_at 28 | FROM statistics 29 | GROUP BY id) AS latest_s 30 | ON "statistics".id = latest_s.statistic_id AND 31 | "statistics".created_at = 32 | latest_s.created_at) AS statistics 33 | ON statistics.id = v.id ); 34 | 35 | COMMIT; 36 | -------------------------------------------------------------------------------- /migrations/7_create_is_dynamic_cover_column.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | ALTER TABLE videos 4 | ADD COLUMN is_dynamic_cover BOOLEAN NOT NULL DEFAULT FALSE; 5 | 6 | DROP VIEW IF EXISTS video_list; 7 | 8 | CREATE VIEW video_list AS ( 9 | SELECT v.*, 10 | members.sec_uid, 11 | members.uid, 12 | members.unique_id, 13 | members.short_id, 14 | members."name", 15 | members.avatar_url, 16 | members.signature, 17 | statistics.share, 18 | statistics.forward, 19 | statistics.digg, 20 | statistics.play, 21 | statistics.comment 22 | FROM (SELECT videos.*, array_agg(DISTINCT video_urls.url) AS video_urls 23 | FROM videos JOIN video_urls ON video_urls.video_id = videos.id 24 | GROUP BY videos.id) AS v 25 | JOIN members ON members.sec_uid = v.author_sec_id 26 | LEFT JOIN (SELECT * 27 | FROM statistics JOIN (SELECT id AS statistic_id, MAX(created_at) AS created_at 28 | FROM statistics 29 | GROUP BY id) AS latest_s 30 | ON "statistics".id = latest_s.statistic_id AND 31 | "statistics".created_at = 32 | latest_s.created_at) AS statistics 33 | ON statistics.id = v.id ); 34 | 35 | COMMIT; 36 | -------------------------------------------------------------------------------- /migrations/8_set_view_default_value.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP VIEW IF EXISTS video_list; 4 | 5 | CREATE VIEW video_list AS ( 6 | SELECT v.*, 7 | members.sec_uid, 8 | members.uid, 9 | members.unique_id, 10 | members.short_id, 11 | members."name", 12 | members.avatar_url, 13 | members.signature, 14 | COALESCE(statistics.forward, 0) AS forward, 15 | COALESCE(statistics.digg, 0) AS digg, 16 | COALESCE(statistics.play, 0) AS play, 17 | COALESCE(statistics.share, 0) AS share, 18 | COALESCE(statistics.comment, 0) AS comment 19 | FROM (SELECT videos.*, array_agg(DISTINCT video_urls.url) AS video_urls 20 | FROM videos JOIN video_urls ON video_urls.video_id = videos.id 21 | GROUP BY videos.id) AS v 22 | JOIN members ON members.sec_uid = v.author_sec_id 23 | LEFT JOIN (SELECT * 24 | FROM statistics JOIN (SELECT id AS statistic_id, MAX(created_at) AS created_at 25 | FROM statistics 26 | GROUP BY id) AS latest_s 27 | ON "statistics".id = latest_s.statistic_id AND 28 | "statistics".created_at = 29 | latest_s.created_at) AS statistics 30 | ON statistics.id = v.id ); 31 | 32 | COMMIT; 33 | -------------------------------------------------------------------------------- /internal/db/statistics.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package db 6 | 7 | import ( 8 | "context" 9 | "time" 10 | 11 | "upper.io/db.v3/lib/sqlbuilder" 12 | ) 13 | 14 | var _ StatisticsStore = (*statistics)(nil) 15 | 16 | var Statistics StatisticsStore 17 | 18 | type StatisticsStore interface { 19 | // Create creates a new statistic record with the given options. 20 | Create(ctx context.Context, id string, opts CreateStatisticOptions) error 21 | } 22 | 23 | func NewStatisticsStore(db sqlbuilder.Database) StatisticsStore { 24 | return &statistics{db} 25 | } 26 | 27 | type Statistic struct { 28 | ID string `db:"id" json:"id"` 29 | Share int64 `db:"share" json:"share"` 30 | Forward int64 `db:"forward" json:"forward"` 31 | Digg int64 `db:"digg" json:"digg"` 32 | Play int64 `db:"play" json:"play"` 33 | Comment int64 `db:"comment" json:"comment"` 34 | CreatedAt time.Time `db:"created_at" json:"-"` 35 | } 36 | 37 | type statistics struct { 38 | sqlbuilder.Database 39 | } 40 | 41 | type CreateStatisticOptions struct { 42 | Share int64 43 | Forward int64 44 | Digg int64 45 | Play int64 46 | Comment int64 47 | } 48 | 49 | func (db *statistics) Create(ctx context.Context, id string, opts CreateStatisticOptions) error { 50 | if opts.Share+opts.Forward+opts.Digg+opts.Play+opts.Comment == 0 { 51 | return nil 52 | } 53 | 54 | var statistic Statistic 55 | if err := db.WithContext(ctx).SelectFrom("statistic").Where( 56 | "id = ? AND share = ? AND forward = ? AND digg = ? AND play = ? AND comment = ?", 57 | id, opts.Share, opts.Forward, opts.Digg, opts.Play, opts.Comment).One(&statistic); err == nil { 58 | return nil 59 | } 60 | 61 | _, err := db.WithContext(ctx).InsertInto("statistics"). 62 | Columns("id", "share", "forward", "digg", "play", "comment"). 63 | Values(id, opts.Share, opts.Forward, opts.Digg, opts.Play, opts.Comment). 64 | Exec() 65 | return err 66 | } 67 | -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 66 | 67 | 68 | 85 | -------------------------------------------------------------------------------- /migrations/6_create_statistics_table.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | CREATE TABLE IF NOT EXISTS statistics ( 4 | id TEXT NOT NULL, 5 | share INT NOT NULL, 6 | forward INT NOT NULL, 7 | digg INT NOT NULL, 8 | play INT NOT NULL, 9 | comment INT NOT NULL, 10 | created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() 11 | ); 12 | 13 | CREATE INDEX IF NOT EXISTS statistics_id_created_at ON statistics( id, created_at ); 14 | 15 | DROP VIEW IF EXISTS video_list; 16 | 17 | CREATE VIEW video_list AS ( 18 | SELECT v.*, 19 | members.sec_uid, 20 | members.uid, 21 | members.unique_id, 22 | members.short_id, 23 | members."name", 24 | members.avatar_url, 25 | members.signature, 26 | statistics.share, 27 | statistics.forward, 28 | statistics.digg, 29 | statistics.play, 30 | statistics.comment 31 | FROM (SELECT videos.*, array_agg(DISTINCT video_urls.url) AS video_urls 32 | FROM videos JOIN video_urls ON video_urls.video_id = videos.id 33 | GROUP BY videos.id) AS v 34 | JOIN members ON members.sec_uid = v.author_sec_id 35 | LEFT JOIN (SELECT * 36 | FROM statistics JOIN (SELECT id AS statistic_id, MAX(created_at) AS created_at 37 | FROM statistics 38 | GROUP BY id) AS latest_s 39 | ON "statistics".id = latest_s.statistic_id AND 40 | "statistics".created_at = 41 | latest_s.created_at) AS statistics 42 | ON statistics.id = v.id ); 43 | 44 | COMMIT; 45 | -------------------------------------------------------------------------------- /internal/db/comments.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package db 6 | 7 | import ( 8 | "context" 9 | "encoding/json" 10 | "time" 11 | 12 | "github.com/pkg/errors" 13 | "upper.io/db.v3/lib/sqlbuilder" 14 | 15 | "github.com/asoul-sig/asoul-video/internal/dbutil" 16 | ) 17 | 18 | var _ CommentsStore = (*comments)(nil) 19 | 20 | var Comments CommentsStore 21 | 22 | type CommentsStore interface { 23 | // Create creates a new comment with the given options. 24 | // If the comment already exists, it returns ErrCommentExists. 25 | Create(ctx context.Context, cid string, opts CreateCommentOptions) error 26 | } 27 | 28 | func NewCommentsStore(db sqlbuilder.Database) CommentsStore { 29 | return &comments{db} 30 | } 31 | 32 | type Comment struct { 33 | Cid string `db:"cid" json:"cid"` 34 | VideoID string `db:"video_id" json:"video_id"` 35 | DiggCount int64 `db:"digg_count" json:"digg_count"` 36 | Text string `db:"text" json:"text"` 37 | TextClean string `db:"text_clean" json:"text_clean"` 38 | TextExtra json.RawMessage `db:"text_extra" json:"text_extra"` 39 | UserNickname string `db:"user_nickname" json:"user_nickname"` 40 | UserAvatarURI string `db:"user_avatar_uri" json:"user_avatar_uri"` 41 | UserSecUID string `db:"user_sec_uid" json:"user_sec_uid"` 42 | CreatedAt time.Time `db:"created_at" json:"created_at"` 43 | } 44 | 45 | type comments struct { 46 | sqlbuilder.Database 47 | } 48 | 49 | type CreateCommentOptions struct { 50 | VideoID string 51 | Text string 52 | TextClean string 53 | TextExtra json.RawMessage 54 | UserNickname string 55 | UserAvatarURI string 56 | UserSecUID string 57 | CreatedAt time.Time 58 | } 59 | 60 | var ErrCommentExists = errors.New("comment exists") 61 | 62 | func (db *comments) Create(ctx context.Context, cid string, opts CreateCommentOptions) error { 63 | _, err := db.WithContext(ctx).InsertInto("comments"). 64 | Columns("cid", "video_id", "text", "text_clean", "text_extra", "user_nickname", "user_avatar_uri", "user_sec_uid", "created_at"). 65 | Values(cid, opts.VideoID, opts.Text, opts.TextClean, opts.TextExtra, opts.UserNickname, opts.UserAvatarURI, opts.UserSecUID, opts.CreatedAt). 66 | Exec() 67 | 68 | if err != nil { 69 | if dbutil.IsUniqueViolation(err, "comments_pkey") { 70 | return ErrCommentExists 71 | } 72 | return err 73 | } 74 | return nil 75 | } 76 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '16 0 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'go', 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v2 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v2 71 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | gocontext "context" 5 | "io/fs" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/flamego/flamego" 10 | "github.com/robfig/cron/v3" 11 | log "unknwon.dev/clog/v2" 12 | 13 | "github.com/asoul-sig/asoul-video/frontend" 14 | "github.com/asoul-sig/asoul-video/internal/context" 15 | "github.com/asoul-sig/asoul-video/internal/db" 16 | "github.com/asoul-sig/asoul-video/internal/route" 17 | ) 18 | 19 | var ( 20 | BuildTime string 21 | BuildCommit string 22 | ) 23 | 24 | func main() { 25 | defer log.Stop() 26 | err := log.NewConsole() 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | if err := db.Init(); err != nil { 32 | log.Fatal("Failed to connect to database: %v", err) 33 | } 34 | 35 | // Register cron task. 36 | ctx := gocontext.Background() 37 | if err := db.Videos.Refresh(ctx); err != nil { 38 | log.Error("Failed to refresh materialized views: %v", err) 39 | } 40 | c := cron.New() 41 | if _, err := c.AddFunc("@every 1h", func() { 42 | if err := db.Videos.Refresh(ctx); err != nil { 43 | log.Error("Failed to refresh materialized views: %v", err) 44 | } 45 | log.Trace("Refresh materialized views.") 46 | }); err != nil { 47 | log.Fatal("Failed to add cron function: %v", err) 48 | } 49 | c.Start() 50 | 51 | f := flamego.Classic() 52 | f.Use(func(ctx flamego.Context) { 53 | ctx.ResponseWriter().Header().Set("Access-Control-Allow-Methods", http.MethodGet) 54 | ctx.ResponseWriter().Header().Set("Access-Control-Max-Age", "600") 55 | ctx.ResponseWriter().Header().Set("Access-Control-Allow-Origin", "*") 56 | }) 57 | f.Use(context.Contexter()) 58 | 59 | fe, err := fs.Sub(frontend.FS, "dist") 60 | if err != nil { 61 | log.Fatal("Failed to sub filesystem: %v", err) 62 | } 63 | f.Use(flamego.Static(flamego.StaticOptions{ 64 | FileSystem: http.FS(fe), 65 | })) 66 | 67 | f.Group("/api", func() { 68 | member := route.NewMemberHandler() 69 | f.Get("/members", member.List) 70 | f.Get("/member/{secUID}", member.GetBySecUID) 71 | 72 | video := route.NewVideoHandler() 73 | f.Get("/videos", video.List) 74 | f.Group("/video", func() { 75 | f.Get("/{id}", video.GetByID) 76 | f.Get("/random", video.Random) 77 | }) 78 | }) 79 | 80 | // Crawler report service. 81 | source := route.NewSourceHandler() 82 | f.Group("/source", func() { 83 | f.Post("/report", source.Report) 84 | f.Get("/video_urls", source.VideoURLs) 85 | f.Get("/video_ids", source.VideoIDs) 86 | }, source.VerifyKey(os.Getenv("SOURCE_REPORT_KEY"))) 87 | 88 | f.Get("/ping", func(ctx context.Context) { 89 | ctx.Success(map[string]interface{}{ 90 | "build_time": BuildTime, 91 | "build_commit": BuildCommit, 92 | }) 93 | }) 94 | 95 | f.Run() 96 | } 97 | -------------------------------------------------------------------------------- /pkg/model/model.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package model 6 | 7 | import ( 8 | "encoding/json" 9 | "time" 10 | ) 11 | 12 | type Statistic struct { 13 | Share int64 `db:"share" json:"share"` 14 | Forward int64 `db:"forward" json:"forward"` 15 | Digg int64 `db:"digg" json:"digg"` 16 | Play int64 `db:"play" json:"play"` 17 | Comment int64 `db:"comment" json:"comment"` 18 | } 19 | 20 | type UpdateMember struct { 21 | SecUID MemberSecUID `json:"sec_uid"` 22 | UID string `json:"uid"` 23 | UniqueID string `json:"unique_id"` 24 | ShortUID string `json:"short_uid"` 25 | Name string `json:"name"` 26 | AvatarURL string `json:"avatar_url"` 27 | Signature string `json:"signature"` 28 | } 29 | 30 | type CreateVideo struct { 31 | ID string `json:"id"` 32 | VID string `json:"vid"` 33 | AuthorSecUID MemberSecUID `json:"author_sec_uid"` 34 | Description string `json:"description"` 35 | TextExtra []string `json:"text_extra"` 36 | OriginCoverURLs []string `json:"origin_cover_urls"` 37 | DynamicCoverURLs []string `json:"dynamic_cover_urls"` 38 | IsDynamicCover bool `json:"is_dynamic_cover"` 39 | VideoHeight int `json:"video_height"` 40 | VideoWidth int `json:"video_width"` 41 | VideoDuration int64 `json:"video_duration"` 42 | VideoRatio string `json:"video_ratio"` 43 | VideoURLs []string `json:"video_urls"` 44 | VideoCDNURL string `json:"video_cdn_url"` 45 | 46 | Statistic 47 | } 48 | 49 | type UpdateVideoMeta struct { 50 | ID string `json:"id"` 51 | VID string `json:"vid"` 52 | OriginCoverURLs []string `json:"origin_cover_urls"` 53 | DynamicCoverURLs []string `json:"dynamic_cover_urls"` 54 | IsDynamicCover bool `json:"is_dynamic_cover"` 55 | CreatedAt time.Time `json:"created_at"` 56 | 57 | Statistic 58 | } 59 | 60 | type CreateComment struct { 61 | Cid string `json:"cid"` 62 | VideoID string `json:"video_id"` 63 | Text string `json:"text"` 64 | TextClean string `json:"text_clean"` 65 | TextExtra json.RawMessage `json:"text_extra"` 66 | UserNickname string `json:"user_nickname"` 67 | UserAvatarURI string `json:"user_avatar_uri"` 68 | UserSecUID string `json:"user_sec_uid"` 69 | CreatedAt time.Time `json:"created_at"` 70 | } 71 | 72 | type UpdateFacePoint struct { 73 | ID string `json:"id"` 74 | FacePoints json.RawMessage `json:"face_points"` 75 | CoverWidth int `json:"cover_width"` 76 | CoverHeight int `json:"cover_height"` 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎬 asoul-video ![Go](https://github.com/asoul-video/asoul-video/workflows/Go/badge.svg) [![Go Report Card](https://goreportcard.com/badge/github.com/asoul-video/asoul-video)](https://goreportcard.com/report/github.com/asoul-video/asoul-video) [![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?logo=sourcegraph)](https://sourcegraph.com/github.com/asoul-video/asoul-video) 2 | 3 | ![](https://screenshotapi-dot-net.storage.googleapis.com/asoul_video__077bf1d6aeee.png) 4 | 5 | ## 配置开发环境 6 | 7 | ### 前端 8 | 9 | TBD 10 | 11 | ### 后端 12 | 13 | A-SOUL Video 后端二进制文件需要在 Linux 系统上运行,但你可以在 macOS、Windows 等系统上进行开发。 14 | 15 | #### 步骤 1: 安装依赖 16 | 17 | A-SOUL Video 后端需要安装以下依赖: 18 | 19 | - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) (v1.8.3 或更高版本) 20 | - [Go](https://golang.org/doc/install) (v1.16 或更高版本) 21 | - [PostgreSQL](https://wiki.postgresql.org/wiki/Detailed_installation_guides) (v12 或更高版本) 22 | - [Golang Migrate](https://github.com/golang-migrate/migrate/) (v4.7.0 或更高版本) 23 | 24 | ##### macOS 25 | 26 | 1. 安装 [Homebrew](https://brew.sh/). 27 | 1. 安装依赖: 28 | 29 | ```bash 30 | brew install go postgresql git 31 | ``` 32 | 33 | 1. 配置 PostgreSQL 数据库自启动: 34 | 35 | ```bash 36 | brew services start postgresql 37 | ``` 38 | 39 | 1. 确保在 `$PATH` 环境变量中设置了 PostgreSQL 客户端命令 `psql` 的路径。通过 Homebrew 的安装默认不会设置该环境变量。执行 `brew info postgresql` 40 | 命令,可以在 `Caveats` 段落中看到 Homebrew 提供的安装 `psql` 的方法。除此之外,也可以使用下方的命令进行安装,注意你可能需要根据本机 Homebrew 以及终端环境修改命令中的参数。 41 | 42 | ```bash 43 | hash psql || { echo 'export PATH="/usr/local/opt/postgresql/bin:$PATH"' >> ~/.bash_profile } 44 | source ~/.bash_profile 45 | ``` 46 | 47 | #### 步骤 2: 数据库初始化 48 | 49 | 你需要创建一个全新的 Postgres 数据库和一个对该数据库拥有完全操作权限的数据库用户。 50 | 51 | 1. 为当前 UNIX 用户创建数据库。 52 | 53 | ```bash 54 | # 对于 Linux 用户,首先需要切换到 postgres 用户终端下 55 | sudo su - postgres 56 | ``` 57 | 58 | ```bash 59 | createdb 60 | ``` 61 | 62 | 2. 创建 A-SOUL Video 用户并设置密码。 63 | 64 | ```bash 65 | createuser --superuser asoulvideo 66 | psql -c "ALTER USER asoulvideo WITH PASSWORD 'asoulvideo';" 67 | ``` 68 | 69 | 3. 创建 A-SOUL Video 数据库。 70 | 71 | ```bash 72 | createdb --owner=asoulvideo --encoding=UTF8 --template=template0 asoulvideo 73 | ``` 74 | 75 | #### 步骤 3: 拉取代码 76 | 77 | 通常来说,你并不需要拉取所有的历史代码,因此可以设置 `--depth 1` 参数。 78 | 79 | ```bash 80 | git clone --depth 1 https://github.com/asoul-video/asoul-video 81 | ``` 82 | 83 | **注意** 本仓库开启 Go Module,请将仓库目录放置在你的 `$GOPATH` 目录之外。 84 | 85 | #### 步骤 4: 配置数据库连接 86 | 87 | A-SOUL Video 后端从以下环境变量中读取数据库连接参数。 [`PG*` 环境变量](http://www.postgresql.org/docs/current/static/libpq-envars.html). 88 | 89 | 将以下这些环境变量参数添加至 `~/.bashrc` 文件中: 90 | 91 | ``` 92 | export PGHOST=localhost 93 | export PGUSER=asoulvideo 94 | export PGPASSWORD=asoulvideo 95 | export PGDATABASE=asoulvideo 96 | export PGSSLMODE=disable 97 | ``` 98 | 99 | 你也可以使用类似 [`direnv`](https://direnv.net/) 这样的工具来管理你的环境变量。 100 | 101 | #### 步骤 5: 启动 Web 服务器 102 | 103 | 启动 Web 服务器前,你需要确保以下环境变量中的参数数正确可用的,并将他们添加至你的 `~/.bashrc` 文件中: 104 | 105 | ``` 106 | # 爬虫上报数据时的鉴权参数 107 | export SOURCE_REPORT_KEY= 108 | ``` 109 | 110 | ```bash 111 | go build . && ./asoul-video 112 | ``` 113 | 114 | ## License 115 | 116 | MIT 117 | -------------------------------------------------------------------------------- /internal/db/members.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package db 6 | 7 | import ( 8 | "context" 9 | 10 | "github.com/pkg/errors" 11 | dbv3 "upper.io/db.v3" 12 | "upper.io/db.v3/lib/sqlbuilder" 13 | 14 | "github.com/asoul-sig/asoul-video/pkg/model" 15 | ) 16 | 17 | var _ MembersStore = (*members)(nil) 18 | 19 | var Members MembersStore 20 | 21 | type MembersStore interface { 22 | // Upsert creates a new member profile record with the given options, 23 | // it updates the `name` `avatar_url` `signature` field if the member is exists. 24 | Upsert(ctx context.Context, opts UpsertMemberOptions) error 25 | // GetBySecID returns the latest member profile with the given SecUID. 26 | GetBySecID(ctx context.Context, secUID model.MemberSecUID) (*Member, error) 27 | // GetBySecIDs returns the members' profile with the given SecUIDs. 28 | // It will be ignored if the member does not exist. 29 | GetBySecIDs(ctx context.Context, secUIDs ...model.MemberSecUID) ([]*Member, error) 30 | // List returns all the members. 31 | List(ctx context.Context) ([]*Member, error) 32 | } 33 | 34 | func NewMembersStore(db sqlbuilder.Database) MembersStore { 35 | return &members{db} 36 | } 37 | 38 | type Member struct { 39 | SecUID model.MemberSecUID `db:"sec_uid" json:"sec_uid"` 40 | UID string `db:"uid" json:"uid"` 41 | UniqueID string `db:"unique_id" json:"unique_id"` 42 | ShortUID string `db:"short_id" json:"short_uid"` 43 | Name string `db:"name" json:"name"` 44 | AvatarURL string `db:"avatar_url" json:"avatar_url"` 45 | Signature string `db:"signature" json:"signature"` 46 | } 47 | 48 | type members struct { 49 | sqlbuilder.Database 50 | } 51 | 52 | type UpsertMemberOptions struct { 53 | SecUID model.MemberSecUID 54 | UID string 55 | UniqueID string 56 | ShortUID string 57 | Name string 58 | AvatarURL string 59 | Signature string 60 | } 61 | 62 | func (db *members) Upsert(ctx context.Context, opts UpsertMemberOptions) error { 63 | _, err := db.GetBySecID(ctx, opts.SecUID) 64 | if err == nil { 65 | if _, err := db.WithContext(ctx).Update("members").Set( 66 | "name", opts.Name, 67 | "avatar_url", opts.AvatarURL, 68 | "signature", opts.Signature). 69 | Where("sec_uid = ?", opts.SecUID).Exec(); err != nil { 70 | return errors.Wrap(err, "update member") 71 | } 72 | return nil 73 | 74 | } else if err != ErrMemberNotFound { 75 | return errors.Wrap(err, "get member by sec_id") 76 | } 77 | 78 | _, err = db.WithContext(ctx).InsertInto("members"). 79 | Columns("uid", "unique_id", "sec_uid", "short_id", "name", "avatar_url", "signature"). 80 | Values(opts.UID, opts.UniqueID, opts.SecUID, opts.ShortUID, opts.Name, opts.AvatarURL, opts.Signature). 81 | Exec() 82 | return err 83 | } 84 | 85 | var ErrMemberNotFound = errors.New("member dose not exist") 86 | 87 | func (db *members) GetBySecID(ctx context.Context, secUID model.MemberSecUID) (*Member, error) { 88 | var member Member 89 | 90 | err := db.WithContext(ctx).SelectFrom("members"). 91 | Where("sec_uid = ?", secUID). 92 | OrderBy("created_at DESC"). 93 | One(&member) 94 | if err != nil { 95 | if err == dbv3.ErrNoMoreRows { 96 | return nil, ErrMemberNotFound 97 | } 98 | return nil, err 99 | } 100 | 101 | return &member, nil 102 | } 103 | 104 | func (db *members) GetBySecIDs(ctx context.Context, secUIDs ...model.MemberSecUID) ([]*Member, error) { 105 | var members []*Member 106 | 107 | return members, db.WithContext(ctx).SelectFrom("members"). 108 | Where("sec_uid IN ?", secUIDs). 109 | OrderBy("created_at DESC"). 110 | All(&members) 111 | } 112 | 113 | func (db *members) List(ctx context.Context) ([]*Member, error) { 114 | var members []*Member 115 | return members, db.WithContext(ctx).SelectFrom("members").OrderBy("uid").All(&members) 116 | } 117 | -------------------------------------------------------------------------------- /internal/db/video_urls.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package db 6 | 7 | import ( 8 | "context" 9 | "net/url" 10 | "strings" 11 | "time" 12 | 13 | "github.com/pkg/errors" 14 | "upper.io/db.v3/lib/sqlbuilder" 15 | 16 | "github.com/asoul-sig/asoul-video/internal/dbutil" 17 | ) 18 | 19 | type VideoStatus string 20 | 21 | var ( 22 | VideoStatusAvailable VideoStatus = "available" 23 | VideoStatusUnavailable VideoStatus = "unavailable" 24 | ) 25 | 26 | var _ VideoURLsStore = (*videoURLs)(nil) 27 | 28 | var VideoURLs VideoURLsStore 29 | 30 | type VideoURLsStore interface { 31 | // Create creates a new video url with the given video ID and url. 32 | Create(ctx context.Context, videoID, url string) error 33 | // GetByVideoID returns the available video urls with the given video ID. 34 | GetByVideoID(ctx context.Context, videoID string) ([]string, error) 35 | // GetAvailableVideoURLs returns all the available video urls. 36 | GetAvailableVideoURLs(ctx context.Context) ([]string, error) 37 | // SetStatus set the video url status. 38 | SetStatus(ctx context.Context, videoURL string, status VideoStatus) error 39 | } 40 | 41 | func NewVideoURLsStore(db sqlbuilder.Database) VideoURLsStore { 42 | return &videoURLs{db} 43 | } 44 | 45 | type VideoURL struct { 46 | VideoID string `db:"video_id"` 47 | URL string `db:"url"` 48 | Status string `db:"status"` 49 | LastCheckAt time.Time `db:"last_check_at"` 50 | } 51 | 52 | type videoURLs struct { 53 | sqlbuilder.Database 54 | } 55 | 56 | var ErrVideoURLExists = errors.New("duplicate video url") 57 | 58 | func (db *videoURLs) Create(ctx context.Context, videoID, u string) error { 59 | videoURL, err := url.Parse(u) 60 | if err != nil { 61 | return errors.Wrap(err, "parse URL") 62 | } 63 | if strings.HasSuffix(videoURL.Host, "douyinvod.com") { // Remove temporary video URL. 64 | return nil 65 | } 66 | 67 | _, err = db.WithContext(ctx).InsertInto("video_urls"). 68 | Columns("video_id", "url", "status"). 69 | Values(videoID, u, VideoStatusAvailable). 70 | Exec() 71 | if err != nil { 72 | if dbutil.IsUniqueViolation(err, "video_urls_pkey") { 73 | return ErrVideoURLExists 74 | } 75 | return err 76 | } 77 | return nil 78 | } 79 | 80 | func (db *videoURLs) GetByVideoID(ctx context.Context, videoID string) ([]string, error) { 81 | var videoURLs []*VideoURL 82 | if err := db.WithContext(ctx).SelectFrom("video_urls"). 83 | Where("video_id = ? AND status = ?", videoID, VideoStatusAvailable). 84 | All(&videoURLs); err != nil { 85 | return nil, errors.Wrap(err, "get video urls") 86 | } 87 | 88 | urls := make([]string, 0, len(videoURLs)) 89 | for _, v := range videoURLs { 90 | urls = append(urls, v.URL) 91 | } 92 | return urls, nil 93 | } 94 | 95 | func (db *videoURLs) GetAvailableVideoURLs(ctx context.Context) ([]string, error) { 96 | var videoURLs []*VideoURL 97 | if err := db.WithContext(ctx).SelectFrom("video_urls"). 98 | Where("status = ?", VideoStatusAvailable). 99 | All(&videoURLs); err != nil { 100 | return nil, errors.Wrap(err, "get video urls") 101 | } 102 | 103 | urls := make([]string, 0, len(videoURLs)) 104 | for _, v := range videoURLs { 105 | urls = append(urls, v.URL) 106 | } 107 | return urls, nil 108 | } 109 | 110 | func (db *videoURLs) SetStatus(ctx context.Context, videoURL string, status VideoStatus) error { 111 | q := db.WithContext(ctx).Update("video_urls") 112 | 113 | switch status { 114 | case VideoStatusAvailable: 115 | q = q.Set("status", VideoStatusAvailable, "last_check_at", time.Now()) 116 | case VideoStatusUnavailable: 117 | q = q.Set("status", VideoStatusUnavailable, "last_check_at", time.Now()) 118 | default: 119 | return errors.Errorf("unexpected status: %q", status) 120 | } 121 | 122 | _, err := q.Where("video_id = ?", videoURL).Exec() 123 | if err != nil { 124 | return errors.Wrap(err, "update status") 125 | } 126 | return nil 127 | } 128 | -------------------------------------------------------------------------------- /assets/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | ASOUL-Video 4 | 5 | 129 | 130 | 131 | 132 | 143 | 144 |
145 |
146 |
147 | 148 |

ASOUL-Video 前端仍在建设中......

149 |

但我们目前可以提供 Web API。

150 | 151 | 174 |
175 |
176 | 177 |
178 | 179 | -------------------------------------------------------------------------------- /internal/route/source.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package route 6 | 7 | import ( 8 | "encoding/json" 9 | "net/http" 10 | 11 | jsoniter "github.com/json-iterator/go" 12 | "github.com/pkg/errors" 13 | log "unknwon.dev/clog/v2" 14 | 15 | "github.com/asoul-sig/asoul-video/internal/context" 16 | "github.com/asoul-sig/asoul-video/internal/db" 17 | "github.com/asoul-sig/asoul-video/pkg/model" 18 | ) 19 | 20 | type Source struct{} 21 | 22 | // NewSourceHandler creates a new Source router. 23 | func NewSourceHandler() *Source { 24 | return &Source{} 25 | } 26 | 27 | // VerifyKey is the middleware which verifies the crawler key. 28 | // Only the real acao we can trust. 29 | func (*Source) VerifyKey(key string) func(ctx context.Context) { 30 | return func(ctx context.Context) { 31 | if ctx.Request().Header.Get("Authorization") != key { 32 | ctx.Error(http.StatusForbidden, errors.New("error key")) 33 | } 34 | } 35 | } 36 | 37 | func (*Source) Report(ctx context.Context) { 38 | var req struct { 39 | Type model.ReportType `json:"type"` 40 | Data jsoniter.RawMessage `json:"data"` 41 | } 42 | if err := jsoniter.NewDecoder(ctx.Request().Request.Body).Decode(&req); err != nil { 43 | ctx.Error(http.StatusBadRequest, err) 44 | return 45 | } 46 | 47 | switch req.Type { 48 | case model.ReportTypeUpdateMember: 49 | var updateMember model.UpdateMember 50 | if err := jsoniter.Unmarshal(req.Data, &updateMember); err != nil { 51 | ctx.Error(http.StatusBadRequest, err) 52 | return 53 | } 54 | 55 | if err := db.Members.Upsert(ctx.Request().Context(), db.UpsertMemberOptions{ 56 | SecUID: updateMember.SecUID, 57 | UID: updateMember.UID, 58 | UniqueID: updateMember.UniqueID, 59 | ShortUID: updateMember.ShortUID, 60 | Name: updateMember.Name, 61 | AvatarURL: updateMember.AvatarURL, 62 | Signature: updateMember.Signature, 63 | }); err != nil { 64 | log.Error("Failed to create new member: %v", err) 65 | ctx.ServerError() 66 | return 67 | } 68 | 69 | case model.ReportTypeCreateVideo: 70 | var createVideos []model.CreateVideo 71 | if err := jsoniter.Unmarshal(req.Data, &createVideos); err != nil { 72 | ctx.Error(http.StatusBadRequest, err) 73 | return 74 | } 75 | 76 | for _, createVideo := range createVideos { 77 | if err := db.Videos.Create(ctx.Request().Context(), createVideo.ID, db.CreateVideoOptions{ 78 | VID: createVideo.VID, 79 | AuthorSecUID: createVideo.AuthorSecUID, 80 | Description: createVideo.Description, 81 | TextExtra: createVideo.TextExtra, 82 | OriginCoverURLs: createVideo.OriginCoverURLs, 83 | DynamicCoverURLs: createVideo.DynamicCoverURLs, 84 | IsDynamicCover: createVideo.IsDynamicCover, 85 | VideoHeight: createVideo.VideoHeight, 86 | VideoWidth: createVideo.VideoWidth, 87 | VideoDuration: createVideo.VideoDuration, 88 | VideoRatio: createVideo.VideoRatio, 89 | }); err != nil { 90 | log.Error("Failed to create new video: %v", err) 91 | continue 92 | } 93 | 94 | if err := db.Statistics.Create(ctx.Request().Context(), createVideo.ID, db.CreateStatisticOptions{ 95 | Share: createVideo.Share, 96 | Forward: createVideo.Forward, 97 | Digg: createVideo.Digg, 98 | Play: createVideo.Play, 99 | Comment: createVideo.Comment, 100 | }); err != nil { 101 | log.Error("Failed to create video statistic: %v", err) 102 | } 103 | } 104 | 105 | case model.ReportTypeUpdateVideoMeta: 106 | var updateVideoMeta []*model.UpdateVideoMeta 107 | if err := jsoniter.Unmarshal(req.Data, &updateVideoMeta); err != nil { 108 | ctx.Error(http.StatusBadRequest, err) 109 | return 110 | } 111 | 112 | for _, videoMeta := range updateVideoMeta { 113 | if err := db.Videos.Update(ctx.Request().Context(), videoMeta.ID, db.UpdateVideoOptions{ 114 | VID: videoMeta.VID, 115 | OriginCoverURLs: videoMeta.OriginCoverURLs, 116 | DynamicCoverURLs: videoMeta.DynamicCoverURLs, 117 | IsDynamicCover: videoMeta.IsDynamicCover, 118 | CreatedAt: videoMeta.CreatedAt, 119 | }); err != nil { 120 | log.Error("Failed to update video meta data: %v", err) 121 | } 122 | 123 | if err := db.Statistics.Create(ctx.Request().Context(), videoMeta.ID, db.CreateStatisticOptions{ 124 | Share: videoMeta.Share, 125 | Forward: videoMeta.Forward, 126 | Digg: videoMeta.Digg, 127 | Play: videoMeta.Play, 128 | Comment: videoMeta.Comment, 129 | }); err != nil { 130 | log.Error("Failed to create video statistic: %v", err) 131 | } 132 | } 133 | 134 | case model.ReportTypeComment: 135 | var createComment []*model.CreateComment 136 | if err := json.Unmarshal(req.Data, &createComment); err != nil { 137 | ctx.Error(http.StatusBadRequest, err) 138 | return 139 | } 140 | 141 | for _, comment := range createComment { 142 | if comment.Text == "" { 143 | continue 144 | } 145 | 146 | if err := db.Comments.Create(ctx.Request().Context(), comment.Cid, db.CreateCommentOptions{ 147 | VideoID: comment.VideoID, 148 | Text: comment.Text, 149 | TextClean: comment.TextClean, 150 | TextExtra: comment.TextExtra, 151 | UserNickname: comment.UserNickname, 152 | UserAvatarURI: comment.UserAvatarURI, 153 | UserSecUID: comment.UserSecUID, 154 | CreatedAt: comment.CreatedAt, 155 | }); err != nil { 156 | if err != db.ErrCommentExists { 157 | log.Error("Failed to create new comment: %v", err) 158 | } 159 | } 160 | } 161 | 162 | case model.ReportTypeFacePoint: 163 | var facePoint model.UpdateFacePoint 164 | if err := json.Unmarshal(req.Data, &facePoint); err != nil { 165 | ctx.Error(http.StatusBadRequest, err) 166 | return 167 | } 168 | 169 | 170 | if err := db.Videos.Update(ctx.Request().Context(), facePoint.ID, db.UpdateVideoOptions{ 171 | FacePoints: facePoint.FacePoints, 172 | CoverHeight: facePoint.CoverHeight, 173 | CoverWidth: facePoint.CoverWidth, 174 | }); err != nil { 175 | log.Error("Failed to update video face point: %v", err) 176 | } 177 | 178 | default: 179 | ctx.Error(http.StatusBadRequest, errors.Errorf("unexpected report type %q", req.Type)) 180 | return 181 | } 182 | 183 | ctx.ResponseWriter().WriteHeader(http.StatusNoContent) 184 | } 185 | 186 | func (*Source) VideoURLs(ctx context.Context) { 187 | urls, err := db.VideoURLs.GetAvailableVideoURLs(ctx.Request().Context()) 188 | if err != nil { 189 | ctx.ServerError() 190 | log.Error("Failed to get available video urls: %v", err) 191 | return 192 | } 193 | ctx.Success(urls) 194 | } 195 | 196 | func (*Source) VideoIDs(ctx context.Context) { 197 | uids, err := db.Videos.ListIDs(ctx.Request().Context()) 198 | if err != nil { 199 | ctx.ServerError() 200 | log.Error("Failed to get video ids: %v", err) 201 | return 202 | } 203 | ctx.Success(uids) 204 | } 205 | -------------------------------------------------------------------------------- /internal/db/videos.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 E99p1ant. All rights reserved. 2 | // Use of this source code is governed by a MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package db 6 | 7 | import ( 8 | "context" 9 | "encoding/json" 10 | "math/rand" 11 | "time" 12 | 13 | "github.com/pkg/errors" 14 | dbv3 "upper.io/db.v3" 15 | "upper.io/db.v3/lib/sqlbuilder" 16 | 17 | "github.com/asoul-sig/asoul-video/internal/dbutil" 18 | "github.com/asoul-sig/asoul-video/pkg/model" 19 | ) 20 | 21 | var _ VideosStore = (*videos)(nil) 22 | 23 | var Videos VideosStore 24 | 25 | type VideosStore interface { 26 | // Create creates a new video record with the given options. 27 | Create(ctx context.Context, id string, opts CreateVideoOptions) error 28 | // Update updates the video with the given options. 29 | Update(ctx context.Context, id string, opts UpdateVideoOptions) error 30 | // GetByID returns video with the given id, it returns `ErrVideoNotFound` error if video does not exist. 31 | GetByID(ctx context.Context, id string) (*Video, error) 32 | // List returns the video list. 33 | List(ctx context.Context, opts ListVideoOptions) ([]*Video, error) 34 | // ListIDs returns all the video IDs. 35 | ListIDs(ctx context.Context) ([]string, error) 36 | // Random returns a video randomly. 37 | Random(ctx context.Context) (*Video, error) 38 | // Refresh refreshes the materialized view. 39 | Refresh(ctx context.Context) error 40 | } 41 | 42 | func NewVideosStore(db sqlbuilder.Database) VideosStore { 43 | return &videos{db} 44 | } 45 | 46 | type Video struct { 47 | ID string `db:"id" json:"id"` 48 | VID string `db:"vid" json:"vid"` 49 | AuthorSecUID model.MemberSecUID `db:"author_sec_id" json:"author_sec_uid"` 50 | Author *Member `db:",inline" json:"author"` 51 | Statistic model.Statistic `db:",inline" json:"statistic"` 52 | Description string `db:"description" json:"description"` 53 | TextExtra []string `db:"text_extra" json:"text_extra"` 54 | OriginCoverURLs []string `db:"origin_cover_urls" json:"origin_cover_urls"` 55 | DynamicCoverURLs []string `db:"dynamic_cover_urls" json:"dynamic_cover_urls"` 56 | IsDynamicCover bool `db:"is_dynamic_cover" json:"is_dynamic_cover"` 57 | FacePoints *dbutil.JSON `db:"face_points" json:"face_points"` 58 | CoverHeight int `db:"cover_height" json:"cover_height"` 59 | CoverWidth int `db:"cover_width" json:"cover_width"` 60 | VideoHeight int `db:"video_height" json:"video_height"` 61 | VideoWidth int `db:"video_width" json:"video_width"` 62 | VideoDuration int64 `db:"video_duration" json:"video_duration"` 63 | VideoRatio string `db:"video_ratio" json:"video_ratio"` 64 | CreatedAt time.Time `db:"created_at" json:"created_at"` 65 | } 66 | 67 | type videos struct { 68 | sqlbuilder.Database 69 | } 70 | 71 | type CreateVideoOptions struct { 72 | VID string 73 | AuthorSecUID model.MemberSecUID 74 | Description string 75 | TextExtra []string 76 | OriginCoverURLs []string 77 | DynamicCoverURLs []string 78 | IsDynamicCover bool 79 | VideoHeight int 80 | VideoWidth int 81 | VideoDuration int64 82 | VideoRatio string 83 | } 84 | 85 | var ErrVideoExists = errors.New("duplicate video") 86 | 87 | func (db *videos) Create(ctx context.Context, id string, opts CreateVideoOptions) error { 88 | _, err := db.WithContext(ctx).InsertInto("videos"). 89 | Columns("id", "vid", "author_sec_id", "description", "text_extra", "origin_cover_urls", "dynamic_cover_urls", "is_dynamic_cover", "video_height", "video_width", "video_duration", "video_ratio"). 90 | Values(id, opts.VID, opts.AuthorSecUID, opts.Description, opts.TextExtra, opts.OriginCoverURLs, opts.DynamicCoverURLs, opts.IsDynamicCover, opts.VideoHeight, opts.VideoWidth, opts.VideoDuration, opts.VideoRatio). 91 | Exec() 92 | if err != nil { 93 | if dbutil.IsUniqueViolation(err, "videos_pkey") { 94 | if err := db.Update(ctx, id, UpdateVideoOptions{ 95 | VID: opts.VID, 96 | IsDynamicCover: opts.IsDynamicCover, 97 | OriginCoverURLs: opts.OriginCoverURLs, 98 | DynamicCoverURLs: opts.DynamicCoverURLs, 99 | }); err != nil { 100 | return errors.Wrap(err, "update video") 101 | } 102 | } else { 103 | return errors.Wrap(err, "create video") 104 | } 105 | } 106 | return nil 107 | } 108 | 109 | type UpdateVideoOptions struct { 110 | VID string 111 | IsDynamicCover bool 112 | OriginCoverURLs []string 113 | DynamicCoverURLs []string 114 | FacePoints json.RawMessage 115 | CoverHeight int 116 | CoverWidth int 117 | CreatedAt time.Time 118 | } 119 | 120 | func (db *videos) Update(ctx context.Context, id string, opts UpdateVideoOptions) error { 121 | _, err := db.GetByID(ctx, id) 122 | if err != nil { 123 | return errors.Wrap(err, "get video by id") 124 | } 125 | 126 | updateSets := make([]interface{}, 0, 10) 127 | updateSets = append(updateSets, "is_dynamic_cover", opts.IsDynamicCover) 128 | 129 | if opts.VID != "" { 130 | updateSets = append(updateSets, "vid", opts.VID) 131 | } 132 | if len(opts.OriginCoverURLs) > 0 { 133 | updateSets = append(updateSets, "origin_cover_urls", opts.OriginCoverURLs) 134 | } 135 | if len(opts.DynamicCoverURLs) > 0 { 136 | updateSets = append(updateSets, "dynamic_cover_urls", opts.DynamicCoverURLs) 137 | } 138 | if len(opts.FacePoints) > 4 { 139 | updateSets = append(updateSets, "face_points", opts.FacePoints) 140 | } 141 | if opts.CoverHeight != 0 { 142 | updateSets = append(updateSets, "cover_height", opts.CoverHeight) 143 | } 144 | if opts.CoverWidth != 0 { 145 | updateSets = append(updateSets, "cover_width", opts.CoverWidth) 146 | } 147 | if !opts.CreatedAt.IsZero() { 148 | updateSets = append(updateSets, "created_at", opts.CreatedAt) 149 | } 150 | if len(updateSets) == 0 { 151 | return nil 152 | } 153 | 154 | updateSets = append(updateSets, "updated_at", time.Now()) 155 | _, err = db.WithContext(ctx).Update("videos"). 156 | Set(updateSets...). 157 | Where("id = ?", id).Exec() 158 | return err 159 | } 160 | 161 | var ErrVideoNotFound = errors.New("video dose not exist") 162 | 163 | func (db *videos) GetByID(ctx context.Context, id string) (*Video, error) { 164 | var video Video 165 | if err := db.WithContext(ctx).SelectFrom("video_list").Where("id = ?", id).One(&video); err != nil { 166 | if err == dbv3.ErrNoMoreRows { 167 | return nil, ErrVideoNotFound 168 | } 169 | return nil, err 170 | } 171 | return &video, nil 172 | } 173 | 174 | type ListVideoOptions struct { 175 | Keyword string 176 | SecUIDs []string 177 | OrderBy string 178 | Order string 179 | 180 | Page int 181 | PageSize int 182 | } 183 | 184 | func (db *videos) List(ctx context.Context, opts ListVideoOptions) ([]*Video, error) { 185 | if opts.OrderBy != "video_duration" && opts.OrderBy != "created_at" { 186 | opts.OrderBy = "" 187 | } 188 | 189 | if opts.Order != "asc" { 190 | opts.Order = "desc" 191 | } 192 | 193 | if opts.Page <= 0 { 194 | opts.Page = 1 195 | } 196 | 197 | if opts.PageSize <= 0 || opts.PageSize >= 30 { 198 | opts.PageSize = 30 199 | } 200 | 201 | query := db.WithContext(ctx).SelectFrom("video_list") 202 | 203 | if len(opts.SecUIDs) != 0 { 204 | query = query.Where("author_sec_id IN ?", opts.SecUIDs) 205 | } 206 | 207 | if opts.Keyword != "" { 208 | query = query.And("description ILIKE ?", "%"+opts.Keyword+"%") 209 | } 210 | 211 | if opts.OrderBy != "" { 212 | query = query.OrderBy(opts.OrderBy + " " + opts.Order) 213 | } 214 | 215 | // Pagination 216 | query = query.Limit(opts.PageSize).Offset((opts.Page - 1) * opts.PageSize) 217 | 218 | var videos []*Video 219 | if err := query.All(&videos); err != nil { 220 | return nil, errors.Wrap(err, "get videos") 221 | } 222 | return videos, nil 223 | } 224 | 225 | func (db *videos) ListIDs(ctx context.Context) ([]string, error) { 226 | var idRows []struct { 227 | ID string `db:"id"` 228 | } 229 | if err := db.WithContext(ctx).Select("id").From("videos").OrderBy("id DESC").All(&idRows); err != nil { 230 | return nil, errors.Wrap(err, "select") 231 | } 232 | 233 | ids := make([]string, 0, len(idRows)) 234 | for _, row := range idRows { 235 | ids = append(ids, row.ID) 236 | } 237 | return ids, nil 238 | } 239 | 240 | func (db *videos) Random(ctx context.Context) (*Video, error) { 241 | var count int 242 | row, err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM video_list;") 243 | if err != nil { 244 | return nil, errors.Wrap(err, "count") 245 | } 246 | if err := row.Scan(&count); err != nil { 247 | return nil, errors.Wrap(err, "count") 248 | } 249 | 250 | var video Video 251 | if err := db.SelectFrom("video_list").Offset(rand.Intn(count)).Limit(1).One(&video); err != nil { 252 | return nil, errors.Wrap(err, "get video") 253 | } 254 | return &video, nil 255 | } 256 | 257 | func (db *videos) Refresh(ctx context.Context) error { 258 | _, err := db.WithContext(ctx).Exec("REFRESH MATERIALIZED VIEW video_list;") 259 | return err 260 | } 261 | -------------------------------------------------------------------------------- /frontend/src/views/Index.vue: -------------------------------------------------------------------------------- 1 | 87 | 88 | 365 | 366 | 369 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.63.0/go.mod h1:GmezbQc7T2snqkEXWfZ0sy0VfkB/ivI2DdtJL2DEmlg= 16 | cloud.google.com/go v0.64.0/go.mod h1:xfORb36jGvE+6EexW71nMEtL025s3x6xvuYUKM4JLv4= 17 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 18 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 19 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 20 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 21 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 22 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 23 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 24 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 25 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 26 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 27 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 28 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 29 | cloud.google.com/go/spanner v1.9.0/go.mod h1:xvlEn0NZ5v1iJPYsBnUVRDNvccDxsBTEi16pJRKQVws= 30 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 31 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 32 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 33 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 34 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 35 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 36 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= 37 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 38 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 39 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 40 | github.com/ClickHouse/clickhouse-go v1.3.12/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= 41 | github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= 42 | github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= 43 | github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 44 | github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 h1:ygIc8M6trr62pF5DucadTWGdEB4mEyvzi0e2nbcmcyA= 45 | github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= 46 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 47 | github.com/Shyp/go-dberror v0.0.0-20180123195207-36ecba57721e h1:IZUh3h8z+h/7feJrZvvE9wAsL6//9T/D1VYLHEejNtY= 48 | github.com/Shyp/go-dberror v0.0.0-20180123195207-36ecba57721e/go.mod h1:MhWOxc4KCt6KrmX1kPy9pI8Rx1ZA3IXjI2OHmMURdwA= 49 | github.com/alecthomas/participle/v2 v2.0.0-alpha5/go.mod h1:Z1zPLDbcGsVsBYsThKXY00i84575bN/nMczzIrU4rWU= 50 | github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= 51 | github.com/alecthomas/participle/v2 v2.0.0-alpha7/go.mod h1:NumScqsC42o9x+dGj8/YqsIfhrIQjFEOFovxotbBirA= 52 | github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1 h1:GDQdwm/gAcJcLAKQQZGOJ4knlw+7rfEQQcmwTbt4p5E= 53 | github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= 54 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 55 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 56 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 57 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 58 | github.com/apache/arrow/go/arrow v0.0.0-20200601151325-b2287a20f230/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0= 59 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 60 | github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= 61 | github.com/beeker1121/goque v1.0.3-0.20191103205551-d618510128af/go.mod h1:84CWnaDz4g1tEVnFLnuBigmGK15oPohy0RfvSN8d4eg= 62 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 63 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 64 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 65 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 66 | github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= 67 | github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= 68 | github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= 69 | github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= 70 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 71 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 72 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 73 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 74 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 75 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 76 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 77 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 78 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 79 | github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= 80 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 81 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 82 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 83 | github.com/cockroachdb/cockroach-go v0.0.0-20190925194419-606b3d062051/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= 84 | github.com/containerd/containerd v1.4.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 85 | github.com/containerd/containerd v1.4.1 h1:pASeJT3R3YyVn+94qEPk0SnU1OQ20Jd/T+SPKy9xehY= 86 | github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= 87 | github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= 88 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 89 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 90 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 91 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 92 | github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 93 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 94 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 95 | github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= 96 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 97 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 98 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 99 | github.com/denisenkom/go-mssqldb v0.0.0-20200620013148-b91950f658ec/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 100 | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= 101 | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= 102 | github.com/dhui/dktest v0.3.3 h1:DBuH/9GFaWbDRa42qsut/hbQu+srAQ0rPWnUoiGX7CA= 103 | github.com/dhui/dktest v0.3.3/go.mod h1:EML9sP4sqJELHn4jV7B0TY8oF6077nk83/tz7M56jcQ= 104 | github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= 105 | github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 106 | github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= 107 | github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= 108 | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= 109 | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= 110 | github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= 111 | github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= 112 | github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= 113 | github.com/eggsampler/acme/v3 v3.0.0/go.mod h1:gw64Ckma6iKulWks9BtE/g/9z/Vdz9D1lM7x7M1X1Ag= 114 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 115 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 116 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 117 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 118 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 119 | github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= 120 | github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= 121 | github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01/go.mod h1:ypD5nozFk9vcGw1ATYefw6jHe/jZP++Z15/+VTMcWhc= 122 | github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52/go.mod h1:yIquW87NGRw1FU5p5lEkpnt/QxoH5uPAOUlOVkAUuMg= 123 | github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= 124 | github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= 125 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 126 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 127 | github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= 128 | github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= 129 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= 130 | github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 131 | github.com/flamego/flamego v0.0.0-20210515130931-267d0ace579b/go.mod h1:DkwGPPSOX6S/4th2btOuP3HQX8zL59GZbxxOt6aFF0A= 132 | github.com/flamego/flamego v0.0.0-20210913073131-adc6656c34a1 h1:+WQYuogBWs50/qWau4AaqCTJzGyrx6du7bTyLPoVAtU= 133 | github.com/flamego/flamego v0.0.0-20210913073131-adc6656c34a1/go.mod h1:apiAxIxeHujHFX4Yr0BHmQFJuZUM07XztdQSChbeuPw= 134 | github.com/flamego/template v0.0.0-20210914144450-be182d441b73 h1:Zlafkjv8W1QqlfNqH8kKmelAt8X/CPkUuqo6otv4F0o= 135 | github.com/flamego/template v0.0.0-20210914144450-be182d441b73/go.mod h1:9bdmujHm26rSXXYmDQ3pfzUoKuV0R3BahgmSsSbvqUU= 136 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 137 | github.com/fsouza/fake-gcs-server v1.17.0/go.mod h1:D1rTE4YCyHFNa99oyJJ5HyclvN/0uQR+pM/VdlL83bw= 138 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 139 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 140 | github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 141 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 142 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 143 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 144 | github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY= 145 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 146 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 147 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 148 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 149 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 150 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 151 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 152 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 153 | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 154 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= 155 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 156 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 157 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 158 | github.com/gobuffalo/attrs v0.1.0/go.mod h1:fmNpaWyHM0tRm8gCZWKx8yY9fvaNLo2PyzBNSrBZ5Hw= 159 | github.com/gobuffalo/envy v1.8.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= 160 | github.com/gobuffalo/envy v1.9.0/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= 161 | github.com/gobuffalo/fizz v1.10.0/go.mod h1:J2XGPO0AfJ1zKw7+2BA+6FEGAkyEsdCOLvN93WCT2WI= 162 | github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= 163 | github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= 164 | github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc= 165 | github.com/gobuffalo/genny/v2 v2.0.5/go.mod h1:kRkJuAw9mdI37AiEYjV4Dl+TgkBDYf8HZVjLkqe5eBg= 166 | github.com/gobuffalo/github_flavored_markdown v1.1.0/go.mod h1:TSpTKWcRTI0+v7W3x8dkSKMLJSUpuVitlptCkpeY8ic= 167 | github.com/gobuffalo/helpers v0.6.0/go.mod h1:pncVrer7x/KRvnL5aJABLAuT/RhKRR9klL6dkUOhyv8= 168 | github.com/gobuffalo/helpers v0.6.1/go.mod h1:wInbDi0vTJKZBviURTLRMFLE4+nF2uRuuL2fnlYo7w4= 169 | github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= 170 | github.com/gobuffalo/logger v1.0.3/go.mod h1:SoeejUwldiS7ZsyCBphOGURmWdwUFXs0J7TCjEhjKxM= 171 | github.com/gobuffalo/nulls v0.2.0/go.mod h1:w4q8RoSCEt87Q0K0sRIZWYeIxkxog5mh3eN3C/n+dUc= 172 | github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= 173 | github.com/gobuffalo/packd v1.0.0/go.mod h1:6VTc4htmJRFB7u1m/4LeMTWjFoYrUiBkU9Fdec9hrhI= 174 | github.com/gobuffalo/packr/v2 v2.8.0/go.mod h1:PDk2k3vGevNE3SwVyVRgQCCXETC9SaONCNSXT1Q8M1g= 175 | github.com/gobuffalo/plush/v4 v4.0.0/go.mod h1:ErFS3UxKqEb8fpFJT7lYErfN/Nw6vHGiDMTjxpk5bQ0= 176 | github.com/gobuffalo/pop/v5 v5.3.1/go.mod h1:vcEDhh6cJ3WVENqJDFt/6z7zNb7lLnlN8vj3n5G9rYA= 177 | github.com/gobuffalo/tags/v3 v3.0.2/go.mod h1:ZQeN6TCTiwAFnS0dNcbDtSgZDwNKSpqajvVtt6mlYpA= 178 | github.com/gobuffalo/tags/v3 v3.1.0/go.mod h1:ZQeN6TCTiwAFnS0dNcbDtSgZDwNKSpqajvVtt6mlYpA= 179 | github.com/gobuffalo/validate/v3 v3.0.0/go.mod h1:HFpjq+AIiA2RHoQnQVTFKF/ZpUPXwyw82LgyDPxQ9r0= 180 | github.com/gobuffalo/validate/v3 v3.1.0/go.mod h1:HFpjq+AIiA2RHoQnQVTFKF/ZpUPXwyw82LgyDPxQ9r0= 181 | github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0= 182 | github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 183 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 184 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 185 | github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= 186 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 187 | github.com/golang-migrate/migrate/v4 v4.14.1 h1:qmRd/rNGjM1r3Ve5gHd5ZplytrD02UcItYNxJ3iUHHE= 188 | github.com/golang-migrate/migrate/v4 v4.14.1/go.mod h1:l7Ks0Au6fYHuUIxUhQ0rcVX1uLlJg54C/VvW7tvxSz0= 189 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 190 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 191 | github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 192 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 193 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 194 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 195 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 196 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 197 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 198 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 199 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 200 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 201 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 202 | github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 203 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 204 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 205 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 206 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 207 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 208 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 209 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 210 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 211 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 212 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 213 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 214 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 215 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 216 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 217 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 218 | github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 219 | github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 220 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 221 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 222 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 223 | github.com/google/certificate-transparency-go v1.0.22-0.20181127102053-c25855a82c75/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= 224 | github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 225 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 226 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 227 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 228 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 229 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 230 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 231 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 232 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 233 | github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= 234 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 235 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 236 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 237 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 238 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 239 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 240 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 241 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 242 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 243 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 244 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 245 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 246 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 247 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 248 | github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= 249 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 250 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 251 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 252 | github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= 253 | github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= 254 | github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 255 | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= 256 | github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 257 | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 258 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= 259 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 260 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 261 | github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 262 | github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= 263 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 264 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 265 | github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= 266 | github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 267 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 268 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 269 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 270 | github.com/honeycombio/beeline-go v1.1.1/go.mod h1:kN0cfUGBMfA87DyCYbiiLoSzWsnw3bluZvNEWtatHxk= 271 | github.com/honeycombio/libhoney-go v1.15.2/go.mod h1:JzhRPYgoBCd0rZvudrqmej4Ntx0w7AT3wAJpf5+t1WA= 272 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 273 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 274 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 275 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 276 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 277 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 278 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 279 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 280 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 281 | github.com/jackc/pgconn v1.3.2/go.mod h1:LvCquS3HbBKwgl7KbX9KyqEIumJAbm1UMcTvGaIf3bM= 282 | github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= 283 | github.com/jackc/pgconn v1.6.0/go.mod h1:yeseQo4xhQbgyJs2c87RAXOH2i624N0Fh1KSPJya7qo= 284 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 285 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 286 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 287 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 288 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 289 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 290 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 291 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 292 | github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 293 | github.com/jackc/pgproto3/v2 v2.0.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 294 | github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 295 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 296 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 297 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 298 | github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik= 299 | github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= 300 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 301 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 302 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 303 | github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg= 304 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 305 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 306 | github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 307 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 308 | github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= 309 | github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= 310 | github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= 311 | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= 312 | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 313 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 314 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 315 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 316 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 317 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 318 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 319 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 320 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 321 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 322 | github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= 323 | github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= 324 | github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= 325 | github.com/karrick/godirwalk v1.15.3/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= 326 | github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= 327 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 328 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 329 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 330 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 331 | github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= 332 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 333 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 334 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 335 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 336 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 337 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 338 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 339 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 340 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 341 | github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4= 342 | github.com/labstack/echo/v4 v4.3.0/go.mod h1:PvmtTvhVqKDzDQy4d3bWzPjZLzom4iQbAZy2sgZ/qI8= 343 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 344 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 345 | github.com/letsencrypt/boulder v0.0.0-20210917202203-e27634717069 h1:DeSUUAVBNrrp4ns6UxLSVRRD+yUAMIdr8/JrkBKnFyA= 346 | github.com/letsencrypt/boulder v0.0.0-20210917202203-e27634717069/go.mod h1:j+EafOUyKBj92XXCObHJ/vCXDyJimI/fqzlyjCcgwLM= 347 | github.com/letsencrypt/challtestsrv v1.2.0/go.mod h1:/gzSMb+5FjprRIa1TtW6ngjhUOr8JbEFM2XESzK2zPg= 348 | github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= 349 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 350 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 351 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 352 | github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 353 | github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= 354 | github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 355 | github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= 356 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 357 | github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= 358 | github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= 359 | github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= 360 | github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= 361 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 362 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 363 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 364 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 365 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= 366 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 367 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 368 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 369 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 370 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 371 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 372 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 373 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 374 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 375 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 376 | github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 377 | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 378 | github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 379 | github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 380 | github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= 381 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 382 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 383 | github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= 384 | github.com/miekg/dns v1.1.1/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 385 | github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= 386 | github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 387 | github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= 388 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 389 | github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 390 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 391 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 392 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 393 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 394 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 395 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 396 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 397 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 398 | github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= 399 | github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= 400 | github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= 401 | github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY= 402 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 403 | github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= 404 | github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= 405 | github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= 406 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 407 | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 408 | github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= 409 | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= 410 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 411 | github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= 412 | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= 413 | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= 414 | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= 415 | github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= 416 | github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= 417 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 418 | github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 419 | github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= 420 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 421 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 422 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 423 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 424 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 425 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 426 | github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU= 427 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 428 | github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= 429 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 430 | github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= 431 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 432 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 433 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 434 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 435 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 436 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 437 | github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= 438 | github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 439 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 440 | github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= 441 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 442 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 443 | github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 444 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 445 | github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= 446 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 447 | github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= 448 | github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 449 | github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= 450 | github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= 451 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 452 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 453 | github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 454 | github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 455 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 456 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 457 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 458 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 459 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 460 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 461 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 462 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 463 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 464 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 465 | github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 466 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 467 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 468 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 469 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 470 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 471 | github.com/snowflakedb/glog v0.0.0-20180824191149-f5055e6f21ce/go.mod h1:EB/w24pR5VKI60ecFnKqXzxX3dOorz1rnVicQTQrGM0= 472 | github.com/snowflakedb/gosnowflake v1.3.5/go.mod h1:13Ky+lxzIm3VqNDZJdyvu9MCGy+WgRdYFdXp96UcLZU= 473 | github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= 474 | github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= 475 | github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= 476 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 477 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 478 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 479 | github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= 480 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 481 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 482 | github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= 483 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 484 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 485 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 486 | github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 487 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 488 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 489 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 490 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 491 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 492 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 493 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 494 | github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= 495 | github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 496 | github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= 497 | github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 498 | github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= 499 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 500 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 501 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 502 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 503 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 504 | github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= 505 | github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= 506 | github.com/weppos/publicsuffix-go v0.15.1-0.20210513073137-f2f762ef3452/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= 507 | github.com/weppos/publicsuffix-go v0.15.1-0.20210823091527-b19572c4b3c2/go.mod h1:HYux0V0Zi04bHNwOHy4cXJVz/TQjYonnF6aoYhj+3QE= 508 | github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= 509 | github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= 510 | github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= 511 | github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 512 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 513 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 514 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 515 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 516 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 517 | github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= 518 | github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= 519 | github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= 520 | github.com/zmap/zcrypto v0.0.0-20210513123304-ea3fdbd5ea27/go.mod h1:M+NpodK20wxxR34wiF1hYGKFfCf21ZfEwCwtXoEAyOY= 521 | github.com/zmap/zlint/v3 v3.2.0/go.mod h1:Cg0VunVotKVXQyPMXtgrYoHW0guvugb13+p/6EgET/M= 522 | gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= 523 | go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= 524 | go.mongodb.org/mongo-driver v1.1.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= 525 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 526 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 527 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 528 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 529 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 530 | go.opentelemetry.io/contrib/propagators v0.19.0/go.mod h1:4QOdZClXISU5S43xZxk5tYaWcpb+lehqfKtE6PK6msE= 531 | go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg= 532 | go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc= 533 | go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA= 534 | go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg= 535 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 536 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 537 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 538 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 539 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 540 | goji.io/v3 v3.0.0/go.mod h1:c02FFnNiVNCDo+DpR2IhBQpM9r5G1BG/MkHNTPUJ13U= 541 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 542 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 543 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 544 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 545 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 546 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 547 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 548 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 549 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 550 | golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 551 | golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 552 | golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 553 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 554 | golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 555 | golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 556 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 557 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 558 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 559 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 560 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 561 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 562 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 563 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 564 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 565 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 566 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 567 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 568 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 569 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 570 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 571 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 572 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 573 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 574 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 575 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 576 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 577 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 578 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 579 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 580 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 581 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 582 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 583 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 584 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 585 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 586 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 587 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 588 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 589 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 590 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 591 | golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 592 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 593 | golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 594 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 595 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 596 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 597 | golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 598 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 599 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 600 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 601 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 602 | golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 603 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 604 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 605 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 606 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 607 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 608 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 609 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 610 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 611 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 612 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 613 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 614 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 615 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 616 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 617 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 618 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 619 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 620 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 621 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 622 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 623 | golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 624 | golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 625 | golang.org/x/net v0.0.0-20201029221708-28c70e62bb1d/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 626 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 627 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 628 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= 629 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 630 | golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 631 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 632 | golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 633 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 634 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 635 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 636 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 637 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 638 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 639 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 640 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 641 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 642 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 643 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 644 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 645 | golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 646 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 647 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 648 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 649 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 650 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 651 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 652 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 653 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 654 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 655 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 656 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 657 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 658 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 659 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 660 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 661 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 662 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 663 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 664 | golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 665 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 666 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 667 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 668 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 669 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 670 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 671 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 672 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 673 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 674 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 675 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 676 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 677 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 678 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 679 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 680 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 681 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 682 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 683 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 684 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 685 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 686 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 687 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 688 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 689 | golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 690 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 691 | golang.org/x/sys v0.0.0-20201029080932-201ba4db2418/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 692 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 693 | golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 694 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 695 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A= 696 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 697 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 698 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 699 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 700 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 701 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 702 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 703 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 704 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 705 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 706 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 707 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 708 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 709 | golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 710 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 711 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 712 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 713 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 714 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 715 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 716 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 717 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 718 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 719 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 720 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 721 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 722 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 723 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 724 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 725 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 726 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 727 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 728 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 729 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 730 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 731 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 732 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 733 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 734 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 735 | golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 736 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 737 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 738 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 739 | golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 740 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 741 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 742 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 743 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 744 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 745 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 746 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 747 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 748 | golang.org/x/tools v0.0.0-20200308013534-11ec41452d41/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 749 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 750 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 751 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 752 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 753 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 754 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 755 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 756 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 757 | golang.org/x/tools v0.0.0-20200806022845-90696ccdc692/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 758 | golang.org/x/tools v0.0.0-20200814230902-9882f1d1823d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 759 | golang.org/x/tools v0.0.0-20200817023811-d00afeaade8f/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 760 | golang.org/x/tools v0.0.0-20200818005847-188abfa75333/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 761 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 762 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 763 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 764 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 765 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 766 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 767 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 768 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 769 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 770 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 771 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 772 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 773 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 774 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 775 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 776 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 777 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 778 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 779 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 780 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 781 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 782 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 783 | google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 784 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 785 | google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 786 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 787 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 788 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 789 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 790 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 791 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 792 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 793 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 794 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 795 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 796 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 797 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 798 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 799 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 800 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 801 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 802 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 803 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 804 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 805 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 806 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 807 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 808 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 809 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 810 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 811 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 812 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 813 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 814 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 815 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 816 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 817 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 818 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 819 | google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 820 | google.golang.org/genproto v0.0.0-20200815001618-f69a88009b70/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 821 | google.golang.org/genproto v0.0.0-20200911024640-645f7a48b24f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 822 | google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3 h1:sg8vLDNIxFPHTchfhH1E3AI32BL3f23oie38xUWnJM8= 823 | google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 824 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 825 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 826 | google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 827 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 828 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 829 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 830 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 831 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 832 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 833 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 834 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 835 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 836 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 837 | google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 838 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 839 | google.golang.org/grpc v1.36.1 h1:cmUfbeGKnz9+2DD/UYsMQXeqbHZqZDs4eQwW0sFOpBY= 840 | google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 841 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 842 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 843 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 844 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 845 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 846 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 847 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 848 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 849 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 850 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 851 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 852 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 853 | gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU= 854 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 855 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 856 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 857 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 858 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 859 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 860 | gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= 861 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= 862 | gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 863 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 864 | gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= 865 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 866 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 867 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 868 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 869 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 870 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 871 | gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 872 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 873 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 874 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 875 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 876 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 877 | gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= 878 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 879 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 880 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 881 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 882 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 883 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 884 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 885 | modernc.org/b v1.0.0/go.mod h1:uZWcZfRj1BpYzfN9JTerzlNUnnPsV9O2ZA8JsRcubNg= 886 | modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8= 887 | modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw= 888 | modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8= 889 | modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= 890 | modernc.org/internal v1.0.0/go.mod h1:VUD/+JAkhCpvkUitlEOnhpVxCgsBI90oTzSCRcqQVSM= 891 | modernc.org/lldb v1.0.0/go.mod h1:jcRvJGWfCGodDZz8BPwiKMJxGJngQ/5DrRapkQnLob8= 892 | modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= 893 | modernc.org/ql v1.0.0/go.mod h1:xGVyrLIatPcO2C1JvI/Co8c0sr6y91HKFNy4pt9JXEY= 894 | modernc.org/sortutil v1.1.0/go.mod h1:ZyL98OQHJgH9IEfN71VsamvJgrtRX9Dj2gX+vH86L1k= 895 | modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= 896 | modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4= 897 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 898 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 899 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 900 | unknwon.dev/clog/v2 v2.2.0 h1:jkPdsxux0MC04BT/9NHbT75z4prK92SH10VBNmIpVCc= 901 | unknwon.dev/clog/v2 v2.2.0/go.mod h1:zvUlyibDHI4mykYdWyWje2G9nF/nBzfDOqRo2my4mWc= 902 | upper.io/db.v3 v3.8.0+incompatible h1:XNeEO2vQRVqq70M98ghzq6M30F5Bzo+99ess5v+eVYw= 903 | upper.io/db.v3 v3.8.0+incompatible/go.mod h1:FgTdD24eBjJAbPKsQSiHUNgXjOR4Lub3u1UMHSIh82Y= 904 | --------------------------------------------------------------------------------