├── .github ├── FUNDING.yml └── workflows │ ├── binary-release.yml │ ├── dev-docker.yml │ ├── main-docker.yml │ └── readme-dockerhub.yml ├── .gitignore ├── .version ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── assets ├── Screenshot 2023-04-02 at 22-27-40 Resource Diary.png ├── Screenshot 2023-04-02 at 22-28-56 Resource Diary.png └── logo.png ├── build └── ci │ ├── build-deb.sh │ └── build.sh ├── cmd └── rediary │ └── main.go ├── configs ├── install.sh ├── rediary.service └── rediary@.service ├── docker-compose.yml ├── docs └── BCRYPT.md ├── go.mod ├── go.sum └── internal ├── auth ├── auth.go ├── cookie.go ├── hash.go ├── models-vars.go ├── session.go └── timeparse.go ├── check ├── error.go └── path.go ├── conf ├── getconfig.go └── map-struct.go ├── db ├── edit.go ├── quote_str.go └── sqlite.go ├── models └── models.go └── web ├── actions-tags.go ├── auth-conf.go ├── chart-counters.go ├── config.go ├── diary.go ├── exec-tpl.go ├── filter.go ├── heatmap.go ├── index.go ├── login.go ├── record.go ├── stat.go ├── templates ├── auth.html ├── config.html ├── diary.html ├── footer.html ├── header.html ├── index.html ├── login.html └── stat.html ├── var-const.go └── webgui.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ['https://boosty.to/aceberg/donate', 'https://aceberg.github.io/MyDocs/sponsor'] 4 | -------------------------------------------------------------------------------- /.github/workflows/binary-release.yml: -------------------------------------------------------------------------------- 1 | name: Binary-release 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [created] 7 | 8 | jobs: 9 | generate: 10 | name: Create release-artifacts 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout the repository 14 | uses: actions/checkout@master 15 | 16 | - name: Get version tag from env file 17 | uses: c-py/action-dotenv-to-setenv@v2 18 | with: 19 | env-file: .version 20 | 21 | - uses: actions/setup-go@v4 22 | with: 23 | go-version: 'stable' 24 | - run: go version 25 | 26 | - name: Build and archive 27 | run: build/ci/build.sh ${{ env.VERSION }} 28 | 29 | - name: Build .deb package 30 | run: build/ci/build-deb.sh ${{ env.VERSION }} 31 | 32 | - name: Upload the artifacts 33 | uses: skx/github-action-publish-binaries@master 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | with: 37 | args: 'rediary-*' -------------------------------------------------------------------------------- /.github/workflows/dev-docker.yml: -------------------------------------------------------------------------------- 1 | name: Dev-Docker 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | IMAGE_NAME: rediary 8 | TAGS: dev 9 | 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v3 18 | 19 | - name: Build and Push Docker Image to docker.io 20 | uses: mr-smithers-excellent/docker-build-push@v5 21 | with: 22 | image: ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }} 23 | tags: ${{ env.TAGS }} 24 | registry: docker.io 25 | username: ${{ secrets.DOCKER_USERNAME }} 26 | password: ${{ secrets.DOCKER_PASSWORD }} -------------------------------------------------------------------------------- /.github/workflows/main-docker.yml: -------------------------------------------------------------------------------- 1 | name: Main-Docker 2 | 3 | on: 4 | workflow_dispatch: 5 | # push: 6 | # branches: [ "main" ] 7 | # paths: 8 | # - 'Dockerfile' 9 | # - 'src/**' 10 | 11 | env: 12 | IMAGE_NAME: rediary 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout repository 20 | uses: actions/checkout@v3 21 | 22 | - name: Get version tag from env file 23 | uses: c-py/action-dotenv-to-setenv@v2 24 | with: 25 | env-file: .version 26 | 27 | - name: Set up QEMU 28 | uses: docker/setup-qemu-action@v2 29 | 30 | - name: Set up Docker Buildx 31 | id: buildx 32 | uses: docker/setup-buildx-action@v2 33 | 34 | - name: Login to GHCR 35 | uses: docker/login-action@v2 36 | with: 37 | registry: ghcr.io 38 | username: ${{ github.actor }} 39 | password: ${{ secrets.GITHUB_TOKEN }} 40 | 41 | - name: Login to Docker Hub 42 | uses: docker/login-action@v2 43 | with: 44 | username: ${{ secrets.DOCKER_USERNAME }} 45 | password: ${{ secrets.DOCKER_PASSWORD }} 46 | 47 | - name: Build and push 48 | uses: docker/build-push-action@v4 49 | with: 50 | context: . 51 | platforms: linux/amd64,linux/arm/v7,linux/arm64 52 | push: true 53 | tags: | 54 | ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest 55 | ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} 56 | ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:latest 57 | ghcr.io/${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }} -------------------------------------------------------------------------------- /.github/workflows/readme-dockerhub.yml: -------------------------------------------------------------------------------- 1 | name: Readme-DockerHub 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ "main" ] 7 | paths: 8 | - 'README.md' 9 | 10 | env: 11 | IMAGE_NAME: rediary 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v3 20 | 21 | - name: Sync README.md to DockerHub 22 | uses: ms-jpq/sync-dockerhub-readme@v1 23 | with: 24 | username: ${{ secrets.DOCKER_USERNAME }} 25 | password: ${{ secrets.DOCKER_PASSWORD }} 26 | repository: ${{ secrets.DOCKER_USERNAME }}/${{ env.IMAGE_NAME }} 27 | readme: "./README.md" 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore tmp 2 | tmp/ -------------------------------------------------------------------------------- /.version: -------------------------------------------------------------------------------- 1 | VERSION=1.0.1 -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # Change Log 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [1.0.1] - 2023-11-04 6 | ### Added 7 | - Adjustable mood max 8 | 9 | ## [1.0.0] - 2023-07-25 10 | ### Added 11 | - Session-Cookie Auth 12 | - Bianry and .deb release 13 | 14 | ## [0.2.0] - 2023-06-04 15 | ### Added 16 | - Notes in diary records 17 | 18 | ## [0.1.5] - 2023-06-04 19 | ### Added 20 | - Background color: light or dark 21 | - Clear table button warning 22 | - Clickable calendar 23 | 24 | ## [0.1.4] - 2023-04-02 25 | ### Added 26 | - Filter by tag 27 | 28 | ## [0.1.3] - 2023-03-27 29 | ### Added 30 | - Tag cloud 31 | 32 | ## [0.1.2] - 2023-03-21 33 | ### Added 34 | - JS HeatMap 35 | - Plus and Minus colors Config 36 | 37 | ## [0.1.1] - 2023-03-17 38 | ### Added 39 | - Github Actions 40 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS builder 2 | 3 | RUN apk add build-base 4 | COPY cmd /src/cmd 5 | COPY internal /src/internal 6 | COPY go.mod /src/ 7 | COPY go.sum /src/ 8 | RUN cd /src/cmd/rediary/ && CGO_ENABLED=0 go build -o /rediary . 9 | 10 | 11 | FROM scratch 12 | 13 | WORKDIR /data/rediary 14 | WORKDIR /app 15 | 16 | COPY --from=builder /rediary /app/ 17 | 18 | ENTRYPOINT ["./rediary"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Andrew Erlikh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | mod: 2 | rm go.mod || true && \ 3 | rm go.sum || true && \ 4 | go mod init github.com/aceberg/rediary && \ 5 | go mod tidy 6 | 7 | run: 8 | cd cmd/rediary/ && \ 9 | go run . 10 | 11 | fmt: 12 | go fmt ./... 13 | 14 | lint: 15 | golangci-lint run 16 | golint ./... 17 | 18 | check: fmt lint 19 | 20 | go-build: 21 | cd cmd/rediary/ && \ 22 | CGO_ENABLED=0 go build -o ../../tmp/rediary . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Main-Docker](https://github.com/aceberg/rediary/actions/workflows/main-docker.yml/badge.svg)](https://github.com/aceberg/rediary/actions/workflows/main-docker.yml) 2 | [![Go Report Card](https://goreportcard.com/badge/github.com/aceberg/rediary)](https://goreportcard.com/report/github.com/aceberg/rediary) 3 | [![Maintainability](https://api.codeclimate.com/v1/badges/e8f67994120fc7936aeb/maintainability)](https://codeclimate.com/github/aceberg/rediary/maintainability) 4 | ![Docker Image Size (latest semver)](https://img.shields.io/docker/image-size/aceberg/rediary) 5 | 6 |

7 | 8 | Resource Diary

9 | 10 | Emotional resource diary 11 | 12 | - [Quick start](https://github.com/aceberg/rediary#quick-start) 13 | - [Usage](https://github.com/aceberg/rediary#usage) 14 | - [Config](https://github.com/aceberg/rediary#config) 15 | - [Options](https://github.com/aceberg/rediary#options) 16 | - [Thanks](https://github.com/aceberg/rediary#thanks) 17 | 18 | 19 | ![Screenshot](https://raw.githubusercontent.com/aceberg/rediary/main/assets/Screenshot%202023-04-02%20at%2022-27-40%20Resource%20Diary.png) 20 | 21 | ## Quick start 22 | 23 | ```sh 24 | docker run --name rediary \ 25 | -e "TZ=Asia/Novosibirsk" \ 26 | -v ~/.dockerdata/rediary:/data/rediary \ 27 | -p 8847:8847 \ 28 | aceberg/rediary 29 | ``` 30 | Or use [docker-compose.yml](docker-compose.yml) 31 | 32 | ## Usage 33 | Add your own Tags and Actions on Config page. 34 | 35 | ## Config 36 | 37 | 38 | Configuration can be done through config file or environment variables 39 | 40 | | Variable | Description | Default | 41 | | -------- | ----------- | ------- | 42 | | DB | Path to Database | /data/rediary/sqlite.db | 43 | | HOST | Listen address | 0.0.0.0 | 44 | | PORT | Port for web GUI | 8847 | 45 | | THEME | Any theme name from https://bootswatch.com in lowcase | minty | 46 | | BGCOLOR | Background color: light or dark | light | 47 | | MOODMAX | Length of Minus and Plus scales | 5 | 48 | | TZ | Set your timezone for correct time | "" | 49 | | AUTH | Enable Session-Cookie authentication | false | 50 | | AUTH_USER | Username | "" | 51 | | AUTH_PASSWORD | Encrypted password (bcrypt). [How to encrypt password with bcrypt?](docs/BCRYPT.md) | "" | 52 | | AUTH_EXPIRE | Session expiration time. A number and suffix: **m, h, d** or **M**. | 7d | 53 | 54 | ## Options 55 | 56 | | Key | Description | Default | 57 | | -------- | ----------- | ------- | 58 | | -c | Path to config file | /data/rediary/config.yaml | 59 | 60 | ## Thanks 61 | - All go packages listed in [dependencies](https://github.com/aceberg/rediary/network/dependencies) 62 | - [Bootstrap](https://getbootstrap.com/) 63 | - Themes: [Free themes for Bootstrap](https://bootswatch.com) 64 | - Favicon and logo: [Flaticon](https://www.flaticon.com/icons/) -------------------------------------------------------------------------------- /assets/Screenshot 2023-04-02 at 22-27-40 Resource Diary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceberg/rediary/ae2eaf70a7712effd66eca52e9667239449d9e97/assets/Screenshot 2023-04-02 at 22-27-40 Resource Diary.png -------------------------------------------------------------------------------- /assets/Screenshot 2023-04-02 at 22-28-56 Resource Diary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceberg/rediary/ae2eaf70a7712effd66eca52e9667239449d9e97/assets/Screenshot 2023-04-02 at 22-28-56 Resource Diary.png -------------------------------------------------------------------------------- /assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aceberg/rediary/ae2eaf70a7712effd66eca52e9667239449d9e97/assets/logo.png -------------------------------------------------------------------------------- /build/ci/build-deb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PKGNAME=rediary 4 | PKGDIR=$PKGNAME-$1-0_all 5 | 6 | umask 0022 7 | 8 | mkdir -p $PKGDIR/usr/bin 9 | mkdir -p $PKGDIR/lib/systemd/system 10 | 11 | cp configs/$PKGNAME.service $PKGDIR/lib/systemd/system/ 12 | cp configs/$PKGNAME@.service $PKGDIR/lib/systemd/system/ 13 | 14 | cp $PKGNAME $PKGDIR/usr/bin/ 15 | 16 | mkdir -p $PKGDIR/DEBIAN 17 | 18 | echo "Package: $PKGNAME 19 | Version: $1 20 | Section: utils 21 | Priority: optional 22 | Architecture: all 23 | Maintainer: aceberg 24 | Description: Emotional resource diary 25 | " > $PKGDIR/DEBIAN/control 26 | 27 | echo " 28 | systemctl daemon-reload 29 | " > $PKGDIR/DEBIAN/postinst 30 | 31 | chmod 775 $PKGDIR/DEBIAN/postinst 32 | 33 | dpkg-deb --build --root-owner-group $PKGDIR 34 | 35 | rm -rf $PKGDIR -------------------------------------------------------------------------------- /build/ci/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PKGNAME=rediary 4 | PKGDIR=/opt/$PKGNAME 5 | 6 | cd cmd/$PKGNAME/ && CGO_ENABLED=0 go build -o ../../$PKGNAME . 7 | cd ../../ 8 | 9 | umask 0022 10 | 11 | mkdir -p $PKGDIR 12 | cp $PKGNAME $PKGDIR/ 13 | cp configs/$PKGNAME.service $PKGDIR/ 14 | cp configs/$PKGNAME@.service $PKGDIR/ 15 | cp configs/install.sh $PKGDIR/ 16 | 17 | cd /opt 18 | tar cvzf $PKGNAME-$1.tar.gz $PKGNAME 19 | cd - 20 | cp /opt/$PKGNAME-$1.tar.gz . -------------------------------------------------------------------------------- /cmd/rediary/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | _ "time/tzdata" 7 | 8 | "github.com/aceberg/rediary/internal/check" 9 | "github.com/aceberg/rediary/internal/models" 10 | "github.com/aceberg/rediary/internal/web" 11 | ) 12 | 13 | const confPath = "/data/rediary/config.yaml" 14 | 15 | func main() { 16 | var conf models.Conf 17 | 18 | confPtr := flag.String("c", confPath, "Path to config yaml file") 19 | flag.Parse() 20 | 21 | conf.ConfPath = *confPtr 22 | 23 | check.Path(conf.ConfPath) 24 | 25 | web.Gui(conf) 26 | } 27 | -------------------------------------------------------------------------------- /configs/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cp rediary /usr/bin/ 4 | cp rediary.service /lib/systemd/system/ 5 | cp rediary@.service /lib/systemd/system/ -------------------------------------------------------------------------------- /configs/rediary.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rediary 3 | Documentation=https://github.com/aceberg/rediary 4 | After=network-online.target 5 | Wants=network-online.target 6 | 7 | [Service] 8 | ExecStart=/usr/bin/rediary -c /etc/rediary/config.yaml 9 | Restart=on-failure 10 | 11 | [Install] 12 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /configs/rediary@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rediary 3 | Documentation=https://github.com/aceberg/rediary 4 | After=network-online.target 5 | Wants=network-online.target 6 | 7 | [Service] 8 | User=%i 9 | ExecStart=/usr/bin/rediary -c /home/%i/.config/rediary/config.yaml 10 | Restart=on-failure 11 | 12 | [Install] 13 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | rediary: 4 | image: aceberg/rediary 5 | restart: unless-stopped 6 | ports: 7 | - 8847:8847 8 | volumes: 9 | - ~/.dockerdata/rediary:/data/rediary # app data (set your own path instead of dockerdata) 10 | environment: 11 | TZ: Asia/Novosibirsk # required: needs your TZ for correct time 12 | DB: "/data/rediary/sqlite.db" # optional, default: /data/rediary/sqlite.db 13 | HOST: "0.0.0.0" # optional, default: 0.0.0.0 14 | PORT: "8847" # optional, default: 8847 15 | THEME: "minty" # optional, default: minty -------------------------------------------------------------------------------- /docs/BCRYPT.md: -------------------------------------------------------------------------------- 1 | # How to encrypt password with bcrypt? 2 | 3 | It is not safe to store password unencrypted, so this app uses `bcrypt` encryption. There are several ways to encrypt your password. 4 | 5 | ## 1. Set password through web GUI 6 | Then the app will encrypt it for you. 7 | 8 | ## 2. Encrypt password yourself 9 | On Linux encryption can be done with `htpasswd` command: 10 | ```sh 11 | htpasswd -nbBC 10 USER YourSecretPassword | sed 's/USER://' 12 | ``` 13 | 14 | ## 3. Encrypt password online 15 | There are online tools for `bcrypt` encryption. -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aceberg/rediary 2 | 3 | go 1.21.2 4 | 5 | require ( 6 | github.com/google/uuid v1.4.0 7 | github.com/jmoiron/sqlx v1.3.5 8 | github.com/spf13/viper v1.17.0 9 | golang.org/x/crypto v0.14.0 10 | modernc.org/sqlite v1.27.0 11 | ) 12 | 13 | require ( 14 | github.com/dustin/go-humanize v1.0.1 // indirect 15 | github.com/fsnotify/fsnotify v1.6.0 // indirect 16 | github.com/hashicorp/hcl v1.0.0 // indirect 17 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect 18 | github.com/magiconair/properties v1.8.7 // indirect 19 | github.com/mattn/go-isatty v0.0.17 // indirect 20 | github.com/mitchellh/mapstructure v1.5.0 // indirect 21 | github.com/pelletier/go-toml/v2 v2.1.0 // indirect 22 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect 23 | github.com/sagikazarmark/locafero v0.3.0 // indirect 24 | github.com/sagikazarmark/slog-shim v0.1.0 // indirect 25 | github.com/sourcegraph/conc v0.3.0 // indirect 26 | github.com/spf13/afero v1.10.0 // indirect 27 | github.com/spf13/cast v1.5.1 // indirect 28 | github.com/spf13/pflag v1.0.5 // indirect 29 | github.com/subosito/gotenv v1.6.0 // indirect 30 | go.uber.org/atomic v1.9.0 // indirect 31 | go.uber.org/multierr v1.9.0 // indirect 32 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect 33 | golang.org/x/mod v0.12.0 // indirect 34 | golang.org/x/sys v0.13.0 // indirect 35 | golang.org/x/text v0.13.0 // indirect 36 | golang.org/x/tools v0.13.0 // indirect 37 | gopkg.in/ini.v1 v1.67.0 // indirect 38 | gopkg.in/yaml.v3 v3.0.1 // indirect 39 | lukechampine.com/uint128 v1.2.0 // indirect 40 | modernc.org/cc/v3 v3.40.0 // indirect 41 | modernc.org/ccgo/v3 v3.16.13 // indirect 42 | modernc.org/libc v1.29.0 // indirect 43 | modernc.org/mathutil v1.6.0 // indirect 44 | modernc.org/memory v1.7.2 // indirect 45 | modernc.org/opt v0.1.3 // indirect 46 | modernc.org/strutil v1.1.3 // indirect 47 | modernc.org/token v1.0.1 // indirect 48 | ) 49 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 7 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 8 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 9 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 10 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 11 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 12 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 13 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 14 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 15 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 16 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 17 | cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= 18 | cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= 19 | cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= 20 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 21 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 22 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 23 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 24 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 25 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 26 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 27 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 28 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 29 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 30 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 31 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 32 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 33 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 34 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 35 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 36 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 37 | cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= 38 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 39 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 40 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 41 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 42 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 43 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 44 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 45 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 46 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 47 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 48 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 49 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 50 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 51 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 52 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 53 | github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 54 | github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 55 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 56 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 57 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 58 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 59 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 60 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 61 | github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= 62 | github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= 63 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 64 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 65 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 66 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 67 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 68 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 69 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 70 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 71 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 72 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 73 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 74 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 75 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 76 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 77 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 78 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 79 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 80 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 81 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 82 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 83 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 84 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 85 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 86 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 87 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 88 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 89 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 90 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 91 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 92 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 93 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 94 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 95 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 96 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 97 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 98 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 99 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 100 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 101 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 102 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 103 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 104 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 105 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 106 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 107 | github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 108 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 109 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 110 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 111 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 112 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 113 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 114 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 115 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 116 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 117 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 118 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 119 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 120 | github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 121 | github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= 122 | github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= 123 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 124 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 125 | github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= 126 | github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 127 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 128 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 129 | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 130 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 131 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 132 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 133 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 134 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 135 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 136 | github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= 137 | github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= 138 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 139 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 140 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 141 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 142 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 143 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 144 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 145 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 146 | github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= 147 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 148 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 149 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 150 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 151 | github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= 152 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 153 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 154 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 155 | github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= 156 | github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 157 | github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 158 | github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= 159 | github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 160 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 161 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 162 | github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= 163 | github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 164 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 165 | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 166 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 167 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 168 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 169 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 170 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= 171 | github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 172 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 173 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 174 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 175 | github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= 176 | github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= 177 | github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= 178 | github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= 179 | github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= 180 | github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= 181 | github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= 182 | github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= 183 | github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= 184 | github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= 185 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 186 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 187 | github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI= 188 | github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI= 189 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 190 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 191 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 192 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 193 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 194 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 195 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 196 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 197 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 198 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 199 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 200 | github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= 201 | github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 202 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 203 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 204 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 205 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 206 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 207 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 208 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 209 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 210 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 211 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 212 | go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= 213 | go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 214 | go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= 215 | go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= 216 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 217 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 218 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 219 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 220 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 221 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 222 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 223 | golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= 224 | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 225 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 226 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 227 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 228 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 229 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 230 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 231 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 232 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 233 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 234 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 235 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= 236 | golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 237 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 238 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 239 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 240 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 241 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 242 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 243 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 244 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 245 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 246 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 247 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 248 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 249 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 250 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 251 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 252 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 253 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 254 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 255 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 256 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 257 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 258 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 259 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 260 | golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= 261 | golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 262 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 263 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 264 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 265 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 266 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 267 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 268 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 269 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 270 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 271 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 272 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 273 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 274 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 275 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 276 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 277 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 278 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 279 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 280 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 281 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 282 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 283 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 284 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 285 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 286 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 287 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 288 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 289 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 290 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 291 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 292 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 293 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 294 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 295 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 296 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 297 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 298 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 299 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 300 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 301 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 302 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 303 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 304 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 305 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 306 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 307 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 308 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 309 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 310 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 311 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 312 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 313 | golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= 314 | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 315 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 316 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 317 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 318 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 319 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 320 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 321 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 322 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 323 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 324 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 325 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 326 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 327 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 328 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 329 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 330 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 331 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 332 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 333 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 334 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 335 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 336 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 337 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 338 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 339 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 340 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 341 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 342 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 343 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 344 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 345 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 346 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 347 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 348 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 349 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 350 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 351 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 352 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= 353 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 354 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 355 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 356 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 357 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 358 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 359 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 360 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 361 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 362 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 363 | golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= 364 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 365 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 366 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 367 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 368 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 369 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 370 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 371 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 372 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 373 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 374 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 375 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 376 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 377 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 378 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 379 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 380 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 381 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 382 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 383 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 384 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 385 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 386 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 387 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 388 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 389 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 390 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 391 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 392 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 393 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 394 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 395 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 396 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 397 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 398 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 399 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 400 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 401 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 402 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 403 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 404 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 405 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 406 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 407 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 408 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 409 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 410 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 411 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 412 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 413 | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 414 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 415 | golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= 416 | golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 417 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 418 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 419 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 420 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 421 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 422 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 423 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 424 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 425 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 426 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 427 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 428 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 429 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 430 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 431 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 432 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 433 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 434 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 435 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 436 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 437 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 438 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 439 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 440 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 441 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 442 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 443 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 444 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 445 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 446 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 447 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 448 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 449 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 450 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 451 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 452 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 453 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 454 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 455 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 456 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 457 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 458 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 459 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 460 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 461 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 462 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 463 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 464 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 465 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 466 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 467 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 468 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 469 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 470 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 471 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 472 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 473 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 474 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 475 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 476 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 477 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 478 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 479 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 480 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 481 | google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 482 | google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 483 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 484 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 485 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 486 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 487 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 488 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 489 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 490 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 491 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 492 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 493 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 494 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 495 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 496 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 497 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 498 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 499 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 500 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 501 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 502 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 503 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 504 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 505 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 506 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 507 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 508 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 509 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 510 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 511 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 512 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 513 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 514 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 515 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 516 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 517 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 518 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 519 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 520 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 521 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 522 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 523 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 524 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 525 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 526 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 527 | lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= 528 | lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= 529 | modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw= 530 | modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= 531 | modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= 532 | modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= 533 | modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= 534 | modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= 535 | modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= 536 | modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= 537 | modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= 538 | modernc.org/libc v1.29.0/go.mod h1:DaG/4Q3LRRdqpiLyP0C2m1B8ZMGkQ+cCgOIjEtQlYhQ= 539 | modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= 540 | modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= 541 | modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= 542 | modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= 543 | modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= 544 | modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= 545 | modernc.org/sqlite v1.27.0 h1:MpKAHoyYB7xqcwnUwkuD+npwEa0fojF0B5QRbN+auJ8= 546 | modernc.org/sqlite v1.27.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= 547 | modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= 548 | modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= 549 | modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= 550 | modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= 551 | modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= 552 | modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= 553 | modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= 554 | modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= 555 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 556 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 557 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 558 | -------------------------------------------------------------------------------- /internal/auth/auth.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | ) 7 | 8 | // Auth - main auth func 9 | func Auth(next http.HandlerFunc, conf *Conf) http.HandlerFunc { 10 | return func(w http.ResponseWriter, r *http.Request) { 11 | 12 | if !conf.Auth || conf.User == "" || conf.Password == "" { 13 | next.ServeHTTP(w, r) 14 | return 15 | } 16 | 17 | sessionToken := getTokenFromCookie(r) 18 | 19 | userSession, exists := allSessions[sessionToken] 20 | if !exists { 21 | http.Redirect(w, r, "/login/", 302) 22 | return 23 | } 24 | if userSession.Before(time.Now()) { 25 | delete(allSessions, sessionToken) 26 | http.Redirect(w, r, "/login/", 302) 27 | return 28 | } 29 | 30 | userSession = time.Now().Add(conf.Expire) 31 | allSessions[sessionToken] = userSession 32 | 33 | next.ServeHTTP(w, r) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /internal/auth/cookie.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func setTokenCookie(w http.ResponseWriter, token string) { 8 | 9 | cookie := http.Cookie{Name: cookieName, Value: token, Path: "/"} 10 | http.SetCookie(w, &cookie) 11 | } 12 | 13 | func getTokenFromCookie(r *http.Request) string { 14 | 15 | cookie, err := r.Cookie(cookieName) 16 | if err != nil { 17 | 18 | return "" 19 | } 20 | 21 | return cookie.Value 22 | } 23 | -------------------------------------------------------------------------------- /internal/auth/hash.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "log" 5 | 6 | "golang.org/x/crypto/bcrypt" 7 | ) 8 | 9 | // HashPassword - generate hash from password 10 | func HashPassword(pw string) string { 11 | 12 | hashed, err := bcrypt.GenerateFromPassword([]byte(pw), 10) 13 | if err != nil { 14 | log.Println("PASSWORD ERROR:", err) 15 | return "" 16 | } 17 | 18 | return string(hashed) 19 | } 20 | 21 | // MatchPasswords - check if password and hash matches 22 | func MatchPasswords(hash, pw string) bool { 23 | 24 | err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(pw)) 25 | 26 | return err == nil 27 | } 28 | -------------------------------------------------------------------------------- /internal/auth/models-vars.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Conf - auth config 8 | type Conf struct { 9 | Auth bool 10 | User string 11 | Password string 12 | ExpStr string 13 | Expire time.Duration 14 | } 15 | 16 | var allSessions = map[string]time.Time{} 17 | 18 | var cookieName = "rediary_session_token" 19 | -------------------------------------------------------------------------------- /internal/auth/session.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/google/uuid" 8 | ) 9 | 10 | // StartSession for new login 11 | func StartSession(w http.ResponseWriter, r *http.Request) { 12 | 13 | sessionToken := uuid.NewString() 14 | 15 | allSessions[sessionToken] = time.Now().Add(60 * time.Second) 16 | 17 | setTokenCookie(w, sessionToken) 18 | 19 | http.Redirect(w, r, "/", 302) 20 | 21 | } 22 | 23 | // LogOut - log out 24 | func LogOut(w http.ResponseWriter, r *http.Request) { 25 | 26 | sessionToken := getTokenFromCookie(r) 27 | 28 | delete(allSessions, sessionToken) 29 | 30 | setTokenCookie(w, "") 31 | 32 | http.Redirect(w, r, "/", 302) 33 | } 34 | -------------------------------------------------------------------------------- /internal/auth/timeparse.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "errors" 5 | "time" 6 | ) 7 | 8 | func timeParse(timeout string) (time.Duration, error) { 9 | var err error 10 | var t time.Duration 11 | 12 | length := len(timeout) 13 | if length > 1 { 14 | suffix := timeout[length-1] 15 | 16 | switch string(suffix) { 17 | case "h": 18 | t, err = time.ParseDuration(timeout) 19 | case "m": 20 | t, err = time.ParseDuration(timeout) 21 | case "d": //day 22 | t, err = time.ParseDuration(timeout[:length-1] + "h") 23 | t = 24 * t 24 | case "M": // month 25 | t, err = time.ParseDuration(timeout[:length-1] + "h") 26 | t = 730 * t 27 | default: 28 | err = errors.New("ERROR: TimeParse: wrong time format") 29 | } 30 | } else { 31 | err = errors.New("ERROR: TimeParse: wrong time format") 32 | } 33 | 34 | return t, err 35 | } 36 | 37 | // ToTime - converts string (example: 3d) to time.Duration 38 | func ToTime(s string) time.Duration { 39 | 40 | t, err := timeParse(s) 41 | if err != nil { 42 | t, _ = timeParse("7d") 43 | } 44 | 45 | return t 46 | } 47 | -------------------------------------------------------------------------------- /internal/check/error.go: -------------------------------------------------------------------------------- 1 | package check 2 | 3 | import ( 4 | "log" 5 | ) 6 | 7 | // IfError prints error, if it is not nil 8 | func IfError(err error) bool { 9 | if err == nil { 10 | return false 11 | } 12 | 13 | log.Println("ERROR:", err) 14 | return true 15 | } 16 | -------------------------------------------------------------------------------- /internal/check/path.go: -------------------------------------------------------------------------------- 1 | package check 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | // Path - create path if not exist 9 | func Path(path string) { 10 | 11 | _, err := os.Stat(path) 12 | 13 | if path != "" && err != nil { 14 | 15 | dir := filepath.Dir(path) 16 | 17 | err = os.MkdirAll(dir, os.ModePerm) 18 | IfError(err) 19 | 20 | _, err = os.Create(path) 21 | IfError(err) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /internal/conf/getconfig.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | 6 | "github.com/aceberg/rediary/internal/auth" 7 | "github.com/aceberg/rediary/internal/check" 8 | "github.com/aceberg/rediary/internal/models" 9 | ) 10 | 11 | // Get - read config from file or env 12 | func Get(path string) (models.Conf, auth.Conf) { 13 | var config models.Conf 14 | var actions []models.Action 15 | var tags []models.TagType 16 | 17 | var authConf auth.Conf 18 | 19 | viper.SetDefault("DB", "/data/rediary/sqlite.db") 20 | viper.SetDefault("HOST", "0.0.0.0") 21 | viper.SetDefault("PORT", "8847") 22 | viper.SetDefault("THEME", "minty") 23 | viper.SetDefault("BGCOLOR", "light") 24 | viper.SetDefault("COLORPLUS", "#ff3300") 25 | viper.SetDefault("COLORMINUS", "#00aeff") 26 | viper.SetDefault("MOODMAX", "5") 27 | viper.SetDefault("AUTH_USER", "") 28 | viper.SetDefault("AUTH_PASSWORD", "") 29 | viper.SetDefault("AUTH_EXPIRE", "7d") 30 | 31 | viper.SetConfigFile(path) 32 | viper.SetConfigType("yaml") 33 | err := viper.ReadInConfig() 34 | check.IfError(err) 35 | 36 | viper.AutomaticEnv() // Get ENVIRONMENT variables 37 | 38 | config.DB, _ = viper.Get("DB").(string) 39 | config.Host, _ = viper.Get("HOST").(string) 40 | config.Port, _ = viper.Get("PORT").(string) 41 | config.Theme, _ = viper.Get("THEME").(string) 42 | config.BgColor, _ = viper.Get("BGCOLOR").(string) 43 | config.ColorPlus, _ = viper.Get("COLORPLUS").(string) 44 | config.ColorMinus, _ = viper.Get("COLORMINUS").(string) 45 | config.MoodMax, _ = viper.Get("MOODMAX").(string) 46 | authConf.Auth = viper.GetBool("AUTH") 47 | authConf.User, _ = viper.Get("AUTH_USER").(string) 48 | authConf.Password, _ = viper.Get("AUTH_PASSWORD").(string) 49 | authConf.ExpStr, _ = viper.Get("AUTH_EXPIRE").(string) 50 | 51 | authConf.Expire = auth.ToTime(authConf.ExpStr) 52 | config.Auth = authConf.Auth 53 | 54 | err = viper.UnmarshalKey("actions", &actions) 55 | check.IfError(err) 56 | config.Actions = actions 57 | 58 | err = viper.UnmarshalKey("tags", &tags) 59 | check.IfError(err) 60 | config.TagMap = structToMap(tags) 61 | 62 | return config, authConf 63 | } 64 | 65 | // Write - write config to file 66 | func Write(config models.Conf, authConf auth.Conf) { 67 | 68 | viper.SetConfigFile(config.ConfPath) 69 | viper.SetConfigType("yaml") 70 | 71 | viper.Set("db", config.DB) 72 | viper.Set("host", config.Host) 73 | viper.Set("port", config.Port) 74 | viper.Set("theme", config.Theme) 75 | viper.Set("BGCOLOR", config.BgColor) 76 | viper.Set("colorminus", config.ColorMinus) 77 | viper.Set("colorplus", config.ColorPlus) 78 | viper.Set("moodmax", config.MoodMax) 79 | viper.Set("actions", config.Actions) 80 | viper.Set("tags", mapToStruct(config.TagMap)) 81 | 82 | viper.Set("auth", authConf.Auth) 83 | viper.Set("auth_user", authConf.User) 84 | viper.Set("auth_password", authConf.Password) 85 | viper.Set("auth_expire", authConf.ExpStr) 86 | 87 | err := viper.WriteConfig() 88 | check.IfError(err) 89 | } 90 | -------------------------------------------------------------------------------- /internal/conf/map-struct.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "github.com/aceberg/rediary/internal/models" 5 | ) 6 | 7 | func structToMap(tagStruct []models.TagType) map[string]string { 8 | 9 | tagMap := make(map[string]string) 10 | 11 | for _, tag := range tagStruct { 12 | 13 | tagMap[tag.Name] = tag.Color 14 | } 15 | 16 | return tagMap 17 | } 18 | 19 | func mapToStruct(tagMap map[string]string) []models.TagType { 20 | 21 | var tagStruct []models.TagType 22 | var tag models.TagType 23 | 24 | for key, value := range tagMap { 25 | tag.Name = key 26 | tag.Color = value 27 | tagStruct = append(tagStruct, tag) 28 | } 29 | 30 | return tagStruct 31 | } 32 | -------------------------------------------------------------------------------- /internal/db/edit.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/aceberg/rediary/internal/check" 7 | "github.com/aceberg/rediary/internal/models" 8 | ) 9 | 10 | // Create - create table if not exists 11 | func Create(path string) { 12 | 13 | sqlStatement := `CREATE TABLE IF NOT EXISTS records ( 14 | "ID" INTEGER PRIMARY KEY, 15 | "DATE" TEXT, 16 | "TAG" TEXT, 17 | "NAME" TEXT, 18 | "COLOR" TEXT, 19 | "NOTE" TEXT, 20 | "MINUS" TEXT, 21 | "PLUS" TEXT, 22 | "TOTAL" TEXT 23 | );` 24 | err := exec(path, sqlStatement) 25 | check.IfError(err) 26 | } 27 | 28 | // Insert - insert one rec into DB 29 | func Insert(path string, rec models.Record) { 30 | 31 | sqlStatement := `INSERT INTO records (DATE, TAG, NAME, COLOR, NOTE, MINUS, PLUS, TOTAL) 32 | VALUES ('%s','%s','%s','%s','%s','%d','%d','%d');` 33 | 34 | rec.Name = quoteStr(rec.Name) 35 | rec.Tag = quoteStr(rec.Tag) 36 | 37 | sqlStatement = fmt.Sprintf(sqlStatement, rec.Date, rec.Tag, rec.Name, rec.Color, rec.Note, rec.Minus, rec.Plus, rec.Total) 38 | 39 | err := exec(path, sqlStatement) 40 | check.IfError(err) 41 | } 42 | 43 | // Delete - delete one record 44 | func Delete(path string, id int) { 45 | 46 | sqlStatement := `DELETE FROM records WHERE ID='%d';` 47 | 48 | sqlStatement = fmt.Sprintf(sqlStatement, id) 49 | 50 | err := exec(path, sqlStatement) 51 | check.IfError(err) 52 | } 53 | 54 | // Clear - delete all records from table 55 | func Clear(path string) { 56 | sqlStatement := `DELETE FROM records;` 57 | err := exec(path, sqlStatement) 58 | check.IfError(err) 59 | } 60 | 61 | // Migrate - add column to table 62 | func Migrate(path string) { 63 | 64 | sqlStatement := `SELECT 1 FROM records WHERE NOTE;` 65 | err := exec(path, sqlStatement) 66 | 67 | if err != nil { 68 | 69 | sqlStatement = `ALTER TABLE records ADD NOTE TEXT DEFAULT "";` 70 | err = exec(path, sqlStatement) 71 | check.IfError(err) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /internal/db/quote_str.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import "strings" 4 | 5 | func quoteStr(str string) string { 6 | return strings.ReplaceAll(str, "'", "''") 7 | } 8 | -------------------------------------------------------------------------------- /internal/db/sqlite.go: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import ( 4 | "github.com/jmoiron/sqlx" 5 | 6 | // Import module for SQLite DB 7 | _ "modernc.org/sqlite" 8 | 9 | "github.com/aceberg/rediary/internal/check" 10 | "github.com/aceberg/rediary/internal/models" 11 | ) 12 | 13 | func connect(path string) *sqlx.DB { 14 | dbx, err := sqlx.Connect("sqlite", path) 15 | check.IfError(err) 16 | 17 | return dbx 18 | } 19 | 20 | func exec(path string, sqlStatement string) error { 21 | 22 | dbx := connect(path) 23 | 24 | _, err := dbx.Exec(sqlStatement) 25 | 26 | return err 27 | } 28 | 29 | // Select - select all from DB 30 | func Select(path string) []models.Record { 31 | var recs []models.Record 32 | 33 | dbx := connect(path) 34 | 35 | err := dbx.Select(&recs, "SELECT * FROM records ORDER BY DATE DESC") 36 | check.IfError(err) 37 | 38 | return recs 39 | } 40 | -------------------------------------------------------------------------------- /internal/models/models.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/aceberg/rediary/internal/auth" 5 | ) 6 | 7 | // Conf - web gui config 8 | type Conf struct { 9 | DB string 10 | Host string 11 | Port string 12 | Theme string 13 | BgColor string 14 | Icon string 15 | ConfPath string 16 | ColorPlus string 17 | ColorMinus string 18 | MoodMax string 19 | Actions []Action 20 | TagMap map[string]string 21 | Auth bool 22 | } 23 | 24 | // Action - one action 25 | type Action struct { 26 | Name string `mapstructure:"name"` 27 | Tag string `mapstructure:"tag"` 28 | } 29 | 30 | // TagType - one tag 31 | type TagType struct { 32 | Name string `mapstructure:"name"` 33 | Color string `mapstructure:"color"` 34 | } 35 | 36 | // ChartJS - data for charts 37 | type ChartJS struct { 38 | Tag []string 39 | Color []string 40 | Count []int 41 | } 42 | 43 | // HeatMap - data for heatmap 44 | type HeatMap struct { 45 | X string 46 | Y string 47 | D string 48 | V int 49 | } 50 | 51 | // Record - write to DB 52 | type Record struct { 53 | ID int `db:"ID"` 54 | Date string `db:"DATE"` 55 | Tag string `db:"TAG"` 56 | Name string `db:"NAME"` 57 | Color string `db:"COLOR"` 58 | Note string `db:"NOTE"` 59 | Minus int `db:"MINUS"` 60 | Plus int `db:"PLUS"` 61 | Total int `db:"TOTAL"` 62 | } 63 | 64 | // GuiData - web gui data 65 | type GuiData struct { 66 | Config Conf 67 | Records []Record 68 | OneRec Record 69 | Themes []string 70 | Chart ChartJS 71 | Heat []HeatMap 72 | Auth auth.Conf 73 | } 74 | -------------------------------------------------------------------------------- /internal/web/actions-tags.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | // "log" 5 | "net/http" 6 | "sort" 7 | "strings" 8 | 9 | "github.com/aceberg/rediary/internal/conf" 10 | "github.com/aceberg/rediary/internal/models" 11 | ) 12 | 13 | func addActionHandler(w http.ResponseWriter, r *http.Request) { 14 | var action models.Action 15 | 16 | action.Name = r.FormValue("name") 17 | action.Tag = r.FormValue("tag") 18 | 19 | if action.Name != "" && !strings.Contains(action.Name, ":") { 20 | AppConfig.Actions = append(AppConfig.Actions, action) 21 | 22 | sort.Slice(AppConfig.Actions, func(i, j int) bool { 23 | return AppConfig.Actions[i].Name < AppConfig.Actions[j].Name 24 | }) 25 | 26 | sort.Slice(AppConfig.Actions, func(i, j int) bool { 27 | return AppConfig.Actions[i].Tag < AppConfig.Actions[j].Tag 28 | }) 29 | 30 | conf.Write(AppConfig, authConf) 31 | } 32 | 33 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 34 | } 35 | 36 | func delActionHandler(w http.ResponseWriter, r *http.Request) { 37 | var newActions []models.Action 38 | 39 | tagname := r.FormValue("name") 40 | 41 | if tagname != "" { 42 | tnslice := strings.Split(tagname, ":") 43 | tag := tnslice[0] 44 | name := tnslice[1] 45 | 46 | for _, a := range AppConfig.Actions { 47 | if a.Tag != tag || a.Name != name { 48 | newActions = append(newActions, a) 49 | } 50 | } 51 | AppConfig.Actions = newActions 52 | 53 | conf.Write(AppConfig, authConf) 54 | } 55 | 56 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 57 | } 58 | 59 | func addTagHandler(w http.ResponseWriter, r *http.Request) { 60 | 61 | tag := r.FormValue("tag") 62 | color := r.FormValue("color") 63 | 64 | if tag != "" && !strings.Contains(tag, ":") { 65 | AppConfig.TagMap[tag] = color 66 | conf.Write(AppConfig, authConf) 67 | } 68 | 69 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 70 | } 71 | 72 | func delTagHandler(w http.ResponseWriter, r *http.Request) { 73 | 74 | tag := r.FormValue("tag") 75 | 76 | delete(AppConfig.TagMap, tag) 77 | 78 | conf.Write(AppConfig, authConf) 79 | 80 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 81 | } 82 | -------------------------------------------------------------------------------- /internal/web/auth-conf.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/aceberg/rediary/internal/auth" 8 | "github.com/aceberg/rediary/internal/conf" 9 | "github.com/aceberg/rediary/internal/models" 10 | ) 11 | 12 | func authConfHandler(w http.ResponseWriter, r *http.Request) { 13 | var guiData models.GuiData 14 | 15 | guiData.Config = AppConfig 16 | guiData.Auth.Auth = authConf.Auth 17 | guiData.Auth.User = authConf.User 18 | guiData.Auth.ExpStr = authConf.ExpStr 19 | 20 | execTemplate(w, "auth", guiData) 21 | } 22 | 23 | func saveAuthHandler(w http.ResponseWriter, r *http.Request) { 24 | 25 | authConf.User = r.FormValue("user") 26 | authConf.ExpStr = r.FormValue("expire") 27 | 28 | authStr := r.FormValue("auth") 29 | pw := r.FormValue("password") 30 | 31 | if authStr == "on" { 32 | authConf.Auth = true 33 | } else { 34 | authConf.Auth = false 35 | } 36 | AppConfig.Auth = authConf.Auth 37 | 38 | if pw != "" { 39 | authConf.Password = auth.HashPassword(pw) 40 | } 41 | 42 | authConf.Expire = auth.ToTime(authConf.ExpStr) 43 | 44 | if authConf.Auth && (authConf.User == "" || authConf.Password == "") { 45 | log.Println("WARNING: Auth won't work with empty login or password.") 46 | authConf.Auth = false 47 | } 48 | 49 | conf.Write(AppConfig, authConf) 50 | 51 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 52 | } 53 | -------------------------------------------------------------------------------- /internal/web/chart-counters.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "github.com/aceberg/rediary/internal/models" 5 | ) 6 | 7 | func countTotal(records []models.Record) models.Record { 8 | var total models.Record 9 | 10 | for _, rec := range records { 11 | total.Minus = total.Minus + rec.Minus 12 | total.Plus = total.Plus + rec.Plus 13 | total.Total = total.Total + rec.Total 14 | } 15 | 16 | return total 17 | } 18 | 19 | func countTags(records []models.Record) models.ChartJS { 20 | var chart models.ChartJS 21 | 22 | countTagMap := make(map[string]int) 23 | 24 | for _, rec := range records { 25 | _, exists := countTagMap[rec.Tag] 26 | if exists { 27 | countTagMap[rec.Tag] = countTagMap[rec.Tag] + rec.Total 28 | } else { 29 | countTagMap[rec.Tag] = rec.Total 30 | } 31 | } 32 | 33 | for tag, count := range countTagMap { 34 | chart.Tag = append(chart.Tag, tag) 35 | chart.Color = append(chart.Color, AppConfig.TagMap[tag]) 36 | chart.Count = append(chart.Count, count) 37 | } 38 | 39 | return chart 40 | } 41 | 42 | func countNames(records []models.Record) models.ChartJS { 43 | var chart models.ChartJS 44 | 45 | countTagMap := make(map[string]int) 46 | 47 | for _, rec := range records { 48 | _, exists := countTagMap[rec.Name] 49 | if exists { 50 | countTagMap[rec.Name] = countTagMap[rec.Name] + rec.Total 51 | } else { 52 | countTagMap[rec.Name] = rec.Total 53 | } 54 | } 55 | 56 | for tag, count := range countTagMap { 57 | chart.Tag = append(chart.Tag, tag) 58 | chart.Count = append(chart.Count, count) 59 | } 60 | 61 | return chart 62 | } 63 | 64 | func countCloud(records []models.Record) models.ChartJS { 65 | var chart models.ChartJS 66 | 67 | countTagMap := make(map[string]int) 68 | 69 | for _, rec := range records { 70 | _, exists := countTagMap[rec.Name] 71 | if exists { 72 | countTagMap[rec.Name] = countTagMap[rec.Name] + 1 73 | } else { 74 | countTagMap[rec.Name] = 1 75 | } 76 | } 77 | 78 | for tag, count := range countTagMap { 79 | chart.Tag = append(chart.Tag, tag) 80 | chart.Count = append(chart.Count, count*10) 81 | } 82 | 83 | return chart 84 | } 85 | -------------------------------------------------------------------------------- /internal/web/config.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/aceberg/rediary/internal/conf" 8 | "github.com/aceberg/rediary/internal/db" 9 | "github.com/aceberg/rediary/internal/models" 10 | ) 11 | 12 | func configHandler(w http.ResponseWriter, r *http.Request) { 13 | var guiData models.GuiData 14 | 15 | guiData.Config = AppConfig 16 | guiData.Themes = []string{"cerulean", "cosmo", "cyborg", "darkly", "flatly", "journal", "litera", "lumen", "lux", "materia", "minty", "morph", "pulse", "quartz", "sandstone", "simplex", "sketchy", "slate", "solar", "spacelab", "superhero", "united", "vapor", "yeti", "zephyr"} 17 | 18 | execTemplate(w, "config", guiData) 19 | } 20 | 21 | func saveConfigHandler(w http.ResponseWriter, r *http.Request) { 22 | 23 | AppConfig.DB = r.FormValue("db") 24 | AppConfig.Host = r.FormValue("host") 25 | AppConfig.Port = r.FormValue("port") 26 | AppConfig.Theme = r.FormValue("theme") 27 | AppConfig.BgColor = r.FormValue("bgcolor") 28 | AppConfig.MoodMax = r.FormValue("moodmax") 29 | 30 | conf.Write(AppConfig, authConf) 31 | 32 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 33 | } 34 | 35 | func saveColorsHandler(w http.ResponseWriter, r *http.Request) { 36 | 37 | AppConfig.ColorMinus = r.FormValue("minus") 38 | AppConfig.ColorPlus = r.FormValue("plus") 39 | 40 | conf.Write(AppConfig, authConf) 41 | 42 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 43 | } 44 | 45 | func clearHandler(w http.ResponseWriter, r *http.Request) { 46 | 47 | log.Println("INFO: deleting all records from DB") 48 | 49 | db.Clear(AppConfig.DB) 50 | 51 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 52 | } 53 | -------------------------------------------------------------------------------- /internal/web/diary.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/aceberg/rediary/internal/db" 7 | "github.com/aceberg/rediary/internal/models" 8 | ) 9 | 10 | func diaryHandler(w http.ResponseWriter, r *http.Request) { 11 | var guiData models.GuiData 12 | 13 | guiData.Config = AppConfig 14 | 15 | show := r.URL.Query().Get("show") 16 | tag := r.URL.Query().Get("tag") 17 | 18 | if tag == "" { 19 | if show == "" { 20 | AllRecords = db.Select(AppConfig.DB) 21 | show = "week" 22 | } 23 | guiData.Records = filterRecords(AllRecords, show) 24 | guiData.OneRec = countTotal(guiData.Records) 25 | guiData.Chart = countTags(guiData.Records) 26 | } else { 27 | AllRecords = filterByTag(AllRecords, tag) 28 | guiData.Records = filterRecords(AllRecords, "week") 29 | guiData.OneRec = countTotal(guiData.Records) 30 | guiData.Chart = countNames(guiData.Records) 31 | } 32 | 33 | execTemplate(w, "diary", guiData) 34 | } 35 | 36 | func diaryShowHandler(w http.ResponseWriter, r *http.Request) { 37 | var guiData models.GuiData 38 | 39 | guiData.Config = AppConfig 40 | 41 | from := r.URL.Query().Get("from") 42 | to := r.URL.Query().Get("to") 43 | 44 | guiData.Records = fromDateToDate(AllRecords, from, to) 45 | 46 | guiData.OneRec = countTotal(guiData.Records) 47 | guiData.Chart = countTags(guiData.Records) 48 | 49 | execTemplate(w, "diary", guiData) 50 | } 51 | -------------------------------------------------------------------------------- /internal/web/exec-tpl.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "html/template" 5 | "net/http" 6 | 7 | "github.com/aceberg/rediary/internal/check" 8 | "github.com/aceberg/rediary/internal/models" 9 | ) 10 | 11 | func execTemplate(w http.ResponseWriter, tpl string, guiData models.GuiData) { 12 | // tmpl, err := template.ParseFiles(TemplPath+tpl+".html", TemplPath+"header.html", TemplPath+"footer.html") 13 | tmpl, err := template.ParseFS(TemplHTML, TemplPath+tpl+".html", TemplPath+"header.html", TemplPath+"footer.html") 14 | check.IfError(err) 15 | err = tmpl.ExecuteTemplate(w, "header", guiData) 16 | check.IfError(err) 17 | err = tmpl.ExecuteTemplate(w, tpl, guiData) 18 | check.IfError(err) 19 | } 20 | -------------------------------------------------------------------------------- /internal/web/filter.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/aceberg/rediary/internal/models" 7 | ) 8 | 9 | func filterRecords(records []models.Record, show string) []models.Record { 10 | var filtered []models.Record 11 | 12 | currentTime := time.Now() 13 | max := currentTime.Format("2006-01-02") 14 | 15 | switch show { 16 | case "week": 17 | min := currentTime.AddDate(0, 0, -7).Format("2006-01-02") 18 | filtered = fromDateToDate(records, min, max) 19 | case "month": 20 | min := currentTime.AddDate(0, -1, 0).Format("2006-01-02") 21 | filtered = fromDateToDate(records, min, max) 22 | default: 23 | filtered = records 24 | } 25 | 26 | return filtered 27 | } 28 | 29 | func fromDateToDate(records []models.Record, min, max string) []models.Record { 30 | var filtered []models.Record 31 | 32 | if max == "" { 33 | currentTime := time.Now() 34 | max = currentTime.Format("2006-01-02") 35 | } 36 | 37 | for _, rec := range records { 38 | if rec.Date >= min && rec.Date <= max { 39 | filtered = append(filtered, rec) 40 | } 41 | } 42 | 43 | return filtered 44 | } 45 | 46 | func filterByTag(records []models.Record, tag string) []models.Record { 47 | var filtered []models.Record 48 | 49 | for _, rec := range records { 50 | if rec.Tag == tag { 51 | filtered = append(filtered, rec) 52 | } 53 | } 54 | 55 | return filtered 56 | } 57 | -------------------------------------------------------------------------------- /internal/web/heatmap.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "strconv" 5 | "time" 6 | 7 | "github.com/aceberg/rediary/internal/models" 8 | ) 9 | 10 | func generateHeatmap(records []models.Record) []models.HeatMap { 11 | var heatMap []models.HeatMap 12 | var heat models.HeatMap 13 | totalByDay := make(map[string]int) 14 | 15 | max := time.Now() 16 | min := max.AddDate(0, 0, -35) 17 | 18 | monthRecords := fromDateToDate(records, min.Format("2006-01-02"), max.Format("2006-01-02")) 19 | 20 | for _, rec := range monthRecords { 21 | val, exists := totalByDay[rec.Date] 22 | if exists { 23 | totalByDay[rec.Date] = val + rec.Total 24 | } else { 25 | totalByDay[rec.Date] = rec.Total 26 | } 27 | } 28 | 29 | i := 4 30 | for d := max; !d.Before(min); d = d.AddDate(0, 0, -1) { 31 | heat.D = d.Format("2006-01-02") 32 | val, exists := totalByDay[heat.D] 33 | if exists { 34 | heat.V = val 35 | } else { 36 | heat.V = 0 37 | } 38 | heat.X = d.Weekday().String()[0:2] 39 | heat.Y = strconv.Itoa(i) 40 | 41 | heatMap = append(heatMap, heat) 42 | 43 | if heat.X == "Mo" { 44 | i-- 45 | } 46 | if i < 0 { 47 | break 48 | } 49 | } 50 | 51 | return heatMap 52 | } 53 | -------------------------------------------------------------------------------- /internal/web/index.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/aceberg/rediary/internal/db" 8 | "github.com/aceberg/rediary/internal/models" 9 | ) 10 | 11 | func indexHandler(w http.ResponseWriter, r *http.Request) { 12 | var guiData models.GuiData 13 | 14 | guiData.Config = AppConfig 15 | 16 | AllRecords = db.Select(AppConfig.DB) 17 | guiData.Heat = generateHeatmap(AllRecords) 18 | 19 | today := time.Now().Format("2006-01-02") 20 | monthAgo := time.Now().AddDate(0, -1, 0) 21 | 22 | monthRecords := fromDateToDate(AllRecords, monthAgo.Format("2006-01-02"), today) 23 | guiData.Chart = countCloud(monthRecords) 24 | 25 | guiData.Records = fromDateToDate(AllRecords, today, today) 26 | guiData.OneRec = countTotal(guiData.Records) 27 | guiData.OneRec.Date = today 28 | 29 | execTemplate(w, "index", guiData) 30 | } 31 | -------------------------------------------------------------------------------- /internal/web/login.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/aceberg/rediary/internal/auth" 8 | "github.com/aceberg/rediary/internal/models" 9 | ) 10 | 11 | func loginHandler(w http.ResponseWriter, r *http.Request) { 12 | var guiData models.GuiData 13 | guiData.Config = AppConfig 14 | 15 | username := r.FormValue("username") 16 | password := r.FormValue("password") 17 | logout := r.FormValue("logout") 18 | 19 | if username == authConf.User && auth.MatchPasswords(authConf.Password, password) { 20 | 21 | log.Println("INFO: user '"+username+"' logged in. Session expire time", authConf.Expire) 22 | 23 | auth.StartSession(w, r) 24 | } 25 | if logout == "yes" { 26 | 27 | auth.LogOut(w, r) 28 | } 29 | 30 | execTemplate(w, "login", guiData) 31 | } 32 | -------------------------------------------------------------------------------- /internal/web/record.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | "strconv" 7 | "strings" 8 | "time" 9 | 10 | "github.com/aceberg/rediary/internal/check" 11 | "github.com/aceberg/rediary/internal/db" 12 | "github.com/aceberg/rediary/internal/models" 13 | ) 14 | 15 | func addRecordHandler(w http.ResponseWriter, r *http.Request) { 16 | var rec models.Record 17 | 18 | date := r.FormValue("date") 19 | name := r.FormValue("name") 20 | minus := r.FormValue("minus") 21 | plus := r.FormValue("plus") 22 | note := r.FormValue("note") 23 | 24 | if name != "" { 25 | n := strings.Split(name, ":") 26 | 27 | rec.Tag = n[0] 28 | rec.Name = n[1] 29 | rec.Color = AppConfig.TagMap[rec.Tag] 30 | 31 | rec.Minus, _ = strconv.Atoi(minus) 32 | rec.Plus, _ = strconv.Atoi(plus) 33 | rec.Total = rec.Plus - rec.Minus 34 | 35 | rec.Note = note 36 | 37 | if date == "" { 38 | currentTime := time.Now() 39 | rec.Date = currentTime.Format("2006-01-02") 40 | } else { 41 | rec.Date = date 42 | } 43 | 44 | log.Println("INFO: new record", rec) 45 | 46 | db.Insert(AppConfig.DB, rec) 47 | } 48 | 49 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 50 | } 51 | 52 | func delRecordHandler(w http.ResponseWriter, r *http.Request) { 53 | 54 | idStr := r.URL.Query().Get("id") 55 | 56 | id, err := strconv.Atoi(idStr) 57 | check.IfError(err) 58 | 59 | log.Println("INFO: deleting record with ID =", id) 60 | 61 | db.Delete(AppConfig.DB, id) 62 | 63 | http.Redirect(w, r, r.Header.Get("Referer"), 302) 64 | } 65 | -------------------------------------------------------------------------------- /internal/web/stat.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/aceberg/rediary/internal/db" 7 | "github.com/aceberg/rediary/internal/models" 8 | ) 9 | 10 | func statHandler(w http.ResponseWriter, r *http.Request) { 11 | var guiData models.GuiData 12 | 13 | guiData.Config = AppConfig 14 | AllRecords = db.Select(AppConfig.DB) 15 | 16 | execTemplate(w, "stat", guiData) 17 | } 18 | -------------------------------------------------------------------------------- /internal/web/templates/auth.html: -------------------------------------------------------------------------------- 1 | {{ define "auth" }} 2 | 3 | 4 |
5 |
6 |
7 | 8 | 9 | 10 | 11 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
Enable 12 |
13 | {{ if .Auth.Auth }} 14 | 15 | {{ else }} 16 | 17 | {{ end }} 18 |
19 |
Expire after
Login
New password
39 |
40 |
41 | 47 |
48 |
49 |
50 | 51 | 52 | {{ template "footer" }} 53 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/config.html: -------------------------------------------------------------------------------- 1 | {{ define "config" }} 2 | 3 | 4 |
5 |
6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
DB Path
Host
Port
Theme
Color mode
Mood Max
48 |
49 |
50 |
51 |
52 |
53 | 54 |
55 |
56 |
57 | 60 |
61 |
62 |
63 | Colors 64 |
65 | 66 | 67 | 70 | 71 | 74 | 75 | 76 | 79 | 80 | 83 | 84 |
68 | 69 | Minus 72 | 73 |
77 | 78 | Plus 81 | 82 |
85 | 86 |
87 |
88 |
89 |
90 |
91 | Tags 92 |
93 | 94 | Color picker 95 | 96 | 97 |
98 |
99 |
100 | 105 | 106 |
107 |
108 |
109 | Actions 110 |
111 | 116 | 117 | 118 |
119 |
120 |
121 | 126 | 127 |
128 |
129 |
130 |
131 | 132 | 133 | {{ template "footer" }} 134 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/diary.html: -------------------------------------------------------------------------------- 1 | {{ define "diary"}} 2 | 3 |
4 |
5 | 6 |
7 |
8 |
9 |   10 |   11 |
12 |
13 |
14 | From 15 | 16 | To 17 | 18 | 19 |
20 |
21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {{ range .Records }} 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 45 | 46 | {{ end }} 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | 62 | 63 |
DateTagNameMinusPlusTotal
{{ .Date }}{{ .Tag }}{{ .Name }}-{{ .Minus }}+{{ .Plus }}{{ .Total }} 43 | 44 |
Summary-{{ .OneRec.Minus }}+{{ .OneRec.Plus }} 55 | {{ if gt .OneRec.Total 0 }} 56 | {{ .OneRec.Total }} 57 | {{ else }} 58 | {{ .OneRec.Total }} 59 | {{ end }} 60 |
64 |
65 |
66 | 67 |
68 |
69 |
70 | 87 | {{ template "footer" }} 88 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/footer.html: -------------------------------------------------------------------------------- 1 | {{ define "footer"}} 2 | 3 | 4 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/header.html: -------------------------------------------------------------------------------- 1 | {{ define "header"}} 2 | 3 | 4 | 5 | Resource Diary 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 37 | 38 | 39 | 75 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/index.html: -------------------------------------------------------------------------------- 1 | {{ define "index"}} 2 | 3 |
4 |
5 |
6 |
7 | 8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Date
Name
Minus
Plus
34 | 35 |
36 | 37 |
38 | 39 |
40 |
41 | 42 |
43 |
44 |
45 |
46 |
47 |

48 | Today - {{ .OneRec.Date }} 49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | {{ range .Records }} 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | {{ end }} 69 | 70 | 71 | 72 | 73 | 80 | 81 |
TagNameMinusPlusTotal
{{ .Tag }}{{ .Name }}-{{ .Minus }}+{{ .Plus }}{{ .Total }}
Summary-{{ .OneRec.Minus }}+{{ .OneRec.Plus }} 74 | {{ if gt .OneRec.Total 0 }} 75 | {{ .OneRec.Total }} 76 | {{ else }} 77 | {{ .OneRec.Total }} 78 | {{ end }} 79 |
82 |
83 |
84 |
85 |
86 | 256 | {{ template "footer" }} 257 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/login.html: -------------------------------------------------------------------------------- 1 | {{ define "login" }} 2 | 3 | 4 |
5 |
6 |
7 |
8 |
9 |
10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | 18 | {{ template "footer" }} 19 | {{ end }} -------------------------------------------------------------------------------- /internal/web/templates/stat.html: -------------------------------------------------------------------------------- 1 | {{ define "stat" }} 2 | 3 | 4 |
5 |
6 |
7 | Stat 8 |
9 |
10 |
11 |
12 | 13 | {{ template "footer" }} 14 | {{ end }} -------------------------------------------------------------------------------- /internal/web/var-const.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "embed" 5 | 6 | "github.com/aceberg/rediary/internal/auth" 7 | "github.com/aceberg/rediary/internal/models" 8 | ) 9 | 10 | var ( 11 | // auth config 12 | authConf auth.Conf 13 | // AppConfig - config for Web Gui 14 | AppConfig models.Conf 15 | // AllRecords - all records 16 | AllRecords []models.Record 17 | // TemplHTML - embed templates 18 | // // 19 | //go:embed templates/* 20 | TemplHTML embed.FS 21 | ) 22 | 23 | // TemplPath - path to html templates 24 | const TemplPath = "templates/" 25 | 26 | // TemplPath - path to html templates 27 | // const TemplPath = "../../internal/web/templates/" 28 | 29 | // Icon - favicon 30 | const Icon = "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" 31 | -------------------------------------------------------------------------------- /internal/web/webgui.go: -------------------------------------------------------------------------------- 1 | package web 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/aceberg/rediary/internal/auth" 8 | "github.com/aceberg/rediary/internal/check" 9 | "github.com/aceberg/rediary/internal/conf" 10 | "github.com/aceberg/rediary/internal/db" 11 | "github.com/aceberg/rediary/internal/models" 12 | ) 13 | 14 | // Gui - start web server 15 | func Gui(config models.Conf) { 16 | 17 | AppConfig, authConf = conf.Get(config.ConfPath) 18 | AppConfig.ConfPath = config.ConfPath 19 | AppConfig.Icon = Icon 20 | 21 | db.Create(AppConfig.DB) 22 | db.Migrate(AppConfig.DB) 23 | AllRecords = db.Select(AppConfig.DB) 24 | 25 | log.Println("INFO: starting web gui with", AppConfig.ConfPath) 26 | 27 | address := AppConfig.Host + ":" + AppConfig.Port 28 | log.Println("=================================== ") 29 | log.Printf("Web GUI at http://%s", address) 30 | log.Println("=================================== ") 31 | 32 | http.HandleFunc("/login/", loginHandler) 33 | 34 | http.HandleFunc("/", auth.Auth(indexHandler, &authConf)) 35 | http.HandleFunc("/add_action/", auth.Auth(addActionHandler, &authConf)) 36 | http.HandleFunc("/add_record/", auth.Auth(addRecordHandler, &authConf)) 37 | http.HandleFunc("/add_tag/", auth.Auth(addTagHandler, &authConf)) 38 | http.HandleFunc("/auth_conf/", auth.Auth(authConfHandler, &authConf)) 39 | http.HandleFunc("/auth_save/", auth.Auth(saveAuthHandler, &authConf)) 40 | http.HandleFunc("/clear/", auth.Auth(clearHandler, &authConf)) 41 | http.HandleFunc("/config/", auth.Auth(configHandler, &authConf)) 42 | http.HandleFunc("/del_action/", auth.Auth(delActionHandler, &authConf)) 43 | http.HandleFunc("/del_record/", auth.Auth(delRecordHandler, &authConf)) 44 | http.HandleFunc("/del_tag/", auth.Auth(delTagHandler, &authConf)) 45 | http.HandleFunc("/diary/", auth.Auth(diaryHandler, &authConf)) 46 | http.HandleFunc("/diary_show/", auth.Auth(diaryShowHandler, &authConf)) 47 | http.HandleFunc("/save_colors/", auth.Auth(saveColorsHandler, &authConf)) 48 | http.HandleFunc("/save_config/", auth.Auth(saveConfigHandler, &authConf)) 49 | http.HandleFunc("/stat/", auth.Auth(statHandler, &authConf)) 50 | err := http.ListenAndServe(address, nil) 51 | check.IfError(err) 52 | } 53 | --------------------------------------------------------------------------------