├── .github ├── CODEOWNERS ├── FUNDING.yml ├── renovate.json ├── ISSUE_TEMPLATE │ ├── custom.md │ ├── feature_request.md │ └── bug_report.md ├── CONTRIBUTING.md ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── release.yml │ └── ci.yml ├── dependabot.yml └── CODE_OF_CONDUCT.md ├── gen.sum ├── .githooks ├── pre-commit.d │ ├── generate │ └── lint └── pre-commit ├── internal └── tools │ └── tools_test.go ├── deployments └── bot.moul.io │ ├── config.txt │ ├── Makefile │ └── docker-compose.yml ├── .releaserc.js ├── AUTHORS ├── pkg ├── moulbot │ ├── api.go │ ├── service.go │ ├── opts.go │ ├── driver_discord.go │ ├── driver_github.go │ └── driver_server.go └── moulbotpb │ ├── moulbot_grpc.pb.go │ ├── moulbot.pb.gw.go │ └── moulbot.pb.go ├── tool └── docker-protoc │ ├── Makefile │ └── Dockerfile ├── api └── moulbot.proto ├── .gitignore ├── SECURITY.md ├── .circleci └── config.yml ├── .gitattributes ├── .dockerignore ├── package.json ├── COPYRIGHT ├── .goreleaser.yml ├── .golangci.yml ├── go.mod ├── LICENSE-MIT ├── .editorconfig ├── Dockerfile ├── README.md ├── doc.go ├── Makefile ├── cmd └── moul-bot │ ├── main.go │ └── depaware.txt ├── rules.mk ├── LICENSE-APACHE └── go.sum /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @moul 2 | -------------------------------------------------------------------------------- /gen.sum: -------------------------------------------------------------------------------- 1 | da39a3ee5e6b4b0d3255bfef95601890afd80709 - 2 | -------------------------------------------------------------------------------- /.githooks/pre-commit.d/generate: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make generate 4 | -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | run-parts ./githooks/pre-commit.d/ -v --exit-on-error 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: ["moul"] 2 | patreon: moul 3 | open_collective: moul 4 | custom: 5 | - "https://manfred.life/donate" 6 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "groupName": "all", 6 | "gomodTidy": true 7 | } 8 | -------------------------------------------------------------------------------- /internal/tools/tools_test.go: -------------------------------------------------------------------------------- 1 | // +build tools 2 | 3 | package tools 4 | 5 | import ( 6 | _ "github.com/tailscale/depaware" // required by rules.mk 7 | ) 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom 3 | about: 'Anything else: questions, discussions, thanks, ascii-arts, ...' 4 | title: '' 5 | labels: discussion 6 | assignees: moul 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /deployments/bot.moul.io/config.txt: -------------------------------------------------------------------------------- 1 | ## Discord 2 | enable-discord true 3 | discord-token REPLACE_ME 4 | discord-admin-channel REPLACE_ME 5 | 6 | ## Server 7 | enable-server true 8 | server-bind 0.0.0.0:8000 9 | -------------------------------------------------------------------------------- /.releaserc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | branch: 'master', 3 | plugins: [ 4 | '@semantic-release/commit-analyzer', 5 | '@semantic-release/release-notes-generator', 6 | '@semantic-release/github', 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # This file lists all individuals having contributed content to the repository. 2 | # For how it is generated, see 'https://github.com/moul/rules.mk' 3 | 4 | Manfred Touron <94029+moul@users.noreply.github.com> 5 | moul-bot 6 | Renovate Bot 7 | -------------------------------------------------------------------------------- /pkg/moulbot/api.go: -------------------------------------------------------------------------------- 1 | package moulbot 2 | 3 | import ( 4 | "context" 5 | 6 | "moul.io/bot/pkg/moulbotpb" 7 | ) 8 | 9 | func (svc *Service) Ping(context.Context, *moulbotpb.Ping_Request) (*moulbotpb.Ping_Response, error) { 10 | return &moulbotpb.Ping_Response{}, nil 11 | } 12 | -------------------------------------------------------------------------------- /tool/docker-protoc/Makefile: -------------------------------------------------------------------------------- 1 | IMAGE ?= moul/moul-bot-protoc 2 | VERSION ?= 1 3 | 4 | build: 5 | docker build --pull -t $(IMAGE):$(VERSION) . 6 | 7 | publish: build 8 | docker tag $(IMAGE):$(VERSION) $(IMAGE):latest 9 | docker push $(IMAGE):$(VERSION) 10 | docker push $(IMAGE):latest 11 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, you can first discuss the change you wish to make via issue, 4 | email, or any other method with the maintainers of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /deployments/bot.moul.io/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | all: up logs 3 | 4 | .PHONY: up 5 | up: 6 | docker-compose up -d 7 | 8 | .PHONY: logs 9 | logs: 10 | docker-compose logs --tail=1000 -f 11 | 12 | .PHONY: ps pull restart stop kill 13 | ps pull restart stop kill: 14 | docker-compose $@ 15 | 16 | .PHONY: down 17 | down: 18 | docker-compose down --remove-orphans 19 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Semantic Release 2 | 3 | on: push 4 | 5 | jobs: 6 | semantic-release: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2.4.0 10 | - uses: codfish/semantic-release-action@v1 11 | if: github.ref == 'refs/heads/master' 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /api/moulbot.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package moulbot; 4 | 5 | option go_package = "moul.io/bot/pkg/moulbotpb"; 6 | 7 | import "google/api/annotations.proto"; 8 | 9 | service WebAPI { 10 | rpc Ping(Ping.Request) returns (Ping.Response) { option (google.api.http) = {get: "/ping"}; }; 11 | } 12 | 13 | message Ping { 14 | message Request {} 15 | message Response {} 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | config.txt 2 | # Temporary files 3 | *~ 4 | *# 5 | .#* 6 | coverage.txt 7 | 8 | # Vendors 9 | package-lock.json 10 | node_modules/ 11 | vendor/ 12 | 13 | # Binaries for programs and plugins 14 | dist/ 15 | gin-bin 16 | *.exe 17 | *.exe~ 18 | *.dll 19 | *.so 20 | *.dylib 21 | 22 | # Test binary, build with `go test -c` 23 | *.test 24 | 25 | # Output of the go coverage tool, specifically when used with LiteIDE 26 | *.out 27 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting security issues 2 | 3 | I take security seriously. If you discover a security issue, please bring it to my attention right away! 4 | 5 | ### Reporting a Vulnerability 6 | 7 | Please **DO NOT** file a public issue, instead send your report privately to security@moul.io. 8 | 9 | Security reports are greatly appreciated and I will publicly thank you for it, although I keep your name confidential if you request it. 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: docker 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "04:00" 8 | open-pull-requests-limit: 10 9 | - package-ecosystem: github-actions 10 | directory: "/" 11 | schedule: 12 | interval: daily 13 | time: "04:00" 14 | open-pull-requests-limit: 10 15 | - package-ecosystem: gomod 16 | directory: "/" 17 | schedule: 18 | interval: daily 19 | time: "04:00" 20 | open-pull-requests-limit: 10 21 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | moul: moul/build@1.16.0 # https://github.com/moul/build 5 | 6 | workflows: 7 | main: 8 | jobs: 9 | - moul/golang-build: 10 | gopkg: moul.io/bot 11 | - moul/golang-build: 12 | gopkg: moul.io/bot 13 | tag: '1.13' 14 | - moul/golang-build: 15 | gopkg: moul.io/bot 16 | tag: '1.12' 17 | - moul/golang-build: 18 | gopkg: moul.io/bot 19 | tag: '1.11' 20 | - moul/docker-build 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Collapse vendored and generated files on GitHub 5 | AUTHORS linguist-generated 6 | vendor/* linguist-vendored 7 | rules.mk linguist-vendored 8 | */vendor/* linguist-vendored 9 | *.gen.* linguist-generated 10 | *.pb.go linguist-generated 11 | *.pb.gw.go linguist-generated 12 | go.sum linguist-generated 13 | go.mod linguist-generated 14 | gen.sum linguist-generated 15 | 16 | # Reduce conflicts on markdown files 17 | *.md merge=union 18 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | ## 2 | ## Specific to .dockerignore 3 | ## 4 | 5 | .git/ 6 | Dockerfile 7 | contrib/ 8 | 9 | ## 10 | ## Common with .gitignore 11 | ## 12 | 13 | # Temporary files 14 | *~ 15 | *# 16 | .#* 17 | 18 | # Vendors 19 | node_modules/ 20 | vendor/ 21 | 22 | # Binaries for programs and plugins 23 | dist/ 24 | gin-bin 25 | *.exe 26 | *.exe~ 27 | *.dll 28 | *.so 29 | *.dylib 30 | 31 | # Test binary, build with `go test -c` 32 | *.test 33 | 34 | # Output of the go coverage tool, specifically when used with LiteIDE 35 | *.out 36 | -------------------------------------------------------------------------------- /deployments/bot.moul.io/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | moul-bot: 5 | image: moul/moul-bot:latest 6 | restart: on-failure 7 | volumes: 8 | - .:/app 9 | working_dir: /app 10 | labels: 11 | com.centurylinklabs.watchtower.enable: "true" 12 | command: 13 | run 14 | ports: 15 | - 8000 16 | environment: 17 | - VIRTUAL_HOST=bot.moul.io 18 | - VIRTUAL_PORT=8000 19 | networks: 20 | - default 21 | - service-proxy 22 | 23 | networks: 24 | service-proxy: 25 | external: true 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[IDEA] " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "this project is not a node.js one, package.json is just used to define some metadata", 3 | "name": "@moul.io/bot", 4 | "version": "0.0.1", 5 | "author": "Manfred Touron (https://manfred.life)", 6 | "contributors": [ 7 | "Manfred Touron (https://manfred.life)" 8 | ], 9 | "license": "(Apache-2.0 OR MIT)", 10 | "scripts": { 11 | "start": "bot", 12 | "install": "make install", 13 | "test": "make test" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/moul/bot.git" 18 | }, 19 | "bugs": "https://github.com/moul/bot/issues", 20 | "homepage": "https://moul.io/bot" 21 | } 22 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | Copyright 2020 Manfred Touron and other bot Developers. 2 | 3 | Intellectual Property Notice 4 | ---------------------------- 5 | 6 | bot is licensed under the Apache License, Version 2.0 7 | (see LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or 8 | the MIT license (see LICENSE-MIT or http://opensource.org/licenses/MIT), 9 | at your option. 10 | 11 | Copyrights and patents in the bots project are retained 12 | by contributors. 13 | No copyright assignment is required to contribute to bot. 14 | 15 | SPDX-License-Identifier: (Apache-2.0 OR MIT) 16 | 17 | SPDX usage 18 | ---------- 19 | 20 | Individual files may contain SPDX tags instead of the full license text. 21 | This enables machine processing of license information based on the SPDX 22 | License Identifiers that are available here: https://spdx.org/licenses/ 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Type '....' 17 | 3. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots / Logs** 23 | If applicable, add screenshots or logs to help explain your problem. 24 | 25 | **Versions (please complete the following information, if relevant):** 26 | - Software version: [e.g. v1.2.3, latest, building from sources] 27 | - OS: [e.g. Ubuntu, Mac, iOS, ...] 28 | - Golang version [e.g. 1.13] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | before: 2 | hooks: 3 | - go mod download 4 | builds: 5 | - 6 | goos: [linux, darwin, windows] 7 | goarch: [386, amd64, arm, arm64] 8 | flags: 9 | - "-a" 10 | ldflags: 11 | - '-extldflags "-static"' 12 | env: 13 | - CGO_ENABLED=0 14 | archives: 15 | - wrap_in_directory: true 16 | replacements: 17 | darwin: Darwin 18 | linux: Linux 19 | windows: Windows 20 | 386: i386 21 | amd64: x86_64 22 | checksum: 23 | name_template: 'checksums.txt' 24 | snapshot: 25 | name_template: "{{ .Tag }}-next" 26 | changelog: 27 | sort: asc 28 | filters: 29 | exclude: 30 | - '^docs:' 31 | - '^test:' 32 | brew: 33 | name: bot 34 | github: 35 | owner: moul 36 | name: homebrew-moul 37 | commit_author: 38 | name: bot 39 | email: "bot@moul.io" 40 | homepage: https://manfred.life/ 41 | description: "bot" 42 | -------------------------------------------------------------------------------- /pkg/moulbot/service.go: -------------------------------------------------------------------------------- 1 | package moulbot 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | 8 | "go.uber.org/zap" 9 | "moul.io/banner" 10 | ) 11 | 12 | type Service struct { 13 | logger *zap.Logger 14 | opts Opts 15 | ctx context.Context 16 | cancel func() 17 | 18 | // drivers 19 | 20 | discord discordDriver 21 | server serverDriver 22 | github githubDriver 23 | } 24 | 25 | func New(opts Opts) Service { 26 | opts.applyDefaults() 27 | fmt.Fprintln(os.Stderr, banner.Inline("moul-bot")) 28 | ctx, cancel := context.WithCancel(opts.Context) 29 | svc := Service{ 30 | logger: opts.Logger, 31 | opts: opts, 32 | ctx: ctx, 33 | cancel: cancel, 34 | } 35 | svc.logger.Info("service initialized", zap.Bool("dev-mode", opts.DevMode)) 36 | return svc 37 | } 38 | 39 | func (svc *Service) Close() { 40 | svc.logger.Debug("closing service") 41 | svc.cancel() 42 | fmt.Fprintln(os.Stderr, banner.Inline("kthxbie")) 43 | } 44 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | deadline: 1m 3 | tests: false 4 | skip-files: 5 | - "testing.go" 6 | - ".*\\.pb\\.go" 7 | - ".*\\.gen\\.go" 8 | 9 | linters-settings: 10 | golint: 11 | min-confidence: 0 12 | maligned: 13 | suggest-new: true 14 | goconst: 15 | min-len: 5 16 | min-occurrences: 4 17 | misspell: 18 | locale: US 19 | 20 | linters: 21 | disable-all: true 22 | enable: 23 | - bodyclose 24 | - deadcode 25 | - depguard 26 | - dogsled 27 | - dupl 28 | - errcheck 29 | #- funlen 30 | - gochecknoinits 31 | #- gocognit 32 | - goconst 33 | - gocritic 34 | - gocyclo 35 | - gofmt 36 | - goimports 37 | - golint 38 | - gosimple 39 | - govet 40 | - ineffassign 41 | - interfacer 42 | #- maligned 43 | - misspell 44 | - nakedret 45 | - prealloc 46 | - scopelint 47 | - staticcheck 48 | - structcheck 49 | #- stylecheck 50 | - typecheck 51 | - unconvert 52 | - unparam 53 | - unused 54 | - varcheck 55 | - whitespace 56 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module moul.io/bot 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/bwmarrin/discordgo v0.26.1 7 | github.com/getsentry/sentry-go v0.13.0 8 | github.com/go-chi/chi v4.1.2+incompatible 9 | github.com/gogo/gateway v1.1.0 10 | github.com/golang/protobuf v1.5.2 11 | github.com/google/go-github/v32 v32.1.0 12 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 13 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 14 | github.com/oklog/run v1.1.1-0.20200508094559-c7096881717e 15 | github.com/peterbourgon/ff/v3 v3.1.2 16 | github.com/rs/cors v1.8.2 17 | github.com/soheilhy/cmux v0.1.5 18 | github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 19 | github.com/treastech/logger v0.0.0-20180705232552-e381e9ecf2e3 20 | go.uber.org/zap v1.21.0 21 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f 22 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 23 | google.golang.org/grpc v1.42.0 24 | google.golang.org/protobuf v1.27.1 25 | moul.io/banner v1.0.1 26 | moul.io/godev v1.7.0 27 | moul.io/srand v1.6.1 28 | moul.io/u v1.27.0 29 | moul.io/zapconfig v1.4.0 30 | ) 31 | -------------------------------------------------------------------------------- /tool/docker-protoc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM moul/protoc-gen-gotemplate:latest as pgg 2 | 3 | FROM golang:1.17-alpine as builder 4 | RUN apk --no-cache add make git go rsync libc-dev openssh docker 5 | RUN go get -u \ 6 | github.com/gogo/protobuf/protoc-gen-gogofaster \ 7 | github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway \ 8 | github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger \ 9 | github.com/simplealpine/json2yaml \ 10 | golang.org/x/tools/cmd/goimports 11 | RUN go get -u google.golang.org/protobuf/cmd/protoc-gen-go 12 | RUN go get -u google.golang.org/grpc/cmd/protoc-gen-go-grpc 13 | 14 | FROM golang:1.17-alpine 15 | RUN apk --no-cache add git make protobuf gcc libc-dev npm perl-utils && \ 16 | mkdir -p /.cache/go-build && \ 17 | chmod -R 777 /.cache && \ 18 | npm install -g eclint 19 | COPY --from=pgg /go/bin/* /go/bin/ 20 | COPY --from=builder /go/bin/* /go/bin/ 21 | COPY --from=pgg /protobuf /protobuf 22 | ENV GOPATH=/go \ 23 | PATH=/go/bin:${PATH} \ 24 | GOROOT=/usr/local/go 25 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Manfred Touron (manfred.life) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | 10 | indent_style = space 11 | indent_size = 4 12 | 13 | [*.mod] 14 | indent_style = tab 15 | 16 | [{Makefile,**.mk}] 17 | indent_style = tab 18 | 19 | [*.go] 20 | indent_style = tab 21 | 22 | [*.css] 23 | indent_size = 2 24 | 25 | [*.proto] 26 | indent_size = 2 27 | 28 | [*.ftl] 29 | indent_size = 2 30 | 31 | [*.toml] 32 | indent_size = 2 33 | 34 | [*.swift] 35 | indent_size = 4 36 | 37 | [*.tmpl] 38 | indent_size = 2 39 | 40 | [*.js] 41 | indent_size = 2 42 | block_comment_start = /* 43 | block_comment_end = */ 44 | 45 | [*.{html,htm}] 46 | indent_size = 2 47 | 48 | [*.bat] 49 | end_of_line = crlf 50 | 51 | [*.{yml,yaml}] 52 | indent_size = 2 53 | 54 | [*.json] 55 | indent_size = 2 56 | 57 | [.{babelrc,eslintrc,prettierrc}] 58 | indent_size = 2 59 | 60 | [{Fastfile,.buckconfig,BUCK}] 61 | indent_size = 2 62 | 63 | [*.diff] 64 | indent_size = 1 65 | 66 | [*.m] 67 | indent_size = 1 68 | indent_style = space 69 | block_comment_start = /** 70 | block_comment = * 71 | block_comment_end = */ 72 | 73 | [*.java] 74 | indent_size = 4 75 | indent_style = space 76 | block_comment_start = /** 77 | block_comment = * 78 | block_comment_end = */ 79 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # dynamic config 2 | ARG BUILD_DATE 3 | ARG VCS_REF 4 | ARG VERSION 5 | 6 | # build 7 | FROM golang:1.17.7-alpine as builder 8 | RUN apk add --no-cache git gcc musl-dev make 9 | ENV GO111MODULE=on 10 | WORKDIR /go/src/moul.io/bot 11 | COPY go.* ./ 12 | RUN go mod download 13 | COPY . ./ 14 | RUN make install 15 | 16 | # minimalist runtime 17 | FROM alpine:3.16.3 18 | LABEL org.label-schema.build-date=$BUILD_DATE \ 19 | org.label-schema.name="bot" \ 20 | org.label-schema.description="" \ 21 | org.label-schema.url="https://moul.io/bot/" \ 22 | org.label-schema.vcs-ref=$VCS_REF \ 23 | org.label-schema.vcs-url="https://github.com/moul/bot" \ 24 | org.label-schema.vendor="Manfred Touron" \ 25 | org.label-schema.version=$VERSION \ 26 | org.label-schema.schema-version="1.0" \ 27 | org.label-schema.cmd="docker run -i -t --rm moul/bot" \ 28 | org.label-schema.help="docker exec -it $CONTAINER bot --help" 29 | COPY --from=builder /go/bin/moul-bot /bin/ 30 | ENTRYPOINT ["/bin/moul-bot"] 31 | #CMD [] 32 | -------------------------------------------------------------------------------- /.githooks/pre-commit.d/lint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | STAGED_GO_FILES=$(git diff --cached --name-only | grep "\.go$") 4 | 5 | if [[ "$STAGED_GO_FILES" = "" ]]; then 6 | exit 0 7 | fi 8 | 9 | GOLINT=$GOPATH/bin/golint 10 | GOIMPORTS=$GOPATH/bin/goimports 11 | PASS=true 12 | 13 | # Check for golint 14 | if [[ ! -x "$GOLINT" ]]; then 15 | printf "\t\033[41mPlease install golint\033[0m (go get -u golang.org/x/lint/golint)\n" 16 | PASS=false 17 | fi 18 | 19 | # Check for goimports 20 | if [[ ! -x "$GOIMPORTS" ]]; then 21 | printf "\t\033[41mPlease install goimports\033[0m (go get golang.org/x/tools/cmd/goimports)\n" 22 | PASS=false 23 | fi 24 | 25 | if ! $PASS; then 26 | exit 1 27 | fi 28 | 29 | PASS=true 30 | 31 | for FILE in $STAGED_GO_FILES 32 | do 33 | # Run goimports on the staged file 34 | $GOIMPORTS -w $FILE 35 | 36 | # Run golint on the staged file and check the exit status 37 | $GOLINT "-set_exit_status" $FILE 38 | if [[ $? == 1 ]]; then 39 | printf "\t\033[31mgolint $FILE\033[0m \033[0;30m\033[41mFAILURE!\033[0m\n" 40 | PASS=false 41 | else 42 | printf "\t\033[32mgolint $FILE\033[0m \033[0;30m\033[42mpass\033[0m\n" 43 | fi 44 | done 45 | 46 | if ! $PASS; then 47 | printf "\033[0;30m\033[41mCOMMIT FAILED\033[0m\n" 48 | exit 1 49 | else 50 | printf "\033[0;30m\033[42mCOMMIT SUCCEEDED\033[0m\n" 51 | fi 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /pkg/moulbot/opts.go: -------------------------------------------------------------------------------- 1 | package moulbot 2 | 3 | import ( 4 | "context" 5 | "time" 6 | 7 | "go.uber.org/zap" 8 | ) 9 | 10 | type Opts struct { 11 | Context context.Context 12 | Logger *zap.Logger 13 | DevMode bool 14 | 15 | // Discord 16 | 17 | EnableDiscord bool 18 | DiscordToken string 19 | DiscordAdminChannel string 20 | 21 | // Server 22 | 23 | EnableServer bool 24 | ServerBind string 25 | ServerCORSAllowedOrigins string 26 | ServerRequestTimeout time.Duration 27 | ServerShutdownTimeout time.Duration 28 | ServerWithPprof bool 29 | 30 | // GitHub 31 | 32 | EnableGitHub bool 33 | GitHubMoulToken string 34 | GitHubMoulbotToken string 35 | } 36 | 37 | func (opts *Opts) applyDefaults() { 38 | if opts.Context == nil { 39 | opts.Context = context.TODO() 40 | } 41 | if opts.Logger == nil { 42 | opts.Logger = zap.NewNop() 43 | } 44 | if opts.ServerBind == "" { 45 | opts.ServerBind = ":8000" 46 | } 47 | if opts.ServerCORSAllowedOrigins == "" { 48 | opts.ServerCORSAllowedOrigins = "*" 49 | } 50 | if opts.ServerRequestTimeout == 0 { 51 | opts.ServerRequestTimeout = 5 * time.Second 52 | } 53 | if opts.ServerShutdownTimeout == 0 { 54 | opts.ServerShutdownTimeout = 6 * time.Second 55 | } 56 | } 57 | 58 | func (opts *Opts) Filtered() Opts { 59 | filtered := *opts 60 | if filtered.DiscordToken != "" { 61 | filtered.DiscordToken = "*FILTERED*" 62 | } 63 | if filtered.DiscordAdminChannel != "" { 64 | filtered.DiscordAdminChannel = "*FILTERED*" 65 | } 66 | return filtered 67 | } 68 | 69 | func DefaultOpts() Opts { 70 | opts := Opts{} 71 | opts.applyDefaults() 72 | return opts 73 | } 74 | -------------------------------------------------------------------------------- /pkg/moulbot/driver_discord.go: -------------------------------------------------------------------------------- 1 | package moulbot 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/bwmarrin/discordgo" 9 | "go.uber.org/zap" 10 | "moul.io/banner" 11 | "moul.io/u" 12 | ) 13 | 14 | type discordDriver struct { 15 | session *discordgo.Session 16 | } 17 | 18 | func (svc *Service) StartDiscord() error { 19 | fmt.Fprintln(os.Stderr, banner.Inline("discord")) 20 | svc.logger.Debug("starting discord") 21 | 22 | dg, err := discordgo.New("Bot " + svc.opts.DiscordToken) 23 | if err != nil { 24 | return err 25 | } 26 | 27 | // send hello message 28 | { 29 | msg := "**Hello World!**" 30 | if svc.opts.DevMode { 31 | msg += " (dev)" 32 | } 33 | _, err = dg.ChannelMessageSend(svc.opts.DiscordAdminChannel, msg) 34 | if err != nil { 35 | svc.logger.Warn("send hello message", zap.Error(err)) 36 | } 37 | } 38 | 39 | // handlers 40 | { 41 | dg.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) { 42 | if m.Author.ID == s.State.User.ID { 43 | return 44 | } 45 | if m.Author.Bot { 46 | return 47 | } 48 | log.Println(u.JSON(m)) 49 | _, err := s.ChannelMessageSend(m.ChannelID, ">>> "+m.Content) 50 | if err != nil { 51 | svc.logger.Error("discord.ChannelMessageSend", zap.Error(err)) 52 | } 53 | }) 54 | } 55 | 56 | // start 57 | { 58 | err = dg.Open() 59 | if err != nil { 60 | return err 61 | } 62 | svc.discord.session = dg 63 | 64 | <-svc.ctx.Done() 65 | } 66 | return nil 67 | } 68 | 69 | func (svc *Service) CloseDiscord(error) { 70 | svc.logger.Debug("closing discord", zap.Bool("was-started", svc.discord.session != nil)) 71 | if svc.discord.session != nil { 72 | svc.discord.session.Close() 73 | svc.logger.Debug("discord closed") 74 | } 75 | svc.cancel() 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bot 2 | 3 | :smile: bot 4 | 5 | ![CI](https://github.com/moul/bot/workflows/CI/badge.svg) 6 | [![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white)](https://pkg.go.dev/moul.io/bot) 7 | [![License](https://img.shields.io/badge/license-Apache--2.0%20%2F%20MIT-%2397ca00.svg)](https://github.com/moul/bot/blob/master/COPYRIGHT) 8 | [![GitHub release](https://img.shields.io/github/release/moul/bot.svg)](https://github.com/moul/bot/releases) 9 | [![Go Report Card](https://goreportcard.com/badge/moul.io/bot)](https://goreportcard.com/report/moul.io/bot) 10 | [![CodeFactor](https://www.codefactor.io/repository/github/moul/bot/badge)](https://www.codefactor.io/repository/github/moul/bot) 11 | [![codecov](https://codecov.io/gh/moul/bot/branch/master/graph/badge.svg)](https://codecov.io/gh/moul/bot) 12 | [![Docker Metrics](https://images.microbadger.com/badges/image/moul/bot.svg)](https://microbadger.com/images/moul/bot) 13 | [![GolangCI](https://golangci.com/badges/github.com/moul/bot.svg)](https://golangci.com/r/github.com/moul/bot) 14 | [![Made by Manfred Touron](https://img.shields.io/badge/made%20by-Manfred%20Touron-blue.svg?style=flat)](https://manfred.life/) 15 | 16 | 17 | ## Usage 18 | 19 | TODO 20 | 21 | ## Install 22 | 23 | ### Using go 24 | 25 | ```console 26 | $ go get -u moul.io/bot 27 | ``` 28 | 29 | ### Releases 30 | 31 | See https://github.com/moul/bot/releases 32 | 33 | ## License 34 | 35 | © 2020 [Manfred Touron](https://manfred.life) 36 | 37 | Licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) ([`LICENSE-APACHE`](LICENSE-APACHE)) or the [MIT license](https://opensource.org/licenses/MIT) ([`LICENSE-MIT`](LICENSE-MIT)), at your option. See the [`COPYRIGHT`](COPYRIGHT) file for more details. 38 | 39 | `SPDX-License-Identifier: (Apache-2.0 OR MIT)` 40 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright © 2020 Manfred Touron 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | // message from the author: 5 | // +--------------------------------------------------------------+ 6 | // | * * * ░░░░░░░░░░░░░░░░░░░░ Hello ░░░░░░░░░░░░░░░░░░░░░░░░░░| 7 | // +--------------------------------------------------------------+ 8 | // | | 9 | // | ++ ______________________________________ | 10 | // | ++++ / \ | 11 | // | ++++ | | | 12 | // | ++++++++++ | Feel free to contribute to this | | 13 | // | +++ | | project or contact me on | | 14 | // | ++ | | manfred.life if you like this | | 15 | // | + -== ==| | project! | | 16 | // | ( <*> <*> | | | 17 | // | | | /| :) | | 18 | // | | _) / | | | 19 | // | | +++ / \______________________________________/ | 20 | // | \ =+ / | 21 | // | \ + | 22 | // | |\++++++ | 23 | // | | ++++ ||// | 24 | // | ___| |___ _||/__ __| 25 | // | / --- \ \| ||| __ _ ___ __ __/ /| 26 | // |/ | | \ \ / / ' \/ _ \/ // / / | 27 | // || | | | | | /_/_/_/\___/\_,_/_/ | 28 | // +--------------------------------------------------------------+ 29 | package main // import "moul.io/bot" 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GOPKG ?= moul.io/bot 2 | DOCKER_IMAGE ?= moul/bot 3 | GOBINS ?= ./cmd/moul-bot 4 | 5 | PRE_INSTALL_STEPS += generate 6 | PRE_UNITTEST_STEPS += generate 7 | PRE_TEST_STEPS += generate 8 | PRE_BUILD_STEPS += generate 9 | PRE_LINT_STEPsS += generate 10 | PRE_TIDY_STEPS += generate 11 | PRE_BUMPDEPS_STEPS += generate 12 | 13 | include rules.mk 14 | 15 | .PHONY: run 16 | run: install 17 | moul-bot --dev-mode --enable-server --enable-discord --enable-github run 18 | 19 | .PHONY: run-discord 20 | run-discord: install 21 | moul-bot --dev-mode --enable-discord run 22 | 23 | .PHONY: run-server 24 | run-server: install 25 | moul-bot --dev-mode --enable-server run 26 | 27 | .PHONY: run-github 28 | run-github: install 29 | moul-bot --dev-mode --enable-github run 30 | 31 | PROTOS_SRC := $(wildcard ./api/*.proto) 32 | GEN_DEPS := $(PROTOS_SRC) Makefile 33 | .PHONY: generate 34 | generate: gen.sum 35 | gen.sum: $(GEN_DEPS) 36 | shasum $(GEN_DEPS) | sort > gen.sum.tmp 37 | @diff -q gen.sum gen.sum.tmp || ( \ 38 | set -xe; \ 39 | GO111MODULE=on go mod vendor; \ 40 | docker run \ 41 | --user=`id -u` \ 42 | --volume="$(PWD):/go/src/moul.io/bot" \ 43 | --workdir="/go/src/moul.io/bot" \ 44 | --entrypoint="sh" \ 45 | --rm \ 46 | moul/moul-bot-protoc:1 \ 47 | -xec 'make generate_local'; \ 48 | make tidy \ 49 | ) 50 | @rm -f gen.sum.tmp 51 | 52 | PROTOC_OPTS = -I ./api:/protobuf 53 | .PHONY: generate_local 54 | generate_local: 55 | @set -e; for proto in $(PROTOS_SRC); do ( set -xe; \ 56 | protoc $(PROTOC_OPTS) \ 57 | --grpc-gateway_out=logtostderr=true:"$(GOPATH)/src" \ 58 | --go_out="$(GOPATH)/src" \ 59 | --go-grpc_out="$(GOPATH)/src" \ 60 | "$$proto" \ 61 | ); done 62 | goimports -w ./pkg ./cmd ./internal 63 | shasum $(GEN_SRC) | sort > gen.sum.tmp 64 | mv gen.sum.tmp gen.sum 65 | 66 | .PHONY: clean 67 | clean: 68 | rm -f gen.sum $(wildcard */*/*.pb.go */*/*.pb.gw.go) 69 | @# packr 70 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - master 8 | pull_request: 9 | 10 | jobs: 11 | docker-build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2.4.0 15 | - name: Build the Docker image 16 | run: docker build . --file Dockerfile 17 | golangci-lint: 18 | name: golangci-lint 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v2.4.0 22 | - name: lint 23 | uses: golangci/golangci-lint-action@v3.2.0 24 | with: 25 | version: v1.28 26 | github-token: ${{ secrets.GITHUB_TOKEN }} 27 | # tests-on-windows: 28 | # needs: golangci-lint # run after golangci-lint action to not produce duplicated errors 29 | # runs-on: windows-latest 30 | # strategy: 31 | # matrix: 32 | # golang: 33 | # #- 1.13 34 | # - 1.14 35 | # steps: 36 | # - uses: actions/checkout@v2.4.0 37 | # - name: Install Go 38 | # uses: actions/setup-go@v2 39 | # with: 40 | # go-version: ${{ matrix.golang }} 41 | # - name: Run tests on Windows 42 | # run: make.exe unittest 43 | # continue-on-error: true 44 | # tests-on-mac: 45 | # needs: golangci-lint # run after golangci-lint action to not produce duplicated errors 46 | # runs-on: macos-latest 47 | # strategy: 48 | # matrix: 49 | # golang: 50 | # - 1.14 51 | # steps: 52 | # - uses: actions/checkout@v2.4.0 53 | # - name: Install Go 54 | # uses: actions/setup-go@v2 55 | # with: 56 | # go-version: ${{ matrix.golang }} 57 | # - uses: actions/cache@v2.1.3 58 | # with: 59 | # path: ~/go/pkg/mod 60 | # key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }} 61 | # restore-keys: | 62 | # ${{ runner.os }}-go-${{ matrix.golang }}- 63 | # - name: Run tests on Unix-like operating systems 64 | # run: make unittest 65 | tests-on-linux: 66 | needs: golangci-lint # run after golangci-lint action to not produce duplicated errors 67 | runs-on: ubuntu-latest 68 | strategy: 69 | matrix: 70 | golang: 71 | # - 1.13 72 | - 1.14 73 | steps: 74 | - uses: actions/checkout@v2.4.0 75 | - name: Install Go 76 | uses: actions/setup-go@v2 77 | with: 78 | go-version: ${{ matrix.golang }} 79 | - uses: actions/cache@v3.0.4 80 | with: 81 | path: ~/go/pkg/mod 82 | key: ${{ runner.os }}-go-${{ matrix.golang }}-${{ hashFiles('**/go.sum') }} 83 | restore-keys: | 84 | ${{ runner.os }}-go-${{ matrix.golang }}- 85 | - name: Run tests on Unix-like operating systems 86 | run: make unittest 87 | -------------------------------------------------------------------------------- /pkg/moulbotpb/moulbot_grpc.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go-grpc. DO NOT EDIT. 2 | 3 | package moulbotpb 4 | 5 | import ( 6 | context "context" 7 | 8 | grpc "google.golang.org/grpc" 9 | codes "google.golang.org/grpc/codes" 10 | status "google.golang.org/grpc/status" 11 | ) 12 | 13 | // This is a compile-time assertion to ensure that this generated file 14 | // is compatible with the grpc package it is being compiled against. 15 | const _ = grpc.SupportPackageIsVersion6 16 | 17 | // WebAPIClient is the client API for WebAPI service. 18 | // 19 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. 20 | type WebAPIClient interface { 21 | Ping(ctx context.Context, in *Ping_Request, opts ...grpc.CallOption) (*Ping_Response, error) 22 | } 23 | 24 | type webAPIClient struct { 25 | cc grpc.ClientConnInterface 26 | } 27 | 28 | func NewWebAPIClient(cc grpc.ClientConnInterface) WebAPIClient { 29 | return &webAPIClient{cc} 30 | } 31 | 32 | func (c *webAPIClient) Ping(ctx context.Context, in *Ping_Request, opts ...grpc.CallOption) (*Ping_Response, error) { 33 | out := new(Ping_Response) 34 | err := c.cc.Invoke(ctx, "/moulbot.WebAPI/Ping", in, out, opts...) 35 | if err != nil { 36 | return nil, err 37 | } 38 | return out, nil 39 | } 40 | 41 | // WebAPIServer is the server API for WebAPI service. 42 | type WebAPIServer interface { 43 | Ping(context.Context, *Ping_Request) (*Ping_Response, error) 44 | } 45 | 46 | // UnimplementedWebAPIServer can be embedded to have forward compatible implementations. 47 | type UnimplementedWebAPIServer struct { 48 | } 49 | 50 | func (*UnimplementedWebAPIServer) Ping(context.Context, *Ping_Request) (*Ping_Response, error) { 51 | return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") 52 | } 53 | 54 | func RegisterWebAPIServer(s *grpc.Server, srv WebAPIServer) { 55 | s.RegisterService(&_WebAPI_serviceDesc, srv) 56 | } 57 | 58 | func _WebAPI_Ping_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 59 | in := new(Ping_Request) 60 | if err := dec(in); err != nil { 61 | return nil, err 62 | } 63 | if interceptor == nil { 64 | return srv.(WebAPIServer).Ping(ctx, in) 65 | } 66 | info := &grpc.UnaryServerInfo{ 67 | Server: srv, 68 | FullMethod: "/moulbot.WebAPI/Ping", 69 | } 70 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 71 | return srv.(WebAPIServer).Ping(ctx, req.(*Ping_Request)) 72 | } 73 | return interceptor(ctx, in, info, handler) 74 | } 75 | 76 | var _WebAPI_serviceDesc = grpc.ServiceDesc{ 77 | ServiceName: "moulbot.WebAPI", 78 | HandlerType: (*WebAPIServer)(nil), 79 | Methods: []grpc.MethodDesc{ 80 | { 81 | MethodName: "Ping", 82 | Handler: _WebAPI_Ping_Handler, 83 | }, 84 | }, 85 | Streams: []grpc.StreamDesc{}, 86 | Metadata: "moulbot.proto", 87 | } 88 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at m+coc-report@42.am. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /cmd/moul-bot/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "log" 7 | "math/rand" 8 | "os" 9 | "syscall" 10 | "time" 11 | 12 | sentry "github.com/getsentry/sentry-go" 13 | "github.com/oklog/run" 14 | ff "github.com/peterbourgon/ff/v3" 15 | "github.com/peterbourgon/ff/v3/ffcli" 16 | "moul.io/bot/pkg/moulbot" 17 | "moul.io/srand" 18 | "moul.io/zapconfig" 19 | ) 20 | 21 | func main() { 22 | if err := app(os.Args); err != nil { 23 | log.Fatalf("error: %v", err) 24 | os.Exit(1) 25 | } 26 | } 27 | 28 | var opts moulbot.Opts 29 | 30 | func app(args []string) error { 31 | opts = moulbot.DefaultOpts() 32 | rootFlags := flag.NewFlagSet("root", flag.ExitOnError) 33 | rootFlags.BoolVar(&opts.DevMode, "dev-mode", opts.DevMode, "start in developer mode") 34 | // discord 35 | rootFlags.BoolVar(&opts.EnableDiscord, "enable-discord", opts.EnableDiscord, "enable discord bot") 36 | rootFlags.StringVar(&opts.DiscordToken, "discord-token", opts.DiscordToken, "discord bot token") 37 | rootFlags.StringVar(&opts.DiscordAdminChannel, "discord-admin-channel", opts.DiscordAdminChannel, "discord channel ID for admin messages") 38 | // server 39 | rootFlags.BoolVar(&opts.EnableServer, "enable-server", opts.EnableServer, "enable HTTP+gRPC Server") 40 | rootFlags.StringVar(&opts.ServerBind, "server-bind", opts.ServerBind, "server bind (HTTP + gRPC)") 41 | rootFlags.StringVar(&opts.ServerCORSAllowedOrigins, "server-cors-allowed-origins", opts.ServerCORSAllowedOrigins, "allowed CORS origins") 42 | rootFlags.DurationVar(&opts.ServerRequestTimeout, "server-request-timeout", opts.ServerRequestTimeout, "server request timeout") 43 | rootFlags.DurationVar(&opts.ServerShutdownTimeout, "server-shutdown-timeout", opts.ServerShutdownTimeout, "server shutdown timeout") 44 | rootFlags.BoolVar(&opts.ServerWithPprof, "server-with-pprof", opts.ServerWithPprof, "enable pprof on HTTP server") 45 | // github 46 | rootFlags.BoolVar(&opts.EnableGitHub, "enable-github", opts.EnableGitHub, "enable GitHub") 47 | rootFlags.StringVar(&opts.GitHubMoulToken, "github-moul-token", opts.GitHubMoulToken, `"moul" GitHub token`) 48 | rootFlags.StringVar(&opts.GitHubMoulbotToken, "github-moul-bot-token", opts.GitHubMoulbotToken, `"moul" GitHub token`) 49 | 50 | root := &ffcli.Command{ 51 | FlagSet: rootFlags, 52 | Options: []ff.Option{ 53 | ff.WithEnvVarPrefix("MOULBOT"), 54 | ff.WithConfigFile("config.txt"), 55 | ff.WithConfigFileParser(ff.PlainParser), 56 | ff.WithAllowMissingConfigFile(true), 57 | }, 58 | Subcommands: []*ffcli.Command{ 59 | {Name: "run", Exec: runCmd}, 60 | // FIXME: make a mode that starts a unique bot with multiple interfaces (disocord, http, grpc, ssh, etc) 61 | }, 62 | Exec: func(context.Context, []string) error { 63 | return flag.ErrHelp 64 | }, 65 | } 66 | 67 | return root.ParseAndRun(context.Background(), args[1:]) 68 | } 69 | 70 | func runCmd(ctx context.Context, _ []string) error { 71 | if err := sentry.Init(sentry.ClientOptions{ 72 | Dsn: "https://98bc1fbb4f084a20bd4872240d7a0d01@o419562.ingest.sentry.io/5371975", 73 | // Release: "", 74 | }); err != nil { 75 | return err 76 | } 77 | defer sentry.Flush(2 * time.Second) 78 | sentry.CaptureMessage("Server Started.") 79 | 80 | // init 81 | rand.Seed(srand.MustSecure()) 82 | gr := run.Group{} 83 | gr.Add(run.SignalHandler(ctx, syscall.SIGTERM, syscall.SIGINT, os.Interrupt, os.Kill)) 84 | 85 | // bearer 86 | opts.Logger = zapconfig.Configurator{}.MustBuild() 87 | // opts.Context = ctx 88 | 89 | // init service 90 | svc := moulbot.New(opts) 91 | defer svc.Close() 92 | 93 | // start 94 | if opts.EnableDiscord { 95 | gr.Add(svc.StartDiscord, svc.CloseDiscord) 96 | } 97 | if opts.EnableServer { 98 | gr.Add(svc.StartServer, svc.CloseServer) 99 | } 100 | if opts.EnableGitHub { 101 | gr.Add(svc.StartGitHub, svc.CloseGitHub) 102 | } 103 | return gr.Run() 104 | } 105 | -------------------------------------------------------------------------------- /pkg/moulbotpb/moulbot.pb.gw.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. 2 | // source: moulbot.proto 3 | 4 | /* 5 | Package moulbotpb is a reverse proxy. 6 | 7 | It translates gRPC into RESTful JSON APIs. 8 | */ 9 | package moulbotpb 10 | 11 | import ( 12 | "context" 13 | "io" 14 | "net/http" 15 | 16 | "github.com/golang/protobuf/descriptor" 17 | "github.com/golang/protobuf/proto" 18 | "github.com/grpc-ecosystem/grpc-gateway/runtime" 19 | "github.com/grpc-ecosystem/grpc-gateway/utilities" 20 | "google.golang.org/grpc" 21 | "google.golang.org/grpc/codes" 22 | "google.golang.org/grpc/grpclog" 23 | "google.golang.org/grpc/status" 24 | ) 25 | 26 | // Suppress "imported and not used" errors 27 | var _ codes.Code 28 | var _ io.Reader 29 | var _ status.Status 30 | var _ = runtime.String 31 | var _ = utilities.NewDoubleArray 32 | var _ = descriptor.ForMessage 33 | 34 | func request_WebAPI_Ping_0(ctx context.Context, marshaler runtime.Marshaler, client WebAPIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { 35 | var protoReq Ping_Request 36 | var metadata runtime.ServerMetadata 37 | 38 | msg, err := client.Ping(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) 39 | return msg, metadata, err 40 | 41 | } 42 | 43 | func local_request_WebAPI_Ping_0(ctx context.Context, marshaler runtime.Marshaler, server WebAPIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { 44 | var protoReq Ping_Request 45 | var metadata runtime.ServerMetadata 46 | 47 | msg, err := server.Ping(ctx, &protoReq) 48 | return msg, metadata, err 49 | 50 | } 51 | 52 | // RegisterWebAPIHandlerServer registers the http handlers for service WebAPI to "mux". 53 | // UnaryRPC :call WebAPIServer directly. 54 | // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. 55 | func RegisterWebAPIHandlerServer(ctx context.Context, mux *runtime.ServeMux, server WebAPIServer) error { 56 | 57 | mux.Handle("GET", pattern_WebAPI_Ping_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { 58 | ctx, cancel := context.WithCancel(req.Context()) 59 | defer cancel() 60 | inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) 61 | rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) 62 | if err != nil { 63 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 64 | return 65 | } 66 | resp, md, err := local_request_WebAPI_Ping_0(rctx, inboundMarshaler, server, req, pathParams) 67 | ctx = runtime.NewServerMetadataContext(ctx, md) 68 | if err != nil { 69 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 70 | return 71 | } 72 | 73 | forward_WebAPI_Ping_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) 74 | 75 | }) 76 | 77 | return nil 78 | } 79 | 80 | // RegisterWebAPIHandlerFromEndpoint is same as RegisterWebAPIHandler but 81 | // automatically dials to "endpoint" and closes the connection when "ctx" gets done. 82 | func RegisterWebAPIHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { 83 | conn, err := grpc.Dial(endpoint, opts...) 84 | if err != nil { 85 | return err 86 | } 87 | defer func() { 88 | if err != nil { 89 | if cerr := conn.Close(); cerr != nil { 90 | grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) 91 | } 92 | return 93 | } 94 | go func() { 95 | <-ctx.Done() 96 | if cerr := conn.Close(); cerr != nil { 97 | grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) 98 | } 99 | }() 100 | }() 101 | 102 | return RegisterWebAPIHandler(ctx, mux, conn) 103 | } 104 | 105 | // RegisterWebAPIHandler registers the http handlers for service WebAPI to "mux". 106 | // The handlers forward requests to the grpc endpoint over "conn". 107 | func RegisterWebAPIHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { 108 | return RegisterWebAPIHandlerClient(ctx, mux, NewWebAPIClient(conn)) 109 | } 110 | 111 | // RegisterWebAPIHandlerClient registers the http handlers for service WebAPI 112 | // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "WebAPIClient". 113 | // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "WebAPIClient" 114 | // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in 115 | // "WebAPIClient" to call the correct interceptors. 116 | func RegisterWebAPIHandlerClient(ctx context.Context, mux *runtime.ServeMux, client WebAPIClient) error { 117 | 118 | mux.Handle("GET", pattern_WebAPI_Ping_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { 119 | ctx, cancel := context.WithCancel(req.Context()) 120 | defer cancel() 121 | inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) 122 | rctx, err := runtime.AnnotateContext(ctx, mux, req) 123 | if err != nil { 124 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 125 | return 126 | } 127 | resp, md, err := request_WebAPI_Ping_0(rctx, inboundMarshaler, client, req, pathParams) 128 | ctx = runtime.NewServerMetadataContext(ctx, md) 129 | if err != nil { 130 | runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) 131 | return 132 | } 133 | 134 | forward_WebAPI_Ping_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) 135 | 136 | }) 137 | 138 | return nil 139 | } 140 | 141 | var ( 142 | pattern_WebAPI_Ping_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ping"}, "", runtime.AssumeColonVerbOpt(true))) 143 | ) 144 | 145 | var ( 146 | forward_WebAPI_Ping_0 = runtime.ForwardResponseMessage 147 | ) 148 | -------------------------------------------------------------------------------- /pkg/moulbot/driver_github.go: -------------------------------------------------------------------------------- 1 | package moulbot 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "os" 7 | "strings" 8 | "time" 9 | 10 | "github.com/google/go-github/v32/github" 11 | "go.uber.org/zap" 12 | "golang.org/x/oauth2" 13 | "moul.io/banner" 14 | "moul.io/godev" 15 | "moul.io/u" 16 | ) 17 | 18 | type githubDriver struct { 19 | clients map[string]*github.Client 20 | } 21 | 22 | func (svc *Service) StartGitHub() error { 23 | fmt.Fprintln(os.Stderr, banner.Inline("github")) 24 | svc.logger.Debug( 25 | "starting github", 26 | zap.Bool("moul", svc.opts.GitHubMoulToken != ""), 27 | zap.Bool("moul-bot", svc.opts.GitHubMoulbotToken != ""), 28 | ) 29 | 30 | svc.github.clients = make(map[string]*github.Client) 31 | svc.github.clients["moul"] = githubClient(svc.opts.GitHubMoulToken) 32 | svc.github.clients["moul-bot"] = githubClient(svc.opts.GitHubMoulbotToken) 33 | 34 | // get myself 35 | for key := range svc.github.clients { 36 | err := svc.githubMyself(key) 37 | if err != nil { 38 | return err 39 | } 40 | } 41 | 42 | go svc.githubRoutine() 43 | 44 | <-svc.ctx.Done() 45 | return nil 46 | } 47 | 48 | // nolint:gocyclo 49 | func (svc *Service) githubRoutine() { 50 | alltimeMostRecent := time.Time{} 51 | for { 52 | // check activity 53 | events, _, err := svc.github.clients["moul"].Activity.ListEventsPerformedByUser(svc.ctx, "moul", false, nil) 54 | if err != nil { 55 | svc.logger.Error("ListEventsPerformedByUser", zap.Error(err)) 56 | continue 57 | } 58 | 59 | batchMostRecent := time.Time{} 60 | for _, event := range events { 61 | if !event.GetCreatedAt().After(alltimeMostRecent) { 62 | continue 63 | } 64 | if event.GetCreatedAt().After(batchMostRecent) { 65 | batchMostRecent = event.GetCreatedAt() 66 | } 67 | eventLogger := svc.logger.With(zap.String("type", event.GetType())) 68 | if event.GetPublic() { 69 | eventLogger = eventLogger.With(zap.String("visibility", "public")) 70 | } else { 71 | eventLogger = eventLogger.With(zap.String("visibility", "private")) 72 | } 73 | if event.Repo != nil { 74 | eventLogger = eventLogger.With(zap.String("repo", event.GetRepo().GetName())) 75 | } else { 76 | eventLogger = eventLogger.With(zap.String("repo", "n/a")) 77 | } 78 | if event.Actor != nil { 79 | eventLogger = eventLogger.With(zap.String("actor", event.GetActor().GetLogin())) 80 | } else { 81 | eventLogger = eventLogger.With(zap.String("actor", "n/a")) 82 | } 83 | if event.Org != nil { 84 | eventLogger = eventLogger.With(zap.String("org", event.GetOrg().GetLogin())) 85 | } else { 86 | eventLogger = eventLogger.With(zap.String("org", "n/a")) 87 | } 88 | switch *event.Type { 89 | case "PushEvent", "DeleteEvent": 90 | // skipped 91 | case "PullRequestEvent", "IssueCommentEvent", "IssuesEvent", "MemberEvent": 92 | // light 93 | eventLogger.Debug("event") 94 | case "CreateEvent": 95 | payload, err := event.ParsePayload() 96 | if err != nil { 97 | eventLogger.Error("event.ParsePayload", zap.Error(err)) 98 | } else { 99 | typed, valid := payload.(*github.CreateEvent) 100 | if !valid { 101 | eventLogger.Error("invalid payload") 102 | continue 103 | } 104 | if typed.GetRefType() == "repository" { 105 | eventLogger.Info("new repo", zap.String("name", event.GetRepo().GetName())) 106 | parts := strings.Split(event.GetRepo().GetName(), "/") 107 | 108 | // moul invites moul-bot 109 | var invite *github.CollaboratorInvitation 110 | { 111 | svc.logger.Debug("trying to send an invite to moul-bot") 112 | var err error 113 | invite, _, err = svc.github.clients["moul"].Repositories.AddCollaborator(svc.ctx, parts[0], parts[1], "moul-bot", nil) 114 | if err != nil { 115 | svc.logger.Error("AddCollaborator", zap.Error(err)) 116 | continue 117 | } 118 | } 119 | // moul-bot accepts the invitation 120 | { 121 | if invite.ID != nil { 122 | svc.logger.Debug("accepting invite") 123 | _, err = svc.github.clients["moul-bot"].Users.AcceptInvitation(svc.ctx, invite.GetID()) 124 | if err != nil { 125 | svc.logger.Error("AcceptInvitation", zap.Error(err)) 126 | } 127 | } 128 | } 129 | // moul-bot stars the repository 130 | { 131 | _, err := svc.github.clients["moul-bot"].Activity.Star(svc.ctx, parts[0], parts[1]) 132 | if err != nil { 133 | svc.logger.Error("Star", zap.Error(err)) 134 | } 135 | } 136 | } else { 137 | eventLogger.Warn("unknown CreateEvent RefType", zap.Any("payload", payload)) 138 | } 139 | } 140 | case "ForkEvent": 141 | payload, err := event.ParsePayload() 142 | if err != nil { 143 | eventLogger.Error("event.ParsePayload", zap.Error(err)) 144 | } else { 145 | typed, valid := payload.(*github.ForkEvent) 146 | if !valid { 147 | eventLogger.Error("invalid payload") 148 | continue 149 | } 150 | fmt.Println("typed", u.PrettyJSON(typed)) 151 | repo := typed.GetForkee() 152 | eventLogger.Info("new fork", zap.String("name", repo.GetFullName())) 153 | parts := strings.Split(repo.GetFullName(), "/") 154 | svc.logger.Debug("trying to send an invite to moul-bot") 155 | invite, _, err := svc.github.clients["moul"].Repositories.AddCollaborator(svc.ctx, parts[0], parts[1], "moul-bot", nil) 156 | if err != nil { 157 | svc.logger.Error("AddCollaborator", zap.Error(err)) 158 | continue 159 | } 160 | if invite.ID != nil { 161 | svc.logger.Debug("accepting invite") 162 | _, err = svc.github.clients["moul-bot"].Users.AcceptInvitation(svc.ctx, invite.GetID()) 163 | if err != nil { 164 | svc.logger.Error("AcceptInvitation", zap.Error(err)) 165 | } 166 | } 167 | } 168 | default: 169 | eventLogger.Warn("unknown Event type") 170 | fmt.Println("unknown type", godev.PrettyJSON(event)) 171 | } 172 | } 173 | if alltimeMostRecent.Before(batchMostRecent) { 174 | alltimeMostRecent = batchMostRecent 175 | } 176 | for key := range svc.github.clients { 177 | svc.githubRateLimit(key) 178 | } 179 | select { 180 | case <-time.After(10 * time.Second): 181 | case <-svc.ctx.Done(): 182 | svc.logger.Debug("context done") 183 | return 184 | } 185 | } 186 | } 187 | 188 | func (svc *Service) githubLogger(client string) *zap.Logger { 189 | return svc.logger.With(zap.String("client", client)) 190 | } 191 | 192 | func (svc *Service) githubRateLimit(client string) { 193 | logger := svc.githubLogger(client) 194 | rate, _, err := svc.github.clients[client].RateLimits(svc.ctx) 195 | if err != nil { 196 | logger.Warn("ratelimit error", zap.Error(err)) 197 | return 198 | } 199 | logger.Debug( 200 | "ratelimit", 201 | zap.Int("remaining", rate.GetCore().Remaining), 202 | zap.Int("limit", rate.GetCore().Limit), 203 | ) 204 | } 205 | 206 | func (svc *Service) githubMyself(client string) error { 207 | logger := svc.githubLogger(client) 208 | user, _, err := svc.github.clients[client].Users.Get(svc.ctx, "") 209 | if err != nil { 210 | return err 211 | } 212 | logger.Debug( 213 | "myself", 214 | zap.String("name", user.GetLogin()), 215 | zap.String("name", user.GetName()), 216 | zap.Int("followers", user.GetFollowers()), 217 | zap.Int("following", user.GetFollowing()), 218 | ) 219 | return nil 220 | } 221 | 222 | func (svc *Service) CloseGitHub(error) { 223 | svc.logger.Debug("closing github") 224 | svc.cancel() 225 | } 226 | 227 | func githubClient(token string) *github.Client { 228 | if token != "" { 229 | ctx := context.Background() 230 | ts := oauth2.StaticTokenSource( 231 | &oauth2.Token{AccessToken: token}, 232 | ) 233 | tc := oauth2.NewClient(ctx, ts) 234 | return github.NewClient(tc) 235 | } 236 | 237 | return github.NewClient(nil) 238 | } 239 | -------------------------------------------------------------------------------- /pkg/moulbot/driver_server.go: -------------------------------------------------------------------------------- 1 | package moulbot 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "log" 8 | "net" 9 | "net/http" 10 | "net/http/pprof" 11 | "os" 12 | "runtime/debug" 13 | "strings" 14 | 15 | "github.com/go-chi/chi" 16 | "github.com/go-chi/chi/middleware" 17 | "github.com/gogo/gateway" 18 | grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" 19 | grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" 20 | grpc_zap "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap" 21 | grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" 22 | "github.com/grpc-ecosystem/grpc-gateway/runtime" 23 | "github.com/oklog/run" 24 | "github.com/rs/cors" 25 | "github.com/soheilhy/cmux" 26 | chilogger "github.com/treastech/logger" 27 | "go.uber.org/zap" 28 | "google.golang.org/grpc" 29 | "google.golang.org/grpc/codes" 30 | "google.golang.org/grpc/status" 31 | "moul.io/banner" 32 | "moul.io/bot/pkg/moulbotpb" 33 | ) 34 | 35 | type serverDriver struct { 36 | listener net.Listener 37 | } 38 | 39 | func (svc *Service) StartServer() error { 40 | fmt.Fprintln(os.Stderr, banner.Inline("server")) 41 | svc.logger.Debug("starting server", zap.String("bind", svc.opts.ServerBind)) 42 | 43 | // listeners 44 | var err error 45 | svc.server.listener, err = net.Listen("tcp", svc.opts.ServerBind) 46 | if err != nil { 47 | return err 48 | } 49 | smux := cmux.New(svc.server.listener) 50 | smux.HandleError(func(err error) bool { 51 | svc.logger.Warn("cmux error", zap.Error(err)) 52 | return true 53 | }) 54 | grpcListener := smux.MatchWithWriters(cmux.HTTP2MatchHeaderFieldPrefixSendSettings("content-type", "application/grpc")) 55 | httpListener := smux.Match(cmux.HTTP2(), cmux.HTTP1()) 56 | 57 | // grpc server 58 | grpcServer := svc.grpcServer() 59 | var gr run.Group 60 | gr.Add(func() error { 61 | err := grpcServer.Serve(grpcListener) 62 | if err != cmux.ErrListenerClosed { 63 | return err 64 | } 65 | return nil 66 | }, func(error) { 67 | err := grpcListener.Close() 68 | if err != nil { 69 | svc.logger.Warn("close gRPC listener", zap.Error(err)) 70 | } 71 | }) 72 | 73 | // http server 74 | httpServer, err := svc.httpServer() 75 | if err != nil { 76 | return err 77 | } 78 | gr.Add(func() error { 79 | err := httpServer.Serve(httpListener) 80 | if err != cmux.ErrListenerClosed { 81 | return err 82 | } 83 | return nil 84 | }, func(error) { 85 | ctx, cancel := context.WithTimeout(svc.ctx, svc.opts.ServerShutdownTimeout) 86 | err := httpServer.Shutdown(ctx) 87 | if err != nil { 88 | svc.logger.Warn("shutdown HTTP server", zap.Error(err)) 89 | } 90 | defer cancel() 91 | err = httpListener.Close() 92 | if err != nil { 93 | svc.logger.Warn("close HTTP listener", zap.Error(err)) 94 | } 95 | }) 96 | 97 | // cmux 98 | gr.Add( 99 | smux.Serve, 100 | func(err error) { 101 | svc.logger.Warn("cmux terminated", zap.Error(err)) 102 | }, 103 | ) 104 | 105 | // context 106 | gr.Add(func() error { 107 | <-svc.ctx.Done() 108 | svc.logger.Warn("parent ctx done") 109 | return nil 110 | }, func(error) {}) 111 | 112 | return gr.Run() 113 | } 114 | 115 | func (svc *Service) CloseServer(error) { 116 | svc.logger.Debug("closing server", zap.Bool("was-started", svc.server.listener != nil)) 117 | if svc.server.listener != nil { 118 | svc.server.listener.Close() 119 | } 120 | svc.cancel() 121 | } 122 | 123 | func (svc *Service) ServerListenerAddr() string { 124 | return svc.server.listener.Addr().String() 125 | } 126 | 127 | func (svc *Service) httpServer() (*http.Server, error) { 128 | r := chi.NewRouter() 129 | r.Use(cors.New(cors.Options{ 130 | AllowedOrigins: strings.Split(svc.opts.ServerCORSAllowedOrigins, ","), 131 | AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, 132 | AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, 133 | ExposedHeaders: []string{"Link"}, 134 | AllowCredentials: true, 135 | MaxAge: 300, 136 | }).Handler) 137 | r.Use(chilogger.Logger(svc.logger)) 138 | r.Use(middleware.Recoverer) 139 | r.Use(middleware.Timeout(svc.opts.ServerRequestTimeout)) 140 | r.Use(middleware.RealIP) 141 | r.Use(middleware.RequestID) 142 | 143 | runtimeMux := runtime.NewServeMux( 144 | runtime.WithMarshalerOption(runtime.MIMEWildcard, &gateway.JSONPb{ 145 | EmitDefaults: false, 146 | Indent: " ", 147 | OrigName: true, 148 | }), 149 | runtime.WithProtoErrorHandler(runtime.DefaultHTTPProtoErrorHandler), 150 | ) 151 | var gwmux http.Handler = runtimeMux 152 | dialOpts := []grpc.DialOption{grpc.WithInsecure()} 153 | 154 | err := moulbotpb.RegisterWebAPIHandlerFromEndpoint(svc.ctx, runtimeMux, svc.ServerListenerAddr(), dialOpts) 155 | if err != nil { 156 | return nil, err 157 | } 158 | 159 | r.Mount("/", gwmux) 160 | if svc.opts.ServerWithPprof { 161 | r.HandleFunc("/debug/pprof/*", pprof.Index) 162 | r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 163 | r.HandleFunc("/debug/pprof/profile", pprof.Profile) 164 | r.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 165 | r.HandleFunc("/debug/pprof/trace", pprof.Trace) 166 | } 167 | http.DefaultServeMux = http.NewServeMux() // disables default handlers registered by importing net/http/pprof for security reasons 168 | return &http.Server{ 169 | Addr: "osef", 170 | Handler: r, 171 | }, nil 172 | } 173 | 174 | func (svc *Service) AuthFuncOverride(ctx context.Context, path string) (context.Context, error) { 175 | // accept everything 176 | return ctx, nil 177 | } 178 | 179 | func (svc *Service) grpcServer() *grpc.Server { 180 | authFunc := func(context.Context) (context.Context, error) { 181 | return nil, errors.New("auth: dummy function, see AuthFuncOverride") 182 | } 183 | recoveryOpts := []grpc_recovery.Option{} 184 | if svc.logger.Check(zap.DebugLevel, "") != nil { 185 | recoveryOpts = append(recoveryOpts, grpc_recovery.WithRecoveryHandlerContext(func(ctx context.Context, p interface{}) error { 186 | log.Println("stacktrace from panic: \n" + string(debug.Stack())) 187 | return status.Errorf(codes.Internal, "recover: %s", p) 188 | })) 189 | } 190 | serverStreamOpts := []grpc.StreamServerInterceptor{grpc_recovery.StreamServerInterceptor(recoveryOpts...)} 191 | serverUnaryOpts := []grpc.UnaryServerInterceptor{grpc_recovery.UnaryServerInterceptor(recoveryOpts...)} 192 | serverStreamOpts = append(serverStreamOpts, 193 | grpc_auth.StreamServerInterceptor(authFunc), 194 | // grpc_ctxtags.StreamServerInterceptor(), 195 | grpc_zap.StreamServerInterceptor(svc.logger), 196 | ) 197 | serverUnaryOpts = append( 198 | serverUnaryOpts, 199 | grpc_auth.UnaryServerInterceptor(authFunc), 200 | // grpc_ctxtags.UnaryServerInterceptor(), 201 | grpc_zap.UnaryServerInterceptor(svc.logger), 202 | ) 203 | if svc.logger.Check(zap.DebugLevel, "") != nil { 204 | serverStreamOpts = append(serverStreamOpts, grpcServerStreamInterceptor()) 205 | serverUnaryOpts = append(serverUnaryOpts, grpcServerUnaryInterceptor()) 206 | } 207 | serverStreamOpts = append(serverStreamOpts, grpc_recovery.StreamServerInterceptor(recoveryOpts...)) 208 | serverUnaryOpts = append(serverUnaryOpts, grpc_recovery.UnaryServerInterceptor(recoveryOpts...)) 209 | grpcServer := grpc.NewServer( 210 | grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(serverStreamOpts...)), 211 | grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(serverUnaryOpts...)), 212 | ) 213 | moulbotpb.RegisterWebAPIServer(grpcServer, svc) 214 | 215 | return grpcServer 216 | } 217 | 218 | func grpcServerStreamInterceptor() grpc.StreamServerInterceptor { 219 | return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { 220 | err := handler(srv, stream) 221 | if err != nil { 222 | log.Printf("%+v", err) 223 | } 224 | return err 225 | } 226 | } 227 | 228 | func grpcServerUnaryInterceptor() grpc.UnaryServerInterceptor { 229 | return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { 230 | ret, err := handler(ctx, req) 231 | if err != nil { 232 | log.Printf("%+v", err) 233 | } 234 | return ret, err 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /pkg/moulbotpb/moulbot.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.24.0-devel 4 | // protoc v3.11.2 5 | // source: moulbot.proto 6 | 7 | package moulbotpb 8 | 9 | import ( 10 | reflect "reflect" 11 | sync "sync" 12 | 13 | proto "github.com/golang/protobuf/proto" 14 | _ "google.golang.org/genproto/googleapis/api/annotations" 15 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 16 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 17 | ) 18 | 19 | const ( 20 | // Verify that this generated code is sufficiently up-to-date. 21 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 22 | // Verify that runtime/protoimpl is sufficiently up-to-date. 23 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 24 | ) 25 | 26 | // This is a compile-time assertion that a sufficiently up-to-date version 27 | // of the legacy proto package is being used. 28 | const _ = proto.ProtoPackageIsVersion4 29 | 30 | type Ping struct { 31 | state protoimpl.MessageState 32 | sizeCache protoimpl.SizeCache 33 | unknownFields protoimpl.UnknownFields 34 | } 35 | 36 | func (x *Ping) Reset() { 37 | *x = Ping{} 38 | if protoimpl.UnsafeEnabled { 39 | mi := &file_moulbot_proto_msgTypes[0] 40 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 41 | ms.StoreMessageInfo(mi) 42 | } 43 | } 44 | 45 | func (x *Ping) String() string { 46 | return protoimpl.X.MessageStringOf(x) 47 | } 48 | 49 | func (*Ping) ProtoMessage() {} 50 | 51 | func (x *Ping) ProtoReflect() protoreflect.Message { 52 | mi := &file_moulbot_proto_msgTypes[0] 53 | if protoimpl.UnsafeEnabled && x != nil { 54 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 55 | if ms.LoadMessageInfo() == nil { 56 | ms.StoreMessageInfo(mi) 57 | } 58 | return ms 59 | } 60 | return mi.MessageOf(x) 61 | } 62 | 63 | // Deprecated: Use Ping.ProtoReflect.Descriptor instead. 64 | func (*Ping) Descriptor() ([]byte, []int) { 65 | return file_moulbot_proto_rawDescGZIP(), []int{0} 66 | } 67 | 68 | type Ping_Request struct { 69 | state protoimpl.MessageState 70 | sizeCache protoimpl.SizeCache 71 | unknownFields protoimpl.UnknownFields 72 | } 73 | 74 | func (x *Ping_Request) Reset() { 75 | *x = Ping_Request{} 76 | if protoimpl.UnsafeEnabled { 77 | mi := &file_moulbot_proto_msgTypes[1] 78 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 79 | ms.StoreMessageInfo(mi) 80 | } 81 | } 82 | 83 | func (x *Ping_Request) String() string { 84 | return protoimpl.X.MessageStringOf(x) 85 | } 86 | 87 | func (*Ping_Request) ProtoMessage() {} 88 | 89 | func (x *Ping_Request) ProtoReflect() protoreflect.Message { 90 | mi := &file_moulbot_proto_msgTypes[1] 91 | if protoimpl.UnsafeEnabled && x != nil { 92 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 93 | if ms.LoadMessageInfo() == nil { 94 | ms.StoreMessageInfo(mi) 95 | } 96 | return ms 97 | } 98 | return mi.MessageOf(x) 99 | } 100 | 101 | // Deprecated: Use Ping_Request.ProtoReflect.Descriptor instead. 102 | func (*Ping_Request) Descriptor() ([]byte, []int) { 103 | return file_moulbot_proto_rawDescGZIP(), []int{0, 0} 104 | } 105 | 106 | type Ping_Response struct { 107 | state protoimpl.MessageState 108 | sizeCache protoimpl.SizeCache 109 | unknownFields protoimpl.UnknownFields 110 | } 111 | 112 | func (x *Ping_Response) Reset() { 113 | *x = Ping_Response{} 114 | if protoimpl.UnsafeEnabled { 115 | mi := &file_moulbot_proto_msgTypes[2] 116 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 117 | ms.StoreMessageInfo(mi) 118 | } 119 | } 120 | 121 | func (x *Ping_Response) String() string { 122 | return protoimpl.X.MessageStringOf(x) 123 | } 124 | 125 | func (*Ping_Response) ProtoMessage() {} 126 | 127 | func (x *Ping_Response) ProtoReflect() protoreflect.Message { 128 | mi := &file_moulbot_proto_msgTypes[2] 129 | if protoimpl.UnsafeEnabled && x != nil { 130 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 131 | if ms.LoadMessageInfo() == nil { 132 | ms.StoreMessageInfo(mi) 133 | } 134 | return ms 135 | } 136 | return mi.MessageOf(x) 137 | } 138 | 139 | // Deprecated: Use Ping_Response.ProtoReflect.Descriptor instead. 140 | func (*Ping_Response) Descriptor() ([]byte, []int) { 141 | return file_moulbot_proto_rawDescGZIP(), []int{0, 1} 142 | } 143 | 144 | var File_moulbot_proto protoreflect.FileDescriptor 145 | 146 | var file_moulbot_proto_rawDesc = []byte{ 147 | 0x0a, 0x0d, 0x6d, 0x6f, 0x75, 0x6c, 0x62, 0x6f, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 148 | 0x07, 0x6d, 0x6f, 0x75, 0x6c, 0x62, 0x6f, 0x74, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 149 | 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 150 | 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1d, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x1a, 0x09, 151 | 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x0a, 0x08, 0x52, 0x65, 0x73, 152 | 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x4e, 0x0a, 0x06, 0x57, 0x65, 0x62, 0x41, 0x50, 0x49, 0x12, 153 | 0x44, 0x0a, 0x04, 0x50, 0x69, 0x6e, 0x67, 0x12, 0x15, 0x2e, 0x6d, 0x6f, 0x75, 0x6c, 0x62, 0x6f, 154 | 0x74, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 155 | 0x2e, 0x6d, 0x6f, 0x75, 0x6c, 0x62, 0x6f, 0x74, 0x2e, 0x50, 0x69, 0x6e, 0x67, 0x2e, 0x52, 0x65, 156 | 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x07, 0x12, 0x05, 157 | 0x2f, 0x70, 0x69, 0x6e, 0x67, 0x42, 0x1b, 0x5a, 0x19, 0x6d, 0x6f, 0x75, 0x6c, 0x2e, 0x69, 0x6f, 158 | 0x2f, 0x62, 0x6f, 0x74, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x6f, 0x75, 0x6c, 0x62, 0x6f, 0x74, 159 | 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 160 | } 161 | 162 | var ( 163 | file_moulbot_proto_rawDescOnce sync.Once 164 | file_moulbot_proto_rawDescData = file_moulbot_proto_rawDesc 165 | ) 166 | 167 | func file_moulbot_proto_rawDescGZIP() []byte { 168 | file_moulbot_proto_rawDescOnce.Do(func() { 169 | file_moulbot_proto_rawDescData = protoimpl.X.CompressGZIP(file_moulbot_proto_rawDescData) 170 | }) 171 | return file_moulbot_proto_rawDescData 172 | } 173 | 174 | var file_moulbot_proto_msgTypes = make([]protoimpl.MessageInfo, 3) 175 | var file_moulbot_proto_goTypes = []interface{}{ 176 | (*Ping)(nil), // 0: moulbot.Ping 177 | (*Ping_Request)(nil), // 1: moulbot.Ping.Request 178 | (*Ping_Response)(nil), // 2: moulbot.Ping.Response 179 | } 180 | var file_moulbot_proto_depIdxs = []int32{ 181 | 1, // 0: moulbot.WebAPI.Ping:input_type -> moulbot.Ping.Request 182 | 2, // 1: moulbot.WebAPI.Ping:output_type -> moulbot.Ping.Response 183 | 1, // [1:2] is the sub-list for method output_type 184 | 0, // [0:1] is the sub-list for method input_type 185 | 0, // [0:0] is the sub-list for extension type_name 186 | 0, // [0:0] is the sub-list for extension extendee 187 | 0, // [0:0] is the sub-list for field type_name 188 | } 189 | 190 | func init() { file_moulbot_proto_init() } 191 | func file_moulbot_proto_init() { 192 | if File_moulbot_proto != nil { 193 | return 194 | } 195 | if !protoimpl.UnsafeEnabled { 196 | file_moulbot_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 197 | switch v := v.(*Ping); i { 198 | case 0: 199 | return &v.state 200 | case 1: 201 | return &v.sizeCache 202 | case 2: 203 | return &v.unknownFields 204 | default: 205 | return nil 206 | } 207 | } 208 | file_moulbot_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 209 | switch v := v.(*Ping_Request); i { 210 | case 0: 211 | return &v.state 212 | case 1: 213 | return &v.sizeCache 214 | case 2: 215 | return &v.unknownFields 216 | default: 217 | return nil 218 | } 219 | } 220 | file_moulbot_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 221 | switch v := v.(*Ping_Response); i { 222 | case 0: 223 | return &v.state 224 | case 1: 225 | return &v.sizeCache 226 | case 2: 227 | return &v.unknownFields 228 | default: 229 | return nil 230 | } 231 | } 232 | } 233 | type x struct{} 234 | out := protoimpl.TypeBuilder{ 235 | File: protoimpl.DescBuilder{ 236 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 237 | RawDescriptor: file_moulbot_proto_rawDesc, 238 | NumEnums: 0, 239 | NumMessages: 3, 240 | NumExtensions: 0, 241 | NumServices: 1, 242 | }, 243 | GoTypes: file_moulbot_proto_goTypes, 244 | DependencyIndexes: file_moulbot_proto_depIdxs, 245 | MessageInfos: file_moulbot_proto_msgTypes, 246 | }.Build() 247 | File_moulbot_proto = out.File 248 | file_moulbot_proto_rawDesc = nil 249 | file_moulbot_proto_goTypes = nil 250 | file_moulbot_proto_depIdxs = nil 251 | } 252 | -------------------------------------------------------------------------------- /rules.mk: -------------------------------------------------------------------------------- 1 | # +--------------------------------------------------------------+ 2 | # | * * * moul.io/rules.mk | 3 | # +--------------------------------------------------------------+ 4 | # | | 5 | # | ++ ______________________________________ | 6 | # | ++++ / \ | 7 | # | ++++ | | | 8 | # | ++++++++++ | https://moul.io/rules.mk is a set | | 9 | # | +++ | | of common Makefile rules that can | | 10 | # | ++ | | be configured from the Makefile | | 11 | # | + -== ==| | or with environment variables. | | 12 | # | ( <*> <*> | | | 13 | # | | | /| Manfred Touron | | 14 | # | | _) / | manfred.life | | 15 | # | | +++ / \______________________________________/ | 16 | # | \ =+ / | 17 | # | \ + | 18 | # | |\++++++ | 19 | # | | ++++ ||// | 20 | # | ___| |___ _||/__ __| 21 | # | / --- \ \| ||| __ _ ___ __ __/ /| 22 | # |/ | | \ \ / / ' \/ _ \/ // / / | 23 | # || | | | | | /_/_/_/\___/\_,_/_/ | 24 | # +--------------------------------------------------------------+ 25 | 26 | .PHONY: _default_entrypoint 27 | _default_entrypoint: help 28 | 29 | ## 30 | ## Common helpers 31 | ## 32 | 33 | rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) 34 | check-program = $(foreach exec,$(1),$(if $(shell PATH="$(PATH)" which $(exec)),,$(error "No $(exec) in PATH"))) 35 | my-filter-out = $(foreach v,$(2),$(if $(findstring $(1),$(v)),,$(v))) 36 | novendor = $(call my-filter-out,vendor/,$(1)) 37 | 38 | ## 39 | ## rules.mk 40 | ## 41 | ifneq ($(wildcard rules.mk),) 42 | .PHONY: rulesmk.bumpdeps 43 | rulesmk.bumpdeps: 44 | wget -O rules.mk https://raw.githubusercontent.com/moul/rules.mk/master/rules.mk 45 | BUMPDEPS_STEPS += rulesmk.bumpdeps 46 | endif 47 | 48 | ## 49 | ## Maintainer 50 | ## 51 | 52 | ifneq ($(wildcard .git/HEAD),) 53 | .PHONY: generate.authors 54 | generate.authors: AUTHORS 55 | AUTHORS: .git/ 56 | echo "# This file lists all individuals having contributed content to the repository." > AUTHORS 57 | echo "# For how it is generated, see 'https://github.com/moul/rules.mk'" >> AUTHORS 58 | echo >> AUTHORS 59 | git log --format='%aN <%aE>' | LC_ALL=C.UTF-8 sort -uf >> AUTHORS 60 | GENERATE_STEPS += generate.authors 61 | endif 62 | 63 | ## 64 | ## Golang 65 | ## 66 | 67 | ifndef GOPKG 68 | ifneq ($(wildcard go.mod),) 69 | GOPKG = $(shell sed '/module/!d;s/^omdule\ //' go.mod) 70 | endif 71 | endif 72 | ifdef GOPKG 73 | GO ?= go 74 | GOPATH ?= $(HOME)/go 75 | GO_INSTALL_OPTS ?= 76 | GO_TEST_OPTS ?= -test.timeout=30s 77 | GOMOD_DIRS ?= $(sort $(call novendor,$(dir $(call rwildcard,*,*/go.mod go.mod)))) 78 | GOCOVERAGE_FILE ?= ./coverage.txt 79 | GOTESTJSON_FILE ?= ./go-test.json 80 | GOBUILDLOG_FILE ?= ./go-build.log 81 | GOINSTALLLOG_FILE ?= ./go-install.log 82 | 83 | ifdef GOBINS 84 | .PHONY: go.install 85 | go.install: 86 | ifeq ($(CI),true) 87 | @rm -f /tmp/goinstall.log 88 | @set -e; for dir in $(GOBINS); do ( set -xe; \ 89 | cd $$dir; \ 90 | $(GO) install -v $(GO_INSTALL_OPTS) .; \ 91 | ); done 2>&1 | tee $(GOINSTALLLOG_FILE) 92 | 93 | else 94 | @set -e; for dir in $(GOBINS); do ( set -xe; \ 95 | cd $$dir; \ 96 | $(GO) install $(GO_INSTALL_OPTS) .; \ 97 | ); done 98 | endif 99 | INSTALL_STEPS += go.install 100 | 101 | .PHONY: go.release 102 | go.release: 103 | $(call check-program, goreleaser) 104 | goreleaser --snapshot --skip-publish --rm-dist 105 | @echo -n "Do you want to release? [y/N] " && read ans && \ 106 | if [ $${ans:-N} = y ]; then set -xe; goreleaser --rm-dist; fi 107 | RELEASE_STEPS += go.release 108 | endif 109 | 110 | .PHONY: go.unittest 111 | go.unittest: 112 | ifeq ($(CI),true) 113 | @echo "mode: atomic" > /tmp/gocoverage 114 | @rm -f $(GOTESTJSON_FILE) 115 | @set -e; for dir in $(GOMOD_DIRS); do (set -e; (set -euf pipefail; \ 116 | cd $$dir; \ 117 | (($(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race -json && touch $@.ok) | tee -a $(GOTESTJSON_FILE) 3>&1 1>&2 2>&3 | tee -a $(GOBUILDLOG_FILE); \ 118 | ); \ 119 | rm $@.ok 2>/dev/null || exit 1; \ 120 | if [ -f /tmp/profile.out ]; then \ 121 | cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \ 122 | rm -f /tmp/profile.out; \ 123 | fi)); done 124 | @mv /tmp/gocoverage $(GOCOVERAGE_FILE) 125 | else 126 | @echo "mode: atomic" > /tmp/gocoverage 127 | @set -e; for dir in $(GOMOD_DIRS); do (set -e; (set -xe; \ 128 | cd $$dir; \ 129 | $(GO) test ./... $(GO_TEST_OPTS) -cover -coverprofile=/tmp/profile.out -covermode=atomic -race); \ 130 | if [ -f /tmp/profile.out ]; then \ 131 | cat /tmp/profile.out | sed "/mode: atomic/d" >> /tmp/gocoverage; \ 132 | rm -f /tmp/profile.out; \ 133 | fi); done 134 | @mv /tmp/gocoverage $(GOCOVERAGE_FILE) 135 | endif 136 | 137 | .PHONY: go.checkdoc 138 | go.checkdoc: 139 | go doc $(first $(GOMOD_DIRS)) 140 | 141 | .PHONY: go.coverfunc 142 | go.coverfunc: go.unittest 143 | go tool cover -func=$(GOCOVERAGE_FILE) | grep -v .pb.go: | grep -v .pb.gw.go: 144 | 145 | .PHONY: go.lint 146 | go.lint: 147 | @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \ 148 | cd $$dir; \ 149 | golangci-lint run --verbose ./...; \ 150 | ); done 151 | 152 | .PHONY: go.tidy 153 | go.tidy: 154 | @# tidy dirs with go.mod files 155 | @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \ 156 | cd $$dir; \ 157 | $(GO) mod tidy; \ 158 | ); done 159 | 160 | .PHONY: go.depaware-update 161 | go.depaware-update: go.tidy 162 | @# gen depaware for bins 163 | @set -e; for dir in $(GOBINS); do ( set -xe; \ 164 | cd $$dir; \ 165 | $(GO) run github.com/tailscale/depaware --update .; \ 166 | ); done 167 | @# tidy unused depaware deps if not in a tools_test.go file 168 | @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \ 169 | cd $$dir; \ 170 | $(GO) mod tidy; \ 171 | ); done 172 | 173 | .PHONY: go.depaware-check 174 | go.depaware-check: go.tidy 175 | @# gen depaware for bins 176 | @set -e; for dir in $(GOBINS); do ( set -xe; \ 177 | cd $$dir; \ 178 | $(GO) run github.com/tailscale/depaware --check .; \ 179 | ); done 180 | 181 | 182 | .PHONY: go.build 183 | go.build: 184 | @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \ 185 | cd $$dir; \ 186 | $(GO) build ./...; \ 187 | ); done 188 | 189 | .PHONY: go.bump-deps 190 | go.bumpdeps: 191 | @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \ 192 | cd $$dir; \ 193 | $(GO) get -u ./...; \ 194 | ); done 195 | 196 | .PHONY: go.bump-deps 197 | go.fmt: 198 | @set -e; for dir in $(GOMOD_DIRS); do ( set -xe; \ 199 | cd $$dir; \ 200 | $(GO) run golang.org/x/tools/cmd/goimports -w `go list -f '{{.Dir}}' ./...` \ 201 | ); done 202 | 203 | VERIFY_STEPS += go.depaware-check 204 | BUILD_STEPS += go.build 205 | BUMPDEPS_STEPS += go.bumpdeps go.depaware-update 206 | TIDY_STEPS += go.tidy 207 | LINT_STEPS += go.lint 208 | UNITTEST_STEPS += go.unittest 209 | FMT_STEPS += go.fmt 210 | 211 | # FIXME: disabled, because currently slow 212 | # new rule that is manually run sometimes, i.e. `make pre-release` or `make maintenance`. 213 | # alternative: run it each time the go.mod is changed 214 | #GENERATE_STEPS += go.depaware-update 215 | endif 216 | 217 | ## 218 | ## Gitattributes 219 | ## 220 | 221 | ifneq ($(wildcard .gitattributes),) 222 | .PHONY: _linguist-ignored 223 | _linguist-kept: 224 | @git check-attr linguist-vendored $(shell git check-attr linguist-generated $(shell find . -type f | grep -v .git/) | grep unspecified | cut -d: -f1) | grep unspecified | cut -d: -f1 | sort 225 | 226 | .PHONY: _linguist-kept 227 | _linguist-ignored: 228 | @git check-attr linguist-vendored linguist-ignored `find . -not -path './.git/*' -type f` | grep '\ set$$' | cut -d: -f1 | sort -u 229 | endif 230 | 231 | ## 232 | ## Node 233 | ## 234 | 235 | ifndef NPM_PACKAGES 236 | ifneq ($(wildcard package.json),) 237 | NPM_PACKAGES = . 238 | endif 239 | endif 240 | ifdef NPM_PACKAGES 241 | .PHONY: npm.publish 242 | npm.publish: 243 | @echo -n "Do you want to npm publish? [y/N] " && read ans && \ 244 | @if [ $${ans:-N} = y ]; then \ 245 | set -e; for dir in $(NPM_PACKAGES); do ( set -xe; \ 246 | cd $$dir; \ 247 | npm publish --access=public; \ 248 | ); done; \ 249 | fi 250 | RELEASE_STEPS += npm.publish 251 | endif 252 | 253 | ## 254 | ## Docker 255 | ## 256 | 257 | docker_build = docker build \ 258 | --build-arg VCS_REF=`git rev-parse --short HEAD` \ 259 | --build-arg BUILD_DATE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` \ 260 | --build-arg VERSION=`git describe --tags --always` \ 261 | -t "$2" -f "$1" "$(dir $1)" 262 | 263 | ifndef DOCKERFILE_PATH 264 | DOCKERFILE_PATH = ./Dockerfile 265 | endif 266 | ifndef DOCKER_IMAGE 267 | ifneq ($(wildcard Dockerfile),) 268 | DOCKER_IMAGE = $(notdir $(PWD)) 269 | endif 270 | endif 271 | ifdef DOCKER_IMAGE 272 | ifneq ($(DOCKER_IMAGE),none) 273 | .PHONY: docker.build 274 | docker.build: 275 | $(call check-program, docker) 276 | $(call docker_build,$(DOCKERFILE_PATH),$(DOCKER_IMAGE)) 277 | 278 | BUILD_STEPS += docker.build 279 | endif 280 | endif 281 | 282 | ## 283 | ## Common 284 | ## 285 | 286 | TEST_STEPS += $(UNITTEST_STEPS) 287 | TEST_STEPS += $(LINT_STEPS) 288 | TEST_STEPS += $(TIDY_STEPS) 289 | 290 | ifneq ($(strip $(TEST_STEPS)),) 291 | .PHONY: test 292 | test: $(PRE_TEST_STEPS) $(TEST_STEPS) 293 | endif 294 | 295 | ifdef INSTALL_STEPS 296 | .PHONY: install 297 | install: $(PRE_INSTALL_STEPS) $(INSTALL_STEPS) 298 | endif 299 | 300 | ifdef UNITTEST_STEPS 301 | .PHONY: unittest 302 | unittest: $(PRE_UNITTEST_STEPS) $(UNITTEST_STEPS) 303 | endif 304 | 305 | ifdef LINT_STEPS 306 | .PHONY: lint 307 | lint: $(PRE_LINT_STEPS) $(FMT_STEPS) $(LINT_STEPS) 308 | endif 309 | 310 | ifdef TIDY_STEPS 311 | .PHONY: tidy 312 | tidy: $(PRE_TIDY_STEPS) $(TIDY_STEPS) 313 | endif 314 | 315 | ifdef BUILD_STEPS 316 | .PHONY: build 317 | build: $(PRE_BUILD_STEPS) $(BUILD_STEPS) 318 | endif 319 | 320 | ifdef VERIFY_STEPS 321 | .PHONY: verify 322 | verify: $(PRE_VERIFY_STEPS) $(VERIFY_STEPS) 323 | endif 324 | 325 | ifdef RELEASE_STEPS 326 | .PHONY: release 327 | release: $(PRE_RELEASE_STEPS) $(RELEASE_STEPS) 328 | endif 329 | 330 | ifdef BUMPDEPS_STEPS 331 | .PHONY: bumpdeps 332 | bumpdeps: $(PRE_BUMDEPS_STEPS) $(BUMPDEPS_STEPS) 333 | endif 334 | 335 | ifdef FMT_STEPS 336 | .PHONY: fmt 337 | fmt: $(PRE_FMT_STEPS) $(FMT_STEPS) 338 | endif 339 | 340 | ifdef GENERATE_STEPS 341 | .PHONY: generate 342 | generate: $(PRE_GENERATE_STEPS) $(GENERATE_STEPS) 343 | endif 344 | 345 | .PHONY: help 346 | help:: 347 | @echo "General commands:" 348 | @[ "$(BUILD_STEPS)" != "" ] && echo " build" || true 349 | @[ "$(BUMPDEPS_STEPS)" != "" ] && echo " bumpdeps" || true 350 | @[ "$(FMT_STEPS)" != "" ] && echo " fmt" || true 351 | @[ "$(GENERATE_STEPS)" != "" ] && echo " generate" || true 352 | @[ "$(INSTALL_STEPS)" != "" ] && echo " install" || true 353 | @[ "$(LINT_STEPS)" != "" ] && echo " lint" || true 354 | @[ "$(RELEASE_STEPS)" != "" ] && echo " release" || true 355 | @[ "$(TEST_STEPS)" != "" ] && echo " test" || true 356 | @[ "$(TIDY_STEPS)" != "" ] && echo " tidy" || true 357 | @[ "$(UNITTEST_STEPS)" != "" ] && echo " unittest" || true 358 | @[ "$(VERIFY_STEPS)" != "" ] && echo " verify" || true 359 | @# FIXME: list other commands 360 | 361 | print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true 362 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Manfred Touron (manfred.life) 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /cmd/moul-bot/depaware.txt: -------------------------------------------------------------------------------- 1 | moul.io/bot/cmd/moul-bot dependencies: (generated by github.com/tailscale/depaware) 2 | 3 | github.com/bwmarrin/discordgo from moul.io/bot/pkg/moulbot 4 | github.com/getsentry/sentry-go from moul.io/bot/cmd/moul-bot 5 | github.com/go-chi/chi from github.com/go-chi/chi/middleware+ 6 | github.com/go-chi/chi/middleware from github.com/treastech/logger+ 7 | github.com/gogo/gateway from moul.io/bot/pkg/moulbot 8 | github.com/gogo/protobuf/jsonpb from github.com/gogo/gateway+ 9 | 💣 github.com/gogo/protobuf/proto from github.com/gogo/gateway+ 10 | github.com/gogo/protobuf/sortkeys from github.com/gogo/protobuf/types 11 | github.com/gogo/protobuf/types from github.com/gogo/protobuf/jsonpb 12 | github.com/golang/protobuf/descriptor from github.com/grpc-ecosystem/grpc-gateway/runtime+ 13 | github.com/golang/protobuf/jsonpb from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap+ 14 | github.com/golang/protobuf/proto from github.com/golang/protobuf/descriptor+ 15 | github.com/golang/protobuf/protoc-gen-go/descriptor from github.com/golang/protobuf/descriptor+ 16 | github.com/golang/protobuf/ptypes from google.golang.org/grpc/internal/binarylog+ 17 | github.com/golang/protobuf/ptypes/any from github.com/golang/protobuf/ptypes+ 18 | github.com/golang/protobuf/ptypes/duration from github.com/golang/protobuf/ptypes+ 19 | github.com/golang/protobuf/ptypes/timestamp from github.com/golang/protobuf/ptypes+ 20 | github.com/golang/protobuf/ptypes/wrappers from github.com/grpc-ecosystem/grpc-gateway/runtime 21 | github.com/google/go-github/v32/github from moul.io/bot/pkg/moulbot 22 | github.com/google/go-querystring/query from github.com/google/go-github/v32/github 23 | 💣 github.com/gorilla/websocket from github.com/bwmarrin/discordgo 24 | github.com/grpc-ecosystem/go-grpc-middleware from github.com/grpc-ecosystem/go-grpc-middleware/auth+ 25 | github.com/grpc-ecosystem/go-grpc-middleware/auth from moul.io/bot/pkg/moulbot 26 | github.com/grpc-ecosystem/go-grpc-middleware/logging from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap 27 | github.com/grpc-ecosystem/go-grpc-middleware/logging/zap from moul.io/bot/pkg/moulbot 28 | github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap 29 | github.com/grpc-ecosystem/go-grpc-middleware/recovery from moul.io/bot/pkg/moulbot 30 | github.com/grpc-ecosystem/go-grpc-middleware/tags from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap 31 | github.com/grpc-ecosystem/go-grpc-middleware/util/metautils from github.com/grpc-ecosystem/go-grpc-middleware/auth 32 | github.com/grpc-ecosystem/grpc-gateway/internal from github.com/grpc-ecosystem/grpc-gateway/runtime 33 | github.com/grpc-ecosystem/grpc-gateway/runtime from github.com/gogo/gateway+ 34 | github.com/grpc-ecosystem/grpc-gateway/utilities from github.com/grpc-ecosystem/grpc-gateway/runtime+ 35 | github.com/oklog/run from moul.io/bot/cmd/moul-bot+ 36 | github.com/peterbourgon/ff/v3 from github.com/peterbourgon/ff/v3/ffcli+ 37 | github.com/peterbourgon/ff/v3/ffcli from moul.io/bot/cmd/moul-bot 38 | github.com/rs/cors from moul.io/bot/pkg/moulbot 39 | github.com/soheilhy/cmux from moul.io/bot/pkg/moulbot 40 | github.com/treastech/logger from moul.io/bot/pkg/moulbot 41 | go.uber.org/atomic from go.uber.org/multierr+ 42 | go.uber.org/multierr from go.uber.org/zap+ 43 | go.uber.org/zap from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap+ 44 | go.uber.org/zap/buffer from go.uber.org/zap/internal/bufferpool+ 45 | go.uber.org/zap/internal/bufferpool from go.uber.org/zap+ 46 | go.uber.org/zap/internal/color from go.uber.org/zap/zapcore 47 | go.uber.org/zap/internal/exit from go.uber.org/zap/zapcore 48 | go.uber.org/zap/zapcore from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap+ 49 | google.golang.org/genproto/googleapis/api/annotations from moul.io/bot/pkg/moulbotpb 50 | google.golang.org/genproto/googleapis/api/httpbody from github.com/grpc-ecosystem/grpc-gateway/runtime 51 | google.golang.org/genproto/googleapis/rpc/status from google.golang.org/grpc/internal/status+ 52 | google.golang.org/genproto/protobuf/field_mask from github.com/grpc-ecosystem/grpc-gateway/runtime 53 | google.golang.org/grpc from github.com/grpc-ecosystem/go-grpc-middleware+ 54 | google.golang.org/grpc/attributes from google.golang.org/grpc/credentials+ 55 | google.golang.org/grpc/backoff from google.golang.org/grpc+ 56 | google.golang.org/grpc/balancer from google.golang.org/grpc+ 57 | google.golang.org/grpc/balancer/base from google.golang.org/grpc+ 58 | google.golang.org/grpc/balancer/grpclb/state from google.golang.org/grpc/internal/resolver/dns 59 | google.golang.org/grpc/balancer/roundrobin from google.golang.org/grpc 60 | google.golang.org/grpc/binarylog/grpc_binarylog_v1 from google.golang.org/grpc/internal/binarylog 61 | google.golang.org/grpc/codes from github.com/grpc-ecosystem/go-grpc-middleware/auth+ 62 | google.golang.org/grpc/connectivity from google.golang.org/grpc+ 63 | google.golang.org/grpc/credentials from google.golang.org/grpc+ 64 | google.golang.org/grpc/encoding from google.golang.org/grpc+ 65 | google.golang.org/grpc/encoding/proto from google.golang.org/grpc 66 | google.golang.org/grpc/grpclog from github.com/grpc-ecosystem/go-grpc-middleware/logging/zap+ 67 | google.golang.org/grpc/internal from google.golang.org/grpc+ 68 | google.golang.org/grpc/internal/backoff from google.golang.org/grpc 69 | google.golang.org/grpc/internal/balancerload from google.golang.org/grpc 70 | google.golang.org/grpc/internal/binarylog from google.golang.org/grpc 71 | google.golang.org/grpc/internal/buffer from google.golang.org/grpc 72 | google.golang.org/grpc/internal/channelz from google.golang.org/grpc+ 73 | google.golang.org/grpc/internal/credentials from google.golang.org/grpc/credentials 74 | google.golang.org/grpc/internal/envconfig from google.golang.org/grpc+ 75 | google.golang.org/grpc/internal/grpclog from google.golang.org/grpc/grpclog 76 | google.golang.org/grpc/internal/grpcrand from google.golang.org/grpc+ 77 | google.golang.org/grpc/internal/grpcsync from google.golang.org/grpc 78 | google.golang.org/grpc/internal/grpcutil from google.golang.org/grpc+ 79 | google.golang.org/grpc/internal/resolver/dns from google.golang.org/grpc 80 | google.golang.org/grpc/internal/resolver/passthrough from google.golang.org/grpc 81 | google.golang.org/grpc/internal/serviceconfig from google.golang.org/grpc 82 | google.golang.org/grpc/internal/status from google.golang.org/grpc/status 83 | google.golang.org/grpc/internal/syscall from google.golang.org/grpc/internal/transport 84 | google.golang.org/grpc/internal/transport from google.golang.org/grpc 85 | google.golang.org/grpc/keepalive from google.golang.org/grpc+ 86 | google.golang.org/grpc/metadata from github.com/grpc-ecosystem/go-grpc-middleware/util/metautils+ 87 | google.golang.org/grpc/peer from github.com/grpc-ecosystem/go-grpc-middleware/tags+ 88 | google.golang.org/grpc/resolver from google.golang.org/grpc+ 89 | google.golang.org/grpc/serviceconfig from google.golang.org/grpc+ 90 | google.golang.org/grpc/stats from google.golang.org/grpc+ 91 | google.golang.org/grpc/status from github.com/grpc-ecosystem/go-grpc-middleware/auth+ 92 | google.golang.org/grpc/tap from google.golang.org/grpc+ 93 | google.golang.org/protobuf/encoding/protojson from github.com/golang/protobuf/jsonpb 94 | google.golang.org/protobuf/encoding/prototext from github.com/golang/protobuf/proto+ 95 | google.golang.org/protobuf/encoding/protowire from github.com/golang/protobuf/proto+ 96 | google.golang.org/protobuf/internal/descfmt from google.golang.org/protobuf/internal/filedesc 97 | google.golang.org/protobuf/internal/descopts from google.golang.org/protobuf/internal/filedesc+ 98 | google.golang.org/protobuf/internal/detrand from google.golang.org/protobuf/internal/descfmt+ 99 | google.golang.org/protobuf/internal/encoding/defval from google.golang.org/protobuf/internal/encoding/tag+ 100 | google.golang.org/protobuf/internal/encoding/json from google.golang.org/protobuf/encoding/protojson 101 | google.golang.org/protobuf/internal/encoding/messageset from google.golang.org/protobuf/encoding/protojson+ 102 | google.golang.org/protobuf/internal/encoding/tag from google.golang.org/protobuf/internal/impl 103 | google.golang.org/protobuf/internal/encoding/text from google.golang.org/protobuf/encoding/prototext+ 104 | google.golang.org/protobuf/internal/errors from google.golang.org/protobuf/encoding/protojson+ 105 | google.golang.org/protobuf/internal/fieldsort from google.golang.org/protobuf/internal/impl+ 106 | google.golang.org/protobuf/internal/filedesc from google.golang.org/protobuf/internal/encoding/tag+ 107 | google.golang.org/protobuf/internal/filetype from google.golang.org/protobuf/runtime/protoimpl 108 | google.golang.org/protobuf/internal/flags from google.golang.org/protobuf/encoding/protojson+ 109 | google.golang.org/protobuf/internal/genid from google.golang.org/protobuf/encoding/protojson+ 110 | 💣 google.golang.org/protobuf/internal/impl from google.golang.org/protobuf/internal/filetype+ 111 | google.golang.org/protobuf/internal/mapsort from google.golang.org/protobuf/encoding/prototext+ 112 | google.golang.org/protobuf/internal/pragma from google.golang.org/protobuf/encoding/protojson+ 113 | google.golang.org/protobuf/internal/set from google.golang.org/protobuf/encoding/protojson+ 114 | 💣 google.golang.org/protobuf/internal/strs from google.golang.org/protobuf/encoding/protojson+ 115 | google.golang.org/protobuf/internal/version from google.golang.org/protobuf/runtime/protoimpl 116 | google.golang.org/protobuf/proto from github.com/golang/protobuf/jsonpb+ 117 | google.golang.org/protobuf/reflect/protodesc from github.com/golang/protobuf/descriptor 118 | 💣 google.golang.org/protobuf/reflect/protoreflect from github.com/golang/protobuf/descriptor+ 119 | google.golang.org/protobuf/reflect/protoregistry from github.com/golang/protobuf/jsonpb+ 120 | google.golang.org/protobuf/runtime/protoiface from github.com/golang/protobuf/proto+ 121 | google.golang.org/protobuf/runtime/protoimpl from github.com/golang/protobuf/descriptor+ 122 | google.golang.org/protobuf/types/descriptorpb from github.com/golang/protobuf/protoc-gen-go/descriptor+ 123 | google.golang.org/protobuf/types/known/anypb from github.com/golang/protobuf/ptypes/any+ 124 | google.golang.org/protobuf/types/known/durationpb from github.com/golang/protobuf/ptypes/duration 125 | google.golang.org/protobuf/types/known/fieldmaskpb from google.golang.org/genproto/protobuf/field_mask 126 | google.golang.org/protobuf/types/known/timestamppb from github.com/golang/protobuf/ptypes/timestamp 127 | google.golang.org/protobuf/types/known/wrapperspb from github.com/golang/protobuf/ptypes/wrappers 128 | gopkg.in/yaml.v3 from moul.io/godev 129 | moul.io/banner from moul.io/bot/pkg/moulbot 130 | moul.io/bot/pkg/moulbot from moul.io/bot/cmd/moul-bot 131 | moul.io/bot/pkg/moulbotpb from moul.io/bot/pkg/moulbot 132 | moul.io/godev from moul.io/bot/pkg/moulbot 133 | moul.io/srand from moul.io/bot/cmd/moul-bot 134 | moul.io/u from moul.io/bot/pkg/moulbot 135 | moul.io/zapconfig from moul.io/bot/cmd/moul-bot 136 | golang.org/x/crypto/cast5 from golang.org/x/crypto/openpgp/packet 137 | golang.org/x/crypto/chacha20 from golang.org/x/crypto/chacha20poly1305 138 | golang.org/x/crypto/chacha20poly1305 from crypto/tls 139 | golang.org/x/crypto/cryptobyte from crypto/ecdsa+ 140 | golang.org/x/crypto/cryptobyte/asn1 from crypto/ecdsa+ 141 | golang.org/x/crypto/curve25519 from crypto/tls 142 | golang.org/x/crypto/hkdf from crypto/tls 143 | golang.org/x/crypto/nacl/secretbox from github.com/bwmarrin/discordgo 144 | golang.org/x/crypto/openpgp from github.com/google/go-github/v32/github 145 | golang.org/x/crypto/openpgp/armor from golang.org/x/crypto/openpgp 146 | golang.org/x/crypto/openpgp/elgamal from golang.org/x/crypto/openpgp/packet 147 | golang.org/x/crypto/openpgp/errors from golang.org/x/crypto/openpgp+ 148 | golang.org/x/crypto/openpgp/packet from golang.org/x/crypto/openpgp 149 | golang.org/x/crypto/openpgp/s2k from golang.org/x/crypto/openpgp+ 150 | golang.org/x/crypto/poly1305 from golang.org/x/crypto/chacha20poly1305+ 151 | golang.org/x/crypto/salsa20/salsa from golang.org/x/crypto/nacl/secretbox 152 | golang.org/x/net/context/ctxhttp from golang.org/x/oauth2/internal 153 | golang.org/x/net/dns/dnsmessage from net 154 | golang.org/x/net/http/httpguts from golang.org/x/net/http2+ 155 | golang.org/x/net/http/httpproxy from net/http 156 | golang.org/x/net/http2 from github.com/soheilhy/cmux+ 157 | golang.org/x/net/http2/hpack from github.com/soheilhy/cmux+ 158 | golang.org/x/net/idna from golang.org/x/net/http/httpguts+ 159 | D golang.org/x/net/route from net 160 | golang.org/x/net/trace from google.golang.org/grpc 161 | golang.org/x/oauth2 from moul.io/bot/pkg/moulbot 162 | golang.org/x/oauth2/internal from golang.org/x/oauth2 163 | golang.org/x/sys/cpu from golang.org/x/crypto/chacha20poly1305 164 | L golang.org/x/sys/unix from google.golang.org/grpc/internal/channelz+ 165 | golang.org/x/text/secure/bidirule from golang.org/x/net/idna 166 | golang.org/x/text/transform from golang.org/x/text/secure/bidirule+ 167 | golang.org/x/text/unicode/bidi from golang.org/x/net/idna+ 168 | golang.org/x/text/unicode/norm from golang.org/x/net/idna 169 | archive/zip from moul.io/u 170 | bufio from archive/zip+ 171 | bytes from bufio+ 172 | compress/bzip2 from golang.org/x/crypto/openpgp/packet 173 | compress/flate from archive/zip+ 174 | compress/gzip from github.com/go-chi/chi/middleware+ 175 | compress/zlib from github.com/bwmarrin/discordgo+ 176 | container/list from crypto/tls+ 177 | context from crypto/tls+ 178 | crypto from crypto/ecdsa+ 179 | crypto/aes from crypto/ecdsa+ 180 | crypto/cipher from crypto/aes+ 181 | crypto/des from crypto/tls+ 182 | crypto/dsa from crypto/x509+ 183 | crypto/ecdsa from crypto/tls+ 184 | crypto/ed25519 from crypto/tls+ 185 | crypto/elliptic from crypto/ecdsa+ 186 | crypto/hmac from crypto/tls+ 187 | crypto/md5 from crypto/tls+ 188 | crypto/rand from crypto/ed25519+ 189 | crypto/rc4 from crypto/tls 190 | crypto/rsa from crypto/tls+ 191 | crypto/sha1 from crypto/tls+ 192 | crypto/sha256 from crypto/tls+ 193 | crypto/sha512 from crypto/ecdsa+ 194 | crypto/subtle from crypto/aes+ 195 | crypto/tls from github.com/getsentry/sentry-go+ 196 | crypto/x509 from crypto/tls+ 197 | crypto/x509/pkix from crypto/x509 198 | encoding from encoding/json+ 199 | encoding/asn1 from crypto/x509+ 200 | encoding/base64 from encoding/json+ 201 | encoding/binary from archive/zip+ 202 | encoding/hex from crypto/x509+ 203 | encoding/json from expvar+ 204 | encoding/pem from crypto/tls+ 205 | errors from archive/zip+ 206 | expvar from github.com/go-chi/chi/middleware 207 | flag from github.com/peterbourgon/ff/v3+ 208 | fmt from compress/flate+ 209 | go/ast from go/build+ 210 | go/build from github.com/getsentry/sentry-go 211 | go/doc from go/build 212 | go/parser from go/build 213 | go/scanner from go/ast+ 214 | go/token from go/ast+ 215 | hash from archive/zip+ 216 | hash/adler32 from compress/zlib 217 | hash/crc32 from archive/zip+ 218 | hash/fnv from google.golang.org/protobuf/internal/detrand 219 | html from html/template 220 | html/template from golang.org/x/net/trace+ 221 | image from github.com/bwmarrin/discordgo+ 222 | image/color from image+ 223 | image/jpeg from github.com/bwmarrin/discordgo+ 224 | image/png from github.com/bwmarrin/discordgo 225 | io from archive/zip+ 226 | io/ioutil from archive/zip+ 227 | log from expvar+ 228 | math from compress/flate+ 229 | math/big from crypto/dsa+ 230 | math/bits from compress/flate+ 231 | math/rand from github.com/getsentry/sentry-go+ 232 | mime from github.com/google/go-github/v32/github+ 233 | mime/multipart from github.com/bwmarrin/discordgo+ 234 | mime/quotedprintable from mime/multipart 235 | net from crypto/tls+ 236 | net/http from expvar+ 237 | net/http/httptrace from github.com/gorilla/websocket+ 238 | net/http/httputil from google.golang.org/grpc 239 | net/http/internal from net/http+ 240 | net/http/pprof from github.com/go-chi/chi/middleware+ 241 | net/textproto from github.com/bwmarrin/discordgo+ 242 | net/url from crypto/x509+ 243 | os from archive/zip+ 244 | os/exec from go/build+ 245 | os/signal from github.com/oklog/run+ 246 | path from archive/zip+ 247 | path/filepath from crypto/x509+ 248 | reflect from crypto/x509+ 249 | regexp from github.com/bwmarrin/discordgo+ 250 | regexp/syntax from regexp 251 | runtime/debug from github.com/getsentry/sentry-go+ 252 | runtime/pprof from net/http/pprof 253 | runtime/trace from net/http/pprof 254 | sort from compress/bzip2+ 255 | strconv from compress/flate+ 256 | strings from archive/zip+ 257 | sync from archive/zip+ 258 | sync/atomic from context+ 259 | syscall from crypto/rand+ 260 | text/tabwriter from github.com/peterbourgon/ff/v3/ffcli+ 261 | text/template from go/doc+ 262 | text/template/parse from html/template+ 263 | time from archive/zip+ 264 | unicode from bytes+ 265 | unicode/utf16 from encoding/asn1+ 266 | unicode/utf8 from archive/zip+ 267 | -------------------------------------------------------------------------------- /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.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8= 16 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 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/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 30 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 31 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 32 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 33 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 34 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 35 | github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= 36 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 37 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 38 | github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= 39 | github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= 40 | github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= 41 | github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 42 | github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= 43 | github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= 44 | github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= 45 | github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= 46 | github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= 47 | github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= 48 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 49 | github.com/bwmarrin/discordgo v0.26.1 h1:AIrM+g3cl+iYBr4yBxCBp9tD9jR3K7upEjl0d89FRkE= 50 | github.com/bwmarrin/discordgo v0.26.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= 51 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 52 | github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 53 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 54 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 55 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 56 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 57 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 58 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 59 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 60 | github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= 61 | github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 62 | github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 63 | github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 64 | github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= 65 | github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= 66 | github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= 67 | github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 68 | github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= 69 | github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 70 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 71 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 72 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 73 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 74 | github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= 75 | github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= 76 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 77 | github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= 78 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 79 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 80 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 81 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 82 | github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= 83 | github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= 84 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 85 | github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= 86 | github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= 87 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 88 | github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= 89 | github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo= 90 | github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0= 91 | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= 92 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 93 | github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= 94 | github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= 95 | github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= 96 | github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= 97 | github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= 98 | github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 99 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 100 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 101 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 102 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 103 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 104 | github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= 105 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 106 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 107 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 108 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 109 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 110 | github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= 111 | github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= 112 | github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= 113 | github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= 114 | github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= 115 | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 116 | github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= 117 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 118 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 119 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 120 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 121 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 122 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 123 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 124 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 125 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 126 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 127 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 128 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 129 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 130 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 131 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 132 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 133 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 134 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 135 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 136 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 137 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 138 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 139 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 140 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 141 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 142 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 143 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 144 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 145 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 146 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 147 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 148 | github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= 149 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 150 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 151 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 152 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 153 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 154 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 155 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 156 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 157 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 158 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 159 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 160 | github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II= 161 | github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= 162 | github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= 163 | github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= 164 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 165 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 166 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 167 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 168 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 169 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 170 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 171 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 172 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 173 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 174 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 175 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 176 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 177 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 178 | github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= 179 | github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 180 | github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= 181 | github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 182 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= 183 | github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= 184 | github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= 185 | github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= 186 | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= 187 | github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= 188 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 189 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 190 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 191 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 192 | github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= 193 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= 194 | github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= 195 | github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= 196 | github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= 197 | github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= 198 | github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= 199 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 200 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 201 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 202 | github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 203 | github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= 204 | github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= 205 | github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= 206 | github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= 207 | github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= 208 | github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 209 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 210 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 211 | github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 212 | github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 213 | github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 214 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 215 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 216 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 217 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 218 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 219 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 220 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 221 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 222 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 223 | github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y= 224 | github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= 225 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 226 | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 227 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 228 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 229 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 230 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 231 | github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= 232 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 233 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 234 | github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= 235 | github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= 236 | github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= 237 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 238 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 239 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 240 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 241 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 242 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 243 | github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= 244 | github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= 245 | github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= 246 | github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= 247 | github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= 248 | github.com/oklog/run v1.1.1-0.20200508094559-c7096881717e h1:bxQ+jj+8fdl9112bovUjD/14jj/uboMqjyVoFkqrdGg= 249 | github.com/oklog/run v1.1.1-0.20200508094559-c7096881717e/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= 250 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 251 | github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 252 | github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= 253 | github.com/peterbourgon/ff/v3 v3.1.2 h1:0GNhbRhO9yHA4CC27ymskOsuRpmX0YQxwxM9UPiP6JM= 254 | github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= 255 | github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= 256 | github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= 257 | github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= 258 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= 259 | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= 260 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 261 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 262 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 263 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 264 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 265 | github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= 266 | github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= 267 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 268 | github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= 269 | github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= 270 | github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= 271 | github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 272 | github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= 273 | github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= 274 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 275 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 276 | github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 277 | github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 278 | github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= 279 | github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= 280 | github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 281 | github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= 282 | github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 283 | github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= 284 | github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 285 | github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 286 | github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 287 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 288 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 289 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 290 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 291 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 292 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 293 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 294 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 295 | github.com/tailscale/depaware v0.0.0-20201214215404-77d1e9757027/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= 296 | github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502 h1:34icjjmqJ2HPjrSuJYEkdZ+0ItmGQAQ75cRHIiftIyE= 297 | github.com/tailscale/depaware v0.0.0-20210622194025-720c4b409502/go.mod h1:p9lPsd+cx33L3H9nNoecRRxPssFKUwwI50I3pZ0yT+8= 298 | github.com/treastech/logger v0.0.0-20180705232552-e381e9ecf2e3 h1:0SnC9653NEySn3YUL1UV9o45KfQzszcOpIJ2f2BlrVg= 299 | github.com/treastech/logger v0.0.0-20180705232552-e381e9ecf2e3/go.mod h1:duKQLZRLkdeZQlw8QfGYqhBQrjThZ2qRBwA8HYjARn8= 300 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 301 | github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= 302 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 303 | github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= 304 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 305 | github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= 306 | github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 307 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 308 | github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= 309 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 310 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 311 | github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 312 | github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= 313 | github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= 314 | github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= 315 | github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= 316 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 317 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 318 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 319 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 320 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 321 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 322 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 323 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 324 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 325 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 326 | go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= 327 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 328 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 329 | go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= 330 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 331 | go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= 332 | go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 333 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 334 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 335 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 336 | go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec= 337 | go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= 338 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 339 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 340 | go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= 341 | go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= 342 | go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= 343 | golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 344 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 345 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 346 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 347 | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 348 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 349 | golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 350 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 351 | golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 352 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 353 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= 354 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 355 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 356 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 357 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 358 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 359 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 360 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 361 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 362 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 363 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 364 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 365 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 366 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 367 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 368 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 369 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 370 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 371 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 372 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 373 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 374 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 375 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 376 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= 377 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 378 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 379 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 380 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 381 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 382 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 383 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 384 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 385 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 386 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 387 | golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= 388 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 389 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 390 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 391 | golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 392 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 393 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 394 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 395 | golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 396 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 397 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 398 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 399 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 400 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 401 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 402 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 403 | golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 404 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 405 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 406 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 407 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 408 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 409 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 410 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 411 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 412 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 413 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 414 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 415 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 416 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 417 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 418 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 419 | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 420 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 421 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 422 | golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw= 423 | golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 424 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 425 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 426 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 427 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 428 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 429 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw= 430 | golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 431 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 432 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 433 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 434 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 435 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 436 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 437 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 438 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 439 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 440 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 441 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 442 | golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 443 | golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 444 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 445 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 446 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 447 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 448 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 449 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 450 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 451 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 452 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 453 | golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 454 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 455 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 456 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 457 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 458 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 459 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 460 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 461 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 462 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 463 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 464 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 465 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 466 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 467 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 468 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 469 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 470 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 471 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 472 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 473 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 474 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 475 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 476 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 477 | golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 478 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 479 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 480 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 481 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 482 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 483 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= 484 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 485 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 486 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 487 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 488 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 489 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 490 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 491 | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 492 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 493 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 494 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 495 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 496 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 497 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 498 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 499 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 500 | golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 501 | golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 502 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 503 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 504 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 505 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 506 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 507 | golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 508 | golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 509 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 510 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 511 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 512 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 513 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 514 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 515 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 516 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 517 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 518 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 519 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 520 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 521 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 522 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 523 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 524 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 525 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 526 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 527 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 528 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 529 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 530 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 531 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 532 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 533 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 534 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 535 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 536 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 537 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 538 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 539 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 540 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 541 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 542 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 543 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 544 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 545 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 546 | golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 547 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 548 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 549 | golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= 550 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 551 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 552 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 553 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 554 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 555 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 556 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 557 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 558 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 559 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 560 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 561 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 562 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 563 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 564 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 565 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 566 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 567 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 568 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 569 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 570 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 571 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 572 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 573 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 574 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 575 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 576 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 577 | google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= 578 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 579 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 580 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 581 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 582 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 583 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 584 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 585 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 586 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 587 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 588 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 589 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 590 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 591 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 592 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 593 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 594 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 595 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 596 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 597 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 598 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 599 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 600 | google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 601 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 602 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 603 | google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 604 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 605 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 606 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 607 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 608 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 609 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 610 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0 h1:5Tbluzus3QxoAJx4IefGt1W0HQZW4nuMrVk684jI74Q= 611 | google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= 612 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 613 | google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 614 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 615 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 616 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 617 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 618 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 619 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 620 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 621 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 622 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 623 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 624 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 625 | google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= 626 | google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 627 | google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= 628 | google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A= 629 | google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= 630 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 631 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 632 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 633 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 634 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 635 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 636 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 637 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 638 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 639 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 640 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 641 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 642 | google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= 643 | google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 644 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 645 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 646 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 647 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 648 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 649 | gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 650 | gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 651 | gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 652 | gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 653 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 654 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 655 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 656 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 657 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 658 | gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 659 | gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 660 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 661 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 662 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 663 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 664 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 665 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 666 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 667 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 668 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 669 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 670 | moul.io/banner v1.0.1 h1:+WsemGLhj2pOajw2eR5VYjLhOIqs0XhIRYchzTyMLk0= 671 | moul.io/banner v1.0.1/go.mod h1:XwvIGKkhKRKyN1vIdmR5oaKQLIkMhkMqrsHpS94QzAU= 672 | moul.io/godev v1.7.0 h1:PgnL7BsCQPPjKwu9V0oxIVm2MyZAHAN2sl0S3+E37U0= 673 | moul.io/godev v1.7.0/go.mod h1:5lgSpI1oH7xWpLl2Ew/Nsgk8DiNM6FzN9WV9+lgW8RQ= 674 | moul.io/srand v1.6.1 h1:SJ335F+54ivLdlH7wH52Rtyv0Ffos6DpsF5wu3ZVMXU= 675 | moul.io/srand v1.6.1/go.mod h1:P2uaZB+GFstFNo8sEj6/U8FRV1n25kD0LLckFpJ+qvc= 676 | moul.io/u v1.23.0/go.mod h1:ytlQ/zt+Sdk+PFGEx+fpTivoa0ieA5yMo6itRswIWNQ= 677 | moul.io/u v1.27.0 h1:rF0p184mludn2DzL0unA8Gf/mFWMBerdqOh8cyuQYzQ= 678 | moul.io/u v1.27.0/go.mod h1:ggYDXxUjoHpfDsMPD3STqkUZTyA741PZiQhSd+7kRnA= 679 | moul.io/zapconfig v1.4.0 h1:J3ND5J3e/qQ++jlpqdSR1EtDNV+iujtvXgLsjy1uyq8= 680 | moul.io/zapconfig v1.4.0/go.mod h1:bYTa5j7r82yPmSR6i5CcrPSVoWEbdpN7o9IgndSVby8= 681 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 682 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 683 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 684 | --------------------------------------------------------------------------------