├── .gitignore ├── pkg ├── pathways │ ├── allbasetest.db │ ├── queries │ │ ├── DNA_Gen.sql │ │ ├── get_total_pathways.sql │ │ └── organism_filtered_pathways.sql │ ├── pathways_test.go │ └── pathways.go └── rhea │ ├── rhea_test.go │ ├── rdf.go │ └── rhea.go ├── .devcontainer ├── app.env ├── Dockerfile ├── devcontainer.json └── docker-compose.yml ├── .golangci.yaml ├── models └── user.model.go ├── migrate └── migrate.go ├── .github ├── workflows │ ├── notify.yml │ └── test.yml └── FUNDING.yml ├── initializers ├── connectDB.go └── loadEnv.go ├── main.go ├── LICENSE ├── go.mod ├── README.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md └── go.sum /.gitignore: -------------------------------------------------------------------------------- 1 | ark.db 2 | .DS_Store 3 | data/rhea.rdf.gz 4 | cmd/main 5 | -------------------------------------------------------------------------------- /pkg/pathways/allbasetest.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bebop/ark/HEAD/pkg/pathways/allbasetest.db -------------------------------------------------------------------------------- /.devcontainer/app.env: -------------------------------------------------------------------------------- 1 | POSTGRES_HOST=localhost 2 | POSTGRES_USER=postgres 3 | POSTGRES_PASSWORD=postgres 4 | POSTGRES_DB=postgres 5 | POSTGRES_PORT=5432 6 | 7 | PORT=8000 8 | CLIENT_ORIGIN=http://localhost:3000 -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - asciicheck 4 | - bodyclose 5 | - gofmt 6 | - goprintffuncname 7 | - misspell 8 | - unparam 9 | - whitespace 10 | - megacheck 11 | - govet 12 | -------------------------------------------------------------------------------- /models/user.model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type User struct { 8 | // ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v3();primary_key"` 9 | ID uint `gorm:"primary_key"` 10 | Name string `gorm:"type:varchar(255);not null"` 11 | Email string `gorm:"uniqueIndex;not null"` 12 | CreatedAt time.Time 13 | UpdatedAt time.Time 14 | } 15 | -------------------------------------------------------------------------------- /migrate/migrate.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "github.com/bebop/ark/initializers" 8 | "github.com/bebop/ark/models" 9 | ) 10 | 11 | func init() { 12 | config, err := initializers.LoadConfig(".devcontainer") 13 | if err != nil { 14 | log.Fatal("? Could not load environment variables", err) 15 | } 16 | 17 | initializers.ConnectDB(&config) 18 | } 19 | 20 | func main() { 21 | initializers.DB.AutoMigrate(&models.User{}) 22 | fmt.Println("? Migration complete") 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/notify.yml: -------------------------------------------------------------------------------- 1 | name: notify social media 2 | 3 | on: 4 | release: 5 | issues: 6 | pull_request: 7 | issue_comment: 8 | pull_request_review: 9 | pull_request_review_comment: 10 | push: 11 | branches: 12 | - notify # for testing purposes 13 | - dev 14 | - main 15 | 16 | jobs: 17 | notify: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@master 21 | - name: Actions for Discord 22 | env: 23 | DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} 24 | uses: Ilshidur/action-discord@0.3.2 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: 'build and test within dev container' 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - main 8 | pull_request: 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Checkout (GitHub) 15 | uses: actions/checkout@v3 16 | 17 | - name: Build and run dev container task 18 | uses: devcontainers/ci@v0.3 19 | with: 20 | imageName: ghcr.io/bebop/ark-devcontainer 21 | cacheFrom: ghcr.io/bebop/ark-devcontainer 22 | push: never 23 | # Change this to be your CI task/script 24 | runCmd: go test -v ./... -------------------------------------------------------------------------------- /initializers/connectDB.go: -------------------------------------------------------------------------------- 1 | package initializers 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | "gorm.io/driver/postgres" 8 | "gorm.io/gorm" 9 | ) 10 | 11 | var DB *gorm.DB 12 | 13 | func ConnectDB(config *Config) { 14 | var err error 15 | dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai", config.DBHost, config.DBUserName, config.DBUserPassword, config.DBName, config.DBPort) 16 | 17 | DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{}) 18 | if err != nil { 19 | log.Fatal("Failed to connect to the Database") 20 | } 21 | fmt.Println("? Connected Successfully to the Database") 22 | } 23 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mcr.microsoft.com/devcontainers/go:1-1.21-bullseye 2 | 3 | # [Optional] Uncomment this section to install additional OS packages. 4 | # RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 5 | # && apt-get -y install --no-install-recommends 6 | 7 | # [Optional] Uncomment the next lines to use go get to install anything else you need 8 | # USER vscode 9 | # RUN go get -x 10 | # USER root 11 | 12 | # [Optional] Uncomment this line to install global node packages. 13 | # RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && npm install -g " 2>&1 14 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [TimothyStiles]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /initializers/loadEnv.go: -------------------------------------------------------------------------------- 1 | package initializers 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | ) 6 | 7 | type Config struct { 8 | DBHost string `mapstructure:"POSTGRES_HOST"` 9 | DBUserName string `mapstructure:"POSTGRES_USER"` 10 | DBUserPassword string `mapstructure:"POSTGRES_PASSWORD"` 11 | DBName string `mapstructure:"POSTGRES_DB"` 12 | DBPort string `mapstructure:"POSTGRES_PORT"` 13 | ServerPort string `mapstructure:"PORT"` 14 | 15 | ClientOrigin string `mapstructure:"CLIENT_ORIGIN"` 16 | } 17 | 18 | func LoadConfig(path string) (config Config, err error) { 19 | viper.AddConfigPath(path) 20 | viper.SetConfigType("env") 21 | viper.SetConfigName("app") 22 | 23 | viper.AutomaticEnv() 24 | 25 | err = viper.ReadInConfig() 26 | if err != nil { 27 | return 28 | } 29 | 30 | err = viper.Unmarshal(&config) 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/bebop/ark/initializers" 8 | "github.com/gin-gonic/gin" 9 | ) 10 | 11 | var ( 12 | server *gin.Engine 13 | ) 14 | 15 | func init() { 16 | config, err := initializers.LoadConfig(".devcontainer") 17 | if err != nil { 18 | log.Fatal("? Could not load environment variables", err) 19 | } 20 | 21 | initializers.ConnectDB(&config) 22 | 23 | server = gin.Default() 24 | } 25 | 26 | func main() { 27 | config, err := initializers.LoadConfig(".devcontainer") 28 | if err != nil { 29 | log.Fatal("? Could not load environment variables", err) 30 | } 31 | 32 | router := server.Group("/api") 33 | router.GET("/healthchecker", func(ctx *gin.Context) { 34 | message := "Welcome to Golang with Gorm and Postgres" 35 | ctx.JSON(http.StatusOK, gin.H{"status": "success", "message": message}) 36 | }) 37 | 38 | log.Fatal(server.Run(":" + config.ServerPort)) 39 | } 40 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/go-postgres 3 | { 4 | "name": "Go & PostgreSQL", 5 | "dockerComposeFile": "docker-compose.yml", 6 | "service": "app", 7 | "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", 8 | 9 | // Features to add to the dev container. More info: https://containers.dev/features. 10 | // "features": {}, 11 | 12 | // Configure tool-specific properties. 13 | // "customizations": {}, 14 | 15 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 16 | // "forwardPorts": [5432], 17 | 18 | // Use 'postCreateCommand' to run commands after the container is created. 19 | "postCreateCommand": "go install github.com/cosmtrek/air@latest", 20 | 21 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 22 | // "remoteUser": "root" 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2023 Timothy Stiles, Keoni Gandall 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /.devcontainer/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | volumes: 4 | postgres-data: 5 | 6 | services: 7 | app: 8 | build: 9 | context: . 10 | dockerfile: Dockerfile 11 | env_file: 12 | # Ensure that the variables in .env match the same variables in devcontainer.json 13 | - app.env 14 | 15 | volumes: 16 | - ../..:/workspaces:cached 17 | 18 | # Overrides default command so things don't shut down after the process ends. 19 | command: sleep infinity 20 | 21 | # Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function. 22 | network_mode: service:db 23 | 24 | # Use "forwardPorts" in **devcontainer.json** to forward an app port locally. 25 | # (Adding the "ports" property to this file will not forward from a Codespace.) 26 | 27 | db: 28 | image: postgres:15-bullseye 29 | restart: unless-stopped 30 | volumes: 31 | - postgres-data:/var/lib/postgresql/data 32 | env_file: 33 | # Ensure that the variables in .env match the same variables in devcontainer.json 34 | - app.env 35 | 36 | 37 | # Add "forwardPorts": ["5432"] to **devcontainer.json** to forward PostgreSQL locally. 38 | # (Adding the "ports" property to this file will not forward from a Codespace.) 39 | -------------------------------------------------------------------------------- /pkg/rhea/rhea_test.go: -------------------------------------------------------------------------------- 1 | package rhea 2 | 3 | // commenting out for now but will come back to it soon. -Tim 09/09/2023 4 | 5 | // import ( 6 | // "fmt" 7 | // "log" 8 | // "os" 9 | // "testing" 10 | 11 | // _ "github.com/mattn/go-sqlite3" 12 | // ) 13 | 14 | // var rhea Rhea 15 | 16 | // func TestMain(m *testing.M) { 17 | // var err error 18 | // rhea, err = Read("data/rhea_mini.rdf.gz") 19 | // if err != nil { 20 | // log.Fatalf("Failed to read rhea: %v", err) 21 | // } 22 | 23 | // // Start running tests 24 | // code := m.Run() 25 | // os.Exit(code) 26 | // } 27 | 28 | // func ExampleRhea_ExportJSON() { 29 | // // Convert rhea to JSON 30 | // rheaJson, _ := rhea.ExportJSON() 31 | 32 | // fmt.Println(string(rheaJson)[:100]) 33 | // // Output: {"reactionParticipants":[{"reactionside":"http://rdf.rhea-db.org/10000_L","contains":1,"containsn":f 34 | // } 35 | 36 | // func TestReadRheaToUniprot(t *testing.T) { 37 | // lines := make(chan RheaToUniprot, 100) 38 | // go ReadRheaToUniprotTrembl("data/rhea2uniprot_sprot_minimized.tsv.gz", lines) 39 | 40 | // var line RheaToUniprot 41 | // for l := range lines { 42 | // line = l 43 | // } 44 | 45 | // if line.UniprotID != "P06106" { 46 | // log.Fatalf("Got wrong uniprotId. Expected P06106, got %s", line.UniprotID) 47 | // } 48 | // } 49 | 50 | // func ExampleReadRheaToUniprotSprot() { 51 | // lines := make(chan RheaToUniprot, 100) 52 | // go ReadRheaToUniprotSprot("data/rhea2uniprot_sprot_minimized.tsv", lines) 53 | 54 | // var line RheaToUniprot 55 | // for l := range lines { 56 | // line = l 57 | // } 58 | 59 | // fmt.Println(line) 60 | // // Output: {10048 UN 10048 P06106} 61 | // } 62 | -------------------------------------------------------------------------------- /pkg/pathways/queries/DNA_Gen.sql: -------------------------------------------------------------------------------- 1 | 2 | -- need to do this step because of a technicality in the database's schema. 3 | -- ids involved in reaction pathways may not directly map to uniprot_to_reaction, 4 | -- but they will be associated with a "parent reaction" that IS associated. this generates that table to show potential parents 5 | WITH potentialparents AS ( 6 | select r.id as id1, r.accession as accession1, j.id as id2, j.accession as accession2, k.id as id3, k.accession as accession3 7 | from reaction r 8 | inner join reaction j on r.id-1 = j.id 9 | inner join reaction k on j.id-1 = k.id 10 | where r.id IN (?) 11 | ) 12 | 13 | -- formats the output so that specific reaction accessions show the associated DNA. 14 | -- NOTE: these reactions may be different by -1 or -2 than the input reaction, 15 | -- indicating that the parent reaction has been found and 16 | -- that there is no documented directionality to the reaction within Rhea 17 | select distinct r.id, s.sequence, gf.seqhash, gf.genbank 18 | from reaction r 19 | inner join uniprot_to_reaction ur ON ur.reaction = r.accession 20 | inner join uniprot u ON ur.uniprot = u.accession 21 | inner join seqhash s on s.translation = u.seqhash 22 | inner join genbankfeatures gf on gf.seqhash = s.seqhash 23 | WHERE r.accession IN 24 | ( 25 | -- this checks which actual accessions number to use for the reaction you want 26 | select CASE 27 | when accession1 IN (select reaction from uniprot_to_reaction) 28 | then accession1 29 | when accession2 IN (select reaction from uniprot_to_reaction) 30 | then accession2 31 | when accession3 IN (select reaction from uniprot_to_reaction) 32 | then accession3 33 | END parent_accession 34 | from potentialparents 35 | ) -------------------------------------------------------------------------------- /pkg/pathways/queries/get_total_pathways.sql: -------------------------------------------------------------------------------- 1 | --Authors: Jordan Strasser, David Lambert (SQL Help) 2 | WITH stitch AS ( 3 | select a.accession, a.id as rxn_id, 4 | b.reactionside, 5 | b.reactionsidereactiontype, 6 | c.compound, 7 | d.id as cmpd_id, 8 | d.name 9 | FROM reaction a 10 | inner join reactionsidereaction b on a.accession = b.reaction 11 | inner join reactionparticipant c USING(reactionside) 12 | inner join compound d ON c.compound = d.accession 13 | where b.reactionsidereactiontype <> 'substrateorproduct' 14 | and d.id != 0 15 | ), 16 | not_one(ids) AS ( 17 | SELECT cmpd_id FROM ( 18 | SELECT count(*) as count, cmpd_id 19 | FROM stitch 20 | GROUP BY cmpd_id 21 | ORDER BY count(*) DESC ) 22 | WHERE count > 100 -- modify to filter out commonly available molecules 23 | ), 24 | chain AS ( 25 | select c.rxn_id, c.reactionsidereactiontype as type1, c.cmpd_id as prod_id, c.name as prod_name, 26 | d.reactionsidereactiontype as type2, d.cmpd_id as sub_id, d.name as sub_name, 0 as lvl, 27 | c.name|| ',' ||d.name as name_path, 28 | cast(c.rxn_id as text) as id_path 29 | from 30 | stitch c 31 | inner join stitch d on c.rxn_id = d.rxn_id 32 | where c.cmpd_id = ? 33 | and sub_id NOT IN (SELECT ids from not_one) 34 | and type2 = 'substrate' 35 | and type1 <> 'substrate' 36 | UNION ALL 37 | select e.rxn_id, e.reactionsidereactiontype as type1, e.cmpd_id as prod_id, e.name as prod_name, 38 | f.reactionsidereactiontype as type2, f.cmpd_id as sub_id, f.name as sub_name, chain.lvl + 1 as lvl, 39 | chain.name_path || ',' || f.name as name_path, 40 | chain.id_path || ',' || cast(e.rxn_id as text) as id_path 41 | from 42 | stitch e 43 | inner join stitch f on e.rxn_id = f.rxn_id 44 | inner join chain on e.cmpd_id = chain.sub_id 45 | where lvl < ? 46 | and f.reactionsidereactiontype LIKE '%substrate%' 47 | and e.reactionsidereactiontype NOT LIKE '%substrate%' 48 | and f.cmpd_id NOT IN (SELECT ids FROM not_one) 49 | and instr(chain.name_path, f.name) = 0 50 | ) 51 | select * from chain -------------------------------------------------------------------------------- /pkg/pathways/pathways_test.go: -------------------------------------------------------------------------------- 1 | package pathways 2 | 3 | // import ( 4 | // "testing" 5 | // ) 6 | 7 | // func TestLoadSQLFile(t *testing.T) { 8 | // //this file exists 9 | // _, err := LoadSQLFile("./queries/get_total_pathways.sql") 10 | // if err != nil { 11 | // t.Error(err) 12 | // } 13 | // //this file is intentionally not there, should throw errors 14 | // _, err = LoadSQLFile("./not_there.sql") 15 | // if err == nil { 16 | // t.Error("Error check not working") 17 | // } 18 | // } 19 | 20 | // func TestGetTotalPathways(t *testing.T) { 21 | // result, err := GetTotalPathways("calycosin", 4) 22 | // if len(result) != 9 { 23 | // t.Error("Expected: len(result) = 9, got ", len(result), err) 24 | // } 25 | // _, err = GetTotalPathways("NotAvail", 4) 26 | // if err == nil { 27 | // t.Error("Error check not working for unavail compounds") 28 | // } 29 | // } 30 | // func TestNameToId(t *testing.T) { 31 | // if id, err := NameToId("XMP"); id != 5036 { 32 | // t.Error("Expected: 5036, got: ", err) 33 | // } 34 | // _, err := NameToId("NotThere") 35 | // if err == nil { 36 | // t.Error("Error checker is not working for NameToID") 37 | // } 38 | // } 39 | // func TestOrganismFilteredPathways(t *testing.T) { 40 | // result, err := OrganismFilteredPathways("CP060121", "XMP", 1) 41 | // if len(result) != 37 { 42 | // t.Error("Expected 37 path branches, got: ", len(result), err) 43 | // } 44 | // //intentionally broken. having GBOrganism not there doesn't actually throw an error, just an empty list 45 | // result, _ = OrganismFilteredPathways("NotThere", "XMP", 1) 46 | // if len(result) != 0 { 47 | // t.Error("Error check failed for broken GB Organism ID") 48 | // } 49 | // //intentionally broken 50 | // _, err = OrganismFilteredPathways("CP060121", "NotThere", 1) 51 | // if err == nil { 52 | // t.Error("Error check failed for broken target molecule") 53 | // } 54 | // } 55 | // func TestGetDNA(t *testing.T) { 56 | // pathways, _ := OrganismFilteredPathways("CP060121", "XMP", 1) 57 | // DNAseqs, err := GetDNA(pathways, 1) 58 | // if len(DNAseqs) != 25 { 59 | // t.Error("Expected 25 key-value pairs, got: ", len(DNAseqs), err) 60 | // } 61 | // } 62 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/bebop/ark 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/google/uuid v1.3.1 7 | github.com/jmoiron/sqlx v1.3.4 8 | github.com/lib/pq v1.2.1-0.20191011153232-f91d3411e481 9 | github.com/mattn/go-sqlite3 v1.14.12 10 | github.com/spf13/viper v1.16.0 11 | gorm.io/driver/postgres v1.5.2 12 | gorm.io/gorm v1.25.4 13 | ) 14 | 15 | require ( 16 | github.com/bytedance/sonic v1.9.1 // indirect 17 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect 18 | github.com/fsnotify/fsnotify v1.6.0 // indirect 19 | github.com/gabriel-vasile/mimetype v1.4.2 // indirect 20 | github.com/gin-contrib/sse v0.1.0 // indirect 21 | github.com/gin-gonic/gin v1.9.1 // indirect 22 | github.com/go-playground/locales v0.14.1 // indirect 23 | github.com/go-playground/universal-translator v0.18.1 // indirect 24 | github.com/go-playground/validator/v10 v10.14.0 // indirect 25 | github.com/goccy/go-json v0.10.2 // indirect 26 | github.com/hashicorp/hcl v1.0.0 // indirect 27 | github.com/jackc/pgpassfile v1.0.0 // indirect 28 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 29 | github.com/jackc/pgx/v5 v5.3.1 // indirect 30 | github.com/jinzhu/inflection v1.0.0 // indirect 31 | github.com/jinzhu/now v1.1.5 // indirect 32 | github.com/json-iterator/go v1.1.12 // indirect 33 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 34 | github.com/leodido/go-urn v1.2.4 // indirect 35 | github.com/magiconair/properties v1.8.7 // indirect 36 | github.com/mattn/go-isatty v0.0.19 // indirect 37 | github.com/mitchellh/mapstructure v1.5.0 // indirect 38 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 39 | github.com/modern-go/reflect2 v1.0.2 // indirect 40 | github.com/pelletier/go-toml/v2 v2.0.8 // indirect 41 | github.com/spf13/afero v1.9.5 // indirect 42 | github.com/spf13/cast v1.5.1 // indirect 43 | github.com/spf13/jwalterweatherman v1.1.0 // indirect 44 | github.com/spf13/pflag v1.0.5 // indirect 45 | github.com/subosito/gotenv v1.4.2 // indirect 46 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 47 | github.com/ugorji/go/codec v1.2.11 // indirect 48 | golang.org/x/arch v0.3.0 // indirect 49 | golang.org/x/crypto v0.9.0 // indirect 50 | golang.org/x/net v0.10.0 // indirect 51 | golang.org/x/sys v0.8.0 // indirect 52 | golang.org/x/text v0.9.0 // indirect 53 | google.golang.org/protobuf v1.30.0 // indirect 54 | gopkg.in/ini.v1 v1.67.0 // indirect 55 | gopkg.in/yaml.v3 v3.0.1 // indirect 56 | ) 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ark 2 | 3 | ## ark is a database for engineering organisms 4 | 5 | * **Comprehensive:** ark is a single service that can search, store, and cross reference sequences and pathways from genbank, rhea, chembl, and uniprot 6 | 7 | * **Modern:** ark serves JSON and is written in Go. ark parses legacy file formats so you don't have to. 8 | 9 | * **Stable (soon):** ark will be well tested and designed to be used in industrial, academic, and hobbyist settings 10 | 11 | ## Install 12 | 13 | ark is still in hot development and not production ready. We currently only ship a pre-release dev branch for contributors. 14 | 15 | `git clone https://github.com/TimothyStiles/ark && cd ark && go test -v ./...` 16 | 17 | ## Community 18 | 19 | * **[Discord](https://discord.gg/Hc8Ncwt):** Chat about ark and join us for game nights on our discord server! 20 | 21 | ## Contributing 22 | 23 | * **[Code of conduct](CODE_OF_CONDUCT.md):** Please read the full text so you can understand what we're all about and remember to be excellent to each other! 24 | 25 | * **[Contributor's guide](CONTRIBUTING.md):** Please read through it before you start hacking away and pushing contributions to this fine codebase. 26 | 27 | ## Sponsor 28 | 29 | * **[Sponsor](https://github.com/sponsors/TimothyStiles):** 🤘 Thanks for your support 🤘 30 | 31 | ## License 32 | 33 | * [MIT](LICENSE) 34 | 35 | * Copyright (c) 2022 Timothy Stiles 36 | 37 | 64 | -------------------------------------------------------------------------------- /pkg/pathways/queries/organism_filtered_pathways.sql: -------------------------------------------------------------------------------- 1 | -- Meta: this code takes about 30 seconds to finish, irrespective of the levels depth parameter. 2 | -- When the organism filter is put on the normal pathway generator, speed is reduced by 1/3... 3 | -- native_rxns CTE fetches rxn ids that are native to a user-specified organism 4 | WITH native_rxns as ( 5 | select distinct case 6 | when r.directional = 0 7 | then r.id + 1 8 | else r.id 9 | end id 10 | from uniprot u 11 | inner join uniprot_to_reaction ur on u.accession = ur.uniprot 12 | inner join reaction r on ur.reaction = r.accession 13 | where u.seqhash IN ( 14 | select s.translation 15 | from genbank g inner join genbankfeatures gf 16 | on g.accession = gf.genbank 17 | inner join seqhash s on gf.seqhash = s.seqhash 18 | WHERE g.accession = ? -- organism param 19 | ) 20 | ), 21 | -- native_rxns selects from 'case' because uniprot_to_reaction includes the base parent reactions that are undirectional. 22 | -- sometimes only these parent reaction have an associated enzyme. 23 | -- modified to r.id + 1 so that it can match items within the stitch cte 24 | 25 | -- formats the ark tables in a conenient way to see reaction participants, ids, names 26 | stitch as ( 27 | select a.accession, a.id as rxn_id, 28 | b.reactionside, 29 | b.reactionsidereactiontype, 30 | c.compound, 31 | d.id as cmpd_id, 32 | d.name as name 33 | FROM reaction a 34 | inner join reactionsidereaction b on a.accession = b.reaction 35 | inner join reactionparticipant c USING(reactionside) 36 | inner join compound d ON c.compound = d.accession 37 | where b.reactionsidereactiontype <> 'substrateorproduct' 38 | and d.id != 0 39 | and rxn_id IN (select id from native_rxns) -- organism filter 40 | or rxn_id IN (select id+1 from native_rxns) -- gets reverse reactions also 41 | ), 42 | 43 | -- finds most common compounds in an organism to avoid trivial pathways 44 | common_compounds AS ( 45 | select cmpd_id FROM ( select count(*) as count, cmpd_id, name 46 | from stitch 47 | group by cmpd_id 48 | order by count(*) desc 49 | ) 50 | where count > 30 -- param to filter common substrates 51 | ), 52 | -- recursively goes through stitch, finding the substrates of substrates, until the level param is reached 53 | -- filters reactions to only return ones native to the organism of interest 54 | chain as ( 55 | select c.rxn_id as rxn_id, c.reactionsidereactiontype as type1, c.cmpd_id as prod_id, c.name as prod_name, 56 | d.reactionsidereactiontype as type2, d.cmpd_id as sub_id, d.name as sub_name, 0 as lvl, 57 | c.name|| ',' ||d.name as name_path, 58 | cast(c.rxn_id as text) as id_path 59 | from 60 | stitch c 61 | inner join stitch d on c.rxn_id = d.rxn_id 62 | where c.cmpd_id = ? 63 | and d.cmpd_id NOT IN (select * from common_compounds) 64 | and type2 = 'substrate' 65 | and type1 <> 'substrate' 66 | UNION ALL 67 | select e.rxn_id, e.reactionsidereactiontype as type1, e.cmpd_id as prod_id, e.name as prod_name, 68 | f.reactionsidereactiontype as type2, f.cmpd_id as sub_id, f.name as sub_name, chain.lvl + 1 as lvl, 69 | chain.name_path || ',' || f.name as name_path, 70 | chain.id_path || ',' || cast(e.rxn_id as text) as id_path 71 | from 72 | stitch e 73 | inner join stitch f on e.rxn_id = f.rxn_id 74 | inner join chain on e.cmpd_id = chain.sub_id 75 | where lvl < ? 76 | and f.reactionsidereactiontype LIKE '%substrate%' 77 | and e.reactionsidereactiontype NOT LIKE '%substrate%' 78 | and f.cmpd_id NOT IN (select * from common_compounds) 79 | and instr(chain.name_path, f.name) = 0 80 | ) 81 | select * from chain -------------------------------------------------------------------------------- /pkg/pathways/pathways.go: -------------------------------------------------------------------------------- 1 | package pathways 2 | 3 | // Authors: Jordan Strasser, (Your_name_here) 4 | 5 | import ( 6 | "io/ioutil" 7 | "log" 8 | "path/filepath" 9 | "strings" 10 | 11 | "github.com/jmoiron/sqlx" 12 | _ "github.com/mattn/go-sqlite3" 13 | ) 14 | 15 | // Reads and loads SQL files as string 16 | func LoadSQLFile(path string) (string, error) { 17 | realpath, err := filepath.Abs(path) 18 | if err != nil { 19 | return "", err 20 | } 21 | stuff, err := ioutil.ReadFile(realpath) 22 | if err != nil { 23 | return "", err 24 | } 25 | return string(stuff), err 26 | } 27 | 28 | // Easy database connector 29 | func ConnectDB() (*sqlx.DB, error) { 30 | var db *sqlx.DB 31 | var err error 32 | db, err = sqlx.Connect("sqlite3", "./arktest.db") 33 | if err != nil { 34 | return db, err 35 | } 36 | return db, err 37 | } 38 | 39 | // Gets id from compound name if it exists in ark 40 | func NameToId(name string) (int, error) { 41 | db, err := ConnectDB() 42 | if err != nil { 43 | log.Fatalf("Couldn't connect to DB: %d", err) 44 | } 45 | var id int 46 | query := "SELECT id FROM compound WHERE name = ?" 47 | err = db.Get(&id, query, name) 48 | if err != nil { 49 | return 0, err 50 | //whenever there's an error here we need to log desired compounds 51 | } 52 | return id, err 53 | } 54 | 55 | type pathdata struct { 56 | Rxn_id, Prod_id, Sub_id, Lvl int 57 | Type1, Prod_name, Type2, Sub_name, Name_path, Id_path string 58 | } 59 | type DNA struct { 60 | Id int 61 | Sequence, Seqhash, Genbank string 62 | } 63 | 64 | /* 65 | Recursively searches throughout the database and fetches the pathways that lead to your target compound. 66 | This query excludes any compound that occurs more than 100 times in nodes. That parameter can change, 67 | but once we start including things like NADPH, ATP, H2O, we step into combinatorial explosions. 68 | id_path shows you the chain of equations starting from the top, and path shows you the actual compoounds 69 | that build up a path, which is usually just the most significant reactants and products. 70 | */ 71 | func GetTotalPathways(target_molecule string, levels int) ([]pathdata, error) { 72 | query, err := LoadSQLFile("./queries/get_total_pathways.sql") 73 | if err != nil { 74 | return nil, err 75 | } 76 | db, err := ConnectDB() 77 | if err != nil { 78 | return nil, err 79 | } 80 | target_id, err := NameToId(target_molecule) 81 | if err != nil { 82 | return nil, err 83 | } 84 | result := []pathdata{} 85 | err = db.Select(&result, query, target_id, levels) 86 | if err != nil { 87 | return result, err 88 | } 89 | db.Close() 90 | return result, err 91 | } 92 | 93 | // GetTotalPathways but limited to a single organism 94 | func OrganismFilteredPathways(GBOrganism string, target_molecule string, levels int) ([]pathdata, error) { 95 | query, err := LoadSQLFile("./queries/organism_filtered_pathways.sql") 96 | if err != nil { 97 | return nil, err 98 | } 99 | db, err := ConnectDB() 100 | if err != nil { 101 | return nil, err 102 | } 103 | target_id, err := NameToId(target_molecule) 104 | if err != nil { 105 | return nil, err 106 | } 107 | result := []pathdata{} 108 | err = db.Select(&result, query, GBOrganism, target_id, levels) 109 | if err != nil { 110 | return result, err 111 | } 112 | db.Close() 113 | return result, err 114 | } 115 | 116 | /* 117 | Input is pathway data from OrganismFilteredPathways or GetTotalPathways (if Genbank/Uniprot are complete in ark) 118 | and the pathway depth (levels) you want 119 | Returns a map: 120 | key = compound path, e.g. "XMP->guanine", which ignores the intermediary steps 121 | value = list of DNA structs, which contains info about the DNA sequences you need 122 | to add to an organism for it to do this chemical reaction. An individual DNA struct has Rhea reaction ID, 123 | gene sequence, gene seqhash, and the genbank ID of the organism from which the gene comes. 124 | */ 125 | 126 | func GetDNA(pathways []pathdata, levels int) (map[string][]DNA, error) { 127 | RawQuery, err := LoadSQLFile("./queries/DNA_Gen.sql") 128 | if err != nil { 129 | return nil, err 130 | } 131 | db, err := ConnectDB() 132 | if err != nil { 133 | return nil, err 134 | } 135 | PathwayToDNA := make(map[string][]DNA) 136 | 137 | for _, pathway := range pathways { 138 | if pathway.Lvl == levels { 139 | IdList := strings.Split(pathway.Id_path, ",") 140 | query, args, err := sqlx.In(RawQuery, IdList) 141 | if err != nil { 142 | return PathwayToDNA, err 143 | } 144 | result := []DNA{} 145 | query = db.Rebind(query) 146 | err = db.Select(&result, query, args...) 147 | if err != nil { 148 | return PathwayToDNA, err 149 | } 150 | compounds := strings.Split(pathway.Name_path, ",") 151 | newString := compounds[0] + "->" + compounds[len(compounds)-1] 152 | PathwayToDNA[newString] = result 153 | } 154 | } 155 | return PathwayToDNA, err 156 | } 157 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 2 | # Contributor Covenant Code of Conduct 3 | 4 | ## Our Pledge 5 | 6 | We as members, contributors, and leaders pledge to make participation in our 7 | community a harassment-free experience for everyone, regardless of age, body 8 | size, visible or invisible disability, ethnicity, sex characteristics, gender 9 | identity and expression, level of experience, education, socio-economic status, 10 | nationality, personal appearance, race, religion, or sexual identity 11 | and orientation. 12 | 13 | We pledge to act and interact in ways that contribute to an open, welcoming, 14 | diverse, inclusive, and healthy community. 15 | 16 | ## Our Standards 17 | 18 | Examples of behavior that contributes to a positive environment for our 19 | community include: 20 | 21 | * Demonstrating empathy and kindness toward other people 22 | * Being respectful of differing opinions, viewpoints, and experiences 23 | * Giving and gracefully accepting constructive feedback 24 | * Accepting responsibility and apologizing to those affected by our mistakes, 25 | and learning from the experience 26 | * Focusing on what is best not just for us as individuals, but for the 27 | overall community 28 | 29 | Examples of unacceptable behavior include: 30 | 31 | * The use of sexualized language or imagery, and sexual attention or 32 | advances of any kind 33 | * Trolling, insulting or derogatory comments, and personal or political attacks 34 | * Public or private harassment 35 | * Publishing others' private information, such as a physical or email 36 | address, without their explicit permission 37 | * Other conduct which could reasonably be considered inappropriate in a 38 | professional setting 39 | 40 | ## Enforcement Responsibilities 41 | 42 | Community leaders are responsible for clarifying and enforcing our standards of 43 | acceptable behavior and will take appropriate and fair corrective action in 44 | response to any behavior that they deem inappropriate, threatening, offensive, 45 | or harmful. 46 | 47 | Community leaders have the right and responsibility to remove, edit, or reject 48 | comments, commits, code, wiki edits, issues, and other contributions that are 49 | not aligned to this Code of Conduct, and will communicate reasons for moderation 50 | decisions when appropriate. 51 | 52 | ## Scope 53 | 54 | This Code of Conduct applies within all community spaces, and also applies when 55 | an individual is officially representing the community in public spaces. 56 | Examples of representing our community include using an official e-mail address, 57 | posting via an official social media account, or acting as an appointed 58 | representative at an online or offline event. 59 | 60 | ## Enforcement 61 | 62 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 63 | reported to the community leaders responsible for enforcement at 64 | [INSERT CONTACT METHOD]. 65 | All complaints will be reviewed and investigated promptly and fairly. 66 | 67 | All community leaders are obligated to respect the privacy and security of the 68 | reporter of any incident. 69 | 70 | ## Enforcement Guidelines 71 | 72 | Community leaders will follow these Community Impact Guidelines in determining 73 | the consequences for any action they deem in violation of this Code of Conduct: 74 | 75 | ### 1. Correction 76 | 77 | **Community Impact**: Use of inappropriate language or other behavior deemed 78 | unprofessional or unwelcome in the community. 79 | 80 | **Consequence**: A private, written warning from community leaders, providing 81 | clarity around the nature of the violation and an explanation of why the 82 | behavior was inappropriate. A public apology may be requested. 83 | 84 | ### 2. Warning 85 | 86 | **Community Impact**: A violation through a single incident or series 87 | of actions. 88 | 89 | **Consequence**: A warning with consequences for continued behavior. No 90 | interaction with the people involved, including unsolicited interaction with 91 | those enforcing the Code of Conduct, for a specified period of time. This 92 | includes avoiding interactions in community spaces as well as external channels 93 | like social media. Violating these terms may lead to a temporary or 94 | permanent ban. 95 | 96 | ### 3. Temporary Ban 97 | 98 | **Community Impact**: A serious violation of community standards, including 99 | sustained inappropriate behavior. 100 | 101 | **Consequence**: A temporary ban from any sort of interaction or public 102 | communication with the community for a specified period of time. No public or 103 | private interaction with the people involved, including unsolicited interaction 104 | with those enforcing the Code of Conduct, is allowed during this period. 105 | Violating these terms may lead to a permanent ban. 106 | 107 | ### 4. Permanent Ban 108 | 109 | **Community Impact**: Demonstrating a pattern of violation of community 110 | standards, including sustained inappropriate behavior, harassment of an 111 | individual, or aggression toward or disparagement of classes of individuals. 112 | 113 | **Consequence**: A permanent ban from any sort of public interaction within 114 | the community. 115 | 116 | ## Attribution 117 | 118 | This Code of Conduct is adapted from the [Contributor Covenant version 2.0](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html). 119 | 120 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 121 | enforcement ladder](https://github.com/mozilla/diversity). 122 | 123 | For answers to common questions about this code of conduct, see the [FAQ](https://www.contributor-covenant.org/faq). 124 | 125 | [Translations are also available](https://www.contributor-covenant.org/translations). 126 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Yo, what up! if you're reading this then I'm super psyched because that means that you're thinking about contributing to ark! Thanks so much for your time and consideration. It's rad people like you that make ark such a cool computational synthetic biology tool. 4 | 5 | I wrote this contributor's guide to help newcomers feel welcome. Getting started with a new project can be complicated and I wanted to make it as easy as possible for you to contribute and as easy as possible for me to help. 6 | 7 | Currently any sincere pull request is a good request. 8 | ark is still in pre-release so there are so many way to contribute! 9 | Here's a list of ideas but feel free to suggest anything I may have forgotten to include. 10 | 11 | * Feature requests - especially cool new algorithms with citations. 12 | * Devops features. Github action bots, linters, deployment, etc. 13 | * Unit and integration tests. 14 | * Writing, editing, and translating tutorials, documentation, or blog posts. 15 | * Auditing for accessibility. 16 | * Bug reports. 17 | * Bug triaging. 18 | * Community management. 19 | * Art! Dreams! Your excellence! 20 | * Code that can be pulled into ark itself. 21 | 22 | # Contributor guidelines 23 | ### Excellence, and the contributor's code of conduct 24 | 25 | First up, most importantly we have a contributor's code of conduct. For some reason the internet is a dehumanizing experience and it's easy to forget that aside from the bots we're all humans on this thing. Approach each other with kindness. Please read our [contributor's code of conduct](CODE_OF_CONDUCT.md) and when in doubt just remember our one true rule as once spoken by the ever so wise duo of Bill and Ted. 26 | 27 | `Bill: Be excellent, ... to each other, ...` 28 | 29 | `Ted: and party on, dudes! [sic]` 30 | 31 | ![Abraham Licoln saying, "Be Excellent to each other and party on dudes!". [sic]](https://media.giphy.com/media/ef0zYcF7AKu4b0Sns6/giphy-downsized-large.gif) 32 | 33 | ### Do-ocracy 34 | 35 | ark runs on do-ocracy. Do-ocracy is a simple concept. If you don't like something you don't need permission to fix it, you can just go ahead and fix it! If you actually want to merge your fix, or contribute in someway that benefits everybody, it'd really, really, really help if you got some light consensus from the rest of the ark development community but hey, if you really need to do something then you just gotta do it! Just don't expect me to merge it if it doesn't meet our technical criteria or isn't quite right for ark. 36 | 37 | ### Technical requirements 38 | 39 | Part of what makes ark so special is that we have standards. DNA is already spaghetti code on its own and we just don't need to add to that. 40 | 41 | All successfully merged pull requests must meet the following criteria: 42 | 43 | * All current tests must pass. 44 | 45 | * At least one new test must be written to prove that the merged feature works correctly. 46 | 47 | * At least one new [example test](https://blog.golang.org/examples) must be written to demonstrate the merged feature in our docs. 48 | 49 | * Build tests must pass for all currently supported systems and package managers. Linux, Mac OSX, Windows, etc. 50 | 51 | * Code must be clean, readable, and commented. How you do that is up to you! 52 | 53 | Don't worry if you submit a pull request and all the tests break and the code is not readable. We won't merge it just yet and then you can get some feedback about what needs to be changed before we do! 54 | 55 | ### Be welcoming 56 | 57 | As one final guideline please be welcoming to newcomers and encourage new contributors from all walks of life. I want ark to be for everyone and that includes you and people who don't look, sound, or act like you! 58 | 59 | # Your first contribution 60 | 61 | Unsure where to begin contributing to ark? You can start by looking through these beginner and help-wanted issues: 62 | 63 | [Beginner issues](https://github.com/bebop/ark/issues?q=is%3Aissue+is%3Aopen+label%3A%22beginner%22+) - issues which should only require a few lines of code, and a test or two. 64 | 65 | [Good first issues](https://github.com/bebop/ark/contribute) - issues which are good for first time contributors. 66 | 67 | [Help wanted issues](https://github.com/bebop/ark/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+) - issues which should be a bit more involved than beginner issues. 68 | 69 | [Feature requests](https://github.com/bebop/ark/labels/enhancement) - before requesting a new feature search through previous feature requests to see if it's already been requested. If not then feel free to submit a request and tag it with the enhancement tag! 70 | 71 | ### Working on your first Pull Request? 72 | 73 | You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). 74 | 75 | You can also check out [these](http://makeapullrequest.com/) [tutorials](http://www.firsttimersonly.com/). 76 | 77 | At this point, you're ready to make your changes! Feel free to ask for help; everyone is a beginner at first :smile_cat: 78 | 79 | # Getting started 80 | 81 | For something that is bigger than a one or two line fix: 82 | 83 | 1. Create your own fork of the code. 84 | 2. Make a branch in your fork 85 | 3. Do the changes in your fork's branch. 86 | 4. Send a pull request. 87 | 88 | ## Virtual Environments and Development Containers 89 | 90 | In order to simplify the development experience, and environment setup, the ark Github repository comes packaged to support *Github CodeSpaces* and [*VSCode Development Containers*](https://code.visualstudio.com/docs/remote/containers#_getting-started). *Github CodeSpaces* will give you ability to spin up a Github hosted instance of Ubuntu that would allow you run, test, develop ark from the browser. *VSCode Development Containers* in turn will allow your installation of VSCode to spin up a docker instance of Ubuntu on your computer and automatically mount your code onto it so that you continue developing on this docker instance that has all the required development environment setup. 91 | 92 | ## Recommended Plugins 93 | 94 | Whether you're a beginner with Go or you're an experienced developer, You should see the suggestions popup automatically when you goto the *Plugins* tab in VSCode. Using these plugins can help accelerate the development experience and also allow you to work more collaboratively with other ark developers. 95 | 96 | # How to report a bug 97 | 98 | ### Security disclosures 99 | 100 | If you find a security vulnerability, do NOT open an issue. I've yet to set up a security email for this so please in the interim DM me on twitter for my email [@timothystiles](https://twitter.com/TimothyStiles). 101 | 102 | In order to determine whether you are dealing with a security issue, ask yourself these two questions: 103 | 104 | * Can I access something that's not mine, or something I shouldn't have access to? 105 | * Can I disable something for other people? 106 | 107 | If the answer to either of those two questions are "yes", then you're probably dealing with a security issue. Note that even if you answer "no" to both questions, you may still be dealing with a security issue, so if you're unsure, just DM me [@timothystiles](https://twitter.com/TimothyStiles) for my personal email until I can set up a security related email. 108 | 109 | ### Non-security related bugs 110 | 111 | For non-security bug reports please [submit it using this template!](https://github.com/bebop/ark/issues/new?assignees=&labels=&template=bug_report.md&title=) 112 | 113 | # How to suggest a feature or enhancement 114 | 115 | If you want to suggest a feature it's as easy as filling out this [issue template](https://github.com/bebop/ark/issues/new?assignees=&labels=&template=feature_request.md&title=), but before you do please [check to see if it's already been suggested!](https://github.com/bebop/ark/labels/enhancement) 116 | 117 | # How add a recommended VSCode Plugin 118 | 119 | ark comes with a set of recommended plugins for VSCode. If you have suggestions that will simplify life for the ark dev community, consider doing a pull-request after modifying `.vscode/extensions.json`. 120 | 121 | # In closing 122 | 123 | Thanks, for reading and I'm super psyched to see what you'll do with ark! 124 | -------------------------------------------------------------------------------- /pkg/rhea/rdf.go: -------------------------------------------------------------------------------- 1 | package rhea 2 | 3 | import ( 4 | "encoding/xml" 5 | ) 6 | 7 | /****************************************************************************** 8 | 9 | Lower level structs 10 | 11 | These structs operate at the lowest level to parse the Rhea Rdf database dump 12 | into structs that Golang can understand. Getting all of Rhea from Rdf->Golang 13 | is quite verbose, and so most of the time you should not use these structs unless 14 | you know what you are doing and it cannot be accomplished with higher level structs. 15 | 16 | ******************************************************************************/ 17 | 18 | // Rdf is the RDF XML representation of the Rhea database. 19 | type Rdf struct { 20 | XMLName xml.Name `xml:"RDF"` 21 | Descriptions []Description `xml:"Description"` 22 | } 23 | 24 | // Description is the XML representation of an object in the Rhea database. 25 | type Description struct { 26 | // Reaction 27 | XMLName xml.Name `xml:"Description"` 28 | About string `xml:"about,attr"` 29 | ID int `xml:"id"` 30 | Accession string `xml:"accession"` // Accession refers to a Rhea accession number 31 | Equation string `xml:"equation"` 32 | HTMLEquation string `xml:"htmlEquation"` 33 | IsChemicallyBalanced bool `xml:"isChemicallyBalanced"` 34 | IsTransport bool `xml:"isTransport"` 35 | Citations []Citation `xml:"citation"` 36 | Substrates []Substrate `xml:"substrates"` 37 | Products []Product `xml:"products"` 38 | SubstrateOrProducts []SubstrateOrProduct `xml:"substratesOrProducts"` 39 | Subclass []Subclass `xml:"subClassOf"` 40 | Comment string `xml:"comment"` 41 | EC EC `xml:"ec"` 42 | Status Status `xml:"status"` 43 | Compound CompoundXML `xml:"compound"` 44 | 45 | // ReactionSide / Reaction Participant 46 | BidirectionalReactions []BidirectionalReaction `xml:"bidirectionalReaction"` 47 | DirectionalReactions []DirectionalReaction `xml:"directionalReaction"` 48 | Side Side `xml:"side"` 49 | SeeAlsos SeeAlso `xml:"seeAlso"` 50 | TransformableTo TransformableTo `xml:"transformableTo"` 51 | CuratedOrder int `xml:"curatedOrder"` 52 | Contains Contains `xml:"contains"` 53 | 54 | // ContainsX contains all other name-attribute pairs, with names like "contains1" in mind 55 | ContainsX []ContainsX `xml:",any"` 56 | 57 | // Small Molecule tags 58 | Name string `xml:"name"` 59 | HTMLName string `xml:"htmlName"` 60 | Formula string `xml:"formula"` 61 | Charge string `xml:"charge"` 62 | ChEBI ChEBIXML `xml:"chebi"` 63 | 64 | // Generic Compound 65 | ReactivePartXML ReactivePartXML `xml:"reactivePart"` 66 | 67 | // ReactivePart 68 | Position string `xml:"position"` 69 | 70 | // Polymer 71 | UnderlyingChEBI UnderlyingChEBI `xml:"underlyingChEBI"` 72 | PolymerizationIndex string `xml:"polymerizationIndex"` 73 | 74 | // Transport 75 | Location Location `xml:"location"` 76 | } 77 | 78 | // CitationStrings gives a list of citation strings from a description. 79 | func (d *Description) CitationStrings() []string { 80 | var output []string 81 | for _, x := range d.Citations { 82 | output = append(output, x.Resource) 83 | } 84 | return output 85 | } 86 | 87 | // SubstrateAccessionIDs gives a list of substrate accessions from a description. 88 | func (d *Description) SubstrateAccessionIDs() []string { 89 | var output []string 90 | for _, x := range d.Substrates { 91 | output = append(output, x.Resource) 92 | } 93 | return output 94 | } 95 | 96 | // ProductAccessionIDs gives a list of product accessions from a description. 97 | func (d *Description) ProductAccessionIDs() []string { 98 | var output []string 99 | for _, x := range d.Products { 100 | output = append(output, x.Resource) 101 | } 102 | return output 103 | } 104 | 105 | // SubstrateOrProductAccessionIDs gives a list of substrateOrProduct accessions from a description. 106 | func (d *Description) SubstrateOrProductAccessionIDs() []string { 107 | var output []string 108 | for _, x := range d.SubstrateOrProducts { 109 | output = append(output, x.Resource) 110 | } 111 | return output 112 | } 113 | 114 | // Citation is an XML representation of a citation of a description. 115 | type Citation struct { 116 | XMLName xml.Name `xml:"citation"` 117 | Resource string `xml:"resource,attr"` 118 | } 119 | 120 | // Substrate is an XML representation of a substrate. 121 | type Substrate struct { 122 | XMLName xml.Name `xml:"substrates"` 123 | Resource string `xml:"resource,attr"` 124 | } 125 | 126 | // Product is an XML representation of a product. 127 | type Product struct { 128 | XMLName xml.Name `xml:"products"` 129 | Resource string `xml:"resource,attr"` 130 | } 131 | 132 | // SubstrateOrProduct is an XML representation of a SubstrateOrProduct. 133 | type SubstrateOrProduct struct { 134 | XMLName xml.Name `xml:"substratesOrProducts"` 135 | Resource string `xml:"resource,attr"` 136 | } 137 | 138 | // Subclass is an XML representation of a subclass, which can mean many different things in Rhea. 139 | type Subclass struct { 140 | XMLName xml.Name `xml:"subClassOf"` 141 | Resource string `xml:"resource,attr"` 142 | } 143 | 144 | // EC is an XML representation of an EC number (Enzyme Commission Number) of a description. 145 | type EC struct { 146 | XMLName xml.Name `xml:"ec"` 147 | Resource string `xml:"resource,attr"` 148 | } 149 | 150 | // Status is an XML representation of the current status of an description. 151 | type Status struct { 152 | XMLName xml.Name `xml:"status"` 153 | Resource string `xml:"resource,attr"` 154 | } 155 | 156 | // CompoundXML is an XML representation of a compound. 157 | type CompoundXML struct { 158 | XMLName xml.Name `xml:"compound"` 159 | Resource string `xml:"resource,attr"` 160 | } 161 | 162 | // BidirectionalReaction is an XML representation of a Rhea bidirectional reaction. 163 | type BidirectionalReaction struct { 164 | XMLName xml.Name `xml:"bidirectionalReaction"` 165 | Resource string `xml:"resource,attr"` 166 | } 167 | 168 | // DirectionalReaction is an XML representation of a Rhea directional reaction. 169 | type DirectionalReaction struct { 170 | XMLName xml.Name `xml:"directionalReaction"` 171 | Resource string `xml:"resource,attr"` 172 | } 173 | 174 | // Side is an XML representation of a Rhea ReactionSide. 175 | type Side struct { 176 | XMLName xml.Name `xml:"side"` 177 | Resource string `xml:"resource,attr"` 178 | } 179 | 180 | // SeeAlso is an XML representation of a SeeAlso XML in a description. 181 | type SeeAlso struct { 182 | XMLName xml.Name `xml:"seeAlso"` 183 | Resource string `xml:"resource,attr"` 184 | } 185 | 186 | // TransformableTo is an XML representation of a transformableTo in a description. This essentially links two ReactionSides in Rhea. 187 | type TransformableTo struct { 188 | XMLName xml.Name `xml:"transformableTo"` 189 | Resource string `xml:"resource,attr"` 190 | } 191 | 192 | // Contains is an XML representation of what Compound a ReactionParticipant contains. 193 | type Contains struct { 194 | XMLName xml.Name `xml:"contains"` 195 | Resource string `xml:"resource,attr"` 196 | } 197 | 198 | // ContainsX is a catch-all XML representation of how many compounds a ReactionParticipant would use. 199 | type ContainsX struct { 200 | XMLName xml.Name 201 | Content string `xml:"resource,attr"` 202 | } 203 | 204 | // ChEBIXML is an XML representation of a ChEBI. 205 | type ChEBIXML struct { 206 | XMLName xml.Name `xml:"chebi"` 207 | Resource string `xml:"resource,attr"` 208 | } 209 | 210 | // UnderlyingChEBI is an XML representation of ChEBI that builds a Polymer. 211 | type UnderlyingChEBI struct { 212 | XMLName xml.Name `xml:"underlyingChEBI"` 213 | Resource string `xml:"resource,attr"` 214 | } 215 | 216 | // ReactivePartXML is an XML representation of a ReactivePart. 217 | type ReactivePartXML struct { 218 | XMLName xml.Name `xml:"reactivePart"` 219 | Resource string `xml:"resource,attr"` 220 | } 221 | 222 | // Location is an XML representation of Locations in a cell, usually referring to transport enzymes. 223 | type Location struct { 224 | XMLName xml.Name `xml:"location"` 225 | Resource string `xml:"resource,attr"` 226 | } 227 | -------------------------------------------------------------------------------- /pkg/rhea/rhea.go: -------------------------------------------------------------------------------- 1 | package rhea 2 | 3 | import ( 4 | "bufio" 5 | "compress/gzip" 6 | "encoding/json" 7 | "encoding/xml" 8 | "errors" 9 | "io" 10 | "io/ioutil" 11 | "os" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | /****************************************************************************** 17 | 18 | Higher level structs 19 | 20 | These structs are what you would put into a database or directly use. In order to 21 | create a tree or insert into a normalized database, you would insert in the following 22 | order: 23 | 24 | - Compound 25 | - ReactionSide 26 | - ReactionParticipant 27 | - Reaction 28 | - ReactionSide <-> Reaction 29 | 30 | The entire structure of Rhea can simply be thought of as: 31 | 32 | 1 There are Reactions. Those Reactions can have substrates and products, or substratesOrProducts 33 | in the case that the reaction is bidirectional. 34 | 2 There are ReactionSides. ReactionSides can be thought of as a many-to-many table between Reactions 35 | and ReactionParticipants. It only serves as an in between, saying "this Reaction has these 36 | ReactionParticipants on this side". 37 | 3 There are ReactionParticipants. ReactionParticipants link ReactionSides with ReactiveParts and include 38 | useful information like the number of ReactiveParts/Compounds (or chemicals) needed to do a certain Reaction. 39 | 4 There are Compounds. These are chemicals. Sometimes they're complicated chemicals (like proteins) that 40 | have ReactionSides, or portions of the larger chemical that are actually active in the reaction, though often 41 | they're just small molecules. 42 | 43 | With the "->" representing a "Reaction", and the right and left []ReactionParticipant each representing a "ReactionSide", 44 | the entire Rhea database is basically a series of: 45 | 46 | []ReactionParticipant -> []ReactionParticipant 47 | 48 | ******************************************************************************/ 49 | 50 | // Rhea is a struct of the entire Rhea Database in a simplified higher-level way. 51 | type Rhea struct { 52 | ReactionParticipants []ReactionParticipant `json:"reactionParticipants"` 53 | Compounds []Compound `json:"compounds"` 54 | Reactions []Reaction `json:"reactions"` 55 | } 56 | 57 | // Compound is a struct of a Rhea compound. These are chemicals - sometimes they are 58 | // complicated chemicals like proteins or polymers, but often they are simple molecules. 59 | // When Compounds are complicated molecules, like proteins, they can have reactiveParts 60 | // that actually do the reactions. Compound, as defined here, is a pair containing a 61 | // macro-molecule and a reactivePart. When building into a database, you will have to 62 | // split this pairing for normalization. 63 | type Compound struct { 64 | ID int `json:"id" db:"id"` 65 | Accession string `json:"accession" db:"accession"` 66 | Position string `json:"position" db:"position"` 67 | Name string `json:"name" db:"name"` 68 | HTMLName string `json:"htmlName" db:"htmlname"` 69 | Formula string `json:"formula" db:"formula"` 70 | Charge string `json:"charge" db:"charge"` 71 | ChEBI string `json:"chebi" db:"chebi"` 72 | SubclassOfChEBI string `json:"subclassOfChEBI"` 73 | PolymerizationIndex string `json:"polymerizationIndex" db:"polymerizationindex"` 74 | CompoundID int `json:"compoundid" db:"compoundid"` 75 | CompoundAccession string `json:"compoundaccession" db:"compoundaccession"` 76 | CompoundName string `json:"compoundname" db:"compoundname"` 77 | CompoundHTMLName string `json:"compoundhtmlName" db:"compoundhtmlname"` 78 | CompoundType string `json:"compoundType" db:"compoundtype"` 79 | } 80 | 81 | // ReactionParticipant represents a Rhea ReactionParticipant. ReactionParticipants represent Compounds in Reactions. They 82 | // can contain many of the same Compounds (including polymerized configurations) and are associated with a ReactionSide. 83 | type ReactionParticipant struct { 84 | ReactionSide string `json:"reactionside" db:"reactionside"` 85 | Contains int `json:"contains" db:"contains"` 86 | ContainsN bool `json:"containsn" db:"containsn"` 87 | Minus bool `json:"minus" db:"minus"` // Only set to true if ContainsN == true to handle Nminus1 88 | Plus bool `json:"plus" db:"plus"` // Only set to true if ContainsN == true to handle Nplus1 89 | Accession string `json:"reactionParticipant" db:"ReactionParticipant"` 90 | Compound string `json:"compound" db:"compound"` 91 | } 92 | 93 | // Reaction represents a Rhea reaction. Substrates, Products, and SubstrateOrProducts are all ReactionSide accession 94 | // numbers, which can be linked to the ReactionParticipant's ReactionSide accession 95 | type Reaction struct { 96 | ID int `json:"id" db:"id"` 97 | Directional bool `json:"directional" db:"directional"` 98 | Accession string `json:"accession" db:"accession"` 99 | Status string `json:"status" db:"status"` 100 | Comment string `json:"comment" db:"comment"` 101 | Equation string `json:"equation" db:"equation"` 102 | HTMLEquation string `json:"htmlequation" db:"htmlequation"` 103 | IsChemicallyBalanced bool `json:"ischemicallybalanced" db:"ischemicallybalanced"` 104 | IsTransport bool `json:"istransport" db:"istransport"` 105 | Ec string `json:"ec" db:"ec"` 106 | Location string `json:"location" db:"location"` 107 | Citations []string `json:"citations"` 108 | Substrates []string `json:"substrates"` 109 | Products []string `json:"products"` 110 | SubstrateOrProducts []string `json:"substrateOrProducts"` 111 | } 112 | 113 | /****************************************************************************** 114 | 115 | Parse functions 116 | 117 | These functions take in the rhea.rdf.gz dump file and return a Rhea struct, 118 | which contains all of the higher level structs 119 | 120 | ******************************************************************************/ 121 | 122 | // NewReaction returns a Reaction. 123 | func NewReaction(description Description, subclass Subclass) Reaction { 124 | return Reaction{ 125 | ID: description.ID, 126 | Directional: subclass.Resource == "http://rdf.rhea-db.org/DirectionalReaction", 127 | Accession: description.Accession, 128 | Status: description.Status.Resource, 129 | Comment: description.Comment, 130 | Equation: description.Equation, 131 | HTMLEquation: description.HTMLEquation, 132 | IsChemicallyBalanced: description.IsChemicallyBalanced, 133 | IsTransport: description.IsTransport, 134 | Ec: description.EC.Resource, 135 | Citations: description.CitationStrings(), 136 | Substrates: description.SubstrateAccessionIDs(), 137 | Products: description.ProductAccessionIDs(), 138 | SubstrateOrProducts: description.SubstrateOrProductAccessionIDs(), 139 | Location: description.Location.Resource} 140 | } 141 | 142 | // NewCompound returns a Compound. 143 | func NewCompound(description Description, subclass Subclass) Compound { 144 | var newCompound Compound 145 | compoundType := subclass.Resource[23:] 146 | switch subclass.Resource { 147 | case "http://rdf.rhea-db.org/SmallMolecule", "http://rdf.rhea-db.org/Polymer": 148 | newCompound = Compound{ 149 | ID: description.ID, 150 | Accession: description.About, 151 | Position: description.Position, 152 | Name: description.Name, 153 | HTMLName: description.HTMLName, 154 | Formula: description.Formula, 155 | Charge: description.Charge, 156 | ChEBI: description.ChEBI.Resource, 157 | 158 | CompoundID: description.ID, 159 | CompoundAccession: description.Accession, 160 | CompoundName: description.Name, 161 | CompoundHTMLName: description.HTMLName, 162 | CompoundType: compoundType} 163 | if compoundType == "Polymer" { 164 | newCompound.ChEBI = description.UnderlyingChEBI.Resource 165 | } 166 | // Add subclass ChEBI 167 | for _, sc := range description.Subclass { 168 | if strings.Contains(sc.Resource, "CHEBI") { 169 | newCompound.SubclassOfChEBI = sc.Resource 170 | } 171 | } 172 | case "http://rdf.rhea-db.org/GenericPolypeptide", "http://rdf.rhea-db.org/GenericPolynucleotide", "http://rdf.rhea-db.org/GenericHeteropolysaccharide": 173 | newCompound = Compound{ 174 | Accession: description.About, 175 | CompoundID: description.ID, 176 | CompoundName: description.Name, 177 | CompoundHTMLName: description.HTMLName, 178 | CompoundType: compoundType} 179 | } 180 | return newCompound 181 | } 182 | 183 | // NewReactionParticipant returns a ReactionParticipant. 184 | func NewReactionParticipant(description Description, containsx ContainsX, compoundParticipantMap map[string]string) (ReactionParticipant, error) { 185 | // Get reaction sides 186 | // gzip -d -k -c rhea.rdf.gz | grep -o -P '(?<=contains).*(?= rdf)' | tr ' ' '\n' | sort -u | tr '\n' ' ' 187 | // The exceptions to numeric contains are 2n, N, Nminus1, and Nplus1 188 | var newReactionParticipant ReactionParticipant 189 | switch containsx.XMLName.Local { 190 | case "containsN": 191 | newReactionParticipant = ReactionParticipant{ 192 | ReactionSide: description.About, 193 | Contains: 1, 194 | ContainsN: true, 195 | Minus: false, 196 | Plus: false, 197 | Accession: containsx.Content} 198 | case "contains2n": 199 | newReactionParticipant = ReactionParticipant{ 200 | ReactionSide: description.About, 201 | Contains: 2, 202 | ContainsN: true, 203 | Minus: false, 204 | Plus: false, 205 | Accession: containsx.Content} 206 | case "containsNminus1": 207 | newReactionParticipant = ReactionParticipant{ 208 | ReactionSide: description.About, 209 | Contains: 1, 210 | ContainsN: true, 211 | Minus: true, 212 | Plus: false, 213 | Accession: containsx.Content} 214 | case "containsNplus1": 215 | newReactionParticipant = ReactionParticipant{ 216 | ReactionSide: description.About, 217 | Contains: 1, 218 | ContainsN: true, 219 | Minus: false, 220 | Plus: true, 221 | Accession: containsx.Content} 222 | default: 223 | i, err := strconv.Atoi(containsx.XMLName.Local[8:]) 224 | if err != nil { 225 | return ReactionParticipant{}, err 226 | } 227 | newReactionParticipant = ReactionParticipant{ 228 | ReactionSide: description.About, 229 | Contains: i, 230 | ContainsN: false, 231 | Minus: false, 232 | Plus: false, 233 | Accession: containsx.Content} 234 | } 235 | newReactionParticipant.Compound = compoundParticipantMap[description.Contains.Resource] 236 | return newReactionParticipant, nil 237 | } 238 | 239 | // Parse parses a list of bytes into a higher-level Rhea Struct. 240 | func Parse(rheaBytes []byte) (Rhea, error) { 241 | var err error 242 | // Read rheaBytes into a Rdf object 243 | var rdf Rdf 244 | err = xml.Unmarshal(rheaBytes, &rdf) 245 | if err != nil { 246 | return Rhea{}, err 247 | } 248 | 249 | // Initialize Rhea 250 | var rhea Rhea 251 | compoundParticipantMap := make(map[string]string) 252 | compoundMap := make(map[string]Compound) 253 | 254 | for _, description := range rdf.Descriptions { 255 | // Handle the case of a single compound -> reactive part, such as 256 | // 257 | // 258 | // 259 | if (len(description.Subclass) == 0) && (description.ReactivePartXML.Resource != "") { 260 | compoundParticipantMap[description.ReactivePartXML.Resource] = description.About 261 | } 262 | if description.Compound.Resource != "" { 263 | compoundParticipantMap[description.About] = description.Compound.Resource 264 | } 265 | 266 | for _, subclass := range description.Subclass { 267 | switch subclass.Resource { 268 | case "http://rdf.rhea-db.org/BidirectionalReaction", "http://rdf.rhea-db.org/DirectionalReaction": 269 | newReaction := NewReaction(description, subclass) 270 | rhea.Reactions = append(rhea.Reactions, newReaction) 271 | case "http://rdf.rhea-db.org/SmallMolecule", "http://rdf.rhea-db.org/Polymer": 272 | newCompound := NewCompound(description, subclass) 273 | rhea.Compounds = append(rhea.Compounds, newCompound) 274 | case "http://rdf.rhea-db.org/GenericPolypeptide", "http://rdf.rhea-db.org/GenericPolynucleotide", "http://rdf.rhea-db.org/GenericHeteropolysaccharide": 275 | newCompound := NewCompound(description, subclass) 276 | compoundMap[description.About] = newCompound 277 | compoundParticipantMap[description.ReactivePartXML.Resource] = description.About 278 | } 279 | } 280 | } 281 | 282 | // Go back and get the ReactiveParts 283 | for _, description := range rdf.Descriptions { 284 | for _, subclass := range description.Subclass { 285 | if subclass.Resource == "http://rdf.rhea-db.org/ReactivePart" { 286 | newCompound, ok := compoundMap[compoundParticipantMap[description.About]] 287 | if !ok { 288 | return Rhea{}, errors.New("Could not find " + description.About) 289 | } 290 | newCompound.ID = description.ID 291 | newCompound.CompoundAccession = description.About 292 | newCompound.Position = description.Position 293 | newCompound.Name = description.Name 294 | newCompound.HTMLName = description.HTMLName 295 | newCompound.Formula = description.Formula 296 | newCompound.Charge = description.Charge 297 | newCompound.ChEBI = description.ChEBI.Resource 298 | rhea.Compounds = append(rhea.Compounds, newCompound) 299 | } 300 | } 301 | for _, containsx := range description.ContainsX { 302 | if !strings.Contains(containsx.XMLName.Local, "contains") { 303 | continue 304 | } 305 | newReactionParticipant, err := NewReactionParticipant(description, containsx, compoundParticipantMap) 306 | if err != nil { 307 | return Rhea{}, err 308 | } 309 | rhea.ReactionParticipants = append(rhea.ReactionParticipants, newReactionParticipant) 310 | } 311 | } 312 | return rhea, nil 313 | } 314 | 315 | // ReadGzippedXml reads in a a gzip'd Rhea dump (https://www.rhea-db.org/help/download) into bytes. 316 | func ReadGzippedXml(gzipPath string) ([]byte, error) { 317 | // Get gz'd file bytes 318 | xmlFile, err := os.Open(gzipPath) 319 | if err != nil { 320 | return []byte{}, err 321 | } 322 | 323 | // Decompress gz'd file 324 | r, err := gzip.NewReader(xmlFile) 325 | if err != nil { 326 | return []byte{}, err 327 | } 328 | 329 | // Read decompressed gz'd file 330 | rheaBytes, err := ioutil.ReadAll(r) 331 | if err != nil { 332 | return []byte{}, err 333 | } 334 | return rheaBytes, nil 335 | } 336 | 337 | // Read reads in a gzip'd Rhea dump and converts it into a higher-level 338 | // rhea struct. 339 | func Read(path string) (Rhea, error) { 340 | // Read the Compressed Rhea XML to bytes 341 | var rhea Rhea 342 | rheaBytes, err := ReadGzippedXml(path) 343 | if err != nil { 344 | return rhea, err 345 | } 346 | 347 | // Parse the Rhea bytes into the rhea struct 348 | rhea, err = Parse(rheaBytes) 349 | if err != nil { 350 | return rhea, err 351 | } 352 | return rhea, nil 353 | } 354 | 355 | /****************************************************************************** 356 | 357 | JSON functions 358 | 359 | These functions simply export the Rhea database as a JSON file for consumption 360 | in different programs. 361 | 362 | ******************************************************************************/ 363 | 364 | // ExportJSON exports Rhea as a JSON file 365 | func (rhea *Rhea) ExportJSON() ([]byte, error) { 366 | rheaJSON, err := json.Marshal(rhea) 367 | if err != nil { 368 | return []byte{}, err 369 | } 370 | return rheaJSON, nil 371 | } 372 | 373 | /****************************************************************************** 374 | 375 | RheaToUniprot tsv 376 | 377 | Rhea conveniently provides a TSV list of reaction IDs to Uniprot accession numbers. 378 | These can be used to map Rhea reactions to protein sequences, which is very useful 379 | for actually building synthetic circuits. While these parsers are very basic TSV 380 | parsing, they are convenient to use with the rhea2uniprot data dumps specifically. 381 | 382 | The sprot and trembl data dumps are available at: 383 | https://ftp.expasy.org/databases/rhea/tsv/rhea2uniprot_sprot.tsv 384 | https://ftp.expasy.org/databases/rhea/tsv/rhea2uniprot_trembl.tsv.gz 385 | 386 | The decompressed gzip side of the rhea2uniprot_trembl.tsv.gz file, as of Apr 30, 2021 387 | is 678M. Because it is fairly large, the parser is implemented to stream in the file, 388 | passing the parsed lines into a channel, to save on memory. 389 | 390 | The TSV is structured like: 391 | 392 | ` 393 | RHEA_ID DIRECTION MASTER_ID ID 394 | 10008 UN 10008 O17433 395 | 10008 UN 10008 O34564 396 | ... 397 | ` 398 | 399 | ******************************************************************************/ 400 | 401 | // RheaToUniprot represents a single line of the TSV file. 402 | type RheaToUniprot struct { 403 | RheaID int 404 | Direction string 405 | MasterID int 406 | UniprotID string 407 | } 408 | 409 | // ParseRheaToUniprotTsv parses a rhea2uniprot TSV file and sends values to a channel. 410 | func ParseRheaToUniprotTsv(r io.Reader, lines chan<- RheaToUniprot) { 411 | start := true 412 | scanner := bufio.NewScanner(r) 413 | for scanner.Scan() { 414 | // We skip the header line 415 | if start { 416 | start = false 417 | continue 418 | } 419 | 420 | // Get the line from the scanner 421 | line := scanner.Text() 422 | 423 | // Split the line between tabs 424 | lineSplit := strings.Split(line, "\t") 425 | 426 | // Send line to lines channel 427 | rheaId, err := strconv.Atoi(lineSplit[0]) 428 | if err != nil { 429 | panic(err) 430 | } 431 | masterId, err := strconv.Atoi(lineSplit[2]) 432 | if err != nil { 433 | panic(err) 434 | } 435 | lines <- RheaToUniprot{RheaID: rheaId, Direction: lineSplit[1], MasterID: masterId, UniprotID: lineSplit[3]} 436 | } 437 | close(lines) 438 | } 439 | 440 | // ReadRheaToUniprotSprot reads in the rhea2uniprot sprot TSV file (not gzipped) and sends values into a channel. 441 | func ReadRheaToUniprotSprot(path string, lines chan RheaToUniprot) { 442 | file, _ := os.Open(path) 443 | go ParseRheaToUniprotTsv(file, lines) 444 | } 445 | 446 | // ReadRheaToUniprotTrembl reads in the rhea2uniprot trembl TSV file (gzipped) and sends values into channel. 447 | func ReadRheaToUniprotTrembl(path string, lines chan RheaToUniprot) { 448 | file, _ := os.Open(path) 449 | r, _ := gzip.NewReader(file) 450 | go ParseRheaToUniprotTsv(r, lines) 451 | } 452 | -------------------------------------------------------------------------------- /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/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 42 | github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= 43 | github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= 44 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 45 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 46 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= 47 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 48 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 49 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 50 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 51 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 52 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 53 | github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 54 | github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= 55 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 56 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 57 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 58 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 59 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 60 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 61 | github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= 62 | github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= 63 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 64 | github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= 65 | github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= 66 | github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= 67 | github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= 68 | github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= 69 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 70 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 71 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= 72 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 73 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 74 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 75 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 76 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 77 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 78 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 79 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 80 | github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= 81 | github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= 82 | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= 83 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 84 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 85 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 86 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 87 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 88 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 89 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 90 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 91 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 92 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 93 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 94 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 95 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 96 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 97 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 98 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 99 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 100 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 101 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 102 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 103 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 104 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 105 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 106 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 107 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 108 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 109 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 110 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 111 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 112 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 113 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 114 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 115 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 116 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 117 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 118 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 119 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 120 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 121 | github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 122 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 123 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 124 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 125 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 126 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 127 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 128 | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 129 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 130 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 131 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 132 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 133 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 134 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 135 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 136 | github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 137 | github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 138 | github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= 139 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 140 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 141 | github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= 142 | github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 143 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 144 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 145 | github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 146 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 147 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 148 | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 149 | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= 150 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 151 | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 152 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 153 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 154 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= 155 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 156 | github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= 157 | github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= 158 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 159 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 160 | github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= 161 | github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 162 | github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w= 163 | github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= 164 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 165 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 166 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 167 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 168 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 169 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 170 | github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= 171 | github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 172 | github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= 173 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 174 | github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 175 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 176 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 177 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 178 | github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= 179 | github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= 180 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 181 | github.com/lib/pq v1.2.1-0.20191011153232-f91d3411e481 h1:r9fnMM01mkhtfe6QfLrr/90mBVLnJHge2jGeBvApOjk= 182 | github.com/lib/pq v1.2.1-0.20191011153232-f91d3411e481/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 183 | github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= 184 | github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 185 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= 186 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 187 | github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 188 | github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= 189 | github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 190 | github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= 191 | github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 192 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 193 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 194 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 195 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 196 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 197 | github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= 198 | github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= 199 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 200 | github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= 201 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 202 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 203 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 204 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 205 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 206 | github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= 207 | github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= 208 | github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= 209 | github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= 210 | github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= 211 | github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= 212 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 213 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 214 | github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= 215 | github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= 216 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 217 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 218 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 219 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 220 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 221 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 222 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 223 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 224 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 225 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 226 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 227 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 228 | github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= 229 | github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 230 | github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= 231 | github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= 232 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 233 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 234 | github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= 235 | github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 236 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 237 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 238 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 239 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 240 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 241 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 242 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 243 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 244 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 245 | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= 246 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 247 | golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= 248 | golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 249 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 250 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 251 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 252 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 253 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 254 | golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= 255 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 256 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= 257 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 258 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 259 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 260 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 261 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 262 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 263 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 264 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 265 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 266 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 267 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 268 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 269 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 270 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 271 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 272 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 273 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 274 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 275 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 276 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 277 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 278 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 279 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 280 | golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 281 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 282 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 283 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 284 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 285 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 286 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 287 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 288 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 289 | golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 290 | golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 291 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 292 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 293 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 294 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 295 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 296 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 297 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 298 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 299 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 300 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 301 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 302 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 303 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 304 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 305 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 306 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 307 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 308 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 309 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 310 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 311 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 312 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 313 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 314 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 315 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 316 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 317 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 318 | golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 319 | golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 320 | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 321 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 322 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 323 | golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= 324 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 325 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 326 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 327 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 328 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 329 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 330 | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 331 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 332 | golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 333 | golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 334 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 335 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 336 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 337 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 338 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 339 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 340 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 341 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 342 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 343 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 344 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 345 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 346 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 347 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 348 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 349 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 350 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 351 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 352 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 353 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 354 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 355 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 356 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 357 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 358 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 359 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 360 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 361 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 362 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 363 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 364 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 365 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 366 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 367 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 368 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 369 | golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 370 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 371 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 372 | golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 373 | golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 374 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 375 | golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 376 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 377 | golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 378 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 379 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 380 | golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 381 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 382 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 383 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 384 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 385 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 386 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 387 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 388 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 389 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 390 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 391 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 392 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 393 | golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= 394 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 395 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 396 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 397 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 398 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 399 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 400 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 401 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 402 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 403 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 404 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 405 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 406 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 407 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 408 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 409 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 410 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 411 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 412 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 413 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 414 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 415 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 416 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 417 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 418 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 419 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 420 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 421 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 422 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 423 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 424 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 425 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 426 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 427 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 428 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 429 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 430 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 431 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 432 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 433 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 434 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 435 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 436 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 437 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 438 | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= 439 | golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 440 | golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 441 | golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 442 | golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 443 | golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 444 | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= 445 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 446 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 447 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 448 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 449 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 450 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 451 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 452 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 453 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 454 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 455 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 456 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 457 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 458 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 459 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 460 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 461 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 462 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 463 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 464 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 465 | google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= 466 | google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= 467 | google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= 468 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 469 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 470 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 471 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 472 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 473 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 474 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 475 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 476 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 477 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 478 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 479 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 480 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 481 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 482 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 483 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 484 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 485 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 486 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 487 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 488 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 489 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 490 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 491 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 492 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 493 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 494 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 495 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 496 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 497 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 498 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 499 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 500 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 501 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 502 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 503 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 504 | google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 505 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 506 | google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 507 | google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 508 | google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 509 | google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 510 | google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 511 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 512 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 513 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 514 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 515 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 516 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 517 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 518 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 519 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 520 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 521 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 522 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 523 | google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 524 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 525 | google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= 526 | google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= 527 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 528 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 529 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 530 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 531 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 532 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 533 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 534 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 535 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 536 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 537 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 538 | google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= 539 | google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 540 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 541 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 542 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 543 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 544 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 545 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 546 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 547 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 548 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 549 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 550 | gorm.io/driver/postgres v1.5.2 h1:ytTDxxEv+MplXOfFe3Lzm7SjG09fcdb3Z/c056DTBx0= 551 | gorm.io/driver/postgres v1.5.2/go.mod h1:fmpX0m2I1PKuR7mKZiEluwrP3hbs+ps7JIGMUBpCgl8= 552 | gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= 553 | gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= 554 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 555 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 556 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 557 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 558 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 559 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 560 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 561 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 562 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 563 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 564 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 565 | --------------------------------------------------------------------------------