Merge pull request 'move master to main' (#1) from master into main

Reviewed-on: erius/itmo-go#1
This commit is contained in:
Egor 2024-06-05 17:39:20 +00:00
commit 83f0d33374
269 changed files with 5275 additions and 1624 deletions

View file

@ -1,190 +0,0 @@
- group: Bonus
start: 11-02-2023 18:00
deadline: 29-05-2023 23:59
tasks:
- task: consistenthash
score: 200
- task: gossip
score: 300
- task: smartsched
score: 200
watch:
- distbuild/pkg/scheduler
- task: wasm
score: 300
- group: Analysis
start: 29-04-2023 18:00
deadline: 10-05-2023 23:59
tasks:
- task: testifycheck
score: 200
- task: gzep
score: 100
- group: "[HW] Dist Build"
start: 26-04-2023 12:00
deadline: 29-05-2023 23:59
tasks:
- task: distbuild
score: 0
- group: Low level
start: 22-04-2023 16:00
deadline: 03-05-2023 23:59
tasks:
- task: illegal
score: 100
- task: blowfish
score: 100
- group: Reflect
start: 15-04-2023 16:00
deadline: 25-04-2023 23:59
tasks:
- task: reversemap
score: 100
- task: jsonlist
score: 100
- task: jsonrpc
score: 100
- task: structtags
score: 100
- group: SQL
start: 08-04-2023 16:00
deadline: 18-04-2023 23:59
tasks:
- task: dao
score: 100
- task: ledger
score: 200
- task: shopfront
score: 100
- task: wscat
score: 200
- group: Generics
start: 01-04-2023 16:00
deadline: 11-04-2023 23:59
tasks:
- task: genericsum
score: 100
- task: treeiter
score: 100
- task: coverme
score: 300
- group: HTTP
start: 25-03-2023 16:00
deadline: 06-04-2023 23:59
tasks:
- task: urlshortener
score: 100
- task: digitalclock
score: 100
- task: middleware
score: 200
- task: olympics
score: 200
- task: firewall
score: 200
- group: Concurrency with shared memory
start: 18-03-2023 15:59
deadline: 29-03-2023 23:59
tasks:
- task: dupcall
score: 200
- task: keylock
score: 200
- task: batcher
score: 200
- task: pubsub
score: 300
- group: Testing
start: 11-03-2023 13:00
deadline: 21-03-2023 23:59
tasks:
- task: testequal
score: 100
- task: fileleak
score: 100
- task: tabletest
score: 100
- task: tparallel
score: 200
- task: iprange
score: 100
- group: "[HW] Gitfame"
start: 04-03-2023 16:30
deadline: 19-03-2023 23:59
tasks:
- task: gitfame
score: 0
- group: Goroutines
start: 04-03-2023 16:30
deadline: 14-03-2023 23:59
tasks:
- task: tour1
score: 100
- task: once
score: 100
- task: rwmutex
score: 100
- task: waitgroup
score: 100
- task: cond
score: 100
- task: ratelimit
score: 100
- group: Interfaces
start: 25-02-2023 16:30
deadline: 07-03-2023 23:59
tasks:
- task: otp
score: 100
- task: lrucache
score: 100
- task: externalsort
score: 100
- task: retryupdate
score: 100
- task: ciletters
score: 100
- group: Basics
start: 18-02-2023 16:00
deadline: 28-02-2023 23:59
tasks:
- task: hotelbusiness
score: 100
- task: hogwarts
score: 100
- task: utf8
score: 100
- task: varfmt
score: 100
- task: speller
score: 100
- task: forth
score: 100
- group: Hello World
start: 11-02-2023 18:00
deadline: 21-02-2023 23:59
tasks:
- task: sum
score: 100
- task: tour0
score: 100
- task: wordcount
score: 100
- task: urlfetch
score: 100
- task: fetchall
score: 100

4
.gitignore vendored
View file

@ -3,3 +3,7 @@
.vscode/
/example/
# Go profiling files
*.out
*.test

View file

@ -1,11 +1,7 @@
grade:
image: cr.yandex/crp9onavos88ug32d5r2/grader/go
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_TLS_CERTDIR: ""
APP_HOST: docker
# services:
#- docker:dind
tags:
- experimental
image: gitlab.manytask.org:5050/go/public-2024-spring
script:
- testtool grade
timeout: 10 minutes

263
.manytask.yml Normal file
View file

@ -0,0 +1,263 @@
version: 1
settings: # required
course_name: go
gitlab_base_url: https://gitlab.manytask.org
public_repo: go/public-2024-spring
students_group: go/students-2024-spring
ui:
task_url_template: https://github.com/slon/shad-go/tree/main/$TASK_NAME
# optional, any number of links
links:
"TG Channel": https://t.me/+eb5z6ZS-sI8xZDNi
"TG Chat": https://t.me/+Tk8VTMAk5Tlp7Txm
"LMS": https://lk.yandexdataschool.ru/
"Contribute Manytask": https://github.com/manytask
deadlines:
timezone: Europe/Moscow
deadlines: hard # hard/interpolate
# max_submissions: 10 # optional
# submission_penalty: 0.1 # optional
schedule:
- group: Hello World
start: 2024-01-01 18:00
steps:
0.3: 2024-02-27 23:59
end: 2024-07-10 23:59
tasks:
- task: sum
score: 100
- task: tour0
score: 100
- task: wordcount
score: 100
- task: urlfetch
score: 100
- task: fetchall
score: 100
- group: Basics
start: 2024-02-24 13:00
steps:
0.3: 2024-03-06 06:00
end: 2024-07-10 23:59
tasks:
- task: hotelbusiness
score: 100
- task: hogwarts
score: 100
- task: utf8
score: 100
- task: varfmt
score: 100
- task: speller
score: 100
- task: forth
score: 100
- group: Interfaces
start: 2024-03-02 13:00
steps:
0.3: 2024-03-12 23:59
end: 2024-07-10 23:59
tasks:
- task: otp
score: 100
- task: retryupdate
score: 100
- task: lrucache
score: 100
- task: externalsort
score: 100
- task: ciletters
score: 100
- group: Goroutines
start: 2024-03-03 13:00
steps:
0.3: 2024-03-19 23:59
end: 2024-07-10 23:59
tasks:
- task: tour1
score: 100
- task: once
score: 100
- task: rwmutex
score: 100
- task: waitgroup
score: 100
- task: cond
score: 100
- task: ratelimit
score: 100
- group: "[HW] Gitfame"
start: 2024-03-09 13:00
end: 2024-03-24 23:59
tasks:
- task: gitfame
score: 0
- group: Testing
start: 2024-03-16 13:00
steps:
0.3: 2024-03-27 23:59
end: 2024-07-10 23:59
tasks:
- task: testequal
score: 100
- task: fileleak
score: 100
- task: tabletest
score: 100
- task: tparallel
score: 200
- task: iprange
score: 100
- group: Concurrency with shared memory
start: 2024-03-30 13:00
steps:
0.3: 2024-04-10 23:59
end: 2024-07-10 23:59
tasks:
- task: dupcall
score: 200
- task: keylock
score: 200
- task: batcher
score: 200
- task: pubsub
score: 300
- group: HTTP
start: 2024-04-06 13:00
steps:
0.3: 2024-04-16 23:59
end: 2024-07-10 23:59
tasks:
- task: urlshortener
score: 100
- task: digitalclock
score: 100
- task: middleware
score: 200
- task: firewall
score: 200
- task: olympics
score: 200
- group: SQL
start: 2024-04-13 13:00
steps:
0.3: 2024-04-23 23:59
end: 2024-07-10 23:59
tasks:
- task: dao
score: 100
- task: ledger
score: 200
- task: shopfront
score: 100
- task: wscat
score: 200
- group: "[HW] Dist Build"
start: 2024-04-13 13:00
end: 2024-05-13 23:59
tasks:
- task: distbuild
score: 1
- group: Generics
start: 2024-04-20 13:00
steps:
0.3: 2024-05-02 23:59
end: 2024-07-10 23:59
tasks:
- task: genericsum
score: 100
- task: treeiter
score: 100
- task: coverme
score: 300
- group: Reflect
start: 2024-04-27 13:00
steps:
0.3: 2024-05-07 23:59
end: 2024-07-10 23:59
tasks:
- task: reversemap
score: 100
- task: jsonlist
score: 100
- task: jsonrpc
score: 100
- task: structtags
score: 100
- group: Low level
start: 2024-05-04 13:00
steps:
0.3: 2024-05-14 23:59
end: 2024-07-10 23:59
tasks:
- task: illegal
score: 100
- task: blowfish
score: 100
- task: gzep
score: 100
- group: Analysis
start: 2024-05-11 13:00
steps:
0.3: 2024-05-21 23:59
end: 2024-07-10 23:59
tasks:
- task: testifycheck
score: 200
- group: Bonus
start: 2024-03-03 13:00
end: 2024-07-10 23:59
tasks:
- task: yamlembed
is_bonus: true
score: 100
- task: consistenthash
is_bonus: true
score: 200
- task: gossip
is_bonus: true
score: 300
- task: smartsched
is_bonus: true
score: 200
watch:
- distbuild/pkg/scheduler
- task: wasm
is_bonus: true
score: 300
- task: firegod
is_bonus: true
score: 200
- task: excelwriter
is_bonus: true
score: 200
- task: rsem
is_bonus: true
score: 200
- task: psycher
is_bonus: true
score: 200

View file

@ -1 +1,2 @@
wasm/flappygopher/main_solution.go
rsem/try_lock.lua

View file

@ -1,11 +1,5 @@
check:
image: cr.yandex/crp9onavos88ug32d5r2/grader/go-build
variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_TLS_CERTDIR: ""
APP_HOST: docker
# services:
#- docker:dind
image: gitlab.manytask.org:5050/go/public-2024-spring/build
script:
- golangci-lint run --build-tags private,solution ./...
#- go test -v -tags private,solution ./...
@ -19,8 +13,8 @@ rebuild-base-image:
- docker
when: manual
script:
- docker build -f build.docker -t cr.yandex/crp9onavos88ug32d5r2/grader/go-build .
- docker push cr.yandex/crp9onavos88ug32d5r2/grader/go-build:latest
- docker build -f build.docker -t gitlab.manytask.org:5050/go/public-2024-spring/build .
- docker push gitlab.manytask.org:5050/go/public-2024-spring/build:latest
deploy:
only:
@ -28,9 +22,9 @@ deploy:
tags:
- docker
script:
- docker pull cr.yandex/crp9onavos88ug32d5r2/grader/go-build:latest
- docker build -f testenv.docker -t cr.yandex/crp9onavos88ug32d5r2/grader/go .
- docker push cr.yandex/crp9onavos88ug32d5r2/grader/go:latest
- docker pull gitlab.manytask.org:5050/go/public-2024-spring/build:latest
- docker build -f testenv.docker -t gitlab.manytask.org:5050/go/public-2024-spring .
- docker push gitlab.manytask.org:5050/go/public-2024-spring:latest
build-slides:
only:
@ -38,28 +32,32 @@ build-slides:
tags:
- docker
script:
- docker build lectures -t cr.yandex/crp9onavos88ug32d5r2/go-lectures
- docker push cr.yandex/crp9onavos88ug32d5r2/go-lectures
- docker build lectures -t gitlab.manytask.org:5050/go/public-2024-spring/lectures
- docker push gitlab.manytask.org:5050/go/public-2024-spring/lectures
push-to-public:
stage: .post
image: cr.yandex/crp9onavos88ug32d5r2/grader/go
update-config:
only:
- master
script:
- git remote rm public || true
- git remote add -f public https://svparamoshkin:${CI_PUSH_TOKEN}@gitlab.manytask.org/go/public-itmo-2023-fall
- git config --global user.email 'svparamoshkin@yandex-team.ru'
- git config --global user.name 'svparamoshkin'
- git fetch public
- git branch -D public || true
- git branch public public/master
- testtool export --push --move-to-master=false
- curl -F token=$TESTER_TOKEN http://itmo-go.manytask.org/api/sync_task_columns
- >
curl -v --fail --silent -X POST \
-H "Authorization: Bearer $TESTER_TOKEN" \
-H "Content-type: application/x-yaml" \
--data-binary "@.manytask.yml" \
https://go.manytask.org/api/update_config
- >
curl -v --fail --silent -X POST \
-H "Authorization: Bearer $TESTER_TOKEN" \
https://go.manytask.org/api/update_cache
push-to-github:
push-to-public:
stage: .post
image: cr.yandex/crp9onavos88ug32d5r2/grader/go
image: gitlab.manytask.org:5050/go/public-2024-spring
parallel:
matrix:
- REMOTE:
- git@github.com:slon/shad-go.git
- git@gitlab.manytask.org:go/public-2024-spring.git
only:
- master
script:
@ -69,7 +67,7 @@ push-to-github:
- git branch -D main || true
- git checkout -b main
- git remote rm github || true
- env GIT_SSH_COMMAND="ssh -i ${PWD}/private.key -o StrictHostKeyChecking=no" git remote add -f github git@github.com:slon/shad-go.git
- env GIT_SSH_COMMAND="ssh -i ${PWD}/private.key -o StrictHostKeyChecking=no" git remote add -f github $REMOTE
- env GIT_SSH_COMMAND="ssh -i ${PWD}/private.key -o StrictHostKeyChecking=no" git push github main
deploy-slides:
@ -79,5 +77,5 @@ deploy-slides:
tags:
- web
script:
- docker pull cr.yandex/crp9onavos88ug32d5r2/go-lectures
- docker pull gitlab.manytask.org:5050/go/public-2024-spring/lectures
- cd /srv/manytask/go && docker compose up -d

View file

@ -1,26 +1,28 @@
# Как послать патч
Если вы нашли недоработку в тестах или неточность/опечатку в условии, то вы можете послать MR
Если вы нашли недоработку в тестах или неточность/опечатку в условии, то вы можете послать PR
с исправлением в репозиторий курса.
За все исправления начисляются дополнительные баллы в колонке bugs в таблице.
За все исправления начисляются дополнительные баллы в колонке bonus в таблице.
Размер дополнительных баллов зависит от серьёзности исправления и определяется преподавателями.
## Небольшие исправления
Небольшие исправления на <10 строк проще всего послать через веб интерфейс гитлаба.
Небольшие исправления на <10 строк проще всего послать через веб интерфейс гитхаба.
1. Откройте нужный файл в веб интерфейсе репозитория https://gitlab.com/manytask/itmo-go/private
2. Нажмите на кнопку "Edit". Во всплывающей подсказке нажмите кнопку "Fork".
![](docs/edit-and-fork.png)
3. Внесите изменения в файл. Нажмите "Commit Changes" внизу страницы.
4. Добавьте описание вашего изменения. Нажмите "Submit Merge Request".
1. Откройте нужный файл в веб интерфейсе репозитория https://github.com/slon/shad-go
2. Нажмите на кнопку "Edit in place".
![](docs/edit-in-place.png)
3. На следующем экране нажмите "Fork this repository".
3. Внесите изменения в файл. Нажмите "Commit Changes" сверху страницы.
4. Добавьте описание вашего изменения. Нажмите "Propose changed".
5. Нажмите "Create pull request".
## Продвинутые исправления
Для многофайловых исправлений можно сначала сделать исправление локально:
1. Создайте форк https://gitlab.com/manytask/itmo-go/private аналогично тому, что выше.
1. Создайте форк https://github.com/slon/shad-go аналогично тому, что выше.
2. Закоммитьте все локальные изменения, которые вы не хотите добавлять в репозиторий курса.
@ -30,16 +32,13 @@
git checkout origin/master -b newbranchforupdate
```
4. Внесите локальные изменения и запушьте их в свой форк на [gitlab.com](https://gitlab.com/) (не в `student`), например
4. Внесите локальные изменения и запушьте их в свой форк на [github.com](https://github.com/) (не в `student`), например
```
git add .
git commit -m "Update tests"
git push https://gitlab.com/%USERNAME%/shad-go/
git push https://github.com/%USERNAME%/shad-go/
```
5. В своём форке выберите созданную ветку и создайте Merge Request в репозиторий курса. Обычно GitLab подсказывает недавно запушенную ветку и предлагает создать для неё MR.
5. В своём форке выберите созданную ветку и создайте Pull Request в репозиторий курса. Обычно Github подсказывает недавно запушенную ветку и предлагает создать для неё PR.
![](docs/create-mr.png)
На странице c формой нового Merge Request убедитесь, что ветвь назначения — `slon/shad-go:master`. Нажмите кнопку "Create Merge Request".
![](docs/create-mr-form.png)
На странице c формой нового Pull Request убедитесь, что ветвь назначения — `slon/shad-go:master`. Нажмите кнопку "Create Pull Request".

View file

@ -1,13 +1,5 @@
# Курс по Го в ШАД
Для работы с кодом нужен go 1.18 или выше.
```sh
git clone https://gitlab.com/manytask/itmo-go/private.git
cd shad-go
go test ./sum/...
```
Проект можно открыть в любой go IDE с поддержкой модулей.
## Информация

View file

@ -15,7 +15,7 @@
```
goos: linux
goarch: amd64
pkg: gitlab.com/manytask/itmo-go/private/allocs
pkg: gitlab.com/slon/shad-go/allocs
Benchmark/count-4 73200 16294 ns/op 880 B/op 5 allocs/op
Benchmark/main-4 40485 30113 ns/op 1034 B/op 9 allocs/op
```
@ -23,7 +23,7 @@ Benchmark/main-4 40485 30113 ns/op 1034
Значения бенчмарков для авторского решения:
```goos: linux
goarch: amd64
pkg: gitlab.com/manytask/itmo-go/private/allocs
pkg: gitlab.com/slon/shad-go/allocs
Benchmark/count-4 212850 5471 ns/op 4144 B/op 2 allocs/op
Benchmark/main-4 143937 8247 ns/op 4176 B/op 3 allocs/op
```

View file

@ -5,7 +5,6 @@ package allocs
import (
"fmt"
"io"
"io/ioutil"
"sort"
"strings"
)
@ -24,7 +23,7 @@ func NewBaselineCounter() Counter {
}
func (c BaselineCounter) Count(r io.Reader) error {
data, err := ioutil.ReadAll(r)
data, err := io.ReadAll(r)
if err != nil {
return err
}

View file

@ -2,9 +2,10 @@
package batcher
import "gitlab.com/manytask/itmo-go/private/batcher/slow"
import "gitlab.com/slon/shad-go/batcher/slow"
type Batcher struct{}
type Batcher struct {
}
func NewBatcher(v *slow.Value) *Batcher {
return nil

View file

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gitlab.com/manytask/itmo-go/private/batcher/slow"
"gitlab.com/slon/shad-go/batcher/slow"
)
func TestSimple(t *testing.T) {

View file

@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/blowfish"
"gitlab.com/slon/shad-go/blowfish"
)
var _ cipher.Block = (*blowfish.Blowfish)(nil)

View file

@ -1,4 +1,4 @@
FROM golang:1.20
FROM golang:1.22
# enable backports for git-filter-repo
RUN echo "deb http://deb.debian.org/debian bullseye-backports main" >> /etc/apt/sources.list.d/backports.list
@ -7,4 +7,4 @@ RUN apt-get update && apt-get install -y \
rsync libssl-dev postgresql sudo redis-server git-filter-repo/bullseye-backports \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.51.1
RUN curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.56.2

View file

@ -35,7 +35,7 @@ Your pipeline #194613 has failed! // 194613 -- это ID pipeline'а
// Далее идут последние 10 строк лога gitlab runner'а
testtool: copying go.mod, go.sum and .golangci.yml
testtool: running tests
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/manytask/itmo-go/private/sum
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
--- FAIL: TestSum (0.00s)
sum_test.go:19: 2 + 2 == 0 != 4
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808

View file

@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/tools/testtool"
)
type testCase struct {
@ -93,7 +93,7 @@ testtool: copying !change files
testtool: copying testdata directory
testtool: copying go.mod, go.sum and .golangci.yml
testtool: running tests
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/manytask/itmo-go/private/sum
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
--- FAIL: TestSum (0.00s)
sum_test.go:19: 2 + 2 == 0 != 4
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
@ -113,7 +113,7 @@ ERROR: Job failed: exit code 1`,
Stage: test, Job grade
testtool: copying go.mod, go.sum and .golangci.yml
testtool: running tests
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/manytask/itmo-go/private/sum
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
--- FAIL: TestSum (0.00s)
sum_test.go:19: 2 + 2 == 0 != 4
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
@ -156,7 +156,7 @@ testtool: copying !change files
testtool: copying testdata directory
testtool: copying go.mod, go.sum and .golangci.yml
testtool: running tests
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/manytask/itmo-go/private/sum
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
--- FAIL: TestSum (0.00s)
sum_test.go:19: 2 + 2 == 0 != 4
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808
@ -188,7 +188,7 @@ ERROR: Job failed: exit code 1`,
Stage: %v, Job %v
testtool: copying go.mod, go.sum and .golangci.yml
testtool: running tests
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/manytask/itmo-go/private/sum
testtool: > go test -mod readonly -tags private -c -o /tmp/bincache730817117/5d83984f885e61c1 gitlab.com/slon/shad-go/sum
--- FAIL: TestSum (0.00s)
sum_test.go:19: 2 + 2 == 0 != 4
sum_test.go:19: 9223372036854775807 + 1 == 0 != -9223372036854775808

View file

@ -1,6 +1,7 @@
package cond
import (
"gitlab.com/slon/shad-go/tools/testtool"
"sync"
"testing"
"time"
@ -44,6 +45,38 @@ func TestCondSignal(t *testing.T) {
c.Signal()
}
func TestCondSignalOveruse(t *testing.T) {
var m sync.Mutex
c := New(&m)
running := make(chan bool, 1)
awake := make(chan bool, 1)
for i := 0; i < 5; i++ {
c.Signal() // Checks if empty signals are not deadlocking
}
go func() {
m.Lock()
running <- true
c.Wait() // Checks if it will wait after empty signals
awake <- true
m.Unlock()
}()
<-running
select {
case <-awake:
t.Fatal("goroutine not asleep")
default:
}
m.Lock()
c.Signal()
m.Unlock()
<-awake // Will deadlock if no goroutine wakes up
}
func TestCondSignalGenerations(t *testing.T) {
var m sync.Mutex
c := New(&m)
@ -182,3 +215,7 @@ func TestCondSignalStealing(t *testing.T) {
cond.Broadcast()
}
}
func TestNoSyncPackageImported(t *testing.T) {
testtool.CheckForbiddenImport(t, "sync")
}

View file

@ -57,7 +57,7 @@ func TestHash_EvenDistribution(t *testing.T) {
h.AddNode(&n)
}
counts := map[*node]int{}
counts := map[*node]float64{}
const N = 1 << 16
for i := 0; i < N; i++ {
counts[h.GetNode(fmt.Sprintf("key%d", i))] += 1
@ -65,14 +65,23 @@ func TestHash_EvenDistribution(t *testing.T) {
const P = 1 / float64(K)
const variance = N * (P) * (1 - P)
stddev := math.Sqrt(variance)
t.Logf("P = %v, var = %v, stddev = %v", P, variance, stddev)
idealStddev := math.Sqrt(variance)
t.Logf("P = %v, var = %v, stddev = %v", P, variance, idealStddev)
t.Logf("counts = %v", maps.Values(counts))
total := float64(N)
mean := total / K
var dispersion float64
for _, count := range counts {
require.Greater(t, count, int(N/K-stddev*10))
require.Less(t, count, int(N/K+stddev*10))
dispersion += (count - mean) * (count - mean)
}
realStddev := math.Sqrt(dispersion / K)
t.Logf("read stddev = %v", realStddev)
require.Less(t, math.Abs(realStddev-idealStddev)/idealStddev, float64(4))
}
func TestHash_ConsistentDistribution(t *testing.T) {

View file

@ -12,8 +12,8 @@ import (
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"gitlab.com/manytask/itmo-go/private/coverme/models"
"gitlab.com/manytask/itmo-go/private/coverme/utils"
"gitlab.com/slon/shad-go/coverme/models"
"gitlab.com/slon/shad-go/coverme/utils"
)
type App struct {

View file

@ -8,7 +8,7 @@ import (
"fmt"
"net/http"
"gitlab.com/manytask/itmo-go/private/coverme/models"
"gitlab.com/slon/shad-go/coverme/models"
)
type Client struct {

View file

@ -5,8 +5,8 @@ package main
import (
"flag"
"gitlab.com/manytask/itmo-go/private/coverme/app"
"gitlab.com/manytask/itmo-go/private/coverme/models"
"gitlab.com/slon/shad-go/coverme/app"
"gitlab.com/slon/shad-go/coverme/models"
)
func main() {

View file

@ -31,18 +31,14 @@ sudo apt install postgresql
Альтернативный способ — запустить бд в докере.
Для этого нужно установить docker и docker-compose по инструкции из [dockertest](../dockertest/README.md).
Добиться успешного запуска
```
go test -v ./dockertest/...
```
Запускать тесты можно будет так:
```
(cd dao && docker-compose up -d && sleep 1 && env PGCONN="host=127.0.0.1 port=5432 database=shad-go user=gopher password=pass" go test -v ./... -count=1 || true && docker-compose down)
(cd dao && docker compose up -d --wait && env PGCONN="host=127.0.0.1 port=5432 database=shad-go user=gopher password=pass" go test -v ./... -count=1 || true && docker compose down)
```
Эта команда стартует docker с postgresql, запускает тесты, передав им DSN через переменную окружения, удаляет контейнеры в конце.
Как подчистить контейнеры, если что-то пошло не так:
```
(cd dao && docker-compose down)
(cd dao && docker compose down)
```

View file

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gitlab.com/manytask/itmo-go/private/pgfixture"
"gitlab.com/slon/shad-go/pgfixture"
)
func TestDao(t *testing.T) {
@ -36,7 +36,7 @@ func TestDao(t *testing.T) {
alice, err := dao.Lookup(ctx, aliceID)
require.NoError(t, err)
require.Equal(t, alice, User{ID: aliceID, Name: "Alice"})
require.Equal(t, User{ID: aliceID, Name: "Alice"}, alice)
require.NoError(t, dao.Delete(ctx, bobID))
@ -44,6 +44,7 @@ func TestDao(t *testing.T) {
require.ErrorIs(t, err, sql.ErrNoRows)
require.NoError(t, dao.Update(ctx, &User{ID: charlieID, Name: "Chaplin"}))
require.Error(t, dao.Update(ctx, &User{ID: 999, Name: "FooBar"}))
users, err := dao.List(ctx)
require.NoError(t, err)

View file

@ -8,3 +8,8 @@ services:
POSTGRES_PASSWORD: pass
ports:
- 5432:5432
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U $${POSTGRES_USER}" ]
interval: 1s
timeout: 3s
retries: 5

View file

@ -5,7 +5,6 @@ import (
"fmt"
"image"
"image/png"
"io/ioutil"
"net/http"
"net/url"
"os"
@ -18,10 +17,10 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/tools/testtool"
)
const importPath = "gitlab.com/manytask/itmo-go/private/digitalclock"
const importPath = "gitlab.com/slon/shad-go/digitalclock"
var binCache testtool.BinCache
@ -125,7 +124,7 @@ func TestDigitalClock_valid(t *testing.T) {
port, stop := startServer(t)
defer stop()
files, err := ioutil.ReadDir("./testdata")
files, err := os.ReadDir("./testdata")
require.NoError(t, err)
c := &http.Client{Timeout: time.Second * 10}

View file

@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
@ -17,13 +16,13 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/artifact"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/client"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/dist"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/filecache"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/worker"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/distbuild/pkg/api"
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
"gitlab.com/slon/shad-go/distbuild/pkg/client"
"gitlab.com/slon/shad-go/distbuild/pkg/dist"
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
"gitlab.com/slon/shad-go/distbuild/pkg/worker"
"gitlab.com/slon/shad-go/tools/testtool"
"go.uber.org/zap"
)
@ -50,7 +49,11 @@ type Config struct {
WorkerCount int
}
func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
func newEnv(t *testing.T, config *Config) (e *env) {
t.Cleanup(func() {
goleak.VerifyNone(t)
})
cwd, err := os.Getwd()
require.NoError(t, err)
@ -60,9 +63,9 @@ func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
rootDir := filepath.Join(absCWD, "workdir", t.Name())
require.NoError(t, os.RemoveAll(rootDir))
if err = os.MkdirAll(rootDir, 0o777); err != nil {
if err = os.MkdirAll(rootDir, 0777); err != nil {
if errors.Is(err, os.ErrPermission) {
rootDir, err = ioutil.TempDir("", "")
rootDir, err = os.MkdirTemp("", "")
require.NoError(t, err)
} else {
require.NoError(t, err)
@ -90,6 +93,10 @@ func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
env.Logger, err = cfg.Build()
require.NoError(t, err)
t.Cleanup(func() {
_ = env.Logger.Sync()
})
t.Helper()
t.Logf("test is running inside %s; see test.log file for more info", filepath.Join("workdir", t.Name()))
@ -100,6 +107,7 @@ func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
var cancelRootContext func()
env.Ctx, cancelRootContext = context.WithCancel(context.Background())
t.Cleanup(cancelRootContext)
env.Client = client.NewClient(
env.Logger.Named("client"),
@ -113,6 +121,7 @@ func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
env.Logger.Named("coordinator"),
coordinatorCache,
)
t.Cleanup(env.Coordinator.Stop)
router := http.NewServeMux()
router.Handle("/coordinator/", http.StripPrefix("/coordinator", env.Coordinator))
@ -161,6 +170,11 @@ func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
}
}()
t.Cleanup(func() {
cancelRootContext()
_ = env.HTTP.Shutdown(context.Background())
})
for _, w := range env.Workers {
go func(w *worker.Worker) {
err := w.Run(env.Ctx)
@ -181,20 +195,14 @@ func newEnv(t *testing.T, config *Config) (e *env, cancel func()) {
}
}()
return env, func() {
cancelRootContext()
_ = env.HTTP.Shutdown(context.Background())
_ = env.Logger.Sync()
goleak.VerifyNone(t)
}
return env
}
func newWinFileSink(u *url.URL) (zap.Sink, error) {
if len(u.Opaque) > 0 {
// Remove leading slash left by url.Parse()
return os.OpenFile(u.Opaque[1:], os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
return os.OpenFile(u.Opaque[1:], os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
}
// if url.URL is empty, don't panic slice index error
return os.OpenFile(u.Opaque, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
return os.OpenFile(u.Opaque, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
}

View file

@ -1,7 +1,7 @@
package disttest
import (
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
type JobResult struct {

View file

@ -2,13 +2,14 @@ package disttest
import (
"fmt"
"io/ioutil"
"io"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
var singleWorkerConfig = &Config{WorkerCount: 1}
@ -26,8 +27,7 @@ var echoGraph = build.Graph{
}
func TestSingleCommand(t *testing.T) {
env, cancel := newEnv(t, singleWorkerConfig)
defer cancel()
env := newEnv(t, singleWorkerConfig)
recorder := NewRecorder()
require.NoError(t, env.Client.Build(env.Ctx, echoGraph, recorder))
@ -37,10 +37,9 @@ func TestSingleCommand(t *testing.T) {
}
func TestJobCaching(t *testing.T) {
env, cancel := newEnv(t, singleWorkerConfig)
defer cancel()
env := newEnv(t, singleWorkerConfig)
tmpFile, err := ioutil.TempFile("", "")
tmpFile, err := os.CreateTemp("", "")
require.NoError(t, err)
graph := build.Graph{
@ -62,12 +61,12 @@ func TestJobCaching(t *testing.T) {
assert.Len(t, recorder.Jobs, 1)
assert.Equal(t, &JobResult{Stdout: "OK\n", Code: new(int)}, recorder.Jobs[build.ID{'a'}])
require.NoError(t, ioutil.WriteFile(tmpFile.Name(), []byte("NOTOK\n"), 0o666))
require.NoError(t, os.WriteFile(tmpFile.Name(), []byte("NOTOK\n"), 0666))
// Second build must get results from cache.
require.NoError(t, env.Client.Build(env.Ctx, graph, NewRecorder()))
output, err := ioutil.ReadAll(tmpFile)
output, err := io.ReadAll(tmpFile)
require.NoError(t, err)
require.Equal(t, []byte("NOTOK\n"), output)
}
@ -94,8 +93,7 @@ var sourceFilesGraph = build.Graph{
}
func TestSourceFiles(t *testing.T) {
env, cancel := newEnv(t, singleWorkerConfig)
defer cancel()
env := newEnv(t, singleWorkerConfig)
recorder := NewRecorder()
require.NoError(t, env.Client.Build(env.Ctx, sourceFilesGraph, recorder))
@ -125,8 +123,7 @@ var artifactTransferGraph = build.Graph{
}
func TestArtifactTransferBetweenJobs(t *testing.T) {
env, cancel := newEnv(t, singleWorkerConfig)
defer cancel()
env := newEnv(t, singleWorkerConfig)
recorder := NewRecorder()
require.NoError(t, env.Client.Build(env.Ctx, artifactTransferGraph, recorder))

View file

@ -9,14 +9,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
var threeWorkerConfig = &Config{WorkerCount: 3}
func TestArtifactTransferBetweenWorkers(t *testing.T) {
env, cancel := newEnv(t, threeWorkerConfig)
defer cancel()
env := newEnv(t, threeWorkerConfig)
baseJob := build.Job{
ID: build.ID{'a'},

View file

@ -3,7 +3,7 @@ package api
import (
"context"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
type BuildRequest struct {
@ -25,7 +25,8 @@ type BuildFailed struct {
Error string
}
type BuildFinished struct{}
type BuildFinished struct {
}
type UploadDone struct{}
@ -33,7 +34,8 @@ type SignalRequest struct {
UploadDone *UploadDone
}
type SignalResponse struct{}
type SignalResponse struct {
}
type StatusWriter interface {
Started(rsp *BuildStarted) error

View file

@ -7,10 +7,11 @@ import (
"go.uber.org/zap"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
type BuildClient struct{}
type BuildClient struct {
}
func NewBuildClient(l *zap.Logger, endpoint string) *BuildClient {
panic("implement me")

View file

@ -12,9 +12,9 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
mock "gitlab.com/manytask/itmo-go/private/distbuild/pkg/api/mock"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/api"
mock "gitlab.com/slon/shad-go/distbuild/pkg/api/mock"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
//go:generate mockgen -package mock -destination mock/mock.go . Service
@ -28,7 +28,6 @@ type env struct {
func (e *env) stop() {
e.server.Close()
e.ctrl.Finish()
}
func newEnv(t *testing.T) (*env, func()) {
@ -56,8 +55,8 @@ func TestBuildSignal(t *testing.T) {
ctx := context.Background()
buildIDa := build.ID{0o1}
buildIDb := build.ID{0o2}
buildIDa := build.ID{01}
buildIDb := build.ID{02}
req := &api.SignalRequest{}
rsp := &api.SignalResponse{}
@ -91,10 +90,10 @@ func TestBuildRunning(t *testing.T) {
ctx := context.Background()
buildID := build.ID{0o2}
buildID := build.ID{02}
req := &api.BuildRequest{
Graph: build.Graph{SourceFiles: map[build.ID]string{{0o1}: "a.txt"}},
Graph: build.Graph{SourceFiles: map[build.ID]string{{01}: "a.txt"}},
}
started := &api.BuildStarted{ID: buildID}
@ -141,7 +140,7 @@ func TestBuildResultsStreaming(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
buildID := build.ID{0o2}
buildID := build.ID{02}
req := &api.BuildRequest{}
started := &api.BuildStarted{ID: buildID}

View file

@ -3,7 +3,7 @@ package api
import (
"context"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
// JobResult описывает результат работы джоба.

View file

@ -11,16 +11,15 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/api/mock"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/api"
"gitlab.com/slon/shad-go/distbuild/pkg/api/mock"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
//go:generate mockgen -package mock -destination mock/heartbeat.go . HeartbeatService
func TestHeartbeat(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
l := zaptest.NewLogger(t)
m := mock.NewMockHeartbeatService(ctrl)

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: gitlab.com/manytask/itmo-go/private/distbuild/pkg/api (interfaces: HeartbeatService)
// Source: gitlab.com/slon/shad-go/distbuild/pkg/api (interfaces: HeartbeatService)
// Package mock is a generated GoMock package.
package mock
@ -7,7 +7,7 @@ package mock
import (
context "context"
gomock "github.com/golang/mock/gomock"
api "gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
api "gitlab.com/slon/shad-go/distbuild/pkg/api"
reflect "reflect"
)

View file

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: gitlab.com/manytask/itmo-go/private/distbuild/pkg/api (interfaces: Service)
// Source: gitlab.com/slon/shad-go/distbuild/pkg/api (interfaces: Service)
// Package mock is a generated GoMock package.
package mock
@ -7,8 +7,8 @@ package mock
import (
context "context"
gomock "github.com/golang/mock/gomock"
api "gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
build "gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
api "gitlab.com/slon/shad-go/distbuild/pkg/api"
build "gitlab.com/slon/shad-go/distbuild/pkg/build"
reflect "reflect"
)

View file

@ -4,12 +4,11 @@ import (
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
var (
@ -34,18 +33,18 @@ func NewCache(root string) (*Cache, error) {
if err := os.RemoveAll(tmpDir); err != nil {
return nil, err
}
if err := os.MkdirAll(tmpDir, 0o777); err != nil {
if err := os.MkdirAll(tmpDir, 0777); err != nil {
return nil, err
}
cacheDir := filepath.Join(root, "c")
if err := os.MkdirAll(cacheDir, 0o777); err != nil {
if err := os.MkdirAll(cacheDir, 0777); err != nil {
return nil, err
}
for i := 0; i < 256; i++ {
d := hex.EncodeToString([]byte{uint8(i)})
if err := os.MkdirAll(filepath.Join(cacheDir, d), 0o777); err != nil {
if err := os.MkdirAll(filepath.Join(cacheDir, d), 0777); err != nil {
return nil, err
}
}
@ -110,13 +109,13 @@ func (c *Cache) writeUnlock(id build.ID) {
}
func (c *Cache) Range(artifactFn func(artifact build.ID) error) error {
shards, err := ioutil.ReadDir(c.cacheDir)
shards, err := os.ReadDir(c.cacheDir)
if err != nil {
return err
}
for _, shard := range shards {
dirs, err := ioutil.ReadDir(filepath.Join(c.cacheDir, shard.Name()))
dirs, err := os.ReadDir(filepath.Join(c.cacheDir, shard.Name()))
if err != nil {
return err
}
@ -151,7 +150,7 @@ func (c *Cache) Create(artifact build.ID) (path string, commit, abort func() err
}
path = filepath.Join(c.tmpDir, artifact.String())
if err = os.MkdirAll(path, 0o777); err != nil {
if err = os.MkdirAll(path, 0777); err != nil {
c.writeUnlock(artifact)
return
}

View file

@ -2,15 +2,14 @@ package artifact_test
import (
"errors"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/artifact"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
type testCache struct {
@ -23,7 +22,7 @@ func (c *testCache) cleanup() {
}
func newTestCache(t *testing.T) *testCache {
tmpDir, err := ioutil.TempDir("", "")
tmpDir, err := os.MkdirTemp("", "")
require.NoError(t, err)
cache, err := artifact.NewCache(tmpDir)

View file

@ -5,7 +5,7 @@ package artifact
import (
"context"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
// Download artifact from remote cache into local cache.

View file

@ -2,17 +2,17 @@ package artifact_test
import (
"context"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/artifact"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
func TestArtifactTransfer(t *testing.T) {
@ -23,7 +23,7 @@ func TestArtifactTransfer(t *testing.T) {
dir, commit, _, err := remoteCache.Create(id)
require.NoError(t, err)
require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "a.txt"), []byte("foobar"), 0o777))
require.NoError(t, os.WriteFile(filepath.Join(dir, "a.txt"), []byte("foobar"), 0777))
require.NoError(t, commit())
l := zaptest.NewLogger(t)
@ -42,7 +42,7 @@ func TestArtifactTransfer(t *testing.T) {
require.NoError(t, err)
defer unlock()
content, err := ioutil.ReadFile(filepath.Join(dir, "a.txt"))
content, err := os.ReadFile(filepath.Join(dir, "a.txt"))
require.NoError(t, err)
require.Equal(t, []byte("foobar"), content)

View file

@ -39,7 +39,7 @@ type Job struct {
// exec - выполняет произвольную команду
// cat - записывает строку в файл
//
// Все строки в описании команды могут содержать в себе на переменные. Перед выполнением
// Все строки в описании команды могут содержать в себе ссылки на контекстные переменные. Перед выполнением
// реальной команды, переменные заменяются на их реальные значения.
//
// {{.OutputDir}} - абсолютный путь до выходной директории джоба.

View file

@ -7,10 +7,11 @@ import (
"go.uber.org/zap"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
type Client struct{}
type Client struct {
}
func NewClient(
l *zap.Logger,

View file

@ -8,11 +8,12 @@ import (
"go.uber.org/zap"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/filecache"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/scheduler"
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
"gitlab.com/slon/shad-go/distbuild/pkg/scheduler"
)
type Coordinator struct{}
type Coordinator struct {
}
var defaultConfig = scheduler.Config{
CacheTimeout: time.Millisecond * 10,
@ -26,6 +27,8 @@ func NewCoordinator(
panic("implement me")
}
func (c *Coordinator) Stop() {}
func (c *Coordinator) ServeHTTP(w http.ResponseWriter, r *http.Request) {
panic("implement me")
}

View file

@ -7,10 +7,11 @@ import (
"go.uber.org/zap"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
type Client struct{}
type Client struct {
}
func NewClient(l *zap.Logger, endpoint string) *Client {
panic("implement me")

View file

@ -3,9 +3,9 @@ package filecache_test
import (
"bytes"
"context"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"sync"
"testing"
@ -14,8 +14,8 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/filecache"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
)
type env struct {
@ -52,7 +52,7 @@ func TestFileUpload(t *testing.T) {
content := bytes.Repeat([]byte("foobar"), 1024*1024)
tmpFilePath := filepath.Join(env.cache.tmpDir, "foo.txt")
require.NoError(t, ioutil.WriteFile(tmpFilePath, content, 0o666))
require.NoError(t, os.WriteFile(tmpFilePath, content, 0666))
ctx := context.Background()
@ -65,7 +65,7 @@ func TestFileUpload(t *testing.T) {
require.NoError(t, err)
defer unlock()
actualContent, err := ioutil.ReadFile(path)
actualContent, err := os.ReadFile(path)
require.NoError(t, err)
require.Equal(t, content, actualContent)
})
@ -123,7 +123,7 @@ func TestFileDownload(t *testing.T) {
require.NoError(t, err)
defer unlock()
content, err := ioutil.ReadFile(path)
content, err := os.ReadFile(path)
require.NoError(t, err)
require.Equal(t, []byte("foobar"), content)
}

View file

@ -6,8 +6,8 @@ import (
"os"
"path/filepath"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/artifact"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
var (

View file

@ -2,14 +2,13 @@ package filecache_test
import (
"errors"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/filecache"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
)
type testCache struct {
@ -18,7 +17,7 @@ type testCache struct {
}
func newCache(t *testing.T) *testCache {
tmpDir, err := ioutil.TempDir("", "filecache")
tmpDir, err := os.MkdirTemp("", "filecache")
require.NoError(t, err)
c, err := filecache.New(tmpDir)
@ -36,25 +35,25 @@ func (c *testCache) cleanup() {
func TestFileCache(t *testing.T) {
cache := newCache(t)
_, abort, err := cache.Write(build.ID{0o1})
_, abort, err := cache.Write(build.ID{01})
require.NoError(t, err)
require.NoError(t, abort())
_, _, err = cache.Get(build.ID{0o1})
_, _, err = cache.Get(build.ID{01})
require.Truef(t, errors.Is(err, filecache.ErrNotFound), "%v", err)
f, _, err := cache.Write(build.ID{0o2})
f, _, err := cache.Write(build.ID{02})
require.NoError(t, err)
_, err = f.Write([]byte("foo bar"))
require.NoError(t, err)
require.NoError(t, f.Close())
path, unlock, err := cache.Get(build.ID{0o2})
path, unlock, err := cache.Get(build.ID{02})
require.NoError(t, err)
defer unlock()
content, err := ioutil.ReadFile(path)
content, err := os.ReadFile(path)
require.NoError(t, err)
require.Equal(t, []byte("foo bar"), content)
}

View file

@ -8,8 +8,8 @@ import (
"go.uber.org/zap"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/api"
"gitlab.com/slon/shad-go/distbuild/pkg/build"
)
var TimeAfter = time.After
@ -25,7 +25,8 @@ type Config struct {
DepsTimeout time.Duration
}
type Scheduler struct{}
type Scheduler struct {
}
func NewScheduler(l *zap.Logger, config Config) *Scheduler {
panic("implement me")
@ -46,3 +47,7 @@ func (c *Scheduler) ScheduleJob(job *api.JobSpec) *PendingJob {
func (c *Scheduler) PickJob(ctx context.Context, workerID api.WorkerID) *PendingJob {
panic("implement me")
}
func (c *Scheduler) Stop() {
panic("implement me")
}

View file

@ -2,7 +2,6 @@ package tarstream_test
import (
"bytes"
"io/ioutil"
"os"
"path/filepath"
"testing"
@ -10,11 +9,11 @@ import (
"github.com/stretchr/testify/require"
"golang.org/x/sys/unix"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/tarstream"
"gitlab.com/slon/shad-go/distbuild/pkg/tarstream"
)
func TestTarStream(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "tarstream")
tmpDir, err := os.MkdirTemp("", "tarstream")
require.NoError(t, err)
t.Logf("running inside %s", tmpDir)
@ -22,15 +21,15 @@ func TestTarStream(t *testing.T) {
from := filepath.Join(tmpDir, "from")
to := filepath.Join(tmpDir, "to")
require.NoError(t, os.Mkdir(from, 0o777))
require.NoError(t, os.Mkdir(to, 0o777))
require.NoError(t, os.Mkdir(from, 0777))
require.NoError(t, os.Mkdir(to, 0777))
var buf bytes.Buffer
require.NoError(t, os.Mkdir(filepath.Join(from, "a"), 0o777))
require.NoError(t, os.MkdirAll(filepath.Join(from, "b", "c", "d"), 0o777))
require.NoError(t, ioutil.WriteFile(filepath.Join(from, "a", "x.bin"), []byte("xxx"), 0o777))
require.NoError(t, ioutil.WriteFile(filepath.Join(from, "b", "c", "y.txt"), []byte("yyy"), 0o666))
require.NoError(t, os.Mkdir(filepath.Join(from, "a"), 0777))
require.NoError(t, os.MkdirAll(filepath.Join(from, "b", "c", "d"), 0777))
require.NoError(t, os.WriteFile(filepath.Join(from, "a", "x.bin"), []byte("xxx"), 0777))
require.NoError(t, os.WriteFile(filepath.Join(from, "b", "c", "y.txt"), []byte("yyy"), 0666))
require.NoError(t, tarstream.Send(from, &buf))
@ -53,15 +52,15 @@ func TestTarStream(t *testing.T) {
require.Equal(t, mode.String(), st.Mode().String())
b, err := ioutil.ReadFile(path)
b, err := os.ReadFile(path)
require.NoError(t, err)
require.Equal(t, content, b)
}
checkFile(filepath.Join(to, "a", "x.bin"), []byte("xxx"), 0o755)
checkFile(filepath.Join(to, "b", "c", "y.txt"), []byte("yyy"), 0o644)
checkFile(filepath.Join(to, "a", "x.bin"), []byte("xxx"), 0755)
checkFile(filepath.Join(to, "b", "c", "y.txt"), []byte("yyy"), 0644)
}
func init() {
unix.Umask(0o022)
unix.Umask(0022)
}

View file

@ -8,12 +8,13 @@ import (
"go.uber.org/zap"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/api"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/artifact"
"gitlab.com/manytask/itmo-go/private/distbuild/pkg/filecache"
"gitlab.com/slon/shad-go/distbuild/pkg/api"
"gitlab.com/slon/shad-go/distbuild/pkg/artifact"
"gitlab.com/slon/shad-go/distbuild/pkg/filecache"
)
type Worker struct{}
type Worker struct {
}
func New(
workerID api.WorkerID,

View file

@ -7,7 +7,7 @@
✗ go test -v -run=^$ -bench=BenchmarkSprintf -memprofile=mem.out ./varfmt/...
goos: linux
goarch: amd64
pkg: gitlab.com/manytask/itmo-go/private/varfmt
pkg: gitlab.com/slon/shad-go/varfmt
cpu: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
BenchmarkSprintf
BenchmarkSprintf/small
@ -17,7 +17,7 @@ BenchmarkSprintf/small_string-8 13282659 84.48 ns/op 16 B/op
BenchmarkSprintf/big
BenchmarkSprintf/big-8 20089 62372 ns/op 16388 B/op 1 allocs/op
PASS
ok gitlab.com/manytask/itmo-go/private/varfmt 4.363s
ok gitlab.com/slon/shad-go/varfmt 4.363s
```
Сэмплы профайлера будут записаны в бинарный файл `mem.out`.
@ -53,7 +53,7 @@ Showing nodes accounting for 715.73MB, 99.37% of 720.23MB total
Dropped 24 nodes (cum <= 3.60MB)
flat flat% sum% cum cum%
715.73MB 99.37% 99.37% 716.73MB 99.51% fmt.Sprintf
0 0% 99.37% 716.73MB 99.51% gitlab.com/manytask/itmo-go/private/varfmt.BenchmarkSprintf.func1
0 0% 99.37% 716.73MB 99.51% gitlab.com/slon/shad-go/varfmt.BenchmarkSprintf.func1
0 0% 99.37% 716.73MB 99.51% testing.(*B).launch
0 0% 99.37% 716.73MB 99.51% testing.(*B).runN
(pprof)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

BIN
docs/edit-in-place.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View file

@ -63,8 +63,8 @@ import (
"flag"
"log"
"gitlab.com/manytask/itmo-go/private/gitfame/configs"
"gitlab.com/manytask/itmo-go/private/gitfame/internal"
"gitlab.com/slon/shad-go/gitfame/configs"
"gitlab.com/slon/shad-go/gitfame/internal"
"github.com/spf13/pflag"
@ -81,8 +81,8 @@ import (
"github.com/spf13/pflag"
"gitlab.com/manytask/itmo-go/private/gitfame/configs"
"gitlab.com/manytask/itmo-go/private/gitfame/internal"
"gitlab.com/slon/shad-go/gitfame/configs"
"gitlab.com/slon/shad-go/gitfame/internal"
)
```

View file

@ -48,7 +48,7 @@
Low-level programming. unsafe. Package binary. bytes.Buffer. cgo, syscall.
11. Архитектура GC. Write barrier. Stack growth. GC pause. GOGC. sync.Pool. Шедулер
горутин. GOMACPROCS. Утечка тредов.
горутин. GOMAXPROCS. Утечка тредов.
12. Go tooling. pprof. CPU and Memory profiling. Кросс-компиляция. GOOS, GOARCH. CGO_ENABLED=0.
Build tags. go modules. godoc. Code generation.

View file

@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gitlab.com/slon/shad-go/tools/testtool"
"go.uber.org/goleak"
)
@ -38,6 +39,23 @@ func TestCall_Simple(t *testing.T) {
require.Equal(t, 2, called)
}
func TestCall_NoBusyWait(t *testing.T) {
done := make(chan struct{})
defer close(done)
var call Call
for i := 0; i < 10; i++ {
go func() {
_, _ = call.Do(context.Background(), func(ctx context.Context) (interface{}, error) {
<-done
return nil, nil
})
}()
}
testtool.VerifyNoBusyGoroutines(t)
}
func TestCall_Dedup(t *testing.T) {
defer goleak.VerifyNone(t)

67
excelwriter/README.md Normal file
View file

@ -0,0 +1,67 @@
# excelwriter [reflect]
В этой задаче нужно обернуть библиотеку для работы с exel'ем в reflect, реализовав интерфейс для построчной записи go объектов в excel
```go
type Writer interface {
WriteRow(r any) error
}
```
r — это либо структура, либо map[smth]any, либо указатель на что-то из этого.
smth — это либо строка, либо тип реализующий [TextMarshaler](https://pkg.go.dev/encoding#TextMarshaler)
Как должны сериализовываться поля структур подробно написано в интерфейсе.
Всё, что не специфицировано в доке и не проверяется тестами можно делать как сочтёте разумным.
Также нужно реализовать конструктор
```go
func New(f *excelize.File) Writer {
panic("implement me")
}
```
принимающий на вход инициализированный excel клиент.
Можно считать, что excel файл изначально пустой у которого создана 1 страница. Все записи нужно делать в ней.
Пример использования
```go
type Movie struct {
Title string
Year int `xlsx:"release_year"`
}
func StoreMovies() {
f := excelize.NewFile()
_, _ = f.NewSheet("Sheet1")
w := excelwriter.New(f)
_ = w.WriteRow(&Movie{Title: "Blade Runner", Year: 1982})
_ = w.WriteRow(&Movie{Title: "Blade Runner 2049", Year: 2017})
_ = w.WriteRow(map[string]any{"title": "Into the wild", "release_year": 2007})
out, _ := os.Create("/tmp/movie.xlsx")
_, _ = f.WriteTo(out)
}
```
В результате будет создан excel документ со следующим содержимым
```
title release_year
Blade Runner 1982
Blade Runner 2049 2017
Into the wild 2007
```
В первой строке хранятся имена колонок, которые вычисляются из имён полей, тэгов и ключей map'ов.
Разные структуры могут превращаться в разные наборы колонок.
Для каждого уникального имени должна быть ровно одна колонка, их нужно "создавать" по мере возникновения.
Новые ключи каждого конкретного мапа добавляются в колонки в отсортированном порядке, чтобы при перезапусках на одних и тех же данных получались одинаковые excel'ки.
Помимо имён полей в xlsx тэгах для числовых полей нужно поддержать стили форматирования.
Например, в excel нет отдельного типа для дат. Дата — это 15-и значный double (excel тип Number) со стилем форматирования `d-mmm-yy`. Библиотека для работы с excel'ем определяет [наборы популярных стилей](https://pkg.go.dev/github.com/xuri/excelize/v2#File.NewStyle) в виде enum'а `15 d-mmm-yy`. Это число 15 и нужно поддержать в тэге `xslx:"date,numfmt:15"`.
## Вопросы со звёздочкой
1. Как бы вы поддержали в тэгах стили форматирования ячеек (excelize.Fill, excelize.Border ...)?
2. Как бы вы поддержали в тэгах кастомные стили форматирования числовых значений, те, что не входят в стандартный набор, например `0,"K"`?
3. Как мог бы выглядеть Reader, совместимый с Writer'ом, читающий строчки из excel в Go структуры и map'ы?

48
excelwriter/writer.go Normal file
View file

@ -0,0 +1,48 @@
//go:build !solution
package excelwriter
import (
"github.com/xuri/excelize/v2"
)
type Writer interface {
// WriteRow appends struct fields or map values to excel sheet.
//
// Integers and floats are encoded as excel type Number.
// Strings are encoded as excel type Text.
// Booleans are encoded as excel type Logical.
//
// Pointer values are encoded as the value pointed to. A nil pointer is skipped.
//
// Values implementing encoding.TextMarshaler interface are encoded as excel Text.
//
// Interface values are encoded as the value contained in the interface. A nil interface is skipped.
//
// Channels and functions are skipped.
//
// Structs, maps, slices and arrays are marshaled into json and encoded as excel Text.
//
// Encoding of each struct field can be customized by format string
// stored under the "xlsx" key in the field's tag.
//
// // Field appears in excel under column "my_field".
// Field int `xlsx:"my_field"`
//
// // Field appears in excel under column "my_field" formatted with predeclared style 15 ("d-mmm-yy").
// // Only applicable for integers and floats.
// Field int `xlsx:"my_field,numfmt:15"`
//
// // Field is ignored by this package
// Field int `xlsx:"-"`
//
// The first row is reserved for column names.
// For structs column name must be either lowercase field name or the name from "xlsx" tag if present.
// For maps column name is a map key.
// If map key implements encoding.TextMarshaler then column name is string(key.MarshalText()).
WriteRow(r any) error
}
func New(f *excelize.File) Writer {
panic("implement me")
}

268
excelwriter/writer_test.go Normal file
View file

@ -0,0 +1,268 @@
package excelwriter_test
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/require"
"github.com/xuri/excelize/v2"
"gitlab.com/slon/shad-go/excelwriter"
)
const Sheet = "Sheet1"
type MyInt int
type Basic struct {
I int `xlsx:"i"`
UI uint `xlsx:"ui"`
I16 int16 `xlsx:"i_16"`
UI16 uint16 `xlsx:"ui_16"`
I32 int32 `xlsx:"i_32"`
UI32 uint32 `xlsx:"ui_32"`
I64 int64 `xlsx:"i_64"`
UI64 uint64 `xlsx:"ui_64"`
Float float32 `xlsx:"float"`
Double float64 `xlsx:"double"`
Bool bool `xlsx:"bool"`
String string `xlsx:"string"`
MyInt int `xlsx:"my_int"`
}
type Inner struct {
Name string `xlsx:"name"`
}
type TextInt int
func (i TextInt) MarshalText() ([]byte, error) {
return []byte("__" + fmt.Sprint(i) + "__"), nil
}
type TextStruct struct {
V string
}
func (s TextStruct) MarshalText() (text []byte, err error) {
return []byte("__" + s.V + "__"), nil
}
func TestWriter_basic(t *testing.T) {
f := excelize.NewFile()
_, err := f.NewSheet(Sheet)
require.NoError(t, err)
w := excelwriter.New(f)
b := &Basic{
I: -1,
UI: 1,
I16: -16,
UI16: 16,
I32: -32,
UI32: 32,
I64: -64,
UI64: 64,
Float: -2.5,
Double: 5.5,
Bool: true,
String: "hello",
MyInt: 23,
}
require.NoError(t, w.WriteRow(b))
storeFile(t, f, "basic")
rows := readAll(t, f, true)
require.Equal(t, []string{"i", "ui", "i_16", "ui_16", "i_32", "ui_32", "i_64", "ui_64", "float", "double", "bool", "string", "my_int"}, rows[0])
require.Equal(t, []string{"-1", "1", "-16", "16", "-32", "32", "-64", "64", "-2.5", "5.5", "1", "hello", "23"}, rows[1])
}
func TestWriter_map(t *testing.T) {
f := excelize.NewFile()
_, err := f.NewSheet(Sheet)
require.NoError(t, err)
w := excelwriter.New(f)
require.NoError(t, w.WriteRow(map[string]any{
"id": 29,
"name": "hello",
"title": "yo",
}))
require.NoError(t, w.WriteRow(map[string]any{}))
require.NoError(t, w.WriteRow(map[TextStruct]any{
{"id"}: 18,
{"name"}: "tm",
}))
storeFile(t, f, "map")
rows := readAll(t, f, true)
require.Equal(t, []string{"id", "name", "title", "__id__", "__name__"}, rows[0])
require.Equal(t, []string{"29", "hello", "yo"}, rows[1])
require.Equal(t, []string{"", "", "", "18", "tm"}, rows[2])
}
type E struct {
ID string `xlsx:"id"`
NoTag string
Skipped int `xlsx:"-"`
private float32 `xlsx:"private"`
TextInt TextInt `xlsx:"text-int"`
TextStruct TextStruct `xlsx:"text-struct"`
Struct Inner `xlsx:"inner"`
StructPtr *Inner `xlsx:"inner-ptr"`
Slice []int `xlsx:"slice"`
Array [2]int `xlsx:"arr"`
Map map[string]string `xlsx:"map"`
TMMap map[TextStruct]string `xlsx:"tm-map"`
F func() `xlsx:"func"`
Ch chan int `xlsx:"chan"`
}
func TestWriter_elaborate(t *testing.T) {
f := excelize.NewFile()
_, err := f.NewSheet("Sheet1")
require.NoError(t, err)
w := excelwriter.New(f)
e := &E{
ID: "42",
NoTag: "no-tag",
Skipped: 29,
private: 2,
TextInt: 77,
TextStruct: TextStruct{V: "text-struct"},
Struct: Inner{Name: "inner"},
StructPtr: &Inner{Name: "inner-ptr"},
Slice: []int{1, 2, 3},
Array: [2]int{4, 5},
Map: map[string]string{"foo": "bar"},
TMMap: map[TextStruct]string{{"foo"}: "bar"},
F: func() { fmt.Println("hello") },
Ch: make(chan int, 10),
}
require.NoError(t, w.WriteRow(e))
storeFile(t, f, "elaborate")
rows := readAll(t, f, true)
require.Equal(t, []string{"id", "notag", "private", "text-int", "text-struct", "inner", "inner-ptr", "slice", "arr", "map", "tm-map"}, rows[0])
require.Equal(t, []string{"42", "no-tag", "2", "__77__", "__text-struct__", `{"Name":"inner"}`, `{"Name":"inner-ptr"}`, "[1,2,3]", "[4,5]", `{"foo":"bar"}`, `{"__foo__":"bar"}`}, rows[1])
}
func TestWriter_ptr(t *testing.T) {
f := excelize.NewFile()
_, err := f.NewSheet(Sheet)
require.NoError(t, err)
w := excelwriter.New(f)
require.NoError(t, w.WriteRow(struct{ Name string }{"foo"}))
require.NoError(t, w.WriteRow(&struct{ Name string }{"bar"}))
require.NoError(t, w.WriteRow(map[string]string{"name": "baz"}))
require.NoError(t, w.WriteRow(&map[string]string{"name": "qux"}))
storeFile(t, f, "ptr")
rows := readAll(t, f, true)
require.Equal(t, []string{"name"}, rows[0])
require.Equal(t, []string{"foo"}, rows[1])
require.Equal(t, []string{"bar"}, rows[2])
require.Equal(t, []string{"baz"}, rows[3])
require.Equal(t, []string{"qux"}, rows[4])
}
func TestWriter_unsupported(t *testing.T) {
f := excelize.NewFile()
_, err := f.NewSheet("Sheet1")
require.NoError(t, err)
w := excelwriter.New(f)
require.Error(t, w.WriteRow(2))
require.Error(t, w.WriteRow(nil))
var b *Basic
require.Error(t, w.WriteRow(b))
}
type S struct {
P float64 `xlsx:"percent,numfmt:9"`
D int `xlsx:"date,numfmt:15"`
D2 int `xlsx:",numfmt:15"`
T float64 `xlsx:"time,numfmt:22"`
Y int `xlsx:"jpy,numfmt:194"`
}
func TestWriter_style(t *testing.T) {
f := excelize.NewFile()
_, err := f.NewSheet("Sheet1")
require.NoError(t, err)
w := excelwriter.New(f)
s := &S{
P: 0.5,
D: 100,
D2: 100,
T: 100.5,
Y: 200,
}
require.NoError(t, w.WriteRow(s))
storeFile(t, f, "style")
rows := readAll(t, f, false)
require.Equal(t, []string{"percent", "date", "d2", "time", "jpy"}, rows[0])
require.Equal(t, []string{"50%", "9-Apr-00", "9-Apr-00", "4/9/00 12:00", "¥200.00"}, rows[1])
}
func readAll(t *testing.T, f *excelize.File, raw bool) [][]string {
t.Helper()
var out [][]string
rows, err := f.Rows(Sheet)
require.NoError(t, err)
var opts []excelize.Options
if raw {
opts = append(opts, excelize.Options{RawCellValue: true})
}
for i := 1; rows.Next(); i++ {
row, err := rows.Columns(opts...)
require.NoError(t, err)
out = append(out, row)
}
return out
}
func storeFile(t *testing.T, f *excelize.File, prefix string) {
t.Helper()
out, err := os.CreateTemp("/tmp", prefix+"-*.xlsx")
require.NoError(t, err)
_, err = f.WriteTo(out)
require.NoError(t, err)
t.Logf("stored file in %s", out.Name())
}

View file

@ -4,7 +4,6 @@ import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"os"
"path"
"strings"
@ -12,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/tools/testtool"
)
func TestMerge(t *testing.T) {
@ -33,6 +32,32 @@ func TestMerge(t *testing.T) {
1
1
2
`,
},
{
name: "with empty lines",
in: []string{`
0`, `
1
1
1`, `
0
2`},
out: `
0
0
1
1
1
2
`,
},
} {
@ -65,7 +90,7 @@ func TestSort(t *testing.T) {
testDir := path.Join("./testdata", "sort")
readTestCase := func(dir string) (in []string, out string) {
files, err := ioutil.ReadDir(dir)
files, err := os.ReadDir(dir)
require.NoError(t, err)
for _, f := range files {
@ -84,7 +109,7 @@ func TestSort(t *testing.T) {
testCaseDir := path.Join(testDir, d)
t.Run(d, func(t *testing.T) {
tmpDir, err := ioutil.TempDir("", fmt.Sprintf("sort%s-", d))
tmpDir, err := os.MkdirTemp("", fmt.Sprintf("sort%s-", d))
require.NoError(t, err)
defer func() { _ = os.RemoveAll(tmpDir) }()
@ -95,7 +120,7 @@ func TestSort(t *testing.T) {
w := bufio.NewWriter(&buf)
require.NoError(t, Sort(w, in...))
expected, err := ioutil.ReadFile(out)
expected, err := os.ReadFile(out)
require.NoError(t, err)
require.NoError(t, w.Flush())
@ -107,7 +132,7 @@ func TestSort(t *testing.T) {
func listDirs(t *testing.T, dir string) []string {
t.Helper()
files, err := ioutil.ReadDir(dir)
files, err := os.ReadDir(dir)
require.NoError(t, err)
var dirs []string
@ -134,11 +159,11 @@ func copyFiles(t *testing.T, in []string, dir string) []string {
func copyFile(t *testing.T, f, dir string) string {
t.Helper()
data, err := ioutil.ReadFile(f)
data, err := os.ReadFile(f)
require.NoError(t, err)
dst := path.Join(dir, path.Base(f))
err = ioutil.WriteFile(dst, data, 0o644)
err = os.WriteFile(dst, data, 0644)
require.NoError(t, err)
return dst

BIN
externalsort/testdata/.gitattributes vendored Normal file

Binary file not shown.

View file

@ -2,6 +2,61 @@
package main
func main() {
import (
"fmt"
"io"
"net/http"
"os"
"time"
)
type HTTPGetResult struct {
Success bool
Body string
Elapsed time.Duration
Size int
URL string
Error error
}
func (result HTTPGetResult) String() string {
if result.Success {
return fmt.Sprintf("%v\t%v\t%v", result.Elapsed, result.Size, result.URL)
} else {
return result.Error.Error()
}
}
func GetHTTPBody(url string, ch chan HTTPGetResult) {
startTime := time.Now()
resp, err := http.Get(url)
if err != nil {
ch <- HTTPGetResult{Success: false, Error: err}
return
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
ch <- HTTPGetResult{Success: false, Error: err}
return
}
ch <- HTTPGetResult{
Success: true,
Body: string(data),
Elapsed: time.Since(startTime),
Size: len(data),
URL: url,
}
}
func main() {
startTime := time.Now()
urls, ch := os.Args[1:], make(chan HTTPGetResult)
for _, url := range urls {
go GetHTTPBody(url, ch)
}
for i := 0; i < len(urls); i++ {
fmt.Println(<-ch)
}
fmt.Println(time.Since(startTime), "elapsed")
}

View file

@ -17,10 +17,10 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/tools/testtool"
)
const fetchallImportPath = "gitlab.com/manytask/itmo-go/private/fetchall"
const fetchallImportPath = "gitlab.com/slon/shad-go/fetchall"
var binCache testtool.BinCache

View file

@ -3,7 +3,6 @@ package fileleak_test
import (
"bytes"
"fmt"
"io/ioutil"
"net"
"os"
"syscall"
@ -11,8 +10,8 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/fileleak"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/fileleak"
"gitlab.com/slon/shad-go/tools/testtool"
)
type fakeT struct {
@ -75,7 +74,7 @@ func TestFileLeak_ReopenFile(t *testing.T) {
checkLeak(t, true, func() {
_ = f.Close()
ff, err := ioutil.TempFile("", "")
ff, err := os.CreateTemp("", "")
require.NoError(t, err)
f = ff
})
@ -129,6 +128,7 @@ func TestFileLeak_DupLeak(t *testing.T) {
var err error
fd, err = syscall.Dup(1)
require.NoError(t, err)
})
}

11
firegod/Dockerfile Normal file
View file

@ -0,0 +1,11 @@
FROM golang:1.22
RUN ["mkdir", "-p", "/build"]
WORKDIR /build
COPY . .
RUN ["go", "build", "-tags", "solution", "-o", "/firegod", "./firegod"]
ENTRYPOINT [ "/firegod", "-http=0.0.0.0:8080" ]

55
firegod/README.md Normal file
View file

@ -0,0 +1,55 @@
# firegod
В этой задаче вам нужно научиться пользоваться связкой prometheus+grafana для отладки собственного кода.
Вам дан код сервиса. Нужно добавить в него метрики, и потом используя графану с помощью графиков ответить на ряд вопросов.
В этой задаче нет автоматической проверки. Чтобы получить оценку, нужно закоммитить свои ответы вместе со скриншотами в репозиторий, и поменять значение константы в `Solved` в файле `main.go` на `true`.
## Окружение
В файле `docker-compose.yaml` описан тестовый стенд.
- `prometheus` - контейнер с прометеем, который собирает метрики и выполняет запросы над ними.
- `grafana` - контейнер с графаной, дающий удобный `Web UI` для работы с прометеем.
- `my_service` - 5 реплик вашего сервиса.
Чтобы запустит тестовый стенд, выполните команду `docker compose up --build`. Чтобы перезапустить стенд, остановите `docker compose` нажав `Ctrl+C` и перезапустите команду.
После запуска стенда, проверьте что:
- [targets](http://localhost:9090/targets) показывает правильный список процессов. Один прометей в состоянии `up` и 5 копий вашего сервиса в состоянии `down` с ошибкой `server returned HTTP status 404 Not Found`.
- [grafana](http://localhost:3000/explore) пускает вас в интерфейс с логином `admin` и паролем `grafana`, а на странице Explore видно какие-то метрики (например `up`).
## Сервис
В пакете `dontlook` находится код сервиса. В него смотреть *нельзя*.
Вам нужно дописать код сбора и экспорта метрик в файл `main.go`.
1. Сделайте так, чтобы метрики экспортировались по запросу `GET /metrics`.
2. Включите экспорт метрик go рантайма и процесса (если они уже не экспортируются по дефолту).
3. Добавьте middleware записывающий метрики из http хендлеров.
## Вопросы
1. Сколько процессов каких сервисов подключено к прометею? (пример)
**Ответ**: 1 прометей и 5 моих сервисов.
![](screenshots/up.png)
2. Какой процесс постоянно перезапускается?
3. В каком процесс есть утечка файловых дескрипторов?
4. В каком процессе есть утечка памяти?
5. В каком процессе утекают горутины?
6. Какой хендлер пятисотит больше всех?
7. Сколько всего запросов в секунду приходит в сервис?
8. Какой хендлер медленнее всех отвечает, если сравнивать по 90-ой перцентиле времени ответа?
9. Какой хендлер генерирует больше всего трафика?

View file

@ -0,0 +1,62 @@
services:
prometheus:
image: prom/prometheus
container_name: prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
ports:
- 9090:9090
restart: unless-stopped
volumes:
- ./prometheus:/etc/prometheus
grafana:
image: grafana/grafana
container_name: grafana
ports:
- 3000:3000
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=grafana
volumes:
- ./grafana:/etc/grafana/provisioning/datasources
my-service-0: &service
build:
context: ..
dockerfile: firegod/Dockerfile
restart: always
deploy:
resources:
limits:
cpus: '0.5'
memory: 100M
container_name: my-service-0
environment:
- REPLICA=0
my-service-1:
<<: *service
container_name: my-service-1
environment:
- REPLICA=1
my-service-2:
<<: *service
container_name: my-service-2
environment:
- REPLICA=2
my-service-3:
<<: *service
container_name: my-service-3
environment:
- REPLICA=3
my-service-4:
<<: *service
container_name: my-service-4
environment:
- REPLICA=4

View file

@ -0,0 +1,111 @@
package dontlook
import (
"bytes"
"fmt"
"io"
"net"
"net/http"
"os"
"strings"
"sync/atomic"
"time"
"github.com/go-chi/chi/v5"
)
func NewService(r chi.Router) {
replica := os.Getenv("REPLICA")
switch replica {
case "0":
go func() {
for {
go func() { select {} }()
time.Sleep(time.Millisecond * 100)
}
}()
case "2":
go func() {
var buf []string
for i := 0; true; i++ {
buf = append(buf, strings.Repeat("f", 1<<20))
_ = buf
time.Sleep(time.Millisecond * 100 * time.Duration(i))
}
}()
case "3":
go func() {
for {
_, _ = net.Dial("tcp", "localhost:8080")
time.Sleep(time.Millisecond * 10)
}
}()
case "4":
go func() {
time.Sleep(time.Second * 15)
os.Exit(1)
}()
}
runClient := func(getUrl func() string) {
for {
go func() {
rsp, err := http.Get(fmt.Sprintf("http://localhost:8080%s", getUrl()))
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
_, _ = io.ReadAll(rsp.Body)
_ = rsp.Body.Close()
}()
time.Sleep(time.Microsecond * 100)
}
}
r.Get("/apple", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
time.Sleep(time.Millisecond * 100)
_, _ = w.Write([]byte("OK"))
})
go runClient(func() string { return "/apple" })
r.Get("/banana", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
_, _ = w.Write(bytes.Repeat([]byte("f"), 1<<10))
if replica == "0" {
time.Sleep(time.Second)
}
})
go runClient(func() string { return "/banana" })
var k atomic.Int32
r.Get("/orange", func(w http.ResponseWriter, r *http.Request) {
if k.Add(1)%100 == 0 {
w.WriteHeader(500)
} else {
w.WriteHeader(200)
}
})
go runClient(func() string { return "/orange" })
r.Get("/kiwi/{id}", func(w http.ResponseWriter, r *http.Request) {
if replica == "3" {
w.WriteHeader(200)
} else {
w.WriteHeader(500)
}
})
var i atomic.Int32
go runClient(func() string { return fmt.Sprintf("/kiwi/%d", i.Add(1)) })
}

View file

@ -0,0 +1,9 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: true
access: proxy
editable: true

24
firegod/main.go Normal file
View file

@ -0,0 +1,24 @@
package main
import (
"flag"
"log"
"net/http"
"github.com/go-chi/chi/v5"
"gitlab.com/slon/shad-go/firegod/dontlook"
)
var Solved = false
var flagPort = flag.String("http", "", "")
var router = chi.NewRouter()
func main() {
flag.Parse()
dontlook.NewService(router)
log.Fatal(http.ListenAndServe(*flagPort, router))
}

11
firegod/main_test.go Normal file
View file

@ -0,0 +1,11 @@
package main
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestFiregod(t *testing.T) {
require.True(t, Solved)
}

View file

@ -0,0 +1,36 @@
global:
scrape_interval: 5s
evaluation_interval: 5s
scrape_timeout: 1s
alerting:
alertmanagers:
- static_configs:
- targets: []
scheme: http
timeout: 1s
api_version: v1
scrape_configs:
- job_name: prometheus
honor_timestamps: true
scrape_interval: 5s
scrape_timeout: 1s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- localhost:9090
- job_name: my-service
honor_timestamps: true
scrape_interval: 5s
scrape_timeout: 1s
metrics_path: /metrics
scheme: http
static_configs:
- targets:
- my-service-0:8080
- my-service-1:8080
- my-service-2:8080
- my-service-3:8080
- my-service-4:8080

BIN
firegod/screenshots/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

View file

@ -51,6 +51,6 @@ Forbidden
## Resources
* project layout: https://github.com/golang-standards/project-layout
* reverse proxy: https://en.wikipedia.org/wiki/Reverse_proxy
* reverse proxy: https://pkg.go.dev/net/http/httputil#ReverseProxy
* yaml: https://gopkg.in/yaml.v2
* regexp: https://golang.org/pkg/regexp/

View file

@ -3,7 +3,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
@ -15,10 +14,10 @@ import (
"github.com/go-resty/resty/v2"
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/tools/testtool"
)
const importPath = "gitlab.com/manytask/itmo-go/private/firewall/cmd/firewall"
const importPath = "gitlab.com/slon/shad-go/firewall/cmd/firewall"
var binCache testtool.BinCache
@ -36,7 +35,7 @@ func storeConfig(t *testing.T, conf string) (filename string, cleanup func()) {
t.Helper()
filename = path.Join(os.TempDir(), testtool.RandomName()+".yaml")
err := ioutil.WriteFile(filename, []byte(conf), 0o777)
err := os.WriteFile(filename, []byte(conf), 0777)
require.NoError(t, err)
cleanup = func() { _ = os.Remove(filename) }

View file

@ -79,6 +79,18 @@ Stack:
а `definition` состоит из известных слов и чисел, разделённых пробелами.
Слова можно переопределять.
При реализации механизма определений обратите внимание на юнит-тест
```go
{
description: "no redefinition",
input: []string{": foo 5 ;", ": bar foo ;", ": foo 6 ;", "bar foo"},
expected: []int{5, 6},
},
```
То есть семантика слова вычисляется непосредственно при определении и не меняется при переопределении "зависимостей".
### Проверка решения
Для запуска тестов нужно выполнить следующую команду:

View file

@ -2,17 +2,173 @@
package main
import (
"errors"
"strconv"
"strings"
)
type Evaluator struct {
stack []int
words map[string](func() error)
}
func (e *Evaluator) push(n int) {
e.stack = append(e.stack, n)
}
func (e *Evaluator) pop() (int, error) {
size := len(e.stack)
if size == 0 {
return 0, errors.New("nothing to pop")
}
n := e.stack[size-1]
e.stack = e.stack[:size-1]
return n, nil
}
func (e *Evaluator) popTwo() (int, int, error) {
if len(e.stack) < 2 {
return 0, 0, errors.New("not enough elements on stack")
}
second, _ := e.pop()
first, _ := e.pop()
return first, second, nil
}
// Used to initialzie arithemtic operations in words map
func (e *Evaluator) arithmeticOp(op func(int, int) int) func() error {
return func() error {
a, b, err := e.popTwo()
if err != nil {
return errors.New("not enough elements on stack")
}
e.push(op(a, b))
return nil
}
}
func (e *Evaluator) initBasicWords() {
e.words["+"] = e.arithmeticOp(func(a, b int) int { return a + b })
e.words["-"] = e.arithmeticOp(func(a, b int) int { return a - b })
e.words["*"] = e.arithmeticOp(func(a, b int) int { return a * b })
e.words["/"] = func() error {
a, b, err := e.popTwo()
if err != nil {
return errors.New("not enough elements on stack")
}
if b == 0 {
return errors.New("division by zero")
}
e.push(a / b)
return nil
}
e.words["dup"] = func() error {
size := len(e.stack)
if size == 0 {
return errors.New("not enough elements on stack")
}
e.stack = append(e.stack, e.stack[size-1])
return nil
}
e.words["over"] = func() error {
size := len(e.stack)
if size < 2 {
return errors.New("not enough elements on stack")
}
e.stack = append(e.stack, e.stack[size-2])
return nil
}
e.words["drop"] = func() error {
_, err := e.pop()
return err
}
e.words["swap"] = func() error {
size := len(e.stack)
if size < 2 {
return errors.New("not enough elements on stack")
}
e.stack[size-1], e.stack[size-2] = e.stack[size-2], e.stack[size-1]
return nil
}
}
func (e *Evaluator) getFunc(word string) (func() error, error) {
call, found := e.words[word]
if found {
return call, nil
}
num, err := strconv.Atoi(word)
if err != nil {
return nil, errors.New("word is not numerical or is not defined")
}
call = func() error {
e.push(num)
return nil
}
return call, nil
}
func (e *Evaluator) defineWord(word string, def string) error {
_, err := strconv.Atoi(word)
if err == nil {
return errors.New("word definition must not be numeric")
}
definitionWords := strings.Fields(def)
callChain := make([](func() error), len(definitionWords))
for i, w := range definitionWords {
call, err := e.getFunc(w)
if err != nil {
return err
}
callChain[i] = call
}
e.words[word] = func() error {
for _, call := range callChain {
err := call()
if err != nil {
return err
}
}
return nil
}
return nil
}
// NewEvaluator creates evaluator.
func NewEvaluator() *Evaluator {
return &Evaluator{}
eval := &Evaluator{make([]int, 0), make(map[string](func() error))}
eval.initBasicWords()
return eval
}
// Process evaluates sequence of words or definition.
//
// Returns resulting stack state and an error.
func (e *Evaluator) Process(row string) ([]int, error) {
return nil, nil
row = strings.ToLower(row)
if strings.HasPrefix(row, ":") && strings.HasSuffix(row, ";") {
row = strings.Trim(row, " :;")
wordAndDef := strings.SplitN(row, " ", 2)
if len(wordAndDef) < 2 {
return e.stack, errors.New("couldn't define a new word - incorrect syntax")
}
word, def := wordAndDef[0], wordAndDef[1]
err := e.defineWord(word, def)
if err != nil {
return e.stack, err
}
return e.stack, nil
}
for _, word := range strings.Fields(row) {
call, err := e.getFunc(word)
if err != nil {
return e.stack, err
}
err = call()
if err != nil {
return e.stack, err
}
}
return e.stack, nil
}

View file

@ -99,6 +99,11 @@ var testCases = []testCase{
input: []string{"2 4 * 3 /"},
expected: []int{2},
},
{
description: "add non-empty stack",
input: []string{"1 2 3 +"},
expected: []int{1, 5},
},
{
description: "dup",
input: []string{"1 dup"},

View file

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gitlab.com/manytask/itmo-go/private/genericsum"
"gitlab.com/slon/shad-go/genericsum"
)
func TestMin(t *testing.T) {
@ -184,11 +184,42 @@ func TestIsHermitianMatrix(t *testing.T) {
{7, 2, 12},
{9, 12, 19},
}))
assert.True(t, genericsum.IsHermitianMatrix([][]int8{
{-1, 7, 9},
{7, -2, 12},
{9, 12, -19},
}))
assert.True(t, genericsum.IsHermitianMatrix([][]uint16{
{1, 7, 9},
{7, 2, 12},
{9, 12, 19},
}))
assert.False(t, genericsum.IsHermitianMatrix([][]int{
{1, 12, 8},
{3, 4, 7},
{8, 7, 11},
}))
assert.False(t, genericsum.IsHermitianMatrix([][]int32{
{1, 112, 8},
{-3, 4, -7},
{8, 7, 11},
}))
assert.False(t, genericsum.IsHermitianMatrix([][]uint64{
{1, 12, 8},
{3, 4, 7},
{8, 7, 11},
}))
assert.True(t, genericsum.IsHermitianMatrix([][]float32{
{1.0, 7.0, 9.0},
{7.0, 2.0, 12.0},
{9.0, 12.0, 19.0},
}))
assert.False(t, genericsum.IsHermitianMatrix([][]float32{
{1.0, 12.0, 8.0},
{3.0, 4.0, 7.0},
{8.0, 7.0, 11.0},
}))
assert.True(t, genericsum.IsHermitianMatrix([][]complex64{
{1, 3 + 2i},
{3 - 2i, 4},

View file

@ -175,6 +175,11 @@ export PATH=$GOPATH/bin:$PATH
После этого `gitfame` будет доступен всюду.
В реализации вы можете использовать сторонние библиотеки, которые уже доступны в нашем [`go.mod`](../go.mod). Менять `go.mod` нельзя.
Весь репозиторий курса - это один go модуль с одним go.mod файлом в корне. Корню репозитория соответствует импорт путь `gitlab.com/slon/shad-go`. Если вы создадите пакет в директории `gitfame/internal/git`, то импортировать его нужно будет по пути `gitlab.com/slon/shad-go/gitfame/internal/git`.
### Code review comments
Прочитайте и исправьте [распространённые ошибки](../docs/gitfame_review_comments.md).

View file

@ -2,7 +2,6 @@ package integration
import (
"bytes"
"io/ioutil"
"os"
"os/exec"
"path"
@ -14,10 +13,10 @@ import (
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/tools/testtool"
)
const importPath = "gitlab.com/manytask/itmo-go/private/gitfame/cmd/gitfame"
const importPath = "gitlab.com/slon/shad-go/gitfame/cmd/gitfame"
var binCache testtool.BinCache
@ -43,7 +42,7 @@ func TestGitFame(t *testing.T) {
tc := ReadTestCase(t, filepath.Join(testsDir, dir))
t.Run(dir+"/"+tc.Name, func(t *testing.T) {
dir, err := ioutil.TempDir("", "gitfame-")
dir, err := os.MkdirTemp("", "gitfame-")
require.NoError(t, err)
defer func() { _ = os.RemoveAll(dir) }()
@ -75,7 +74,7 @@ func TestGitFame(t *testing.T) {
func ListTestDirs(t *testing.T, path string) []string {
t.Helper()
files, err := ioutil.ReadDir(path)
files, err := os.ReadDir(path)
require.NoError(t, err)
var names []string
@ -109,7 +108,7 @@ func ReadTestCase(t *testing.T, path string) *TestCase {
desc := ReadTestDescription(t, path)
expected, err := ioutil.ReadFile(filepath.Join(path, "expected.out"))
expected, err := os.ReadFile(filepath.Join(path, "expected.out"))
require.NoError(t, err)
return &TestCase{TestDescription: desc, Expected: expected}
@ -126,7 +125,7 @@ type TestDescription struct {
func ReadTestDescription(t *testing.T, path string) *TestDescription {
t.Helper()
data, err := ioutil.ReadFile(filepath.Join(path, "description.yaml"))
data, err := os.ReadFile(filepath.Join(path, "description.yaml"))
require.NoError(t, err)
var desc TestDescription

84
go.mod
View file

@ -1,66 +1,80 @@
module gitlab.com/manytask/itmo-go/private
module gitlab.com/slon/shad-go
go 1.18
go 1.22.0
require (
github.com/felixge/httpsnoop v1.0.3
github.com/go-chi/chi/v5 v5.0.8
github.com/go-git/go-git/v5 v5.11.0
github.com/go-redis/redis/v8 v8.11.5
github.com/go-resty/resty/v2 v2.1.0
github.com/gofrs/uuid v3.3.0+incompatible
github.com/golang/mock v1.4.1
github.com/google/go-cmp v0.5.9
github.com/golang/mock v1.6.0
github.com/google/btree v1.1.2
github.com/google/go-cmp v0.6.0
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.4
github.com/gorilla/websocket v1.4.2
github.com/jackc/pgx/v4 v4.6.0
github.com/jonboulle/clockwork v0.1.0
github.com/jackc/pgx/v5 v5.5.3
github.com/jonboulle/clockwork v0.4.0
github.com/spf13/cobra v1.1.3
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.2
go.uber.org/goleak v1.0.0
go.uber.org/zap v1.14.0
github.com/stretchr/testify v1.8.4
go.uber.org/goleak v1.3.0
go.uber.org/zap v1.26.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
golang.org/x/perf v0.0.0-20191209155426-36b577b0eb03
golang.org/x/sync v0.1.0
golang.org/x/sys v0.7.0
golang.org/x/tools v0.7.0
golang.org/x/sync v0.6.0
golang.org/x/sys v0.17.0
golang.org/x/tools v0.18.0
google.golang.org/grpc v1.54.0
google.golang.org/protobuf v1.30.0
google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/BurntSushi/toml v0.3.1 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudflare/circl v1.3.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.5.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.0.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8 // indirect
github.com/jackc/pgtype v1.3.0 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/lib/pq v1.10.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.8.0 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
go.uber.org/atomic v1.5.0 // indirect
go.uber.org/multierr v1.3.0 // indirect
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee // indirect
golang.org/x/crypto v0.5.0 // indirect
golang.org/x/lint v0.0.0-20190930215403-16217165b5de // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect
github.com/xuri/excelize/v2 v2.8.1 // indirect
github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/crypto v0.19.0 // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.0.1-2019.2.3 // indirect
)

301
go.sum
View file

@ -11,38 +11,50 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes=
github.com/aclements/go-moremath v0.0.0-20161014184102-0ff62e0875ff/go.mod h1:idZL3yvz4kzx1dsBOAC+oYv6L92P1oFEhUXUB1A/lwQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -50,14 +62,29 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
@ -68,18 +95,19 @@ github.com/go-resty/resty/v2 v2.1.0 h1:Z6IefCpUMfnvItVJaJXWv/pMiiD11So35QgwEELsl
github.com/go-resty/resty/v2 v2.1.0/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84=
github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -93,11 +121,13 @@ github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2
github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@ -137,78 +167,39 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.5.0 h1:oFSOilzIZkyg787M1fEmyMfOUUvwj0daqYMfaWwNL4o=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1 h1:Rdjp4NFjwHnEslx2b66FfCI2S0LhO4itac3hXz6WX9M=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8 h1:Q3tB+ExeflWUW7AFcAhXqk40s9mnNYLk1nOkKNZ5GnU=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.3.0 h1:l8JvKrby3RI7Kg3bYEeU9TA4vqC38QDpFCfcrC7KuN0=
github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik=
github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.6.0 h1:Fh0O9GdlG4gYpjpwOqjdEodJUQM9jzN3Hdv7PN0xmm0=
github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.3 h1:Ces6/M3wbDXYpM8JyyPD57ivTtJACFZJd885pdIaV2s=
github.com/jackc/pgx/v5 v5.5.3/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-sqlite3 v0.0.0-20161215041557-2d44decb4941/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@ -222,14 +213,20 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -239,31 +236,40 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@ -279,50 +285,54 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0=
github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ=
github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE=
github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4=
github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.14.0 h1:/pduUoebOeeJzTDFuoMgC6nRkiasr1sBCIEorly7m4o=
go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -338,14 +348,16 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -361,9 +373,15 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -375,8 +393,11 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -384,25 +405,46 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -414,26 +456,23 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.0.0-20170206182103-3d017632ea10/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
@ -466,16 +505,21 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -488,8 +532,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View file

@ -5,7 +5,7 @@ package gossip
import (
"time"
"gitlab.com/manytask/itmo-go/private/gossip/meshpb"
"gitlab.com/slon/shad-go/gossip/meshpb"
"google.golang.org/grpc"
)

View file

@ -8,8 +8,8 @@ import (
"time"
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/gossip"
"gitlab.com/manytask/itmo-go/private/gossip/meshpb"
"gitlab.com/slon/shad-go/gossip"
"gitlab.com/slon/shad-go/gossip/meshpb"
"go.uber.org/goleak"
"google.golang.org/grpc"
)

View file

@ -2,7 +2,7 @@
syntax = "proto3";
option go_package = "gitlab.com/manytask/itmo-go/private/gossip/meshpb";
option go_package = "gitlab.com/slon/shad-go/gossip/meshpb";
// PeerMeta is arbitrary message that is propagated with peer gossip.
message PeerMeta {

View file

@ -6,14 +6,14 @@
```
goos: linux
goarch: amd64
pkg: gitlab.com/manytask/itmo-go/private/gzep
pkg: gitlab.com/slon/shad-go/gzep
cpu: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz
BenchmarkEncodeSimple
BenchmarkEncodeSimple-8 7047 176628 ns/op 813872 B/op 17 allocs/op
BenchmarkEncode
BenchmarkEncode-8 41706 32616 ns/op 19 B/op 0 allocs/op
PASS
ok gitlab.com/manytask/itmo-go/private/gzep 3.625s
ok gitlab.com/slon/shad-go/gzep 3.625s
```
### С чего начать?

View file

@ -9,8 +9,8 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/manytask/itmo-go/private/gzep"
"gitlab.com/manytask/itmo-go/private/tools/testtool"
"gitlab.com/slon/shad-go/gzep"
"gitlab.com/slon/shad-go/tools/testtool"
)
func BenchmarkEncode(b *testing.B) {
@ -47,6 +47,7 @@ func TestEncode_RoundTrip(t *testing.T) {
require.NoError(t, err, tc.in)
require.Equal(t, tc.in, string(out))
})
}
}

View file

@ -2,6 +2,39 @@
package hogwarts
func GetCourseList(prereqs map[string][]string) []string {
return []string{}
import (
"log"
"slices"
)
func singleCourseList(
course string, prereqs map[string][]string, list []string, traversed []string,
) []string {
if slices.Contains(traversed, course) {
log.Panic("Recursive prereqs, aborting...")
}
traversed = append(traversed, course)
for _, prereqCourse := range prereqs[course] {
if !slices.Contains(list, prereqCourse) {
i := slices.Index(list, course)
if i == -1 {
list = append(list, prereqCourse)
} else {
list = slices.Insert(list, i, prereqCourse)
}
}
list = singleCourseList(prereqCourse, prereqs, list, traversed)
}
return list
}
func GetCourseList(prereqs map[string][]string) []string {
list := make([]string, 0)
for course := range prereqs {
if !slices.Contains(list, course) {
list = append(list, course)
}
list = singleCourseList(course, prereqs, list, []string{})
}
return list
}

View file

@ -2,6 +2,8 @@
package hotelbusiness
import "math"
type Guest struct {
CheckInDate int
CheckOutDate int
@ -13,5 +15,30 @@ type Load struct {
}
func ComputeLoad(guests []Guest) []Load {
return []Load{}
if len(guests) == 0 {
return []Load{}
}
minDate, maxDate := math.MaxInt, math.MinInt
loadsNoEmptyDays := make(map[int]int)
for _, guest := range guests {
if guest.CheckInDate < minDate {
minDate = guest.CheckInDate
}
if guest.CheckOutDate > maxDate {
maxDate = guest.CheckOutDate
}
for i := guest.CheckInDate; i < guest.CheckOutDate; i++ {
loadsNoEmptyDays[i]++
}
}
loads, prevGuestCount := make([]Load, 0), 0
for i := minDate; i <= maxDate; i++ {
guestCount := loadsNoEmptyDays[i]
if prevGuestCount == guestCount {
continue
}
loads = append(loads, Load{i, guestCount})
prevGuestCount = guestCount
}
return loads
}

View file

@ -5,8 +5,8 @@ import (
"github.com/stretchr/testify/assert"
"gitlab.com/manytask/itmo-go/private/illegal"
"gitlab.com/manytask/itmo-go/private/illegal/internal"
"gitlab.com/slon/shad-go/illegal"
"gitlab.com/slon/shad-go/illegal/internal"
)
func TestIllegalField(t *testing.T) {

View file

@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/assert"
"gitlab.com/manytask/itmo-go/private/illegal"
"gitlab.com/slon/shad-go/illegal"
)
func TestStringFromBytes(t *testing.T) {

View file

@ -4,7 +4,7 @@ import (
"fmt"
"log"
"gitlab.com/manytask/itmo-go/private/iprange"
"gitlab.com/slon/shad-go/iprange"
)
func ExampleParseList() {

View file

@ -4,7 +4,7 @@
В обычном `sync.Mutex` лок всего один. В один момент времени этот лок может находиться
у одной горутины. В нашем примитиве локов может быть сколько угодно. Каждый лок мы идентифицируем
ключём - строкой. Каждая горутина приходит к нам со списком ключей и хочет захватить сразу
ключом - строкой. Каждая горутина приходит к нам со списком ключей и хочет захватить сразу
все локи из этого списка. (Наша аналогия с `sync.Mutex` вовсе не значит, что нужно использовать
`sync.Mutex` в реализации. Лучше использовать каналы, чтобы проще было реализовать отмену.)

View file

@ -1,14 +1,19 @@
package keylock_test
import (
"fmt"
"math/rand"
"slices"
"sync"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"gitlab.com/manytask/itmo-go/private/keylock"
"gitlab.com/slon/shad-go/keylock"
"gitlab.com/slon/shad-go/tools/testtool"
)
func timeout(d time.Duration) <-chan struct{} {
@ -57,6 +62,21 @@ func TestKeyLock_Progress(t *testing.T) {
unlock1()
}
func TestKeyLock_NoBusyWait(t *testing.T) {
defer goleak.VerifyNone(t)
l := keylock.New()
_, unlock0 := l.LockKeys([]string{"a", "b"}, nil)
defer unlock0()
go func() {
_, unlock := l.LockKeys([]string{"b", "c"}, nil)
unlock()
}()
testtool.VerifyNoBusyGoroutines(t)
}
func TestKeyLock_DeadlockFree(t *testing.T) {
const N = 10000
@ -116,7 +136,7 @@ func TestKeyLock_SingleKeyStress(t *testing.T) {
go func() {
defer wg.Done()
for i := 0; i < N; i++ {
for j := 0; j < N; j++ {
cancelled, unlock := l.LockKeys([]string{"a"}, timeout(time.Millisecond))
if !cancelled {
unlock()
@ -127,3 +147,58 @@ func TestKeyLock_SingleKeyStress(t *testing.T) {
wg.Wait()
}
func TestKeyLock_MutualExclusionStress(t *testing.T) {
const (
N = 1000
G = 100
M = 15
K = 3
)
defer goleak.VerifyNone(t)
locked := map[string]bool{}
var mu sync.Mutex
l := keylock.New()
var wg sync.WaitGroup
wg.Add(G)
for i := 0; i < G; i++ {
go func() {
defer wg.Done()
for j := 0; j < N; j++ {
keys := []string{}
for k := 0; k < K; k++ {
keys = append(keys, fmt.Sprint(rand.Intn(N)))
}
slices.Sort(keys)
keys = slices.Compact(keys)
_, unlock := l.LockKeys(keys, nil)
mu.Lock()
for _, key := range keys {
assert.False(t, locked[key])
locked[key] = true
}
mu.Unlock()
time.Sleep(time.Millisecond)
mu.Lock()
for _, key := range keys {
locked[key] = false
}
mu.Unlock()
unlock()
}
}()
}
wg.Wait()
}

View file

@ -3,23 +3,9 @@ package keylock
import (
"math/rand"
"strconv"
"sync"
"testing"
)
func BenchmarkMutex_Baseline(b *testing.B) {
var mu sync.Mutex
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
mu.Lock()
_ = 0
mu.Unlock()
}
})
}
func BenchmarkKeyLock_SingleKey(b *testing.B) {
l := New()

View file

@ -3,7 +3,6 @@ package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"time"
@ -30,7 +29,7 @@ func fetch(url string, ch chan<- string) {
}
defer resp.Body.Close() // don't leak resources
nbytes, err := io.Copy(ioutil.Discard, resp.Body)
nbytes, err := io.Copy(io.Discard, resp.Body)
if err != nil {
ch <- fmt.Sprintf("while reading %s: %v", url, err)
return

View file

@ -11,8 +11,7 @@
* Ссылки
.link https://wiki.yandex.ru/shad/groups/2018/Semester4/GoLang/ Вики страница
.link https://gitlab.com/manytask/itmo-go/private Репозиторий
.link https://github.com/slon/shad-go Репозиторий
.link https://t.me/joinchat/BjrYSxdPJGtJdd1pae08Zg Чат курса в телеграме
[[https://p.go.manytask.org]] - эти слайды.
@ -21,7 +20,7 @@
- 12+ занятий
- Семинарские задания после каждой лекции. *Дедлайн*10*дней.*
- 4 _больших_ домашних задания. *Дедлайн*3*недели.*
- Критерий оценки: *TODO*.
- Критерий оценки: *В*LMS* (>N домашек и >X% за семинары).
* Hello world
@ -37,12 +36,25 @@ Systems
Language
* История
- 2009 go public announcement
- 2012 go 1.0
- 2008 github launch
- 2011 C++11
- 2011 pip initial release
- 2010 npm first release
- 2009 nodejs first release
- 2008 python3
- 2006 rust project started
- 2015 rust 1.0
* Современный мир
- Море библиотек. Большие деревья зависимостей.
: Нам нужен язык, который будет помогать контролировать сложность at large.
- Архитектура построена вокруг сервисов, которые общаются по сети.
: Скорее вам придётся писать stateless сервис. Statefull сервисы общаются с базой данных по сети.
: Скорее вам придётся писать stateless сервис. Stateful сервисы общаются с базой данных по сети.
- Многоядерные процессоры даже в телефонах.
* Скорость разработки
@ -149,6 +161,8 @@ Language
var s = ""
var s string = ""
.link https://go.dev/blog/declaration-syntax Почему тип пишется после названия переменной
* uniq
.play -edit uniq/uniq.go
@ -230,7 +244,7 @@ Pointers
var s string
p := &s
s2 = *p
s2 := *p
var p Point
p.X = 1

Some files were not shown because too many files have changed in this diff Show more