├── .gitignore ├── .golangci.yml ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── Makefile ├── README.md ├── api ├── Dockerfile ├── cmd │ ├── cli │ │ ├── cli.go │ │ └── landscape.json │ └── server │ │ ├── .env.example │ │ └── server.go ├── internal │ ├── config │ │ └── config.go │ └── ctx │ │ └── ctx.go └── pkg │ ├── database │ └── database.go │ ├── game │ ├── game.go │ └── game_test.go │ ├── main.go │ ├── processor │ ├── javascript.json │ ├── landscape-complete.json │ ├── landscape.json │ └── processor.go │ └── server │ ├── middleware.go │ ├── routes.go │ └── server.go ├── docker-compose-db.yml ├── docker-compose.yml ├── go.mod ├── go.sum └── web ├── .dockerignore ├── .env.example ├── .eslintignore ├── .eslintrc.cjs ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── Dockerfile ├── README.md ├── nginx ├── nginx.conf └── ui.conf ├── package-lock.json ├── package.json ├── postcss.config.cjs ├── src ├── app.css ├── app.d.ts ├── app.html ├── components │ ├── Button.svelte │ ├── Code.svelte │ ├── Modal.svelte │ └── Question.svelte ├── lib │ ├── results.ts │ └── store.ts ├── routes │ ├── +error.svelte │ ├── +layout.svelte │ ├── +page.svelte │ ├── history │ │ └── +page.svelte │ ├── quiz │ │ └── +page.svelte │ └── result │ │ └── +page.svelte └── types │ ├── history.type.ts │ ├── quiz.type.ts │ └── result.type.ts ├── static └── favicon.png ├── svelte.config.js ├── tailwind.config.cjs ├── tsconfig.json └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | api.bin 3 | notes -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | timeout: 3m 3 | skip-dirs: 4 | - internal/cache 5 | 6 | linters-settings: 7 | depguard: 8 | list-type: blacklist 9 | packages: 10 | # logging is allowed zerolog only 11 | # is allowed to use only package 12 | - log 13 | packages-with-error-message: 14 | - log: "logging is allowed only by github.com/rs/zerolog" 15 | dupl: 16 | threshold: 100 17 | forbidigo: 18 | exclude_godoc_examples: true 19 | funlen: 20 | lines: 100 21 | statements: 50 22 | gci: 23 | local-prefixes: github.com/golangci/golangci-lint 24 | goconst: 25 | min-len: 2 26 | min-occurrences: 2 27 | gocritic: 28 | enabled-tags: 29 | - diagnostic 30 | - experimental 31 | - opinionated 32 | - performance 33 | - style 34 | disabled-checks: 35 | - dupImport # https://github.com/go-critic/go-critic/issues/845 36 | - ifElseChain 37 | - octalLiteral 38 | - whyNoLint 39 | - wrapperFunc 40 | gocognit: 41 | min-complexity: 20 42 | gocyclo: 43 | min-complexity: 15 44 | goimports: 45 | local-prefixes: github.com/golangci/golangci-lint,github.com/dyrector-io/dyrectorio 46 | gomnd: 47 | checks: 48 | - argument 49 | - case 50 | - condition 51 | - return 52 | govet: 53 | check-shadowing: true 54 | lll: 55 | line-length: 140 56 | maligned: 57 | suggest-new: true 58 | misspell: 59 | locale: US 60 | nolintlint: 61 | allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) 62 | allow-unused: false # report any unused nolint directives 63 | require-explanation: false # don't require an explanation for nolint directives 64 | require-specific: false # don't require nolint directives to be specific about which linter is being skipped 65 | tenv: 66 | all: true 67 | staticcheck: 68 | go: "1.18" 69 | checks: 70 | - all 71 | 72 | 73 | linters: 74 | # please, do not use `enable-all`: it's deprecated and will be removed soon. 75 | # inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint 76 | disable-all: true 77 | enable: 78 | - asciicheck 79 | - bodyclose 80 | # todo(nandor-magyar): refactor golang code to comply 81 | # - containedctx 82 | - depguard 83 | - dogsled 84 | - durationcheck 85 | - dupl 86 | - errcheck 87 | - errname 88 | - exportloopref 89 | - exhaustive 90 | - funlen 91 | - gochecknoinits 92 | - goconst 93 | - gocritic 94 | - gocyclo 95 | - gofumpt 96 | - goimports 97 | - gomnd 98 | - goprintffuncname 99 | - gosec 100 | - gosimple 101 | - govet 102 | - importas 103 | - ineffassign 104 | - lll 105 | - misspell 106 | - nakedret 107 | - nilerr 108 | - noctx 109 | - nolintlint 110 | - revive 111 | - rowserrcheck 112 | - staticcheck 113 | - stylecheck 114 | - tenv 115 | - thelper 116 | - typecheck 117 | - unconvert 118 | - unparam 119 | - unused 120 | - whitespace 121 | 122 | issues: 123 | # Excluding configuration per-path, per-linter, per-text and per-source 124 | exclude-rules: 125 | - path: _test\.go 126 | linters: 127 | - gomnd 128 | 129 | 130 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch cli", 6 | "type": "go", 7 | "request": "launch", 8 | "mode": "auto", 9 | "program": "${workspaceFolder}/api/cmd/cli", 10 | "cwd": "${workspaceFolder}/api/cmd/cli" 11 | }, 12 | { 13 | "name": "Launch server", 14 | "type": "go", 15 | "request": "launch", 16 | "mode": "auto", 17 | "program": "${workspaceFolder}/api/cmd/server", 18 | "cwd": "${workspaceFolder}/api/cmd/server" 19 | }, 20 | { 21 | "name": "Debug cli", 22 | "type": "go", 23 | "request": "launch", 24 | "mode": "debug", 25 | "program": "${workspaceFolder}/api/cmd/cli", 26 | "cwd": "${workspaceFolder}/api/cmd/cli" 27 | }, 28 | { 29 | "name": "Debug server", 30 | "type": "go", 31 | "request": "launch", 32 | "buildFlags": "", 33 | "mode": "debug", 34 | "program": "${workspaceFolder}/api/cmd/server", 35 | "cwd": "${workspaceFolder}/api/cmd/server" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "gopls": { 3 | "formatting.gofumpt": true, 4 | } 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 dyrector.io 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: cli 2 | cli: 3 | cd api/cmd/cli && go run . 4 | 5 | .PHONY: server 6 | server: 7 | cd api/cmd/server && \ 8 | go run . 9 | 10 | .PHONY: ui 11 | ui: 12 | cd web && npm start 13 | 14 | .PHONY: compile 15 | compile: 16 | cd api/cmd/server && \ 17 | GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ./api.bin 18 | 19 | .PHONY: build-api 20 | build-api: compile 21 | docker-compose build api 22 | 23 | .PHONY: build-ui 24 | build-ui: 25 | docker-compose build ui 26 | 27 | .PHONY: all 28 | all: build-api build-ui 29 | docker-compose push 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XOR Quiz 2 | 3 | A game that determines your level of knowledge in specific technology areas. 4 | 5 | XOR Quiz - A game that determines your level of knowledge.  | Product Hunt 6 | 7 | ### Disclaimer 8 | 9 | This project is a side project, and a product of a half weekend, if people will find joy in it, we will put more effort into it. Both of us creating it, used a personally new framework. It was pure fun. 10 | 11 | ### Rules 12 | 13 | Every day you get the short description of 5 npm projects and you have to guess what the projects are! You have three attempts per project. 14 | 15 | Depending how many hints you use: 16 | 17 | - 🟢 You got the project right without any hints. 18 | - 🟡 You got the project right, but not on the first try. 19 | - 🔴 You didn't get the project right. 20 | - ⚪ Unanswered questions. 21 | 22 | ### Info 23 | 24 | Your data is stored client-side (browser local storage). More details [here](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage). 25 | The quiz is reset every noon (UTC) quiz starts on February 5 and runs for 15 days, ending on February 20. Have Fun and Good Luck! 🍾 26 | 27 | ⭐ **Drop a star if you want to see more like this!** 28 | 29 | ### License 30 | 31 | You can create your own quiz game using this one, as it is fully open-source with an Apache 2.0 license. 32 | -------------------------------------------------------------------------------- /api/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gcr.io/distroless/static 2 | LABEL maintainer="nandor-magyar" 3 | COPY --chown=nonroot:nonroot ./cmd/server/api.bin /api.bin 4 | ENTRYPOINT ["/api.bin"] -------------------------------------------------------------------------------- /api/cmd/cli/cli.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | 7 | "github.com/dyrector-io/xor/api/pkg/game" 8 | "github.com/dyrector-io/xor/api/pkg/processor" 9 | ) 10 | 11 | const gradingSplit = 3 12 | 13 | func printAnswer(right bool) string { 14 | if right { 15 | return "++" 16 | } 17 | return "--" 18 | } 19 | 20 | func quiz() { 21 | records := processor.ReadJSONData() 22 | 23 | qNum := 5 24 | attempts := 3 25 | 26 | indices := game.PickRandom(qNum, len(records)-1) 27 | answers := map[int]bool{} 28 | 29 | fmt.Printf("How well do you know the landscape? Find out who has this as a value proposition / GitHub description.") 30 | for i := 0; i < qNum; i++ { 31 | fmt.Printf("\n%d. Question\n%s\nStars:%d\n", 32 | i+1, records[indices[i]].Description, records[indices[i]].GithubStars) 33 | fmt.Printf("Code sample:\n%s\n", records[indices[i]].CodeExample) 34 | if records[indices[i]].RandomFact != "" { 35 | fmt.Printf("Random fact:\n%s\n", records[indices[i]].RandomFact) 36 | } 37 | for j := attempts; j > 0; j-- { 38 | input := "" 39 | fmt.Scanln(&input) 40 | if strings.EqualFold(records[indices[i]].Name, input) || 41 | (len(input) > 4 && strings.Contains(records[indices[i]].Name, input)) { 42 | answers[i] = true 43 | fmt.Printf("Nailed it! Onto the next one...\n") 44 | break 45 | } 46 | if j == attempts { 47 | fmt.Printf("Hint: %s\n", records[indices[i]].CodeExample) 48 | } 49 | if input == "" { 50 | fmt.Printf("You have to write something...\n") 51 | j++ 52 | } 53 | fmt.Printf("Not: %v. Try again! %d attempts left\n", input, j-1) 54 | } 55 | fmt.Printf("It was: %s\n\n", records[indices[i]].Name) 56 | } 57 | 58 | good := 0 59 | for _, v := range answers { 60 | if v { 61 | good++ 62 | } 63 | } 64 | fmt.Printf("Your result is: %d/%d\n", good, qNum) 65 | if good < gradingSplit { 66 | fmt.Printf("Better luck next time.\n") 67 | } else if good > gradingSplit { 68 | fmt.Printf("You've got it! GG!") 69 | } 70 | for i := 0; i < qNum; i++ { 71 | fmt.Printf("%d %s | %s\n", i+1, records[indices[i]].Name, printAnswer(answers[i])) 72 | } 73 | } 74 | 75 | func main() { 76 | quiz() 77 | } 78 | -------------------------------------------------------------------------------- /api/cmd/server/.env.example: -------------------------------------------------------------------------------- 1 | DEBUG=true 2 | PORT=3333 3 | # for testing leave it empty for persistence 4 | METHOD=RANDOM 5 | DSN="host=localhost user=postgres password=password dbname=postgres port=5432 sslmode=disable" 6 | END_DATE=2023-01-28 -------------------------------------------------------------------------------- /api/cmd/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/dyrector-io/xor/api/internal/config" 7 | "github.com/dyrector-io/xor/api/pkg/server" 8 | "github.com/rs/zerolog/log" 9 | 10 | "github.com/ilyakaznacheev/cleanenv" 11 | ) 12 | 13 | func ReadConfig(cfg *config.AppConfig) error { 14 | err := cleanenv.ReadConfig(".env", cfg) 15 | 16 | if err != nil && !os.IsNotExist(err) { 17 | return err 18 | } 19 | err = cleanenv.ReadEnv(cfg) 20 | if err != nil { 21 | return err 22 | } 23 | 24 | return nil 25 | } 26 | 27 | func main() { 28 | appConfig := &config.AppConfig{} 29 | 30 | err := ReadConfig(appConfig) 31 | if err != nil { 32 | log.Fatal().Err(err).Send() 33 | } 34 | 35 | log.Info().Object("appConfig", appConfig).Send() 36 | 37 | serv := server.GetChi(appConfig) 38 | 39 | log.Info().Msgf("starting server at: %d", appConfig.Port) 40 | err = serv.ListenAndServe() 41 | if err != nil { 42 | log.Fatal().Err(err).Send() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /api/internal/config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/dyrector-io/xor/api/pkg/processor" 5 | "github.com/rs/zerolog" 6 | "gorm.io/gorm" 7 | ) 8 | 9 | type AppConfig struct { 10 | AllowedOrigins string `env:"ALLOWED_ORIGINS"` 11 | Port uint16 `env:"PORT" env-default:"3333"` 12 | Debug bool `env:"DEBUG"` 13 | DSN string `env:"DSN"` 14 | Method string `env:"METHOD"` 15 | Freq string `env:"FREQ" env-default:"DAILY"` 16 | EndDate string `env:"END_DATE"` 17 | } 18 | type AppState struct { 19 | AppConfig *AppConfig 20 | DBConn *gorm.DB 21 | Ended bool 22 | QuizList processor.QuizSequence 23 | QuizCounter int 24 | } 25 | 26 | func (c *AppConfig) MarshalZerologObject(e *zerolog.Event) { 27 | e.Str("origins", c.AllowedOrigins). 28 | Uint16("port", c.Port). 29 | Bool("debug", c.Debug). 30 | Str("method", c.Method). 31 | Str("freq", c.Freq). 32 | Str("end", c.EndDate) 33 | } 34 | -------------------------------------------------------------------------------- /api/internal/ctx/ctx.go: -------------------------------------------------------------------------------- 1 | package ctx 2 | 3 | import "context" 4 | 5 | type CtxKey int 6 | 7 | const ( 8 | StateKey = iota 9 | ) 10 | 11 | func SetContextVar[T any](c context.Context, key CtxKey, value T) context.Context { 12 | return context.WithValue(c, key, value) 13 | } 14 | 15 | func GetContextVar[T any](c context.Context, key CtxKey) T { 16 | return c.Value(key).(T) 17 | } 18 | -------------------------------------------------------------------------------- /api/pkg/database/database.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | "strings" 9 | "time" 10 | 11 | "github.com/dyrector-io/xor/api/internal/config" 12 | "github.com/dyrector-io/xor/api/pkg/processor" 13 | "github.com/rs/zerolog/log" 14 | "gorm.io/driver/postgres" 15 | "gorm.io/gorm" 16 | 17 | _ "github.com/proullon/ramsql/driver" // ramsql 18 | ) 19 | 20 | const ( 21 | SimpleDateFormat = "2006-01-02" 22 | DBconnectAttempt = 3 23 | DBconnectBackoffSeconds = 10 24 | ) 25 | 26 | type Pick struct { 27 | gorm.Model 28 | // 1,2,3,4,5 format 29 | Picks string 30 | // day of pick 31 | Date time.Time `gorm:"unique"` 32 | } 33 | 34 | type History struct { 35 | Date string 36 | Projects string 37 | } 38 | 39 | func (c *History) Render(w http.ResponseWriter, r *http.Request) error { 40 | return nil 41 | } 42 | 43 | type HistoryList []*History 44 | 45 | func SimpleDay(t time.Time) time.Time { 46 | str := t.Format(SimpleDateFormat) 47 | val, _ := time.Parse(SimpleDateFormat, str) 48 | return val 49 | } 50 | 51 | func PersistPicks(db *gorm.DB, today time.Time, picks []int) error { 52 | strArr := []string{} 53 | for _, p := range picks { 54 | strArr = append(strArr, fmt.Sprintf("%d", p)) 55 | } 56 | 57 | str := strings.Join(strArr, ",") 58 | tx := db.Create(&Pick{Picks: str, Date: SimpleDay(today)}) 59 | if tx.Error != nil { 60 | return tx.Error 61 | } 62 | return nil 63 | } 64 | 65 | func GetPicksForDay(db *gorm.DB, day time.Time) []int { 66 | p := Pick{} 67 | 68 | prunedDay := SimpleDay(day) 69 | err := db.Where(&Pick{Date: prunedDay}).First(&p) 70 | if err.Error != nil { 71 | return []int{} 72 | } 73 | 74 | return ParsePicksToIntArr(p.Picks) 75 | } 76 | 77 | func ParsePicksToIntArr(pickStr string) []int { 78 | str := strings.Split(pickStr, ",") 79 | picks := []int{} 80 | for _, v := range str { 81 | i, err := strconv.ParseInt(v, 10, 32) 82 | if err != nil { 83 | log.Error().Err(err).Msg("very unlikely str to int parse error") 84 | } 85 | picks = append(picks, int(i)) 86 | } 87 | return picks 88 | } 89 | 90 | func GetHistoryDB(db *gorm.DB) HistoryList { 91 | picks := []Pick{} 92 | result := db.Where("Date < ?", SimpleDay(time.Now())).Find(&picks) 93 | if result.Error != nil { 94 | log.Error().Err(result.Error).Msg("could not load history returning empty set") 95 | return HistoryList{} 96 | } 97 | all := processor.ReadJSONData() 98 | hist := HistoryList{} 99 | for i := range picks { 100 | pickList := ParsePicksToIntArr(picks[i].Picks) 101 | projectNames := []string{} 102 | for _, index := range pickList { 103 | projectNames = append(projectNames, all[index].Name) 104 | } 105 | hist = append(hist, &History{ 106 | Date: picks[i].Date.Format(SimpleDateFormat), 107 | Projects: strings.Join(projectNames, ","), 108 | }) 109 | } 110 | return hist 111 | } 112 | 113 | func GetExclusionList(db *gorm.DB) []int { 114 | picks := []Pick{} 115 | result := db.Find(&picks) 116 | if result.Error != nil { 117 | log.Error().Err(result.Error).Msg("could not load history returning empty set") 118 | return []int{} 119 | } 120 | xList := []int{} 121 | for i := range picks { 122 | pickList := ParsePicksToIntArr(picks[i].Picks) 123 | xList = append(xList, pickList...) 124 | } 125 | return xList 126 | } 127 | 128 | func InitPostgres(cfg *config.AppConfig) *gorm.DB { 129 | db := connect(cfg) 130 | err := db.AutoMigrate(&Pick{}) 131 | if err != nil { 132 | log.Fatal().Msgf("sql migrate: %s\n", err) 133 | } 134 | return db 135 | } 136 | 137 | func connect(cfg *config.AppConfig) *gorm.DB { 138 | if cfg.DSN == "" { 139 | sqlDB, err := sql.Open("ramsql", "test") 140 | if err != nil { 141 | log.Fatal().Msgf("ramsql.Open: %s\n", err) 142 | } 143 | 144 | db, err := gorm.Open(postgres.New(postgres.Config{ 145 | Conn: sqlDB, 146 | }), &gorm.Config{}) 147 | if err != nil { 148 | log.Fatal().Msgf("sql.Open: %s\n", err) 149 | } 150 | 151 | return db 152 | } 153 | for i := 0; i < DBconnectAttempt; i++ { 154 | db, err := gorm.Open(postgres.Open(cfg.DSN), &gorm.Config{}) 155 | if err != nil { 156 | log.Error().Err(err).Msgf("sql error, backoff %d %d/%d\n", DBconnectBackoffSeconds, i+1, DBconnectAttempt) 157 | time.Sleep(DBconnectBackoffSeconds * time.Second) 158 | } else { 159 | return db 160 | } 161 | if i == DBconnectAttempt { 162 | log.Fatal().Msg("could not open sql connection") 163 | } 164 | } 165 | log.Fatal().Msg("db connect unreachable code") 166 | return nil 167 | } 168 | -------------------------------------------------------------------------------- /api/pkg/game/game.go: -------------------------------------------------------------------------------- 1 | package game 2 | 3 | import ( 4 | "crypto/rand" 5 | "math/big" 6 | "time" 7 | 8 | "github.com/dyrector-io/xor/api/internal/config" 9 | "github.com/dyrector-io/xor/api/pkg/database" 10 | "github.com/dyrector-io/xor/api/pkg/processor" 11 | "github.com/rs/zerolog/log" 12 | "golang.org/x/exp/slices" 13 | "gorm.io/gorm" 14 | ) 15 | 16 | const ( 17 | FilterIfStartLessThan = 1000 18 | QuestionCount = 5 19 | ) 20 | 21 | const ( 22 | RandomGenMethod = "RANDOM" 23 | LinearGenMethod = "LINEAR" 24 | ) 25 | 26 | func PickRandom(amount, upperLimit int) []int { 27 | picked := []int{} 28 | min := 0 29 | bg := big.NewInt(int64(upperLimit) - int64(min)) 30 | for i := 0; i < amount; i++ { 31 | gen, err := rand.Int(rand.Reader, bg) 32 | if err != nil { 33 | log.Error().Err(err).Send() 34 | } 35 | if i > 0 { 36 | if slices.Contains(picked, int(gen.Int64())) { 37 | i-- 38 | continue 39 | } 40 | } 41 | picked = append(picked, int(gen.Int64())) 42 | } 43 | 44 | return picked 45 | } 46 | 47 | func sdbmHash(data []byte) uint64 { 48 | var hash uint64 49 | 50 | for _, b := range data { 51 | hash = uint64(b) + (hash << 6) + (hash << 16) - hash 52 | } 53 | 54 | return hash 55 | } 56 | 57 | func PickByDate(today time.Time, amount, upperLimit int, excluded []int) []int { 58 | if len(excluded)+amount-1 >= upperLimit { 59 | log.Info().Msgf("ran out of item indices %v/%v", len(excluded), upperLimit) 60 | return []int{} 61 | } 62 | 63 | hash := sdbmHash([]byte(today.Format("2006-01-02"))) 64 | slice := hash / uint64(amount) 65 | log.Info().Msgf("%d", hash) 66 | 67 | picked := []int{} 68 | for i := 0; i < amount; i++ { 69 | gen := hash % uint64(upperLimit) 70 | hash -= slice 71 | 72 | for j := 1; slices.Contains(picked, int(gen)) || slices.Contains(excluded, int(gen)); j++ { 73 | gen = (hash + uint64(j)) % uint64(upperLimit) 74 | } 75 | 76 | picked = append(picked, int(gen)) 77 | } 78 | 79 | log.Info().Msgf("%v", picked) 80 | return picked 81 | } 82 | 83 | func GetPicksIfPresent(db *gorm.DB, today time.Time) []int { 84 | return database.GetPicksForDay(db, today) 85 | } 86 | 87 | func SelectAQuiz(state *config.AppState) { 88 | today := time.Now() 89 | log.Info().Msgf("SelectAQuiz running %v", today) 90 | listAll := processor.ReadJSONData() 91 | var indices []int 92 | if state.AppConfig.EndDate != "" { 93 | end, err := time.Parse("2006-01-02", state.AppConfig.EndDate) 94 | if err != nil { 95 | log.Err(err).Msg("invalid ending date format, expected: 2006-01-02") 96 | } 97 | if today.After(end) { 98 | log.Info().Msgf("End date passed %v>%v", today, state.AppConfig.EndDate) 99 | state.QuizList = processor.QuizSequence{} 100 | state.Ended = true 101 | return 102 | } 103 | } 104 | if state.QuizCounter*QuestionCount >= len(listAll) { 105 | state.QuizList = processor.QuizSequence{} 106 | state.Ended = true 107 | return 108 | } else if state.AppConfig.Method == RandomGenMethod { 109 | indices = PickRandom(QuestionCount, len(listAll)-1) 110 | log.Info().Msg("generating new random quiz") 111 | } else if state.AppConfig.Method == LinearGenMethod { 112 | start := state.QuizCounter * QuestionCount 113 | for i := start; i < start+QuestionCount; i++ { 114 | indices = append(indices, i) 115 | } 116 | state.QuizCounter++ 117 | } else { 118 | indices = GetPicksIfPresent(state.DBConn, today) 119 | if len(indices) == 0 { 120 | log.Info().Msg("generating new quiz") 121 | 122 | indices = PickByDate(today, QuestionCount, len(listAll)-1, database.GetExclusionList(state.DBConn)) 123 | 124 | err := database.PersistPicks(state.DBConn, today, indices) 125 | if err != nil { 126 | log.Error().Err(err).Msg("persisting quiz picks for the day") 127 | } 128 | } else { 129 | log.Info().Msg("found already generated quiz for today") 130 | } 131 | } 132 | 133 | if len(indices) == 0 { 134 | state.Ended = true 135 | log.Info().Msg("no quiz indices were picked, assuming the end") 136 | return 137 | } 138 | 139 | selected := processor.QuizSequence{} 140 | 141 | for _, i := range indices { 142 | selected = append(selected, listAll[i]) 143 | } 144 | 145 | state.QuizList = selected 146 | } 147 | -------------------------------------------------------------------------------- /api/pkg/game/game_test.go: -------------------------------------------------------------------------------- 1 | package game_test 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/dyrector-io/xor/api/pkg/game" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestDatePicking(t *testing.T) { 12 | const pickPerDay = 5 13 | dat, _ := time.Parse("2006-01-02", "2022-12-12") 14 | picks := game.PickByDate(dat, pickPerDay, 15, []int{}) 15 | assert.Equalf(t, []int{12, 7, 2, 8, 3}, picks, "These numbers should've been picked on the first day") 16 | excl := picks 17 | picks = game.PickByDate(dat.AddDate(0, 0, 1), pickPerDay, 15, excl) 18 | assert.Equalf(t, []int{13, 4, 14, 9, 5}, picks, "These numbers should've been picked on the second day") 19 | excl = append(excl, picks...) 20 | picks = game.PickByDate(dat.AddDate(0, 0, 1), pickPerDay, 15, excl) 21 | assert.Equalf(t, []int{10, 6, 0, 11, 1}, picks, "These numbers should've been picked on the third day") 22 | } 23 | -------------------------------------------------------------------------------- /api/pkg/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/dyrector-io/xor/api/pkg/processor" 9 | ) 10 | 11 | func main() { 12 | seq := processor.ReadJSONData() 13 | 14 | toWrite := processor.QuizSequence{} 15 | for _, i := range seq { 16 | if i.GithubStars > 1000 { 17 | toWrite = append(toWrite, i) 18 | } 19 | } 20 | 21 | bytes, err := json.MarshalIndent(toWrite, "", " ") 22 | if err != nil { 23 | panic(err) 24 | } 25 | fmt.Printf("%v", bytes) 26 | 27 | os.WriteFile("landscape.json", bytes, os.ModePerm) 28 | } 29 | -------------------------------------------------------------------------------- /api/pkg/processor/javascript.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "Name": "Lodash", 4 | "Description": "... makes JavaScript easier by taking the hassle out of working with arrays, numbers, objects, strings, etc.", 5 | "CodeExample": "```*redacted*.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 });```", 6 | "RandomFact": "2015 was big year! ... became the most depended on npm package, passed 1 billion downloads, & its v3 release saw massive adoption!", 7 | "GithubStars": 55500, 8 | "GitHubLink": "https://github.com/lodash/lodash", 9 | "WeeklyDownloads": 46000000 10 | }, 11 | { 12 | "Name": "Cloudinary", 13 | "Description": "Effortlessly optimize, transform, upload and manage your cloud's assets.", 14 | "CodeExample": "```*redacted*.url('sample.jpg', {width: 100, height: 150, crop: 'fill', fetch_format: 'auto'})```", 15 | "RandomFact": "Image and Video API for Powerful Visual Experiences - Store, transform, optimize, and deliver all your media assets with easy-to-use APIs, widgets, or user interface.", 16 | "GithubStars": 567, 17 | "GitHubLink": "https://github.com/cloudinary/cloudinary_npm", 18 | "WeeklyDownloads": 183000 19 | }, 20 | { 21 | "Name": "Axios", 22 | "Description": "Promise based HTTP client for the browser and node.js", 23 | "CodeExample": "```*redacted*.({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone'} });```", 24 | "RandomFact": "Matt Zabriskie is the founder of the npm package, started in the summer of 2014.", 25 | "GithubStars": 98500, 26 | "GitHubLink": "https://github.com/axios/axios", 27 | "WeeklyDownloads": 39000000 28 | }, 29 | { 30 | "Name": "chalk", 31 | "Description": "Terminal string styling done right", 32 | "CodeExample": "```log(*redacted*.blue.bgRed.bold('Hello world!'));```", 33 | "RandomFact": "... supports 256 colors and Truecolor (16 million colors) on supported terminal apps. Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying {level: n} as a ... option). For example, ... configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red).", 34 | "GithubStars": 19700, 35 | "GitHubLink": "https://github.com/chalk/chalk", 36 | "WeeklyDownloads": 233114855 37 | }, 38 | { 39 | "Name": "mustache.js", 40 | "Description": "Logic-less {{...}} templates with JavaScript. ... is a zero-dependency implementation of the ... template system in JavaScript.", 41 | "CodeExample": "```const view = {\n title: \"Joe\",\n calc: () => ( 2 + 4 )\n};\nconst output = *redacted*.render(\"{{title}} spends {{calc}}\", view);```", 42 | "RandomFact": "You can use ... to render mustache templates anywhere you can use JavaScript. This includes web browsers, server-side environments such as Node.js, and CouchDB views.", 43 | "GithubStars": 15700, 44 | "GitHubLink": "https://github.com/janl/mustache.js", 45 | "WeeklyDownloads": 3139159 46 | }, 47 | { 48 | "Name": "minimist", 49 | "Description": "This module is the guts of optimist's argument parser without all the fanciful decoration.", 50 | "CodeExample": "```$ node example/parse.js -a beep -b boop { _: [], a: 'beep', b: 'boop' }```", 51 | "RandomFact": "Parse argument options", 52 | "GithubStars": 120, 53 | "GitHubLink": "https://github.com/minimistjs/minimist", 54 | "WeeklyDownloads": 53595074 55 | }, 56 | { 57 | "Name": "Commander.js", 58 | "Description": "The complete solution for node.js command-line interfaces.", 59 | "CodeExample": "```program\n .option('--first')\n .option('-s, --separator ');\nprogram.parse();```", 60 | "RandomFact": "There is an old-school DOS | OS/2 | Windows file manager with a similar name.", 61 | "GithubStars": 24145, 62 | "GitHubLink": "github.com/tj/commander.js", 63 | "WeeklyDownloads": 109892199 64 | }, 65 | { 66 | "Name": "react", 67 | "Description": "A declarative, efficient, and flexible JavaScript library for building user interfaces.", 68 | "CodeExample": "```function HelloMessage({ name }) {\n return
Hello {name}
;\n}\nconst root = createRoot(document.getElementById('container'));\nroot.render();```", 69 | "RandomFact": "... is not a framework.", 70 | "GithubStars": 201267, 71 | "GitHubLink": "github.com/facebook/react", 72 | "WeeklyDownloads": 18599591 73 | }, 74 | { 75 | "Name": "vue", 76 | "Description": "... is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.", 77 | "CodeExample": "```
{{ message }}
\n ```", 78 | "RandomFact": "Single File Components", 79 | "GithubStars": 202078, 80 | "GitHubLink": "github.com/vuejs/core", 81 | "WeeklyDownloads": 3673548 82 | }, 83 | { 84 | "Name": "js-tokens", 85 | "Description": "The tiny, regex powered, lenient, almost spec-compliant JavaScript tokenizer that never fails.", 86 | "CodeExample": "```// Get all tokens as an array:\nconst tokens = Array.from(*redacted*(\"hello, !world\"));```", 87 | "RandomFact": "This package exports a generator function, ..., that turns a string of JavaScript code into token objects.", 88 | "GithubStars": 364, 89 | "GitHubLink": "github.com/lydell/js-tokens", 90 | "WeeklyDownloads": 38561642 91 | }, 92 | { 93 | "Name": "express", 94 | "Description": "Fast, unopinionated, minimalist web framework for Node.js.", 95 | "CodeExample": "```app.get('/', function (req, res) {\n res.send('Hello World')\n})\napp.listen(3000) ```", 96 | "RandomFact": "\"Most of nike.com's ecommerce experience is on top of <...>... in fact they've left the x-powered-by headers intact.\" -- Reddit", 97 | "GithubStars": 59753, 98 | "GitHubLink": "github.com/expressjs/express", 99 | "WeeklyDownloads": 27413998 100 | }, 101 | { 102 | "Name": "underscore", 103 | "Description": "... is a utility-belt library for JavaScript that provides support for the usual functional suspects (each, map, reduce, filter...) without extending any core JavaScript objects.", 104 | "CodeExample": "```var numbers = [1, 2, 3, 4, 5];\n*redacted*.each(numbers, function(value, index){\nconsole.log(value, index);\n});```", 105 | "RandomFact": "... is an open-sourced component of DocumentCloud", 106 | "GithubStars": 26828, 107 | "GitHubLink": "https://github.com/jashkenas/underscore", 108 | "WeeklyDownloads": 10716149 109 | }, 110 | { 111 | "Name": "async", 112 | "Description": "... is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript.", 113 | "CodeExample": "```*redacted*.mapLimit(urls, 5, async function(url) {\n const response = await fetch(url)\n return response.body\n}, (err, results) => {\n if (err) throw err\n // results is now an array of the response bodies\n console.log(results)\n})```", 114 | "RandomFact": "... provides around 70 functions that include the usual 'functional' suspects (map, reduce, filter, each…) as well as some common patterns for asynchronous control flow (parallel, series, waterfall…). ", 115 | "GithubStars": 27798, 116 | "GitHubLink": "https://github.com/caolan/async", 117 | "WeeklyDownloads": 50417200 118 | }, 119 | { 120 | "Name": "moment", 121 | "Description": "A JavaScript date library for parsing, validating, manipulating, and formatting dates.", 122 | "CodeExample": "```let now = *redacted*.format('LLLL');\n```", 123 | "RandomFact": "... is a legacy project, now in maintenance mode. In most cases, you should choose a different library.", 124 | "GithubStars": 47187, 125 | "GitHubLink": "github.com/moment/moment", 126 | "WeeklyDownloads": 20462039 127 | }, 128 | { 129 | "Name": "glob", 130 | "Description": "Match files using the patterns the shell uses, like stars and stuff.", 131 | "CodeExample": "```*redacted*(\"**/*.js\", options, function (er, files) {\n // files is an array of filenames.\n // If the `nonull` option is set, and nothing\n // was found, then files is [\"**/*.js\"]\n // er is an error object or null.\n})```", 132 | "RandomFact": "This is a ... implementation in JavaScript. It uses the minimatch library to do its matching.", 133 | "GithubStars": 7837, 134 | "GitHubLink": "github.com/isaacs/node-glob", 135 | "WeeklyDownloads": 90118870 136 | }, 137 | { 138 | "Name": "readable-stream", 139 | "Description": "Some Node.js functionality for userland", 140 | "CodeExample": "```console.log(\"Every time you press a key, you will see more contents of the source file. Let's begin!\n\")\nprocess.stdin.setRawMode(true)\nprocess.stdin.on('data', function () {\n const c = rst.read(100)\n if (!c) {\n return setTimeout(process.exit, 500)\n }\n process.stdout.write(c)\n})\nprocess.stdin.resume()```", 141 | "RandomFact": "This package is a mirror of the s... implementations in Node.js 18.9.0.", 142 | "GithubStars": 986, 143 | "GitHubLink": "github.com/nodejs/readable-stream", 144 | "WeeklyDownloads": 120467683 145 | }, 146 | { 147 | "Name": "jQuery", 148 | "Description": "... is a fast, small, and feature-rich JavaScript library.", 149 | "CodeExample": "```$(\"#test\").hide();```", 150 | "RandomFact": "... was found on more than 80 million websites in 2022.", 151 | "GithubStars": 57146, 152 | "GitHubLink": "github.com/jquery/jquery", 153 | "WeeklyDownloads": 6231090 154 | }, 155 | { 156 | "Name": "mkdirp", 157 | "Description": "A POSIX feature within Node.js", 158 | "CodeExample": "```// return value is a Promise resolving to the first directory created\n*redacted*('/tmp/foo/bar/baz').then(made =>\n console.log(`made directories, starting with ${made}`)\n)```", 159 | "RandomFact": "Like mkdir -p, but in Node.js!", 160 | "GithubStars": 140, 161 | "GitHubLink": "github.com/isaacs/node-mkdirp", 162 | "WeeklyDownloads": 70745905 163 | }, 164 | { 165 | "Name": "colors.js", 166 | "Description": "get colors in your node.js console", 167 | "CodeExample": "```console.log('hello'.green); // outputs green text\nconsole.log('i like cake and pies'.underline.red); // outputs red underlined text\nconsole.log('inverse the color'.inverse); // inverses the color\nconsole.log('OMG Rainbows!'.rainbow); // rainbow\nconsole.log('Run the trap'.trap); // Drops the bass```", 168 | "RandomFact": "Used by more than 5 millions.", 169 | "GithubStars": 5033, 170 | "GitHubLink": "github.com/Marak/colors.js", 171 | "WeeklyDownloads": 21357058 172 | }, 173 | { 174 | "Name": "semver", 175 | "Description": "The semantic versioner for npm", 176 | "CodeExample": "```*redacted*.minVersion('>=1.0.0'```", 177 | "RandomFact": "The ... parser for node (the one npm uses)", 178 | "GithubStars": 4519, 179 | "GitHubLink": "github.com/npm/node-semver", 180 | "WeeklyDownloads": 240233516 181 | }, 182 | { 183 | "Name": "fs-extra", 184 | "Description": "... adds file system methods that aren't included in the native fs module and adds promise support to the fs methods. It also uses graceful-fs to prevent EMFILE errors. It should be a drop in replacement for fs.", 185 | "CodeExample": "```// Async with promises: ....copy('/tmp/myfile', '/tmp/mynewfile')\n.then(() => console.log('success!'))\n.catch(err => console.error(err))```", 186 | "RandomFact": "Why? I got tired of including mkdirp, rimraf, and ncp in most of my projects.", 187 | "GithubStars": 8885, 188 | "GitHubLink": "github.com/jprichardson/node-fs-extra", 189 | "WeeklyDownloads": 77438580 190 | }, 191 | { 192 | "Name": "escape-string-regexp", 193 | "Description": "Escape RegExp special characters", 194 | "CodeExample": "```const escapedString = *redacted*('How much $ for a \uD83E\uDD84?');\n//=> 'How much \\\\$ for a \uD83E\uDD84\\\\?'\nnew RegExp(escapedString);```", 195 | "RandomFact": "It is from sindresorhus.", 196 | "GithubStars": 532, 197 | "GitHubLink": "github.com/sindresorhus/escape-string-regexp", 198 | "WeeklyDownloads": 95918625 199 | }, 200 | { 201 | "Name": "create-t3-app", 202 | "Description": "Interactive CLI to start a full-stack, typesafe Next.js app.", 203 | "CodeExample": "```pnpm dlx *redacted*@latest --CI --trpc --tailwind```", 204 | "RandomFact": "We made ... to do one thing: Streamline the setup of typesafe Next.js apps WITHOUT compromising modularity.", 205 | "GithubStars": 13914, 206 | "GitHubLink": "github.com/t3-oss/create-t3-app", 207 | "WeeklyDownloads": 3832 208 | }, 209 | { 210 | "Name": "uuid", 211 | "Description": "For the creation of RFC4122 ....s", 212 | "CodeExample": "```*redacted*(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'```", 213 | "RandomFact": "... is a 128-bit label used for information in computer systems.", 214 | "GithubStars": 13051, 215 | "GitHubLink": "github.com/uuidjs/uuid", 216 | "WeeklyDownloads": 78849945 217 | }, 218 | { 219 | "Name": "webpack", 220 | "Description": "... is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.", 221 | "CodeExample": "```module.exports = {\nentry: './src/index.js',\n output: {\n filename: 'main.js',\n path: path.resolve(__dirname, 'dist'),\n},\n};```", 222 | "RandomFact": "The motivations behind ... is to gather all your dependencies, which includes not just code, but other assets as well, and generate a dependency graph.", 223 | "GithubStars": 62454, 224 | "GitHubLink": "github.com/webpack/webpack", 225 | "WeeklyDownloads": 26567685 226 | }, 227 | { 228 | "Name": "rimraf", 229 | "Description": "The UNIX command ... for node.", 230 | "CodeExample": "```*redacted*('./tools/setup', error => {\n if (error) throw new Error(error);\n });```", 231 | "RandomFact": "Do not drink and ...!", 232 | "GithubStars": 5023, 233 | "GitHubLink": "https://github.com/isaacs/rimraf", 234 | "WeeklyDownloads": 75112476 235 | }, 236 | { 237 | "Name": "Next.js", 238 | "Description": "The React Framework, that has uses cases like: Server-side Rendering or Static Generation, and updating or creating content at runtime with Incremental Static Regeneration.", 239 | "CodeExample": "```export default function IndexPage() {\n return (\n
\n Hello World. About\n
\n )\n}```", 240 | "RandomFact": "It provides out-of-the-box tooling and configuration you need to build fast, SEO-friendly React apps.", 241 | "GithubStars": 100078, 242 | "GitHubLink": "https://github.com/vercel/next.js", 243 | "WeeklyDownloads": 3758910 244 | }, 245 | { 246 | "Name": "Angular", 247 | "Description": "... is a development platform for building mobile and desktop web applications using Typescript/JavaScript and other languages.", 248 | "CodeExample": "```import { Component } from ' @angular/core';\n@Component ({\n selector: 'my-app',\n template: 'Products',\n})\nexport class Appproduct {\n}```", 249 | "RandomFact": "... framework is embedded with the original MVC (Model-View-Controller) software architectural setup. However, it is not according to the established standards. ... does not ask developers to split an application into different MVC components and build a code that could unite them.", 250 | "GithubStars": 86092, 251 | "GitHubLink": "github.com/angular/angular", 252 | "WeeklyDownloads": 3175765 253 | }, 254 | { 255 | "Name": "Redux", 256 | "Description": "... is a predictable state container for JavaScript apps.", 257 | "CodeExample": "```function counter(state = 0, action) {\n switch (action.type) {\n case 'INCREMENT':\n return state + 1\n case 'DECREMENT':\n return state - 1\n default:\n return state\n }\n}\n```", 258 | "RandomFact": "... allows you to manage your app's state in a single place and keep changes in your app more predictable and traceable.", 259 | "GithubStars": 59184, 260 | "GitHubLink": "https://github.com/reduxjs/redux", 261 | "WeeklyDownloads": 8788728 262 | }, 263 | { 264 | "Name": "socket.io", 265 | "Description": "... enables real-time bidirectional event-based communication.", 266 | "CodeExample": "```*redacted*.on('connection', socket => {\n socket.emit('request', /* \u2026 */); // emit an event to the socket\n io.emit('broadcast', /* \u2026 */); // emit an event to all connected sockets\n socket.on('reply', () => { /* \u2026 */ }); // listen to the event\n});```", 267 | "RandomFact": "... is a JavaScript library for realtime web applications. It enables realtime, bi-directional communication between web clients and servers. ... primarily uses the WebSocket protocol with polling as a fallback option, while providing the same interface.", 268 | "GithubStars": 57526, 269 | "GitHubLink": "github.com/socketio/socket.io", 270 | "WeeklyDownloads": 5232194 271 | }, 272 | { 273 | "Name": "Jest", 274 | "Description": "Delightful JavaScript Testing.", 275 | "CodeExample": "```test('adds 1 + 2 to equal 3', () => {\n expect(sum(1, 2)).toBe(3);\n});\n// output:\n// PASS ./sum.test.js\n// \u2713 adds 1 + 2 to equal 3 (5ms)```", 276 | "RandomFact": "... is a JavaScript testing framework designed to ensure correctness of any JavaScript codebase. It allows you to write tests with an approachable, familiar and feature-rich API that gives you results quickly.", 277 | "GithubStars": 41310, 278 | "GitHubLink": "github.com/facebook/jest", 279 | "WeeklyDownloads": 20194322 280 | }, 281 | { 282 | "Name": "Prettier", 283 | "Description": "... is an opinionated code formatter with support for ...", 284 | "CodeExample": "```{\n \"trailingComma\": \"es5\",\n \"tabWidth\": 4,\n \"semi\": false,\n \"singleQuote\": true\n}```", 285 | "RandomFact": "It removes all original styling* and ensures that all outputted code conforms to a consistent style. ... takes your code and reprints it from scratch by taking the line length into account.", 286 | "GithubStars": 44800, 287 | "GitHubLink": "https://github.com/prettier/prettier", 288 | "WeeklyDownloads": 27801945 289 | }, 290 | { 291 | "Name": "electron", 292 | "Description": "The ... framework lets you write cross-platform desktop applications using JavaScript, HTML and CSS.", 293 | "CodeExample": "```function createWindow () {\n const win = new BrowserWindow({\n width: 800,\n height: 600,\n webPreferences: {\n preload: path.join(__dirname, 'preload.js')\n }\n })\n win.loadFile('index.html')\n}```", 294 | "RandomFact": "Most people use ... from the command line, but if you require ... inside your Node app (not your ... app) it will return the file path to the binary.", 295 | "GithubStars": 105727, 296 | "GitHubLink": "https://github.com/electron/electron", 297 | "WeeklyDownloads": 605233 298 | }, 299 | { 300 | "Name": "gatsby", 301 | "Description": "... is a free and open source framework based on React that helps developers build blazing fast websites and apps.", 302 | "CodeExample": "```module.exports = { \n graphqlTypegen: { \n typesOutputPath: `...-types.d.ts`, \n generateOnBuild: false, \n documentSearchPaths: [`./...-node.ts`, `./plugins/**/...-node.ts`], \n // Other options... \n }, \n}```", 303 | "RandomFact": "It's been acquired by Netlify recently.", 304 | "GithubStars": 54089, 305 | "GitHubLink": "https://github.com/gatsbyjs/gatsby", 306 | "WeeklyDownloads": 418579 307 | }, 308 | { 309 | "Name": "yarn", 310 | "Description": "Fast, reliable, and secure dependency management.", 311 | "CodeExample": "```// Starting a new project\n*redacted* init\n// Adding a dependency\n*redacted* add package@version\n// Installing all the dependencies of project\n*redacted* // :D```", 312 | "RandomFact": "... uses checksums to verify the integrity of every installed package before its code is executed.", 313 | "GithubStars": 41047, 314 | "GitHubLink": "https://github.com/yarnpkg/yarn", 315 | "WeeklyDownloads": 3751289 316 | }, 317 | { 318 | "Name": "yargs", 319 | "Description": "... be a node.js library fer hearties tryin' ter parse optstrings", 320 | "CodeExample": "```const argv = *redacted*.(hideBin(process.argv)).argv\nif (argv.ships > 3 && argv.distance < 53.5) {\nconsole.log('Plunder more riffiwobbles!')\n} else {\nconsole.log('Retreat from the xupptumblers!')\n}```", 321 | "RandomFact": "... helps you build interactive command line tools, by parsing arguments and generating an elegant user interface.", 322 | "GithubStars": 10300, 323 | "GitHubLink": "github.com/yargs/yargs", 324 | "WeeklyDownloads": 81062853 325 | }, 326 | { 327 | "Name": "source-map", 328 | "Description": "A ...Consumer instance represents a parsed source map which we can query for information about the original file positions by giving it a file position in the generated source.", 329 | "CodeExample": "``` \n ```", 330 | "RandomFact": "Consume and generate source maps.", 331 | "GithubStars": 3200, 332 | "GitHubLink": "github.com/mozilla/source-map", 333 | "WeeklyDownloads": 158734500 334 | }, 335 | { 336 | "Name": "q", 337 | "Description": "If a function cannot return a value or throw an exception without blocking, it can return a promise instead. A promise is an object that represents the return value or the thrown exception that the function may eventually provide. A promise can also be used as a proxy for a remote object to overcome latency. On the first pass, promises can mitigate the “Pyramid of Doom”: the situation where code marches to the right faster than it marches forward.", 338 | "CodeExample": "```Q.fcall(promisedStep1)\n.then(promisedStep2)\n.then(promisedStep3)\n.then(promisedStep4)\n.then(function (value4) {\n// Do something with value4\n})\n.catch(function (error) {\n// Handle any error from all above steps\n})\n.done();\n```", 339 | "RandomFact": "... isn't going anywhere. The code is still here and bugs will be fixed but further development has been unnecessary for many years. We encourage you to read the code and the explainers to glimpse into the history of the internet.", 340 | "GithubStars": 15000, 341 | "GitHubLink": "https://github.com/kriskowal/q", 342 | "WeeklyDownloads": 15474465 343 | }, 344 | { 345 | "Name": "d3", 346 | "Description": "Bring data to life with SVG, Canvas and HTML. ", 347 | "CodeExample": "```d3.select(\"body\").style(\"background-color\", \"black\");```", 348 | "RandomFact": ".. is a JavaScript library for visualizing data using web standards. .. helps you bring data to life using SVG, Canvas and HTML. .. combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.", 349 | "GithubStars": 104000, 350 | "GitHubLink": "https://github.com/d3/d3", 351 | "WeeklyDownloads": 2151974 352 | }, 353 | { 354 | "Name": "vizzu", 355 | "Description": "Library for animated data visualizations and data stories", 356 | "CodeExample": "```let data = {\nseries: [\n{ name: 'Foo', values: ['Alice', 'Bob', 'Ted'] },\n{ name: 'Bar', values: [15, 32, 12] },\n{ name: 'Baz', values: [5, 3, 2] }\n]\n};\nlet chart = new *redacted*('mything', { data });```", 357 | "RandomFact": "... is a free, open-source Javascript/C++ library utilizing a generic dataviz engine that generates many types of charts and seamlessly animates between them. It can be used to create static charts but more importantly, it is designed for building animated data stories and interactive explorers as ... enables showing different perspectives of the data that the viewers can easily follow due to the animation.", 358 | "GithubStars": 1700, 359 | "GitHubLink": "github.com/vizzuhq/vizzu-lib", 360 | "WeeklyDownloads": 18 361 | }, 362 | { 363 | "Name": "meteorjs", 364 | "Description": "... is an open source platform for seamlessly building and deploying Web, Mobile, and Desktop applications in Javascript or TypeScript.", 365 | "CodeExample": "```// On server startup, if the database is empty, create some initial data.\nif (*redacted*.isServer) {\n *redacted*.startup(() => {\n if (Rooms.find().count() === 0) {\n Rooms.insert({ name: 'Initial room' });\n }\n });\n}```", 366 | "RandomFact": "", 367 | "GithubStars": 43253, 368 | "GitHubLink": "https://github.com/meteor/meteor", 369 | "WeeklyDownloads": 1245 370 | }, 371 | { 372 | "Name": "emberjs", 373 | "Description": "... is a productive, battle-tested JavaScript framework for building modern web applications. It includes everything you need to build rich UIs that work on any device.", 374 | "CodeExample": "```

List of Scientists

\n ```", 375 | "RandomFact": "... is built on the Glimmer rendering engine, one of the fastest rendering technologies on the market today, thanks to the way it compiles templates down to a highly-performant virtual machine.", 376 | "GithubStars": 12, 377 | "GitHubLink": "https://github.com/emberjs/ember", 378 | "WeeklyDownloads": 1255 379 | }, 380 | { 381 | "Name": "svelte", 382 | "Description": "... is a new way to build web applications. It's a compiler that takes your declarative components and converts them into efficient JavaScript that surgically updates the DOM.", 383 | "CodeExample": "``` \n

Hello {name}!

```", 384 | "RandomFact": "Instead of using techniques like virtual DOM diffing, ... writes code that surgically updates the DOM when the state of your app changes.", 385 | "GithubStars": 65263, 386 | "GitHubLink": "https://github.com/sveltejs/svelte", 387 | "WeeklyDownloads": 479923 388 | }, 389 | { 390 | "Name": "polymerjs", 391 | "Description": "... lets you build encapsulated, reusable Web Components that work just like standard HTML elements, to use in building web applications.", 392 | "CodeExample": "``` \n \n \n Web Components!```", 393 | "RandomFact": "", 394 | "GithubStars": 21909, 395 | "GitHubLink": "https://github.com/Polymer/polymer", 396 | "WeeklyDownloads": 88830 397 | }, 398 | { 399 | "Name": "fastify", 400 | "Description": "... is a web framework highly focused on providing the best developer experience with the least overhead and a powerful plugin architecture.", 401 | "CodeExample": "```// Declare a route\n*redacted*.get('/', function (request, reply) {\n reply.send({ hello: 'world' })\n})\n// Run the server!\n*redacted*.listen({ port: 3000 }, function (err, address) {\n if (err) {\n *redacted*.log.error(err)\n process.exit(1)\n }\n // Server is now listening on ${address}\n})```", 402 | "RandomFact": "", 403 | "GithubStars": 26310, 404 | "GitHubLink": "https://github.com/fastify/fastify", 405 | "WeeklyDownloads": 929803 406 | }, 407 | { 408 | "Name": "nestjs", 409 | "Description": "A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications on top of TypeScript & JavaScript (ES6, ES7, ES8)", 410 | "CodeExample": "```import { AppModule } from './app.module';\nasync function bootstrap() {\n const app = await *redacted*.create(AppModule);\n await app.listen(3000);\n}\nbootstrap();```", 411 | "RandomFact": "We also dyrectorio also use & love it! :)", 412 | "GithubStars": 53965, 413 | "GitHubLink": "https://github.com/nestjs/nest", 414 | "WeeklyDownloads": 2084251 415 | }, 416 | { 417 | "Name": "Agenda.js", 418 | "Description": "A light-weight job scheduling library for Node.js", 419 | "CodeExample": "```db.*redacted*Jobs.ensureIndex({\n \"name\" : 1,\n \"nextRunAt\" : 1,\n \"priority\" : -1,\n \"lockedAt\" : 1,\n \"disabled\" : 1\n}, \"findAndLockNextJobIndex\")```", 420 | "RandomFact": "Mongo backed (replicateble) persistance.", 421 | "GithubStars": 8689, 422 | "GitHubLink": "https://github.com/agenda/agenda", 423 | "WeeklyDownloads": 89740 424 | }, 425 | { 426 | "Name": "backbone.js", 427 | "Description": "Give your JS App some ... with Models, Views, Collections, and Events. ... supplies structure to JavaScript-heavy applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing application over a RESTful JSON interface.", 428 | "CodeExample": "```$(function () {\n (function () {\n var View = test.View.extend({\n el: \"body\",\n template: _.template(\"

Hello, XOR!

\"),\n initialize: function () {\n this.render();\n },\n render: function () {\n this.$el.html(this.template());\n },\n });\n new View();\n })();\n});\n```", 429 | "RandomFact": "", 430 | "GithubStars": 27984, 431 | "GitHubLink": "https://github.com/jashkenas/backbone", 432 | "WeeklyDownloads": 607180 433 | }, 434 | { 435 | "Name": "kibana", 436 | "Description": "It's an open source (Apache Licensed), browser-based analytics and search dashboard for Elasticsearch.", 437 | "CodeExample": "```//a query\nhttp.request.method: *```", 438 | "RandomFact": "Built in linter, code formatter, ability to build a self-contained executable, test runner, IDE integration, and more.", 439 | "GithubStars": 18195, 440 | "GitHubLink": "github.com/elastic/kibana", 441 | "WeeklyDownloads": 8 442 | }, 443 | { 444 | "Name": "knockout", 445 | "Description": "... is a JavaScript MVVM (a modern variant of MVC) library that makes it easier to create rich, desktop-like user interfaces with JavaScript and HTML.", 446 | "CodeExample": "```// Here's my data model \n var ViewModel = function(first, last) { \n this.firstName = *redacted*.observable(first); \n this.lastNme = *redacted*.observable(last); \n this.fullName = *redacted*.pureComputed(function() { \n // ... tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName. \n return this.firstName() + \" \" + this.lastName(); \n }, this); \n }; \n *redacted*.applyBindings(new ViewModel(\"Planet\", \"Earth\")); // This makes ... get to work```", 447 | "RandomFact": "When your data model's state changes, your UI updates automatically", 448 | "GithubStars": 10279, 449 | "GitHubLink": "https://github.com/knockout/knockout", 450 | "WeeklyDownloads": 70616 451 | }, 452 | { 453 | "Name": "mocha", 454 | "Description": "Simple, flexible, fun JavaScript test framework for Node.js & The Browser", 455 | "CodeExample": "```var assert = require('assert');\ndescribe('Array', function () {\n describe('#indexOf()', function () {\n it('should return -1 when the value is not present', function () {\n assert.equal([1, 2, 3].indexOf(4), -1);\n });\n });\n});```", 456 | "RandomFact": "... is one of the most-depended-upon modules on npm (source: libraries.io)", 457 | "GithubStars": 21871, 458 | "GitHubLink": "https://github.com/mochajs/mocha", 459 | "WeeklyDownloads": 7662359 460 | }, 461 | { 462 | "Name": "Three.js", 463 | "Description": "The aim of the project is to create an easy to use, lightweight, cross-browser, general purpose 3D library.", 464 | "CodeExample": "```const scene = new *redacted*.Scene();\nconst camera = new *redacted*.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );\nconst renderer = new *redacted*.WebGLRenderer();\nrenderer.setSize( window.innerWidth, window.innerHeight );\ndocument.body.appendChild( renderer.domElement );```", 465 | "RandomFact": "The current builds only include a WebGL renderer but WebGPU (experimental), SVG and CSS3D renderers are also available as addons.", 466 | "GithubStars": 88640, 467 | "GitHubLink": "https://github.com/mrdoob/three.js", 468 | "WeeklyDownloads": 922629 469 | }, 470 | { 471 | "Name": "ws", 472 | "Description": "... is a simple to use, blazing fast, and thoroughly tested WebSocket client and server implementation.", 473 | "CodeExample": "```// server-side\nconst server = new WebSocketServer({\n port: 8080,\n perMessageDeflate: {\n zlibDeflateOptions: {\n // See zlib defaults.\n chunkSize: 1024,\n memLevel: 7,\n level: 3\n },\n zlibInflateOptions: {\n chunkSize: 10 * 1024\n },\n // Other options settable:\n clientNoContextTakeover: true, // Defaults to negotiated value.\n serverNoContextTakeover: true, // Defaults to negotiated value.\n serverMaxWindowBits: 10, // Defaults to negotiated value.\n // Below options specified as default values.\n concurrencyLimit: 10, // Limits zlib concurrency for perf.\n threshold: 1024 // Size (in bytes) below which messages\n // should not be compressed if context takeover is disabled.\n }\n});\n// client side\nconst client = new WebSocket('ws://www.host.com/path', {\n perMessageDeflate: false\n});```", 474 | "RandomFact": "", 475 | "GithubStars": 19390, 476 | "GitHubLink": "https://github.com/websockets/ws", 477 | "WeeklyDownloads": 70632670 478 | }, 479 | { 480 | "Name": "Anime.js", 481 | "Description": "One of the best animation libraries that makes staggering follow-through animations so simple, ... is light-weight and comes with a clean yet powerful API.", 482 | "CodeExample": "```*redacted*({\n targets: 'div',\n translateX: 250,\n rotate: '1turn',\n backgroundColor: '#FFF',\n duration: 800\n});```", 483 | "RandomFact": "... works with anything web. CSS, SVG, DOM attributes and JavaScript Objects: animate everything with a single unified API.", 484 | "GithubStars": 44292, 485 | "GitHubLink": "https://github.com/juliangarnier/anime", 486 | "WeeklyDownloads": 139834 487 | }, 488 | { 489 | "Name": "handlebars", 490 | "Description": "... provides the power necessary to let you build semantic templates effectively with no frustration.", 491 | "CodeExample": "```var source = \"

Hello, my name is {{name}}. I am from {{hometown}}. I have \" +\n\"{{kids.length}} kids:

\" +\n\"\";\nvar template = *redacted*.compile(source);\n```", 492 | "RandomFact": "... is an extension to the Mustache templating language created by Chris Wanstrath", 493 | "GithubStars": 17000, 494 | "GitHubLink": "github.com/wycats/handlebars.js", 495 | "WeeklyDownloads": 11499396 496 | }, 497 | { 498 | "Name": "chai", 499 | "Description": "BDD / TDD assertion framework for node.js and the browser that can be paired with any testing framework.", 500 | "CodeExample": "```expect(foo).to.be.a('string');\nexpect(foo).to.equal('bar');\nexpect(foo).to.have.lengthOf(3);\nexpect(tea).to.have.property('flavors')\n .with.lengthOf(3);```", 501 | "RandomFact": "... is an assertion library, similar to Node's built-in assert. It makes testing much easier by giving you lots of assertions you can run against your code.", 502 | "GithubStars": 7800, 503 | "GitHubLink": "https://github.com/chaijs/chai", 504 | "WeeklyDownloads": 6500518 505 | }, 506 | { 507 | "Name": "eslint", 508 | "Description": "An AST-based pattern checker for JavaScript.", 509 | "CodeExample": "```{\n \"rules\": {\n \"semi\": [\"error\", \"always\"],\n \"quotes\": [\"error\", \"double\"]\n }\n}```", 510 | "RandomFact": "... uses Espree for JavaScript parsing.", 511 | "GithubStars": 22131, 512 | "GitHubLink": "https://github.com/eslint/eslint", 513 | "WeeklyDownloads": 30831843 514 | }, 515 | { 516 | "Name": "dotenv", 517 | "Description": "... is a zero-dependency module that loads environment variables from a .env file into process.env.", 518 | "CodeExample": "```ENV_VAR1=value1\nENV_VAR2=value2```", 519 | "RandomFact": "... using BSD-2-Clause license", 520 | "GithubStars": 16618, 521 | "GitHubLink": "https://github.com/motdotla/dotenv", 522 | "WeeklyDownloads": 31298221 523 | }, 524 | { 525 | "Name": "bootstrap", 526 | "Description": "Sleek, intuitive, and powerful front-end framework for faster and easier web development.", 527 | "CodeExample": "```
\n

Hello World!

\n

Resize the browser window to see the effect.

\n

The columns will automatically stack on top of each other when the screen is less than 768px wide.

\n
\n
.col-sm-4
\n
.col-sm-4
\n
.col-sm-4
\n
\n
\n```", 528 | "RandomFact": "Add toggleable hidden elements, modals and offcanvas menus, popovers and tooltips, and so much more—all without jQuery.", 529 | "GithubStars": 161613, 530 | "GitHubLink": "github.com/twbs/bootstrap", 531 | "WeeklyDownloads": 5272727 532 | }, 533 | { 534 | "Name": "tailwindcss", 535 | "Description": "A utility-first CSS framework for rapidly building custom user interfaces.", 536 | "CodeExample": "```
\n \"\" \n
\n
\n

\n \u201C... is the only framework that I've seen scale \n on large teams. It\u2019s easy to customize, adapts to any design, \n and the build size is tiny.\u201D\n

\n
\n
\n
\n Sarah Dayan \n
\n
\n Staff Engineer, Algolia \n
\n
\n
\n
```", 537 | "RandomFact": "Utility classes help you work within the constraints of a system instead of littering your stylesheets with arbitrary values.", 538 | "GithubStars": 64720, 539 | "GitHubLink": "https://github.com/tailwindlabs/tailwindcss", 540 | "WeeklyDownloads": 4919224 541 | }, 542 | { 543 | "Name": "joi", 544 | "Description": "The most powerful schema description language and data validator for JavaScript.", 545 | "CodeExample": "```const schema = *redacted*.object({\n username: *redacted*.string()\n .alphanum()\n .min(3)\n .max(30)\n .required(),\n birth_year: *redacted*.number()\n .integer()\n .min(1900)\n .max(2013),\n})\nschema.validate({ username: 'abc', birth_year: 1994 });\n```", 546 | "RandomFact": "The word is similar to an other with this meaning: a feeling of great pleasure and happiness.", 547 | "GithubStars": 19658, 548 | "GitHubLink": "github.com/hapijs/joi", 549 | "WeeklyDownloads": 7459163 550 | }, 551 | { 552 | "Name": "formik", 553 | "Description": "Build forms in React, without the tears.", 554 | "CodeExample": "```<*redacted*\n initialValues={ {\n firstName: \"\",\n lastName: \"\",\n email: \"\",\n }}\n onSubmit={(values: Values, { setSubmitting }: FormikHelpers) => {\n setTimeout(() => {\n alert(JSON.stringify(values, null, 2));\n setSubmitting(false);\n }, 500);\n }}\n>\n
\n \n \n \n \n \n \n \n \n;\n```", 555 | "RandomFact": "Since form state is inherently local and ephemeral, ... does not use external state management libraries like Redux or MobX.", 556 | "GithubStars": 31853, 557 | "GitHubLink": "github.com/formium/formik", 558 | "WeeklyDownloads": 2200539 559 | }, 560 | { 561 | "Name": "md5", 562 | "Description": "a JavaScript function for hashing messages with ...", 563 | "CodeExample": "```console.log(*redacted*('message'));\n// output: 78e731027d8fd50ed642340b7c9a63b3```", 564 | "RandomFact": "The ... message-digest algorithm is a widely used hash function producing a 128-bit hash value. ... was designed by Ronald Rivest in 1991 to replace an earlier hash function ..., and was specified in 1992 as RFC 1321.", 565 | "GithubStars": 861, 566 | "GitHubLink": "github.com/pvorb/node-md5", 567 | "WeeklyDownloads": 5981906 568 | }, 569 | { 570 | "Name": "tensorflow", 571 | "Description": "A WebGL accelerated JavaScript library for training and deploying ML models.", 572 | "CodeExample": "```import * as tf from '*redacted*';\n// You have the Core API: tf.matMul(), tf.softmax(), ...\n// You also have Layers API: tf.model(), tf.layers.dense(), ...```", 573 | "RandomFact": "Use flexible and intuitive APIs to build models from scratch using the low-level JavaScript linear algebra library or the high-level layers API.", 574 | "GithubStars": 16978, 575 | "GitHubLink": "https://github.com/tensorflow/tfjs", 576 | "WeeklyDownloads": 103687 577 | }, 578 | { 579 | "Name": "mithril.js", 580 | "Description": "A modern client-side JavaScript framework for building Single Page Applications.", 581 | "CodeExample": "```var root = document.body\nm.render(root, \"Hello world\")```", 582 | "RandomFact": "It's small (10.05 KB gzipped), fast and provides routing and XHR utilities out of the box.", 583 | "GithubStars": 13557, 584 | "GitHubLink": "https://github.com/MithrilJS/mithril.js", 585 | "WeeklyDownloads": 43136 586 | }, 587 | { 588 | "Name": "prisma", 589 | "Description": "Next-generation ORM for Node.js & TypeScript", 590 | "CodeExample": "```// schema\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n// Generator\ngenerator client {\n provider = \"...\"\n}\n// Data model\nmodel Post {\n id Int @id @default(autoincrement())\n title String\n content String?\n published Boolean @default(false)\n author User? @relation(fields: [authorId], references: [id])\n authorId Int?\n}\nmodel User {\n id Int @id @default(autoincrement())\n email String @unique\n name String?\n posts Post[]\n}```", 591 | "RandomFact": "Every project that uses a tool from the ... toolkit starts with a ... schema file.", 592 | "GithubStars": 93096, 593 | "GitHubLink": "https://github.com/nodejs/node", 594 | "WeeklyDownloads": 940448 595 | }, 596 | { 597 | "Name": "aurelia", 598 | "Description": "... is a modern, front-end JavaScript framework for building browser, mobile, and desktop applications.", 599 | "CodeExample": "```//app.js \n export class App { \n welcome = \"Hello World!\"; \n quests = [ \n \"To seek the holy grail\", \n \"To take the ring to Mordor\", \n \"To rescue princess Leia\" \n ]; \n } \n \n
\n \n \n
\n

${welcome}, ${name}!

\n

Now set forth ${quest.toLowerCase()}!

```", 600 | "RandomFact": "Version 2, ... applications are built by composing a series of simple components.", 601 | "GithubStars": 1255, 602 | "GitHubLink": "https://github.com/aurelia/aurelia", 603 | "WeeklyDownloads": 932 604 | }, 605 | { 606 | "Name": "leaflet", 607 | "Description": "JavaScript library for mobile-friendly interactive maps", 608 | "CodeExample": "```var map = L.map('map').setView([51.505, -0.09], 13);\nL.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {\n attribution: '© OpenStreetMap contributors'\n}).addTo(map);\nL.marker([51.5, -0.09]).addTo(map)\n .bindPopup('A pretty CSS3 popup.
Easily customizable.')\n .openPopup();```", 609 | "RandomFact": "Weighing just about 42 KB of gzipped JS plus 4 KB of gzipped CSS code", 610 | "GithubStars": 36689, 611 | "GitHubLink": "https://github.com/Leaflet/Leaflet", 612 | "WeeklyDownloads": 775609 613 | }, 614 | { 615 | "Name": "Cleave.js", 616 | "Description": "... has a simple purpose: to help you format input text content automatically.", 617 | "CodeExample": "```// template\n\n// script\nvar c = new *redacted*('.input-phone', {\n phone: true,\n phoneRegionCode: '{country}'\n});```", 618 | "RandomFact": "Used by more than 10700 projects on GitHub.", 619 | "GithubStars": 17682, 620 | "GitHubLink": "https://github.com/nosir/cleave.js", 621 | "WeeklyDownloads": 255682 622 | }, 623 | { 624 | "Name": "alpinejs", 625 | "Description": "A rugged, minimal framework for composing JavaScript behavior in your markup.", 626 | "CodeExample": "```
\n \n \nContent... \n \n
```", 627 | "RandomFact": "... is a rugged, minimal tool for composing behavior directly in your markup. Think of it like jQuery for the modern web. ", 628 | "GithubStars": 22948, 629 | "GitHubLink": "github.com/alpinejs/alpine", 630 | "WeeklyDownloads": 135126 631 | } 632 | ] 633 | -------------------------------------------------------------------------------- /api/pkg/processor/processor.go: -------------------------------------------------------------------------------- 1 | package processor 2 | 3 | import ( 4 | _ "embed" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | 9 | "github.com/rs/zerolog/log" 10 | ) 11 | 12 | type QuizRecord struct { 13 | Name string 14 | Description string 15 | CodeExample string 16 | RandomFact string 17 | GithubStars int 18 | GithubLink string 19 | WeeklyDownloads int 20 | } 21 | 22 | //go:embed javascript.json 23 | var data []byte 24 | 25 | func (c *QuizRecord) String() string { 26 | return fmt.Sprintf("Company: %v, GH: %v,"+ 27 | c.Name, c.Description) 28 | } 29 | 30 | type QuizSequence []*QuizRecord 31 | 32 | func (c *QuizRecord) Render(w http.ResponseWriter, r *http.Request) error { 33 | return nil 34 | } 35 | 36 | func ReadJSONData() QuizSequence { 37 | list := QuizSequence{} 38 | fmt.Printf("%d", len(data)) 39 | err := json.Unmarshal(data, &list) 40 | if err != nil { 41 | log.Fatal().Err(err) 42 | return nil 43 | } 44 | return list 45 | } 46 | 47 | func MaskAndFilter(list QuizSequence, startCountFilter int) QuizSequence { 48 | result := QuizSequence{} 49 | 50 | for _, i := range list { 51 | if startCountFilter > 0 && i.GithubStars < startCountFilter { 52 | continue 53 | } 54 | result = append(result, i) 55 | } 56 | 57 | return result 58 | } 59 | -------------------------------------------------------------------------------- /api/pkg/server/middleware.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/dyrector-io/xor/api/internal/config" 7 | "github.com/dyrector-io/xor/api/internal/ctx" 8 | "github.com/dyrector-io/xor/api/pkg/game" 9 | ) 10 | 11 | func ResetQuiz(next http.Handler) http.Handler { 12 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 13 | appState := ctx.GetContextVar[*config.AppState](r.Context(), ctx.StateKey) 14 | game.SelectAQuiz(appState) 15 | next.ServeHTTP(w, r) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /api/pkg/server/routes.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/dyrector-io/xor/api/internal/config" 8 | "github.com/dyrector-io/xor/api/internal/ctx" 9 | "github.com/dyrector-io/xor/api/pkg/database" 10 | "github.com/dyrector-io/xor/api/pkg/processor" 11 | "github.com/go-chi/render" 12 | "github.com/rs/zerolog/log" 13 | ) 14 | 15 | type QuizListResponse struct { 16 | List processor.QuizSequence 17 | Date string 18 | } 19 | 20 | func (c *QuizListResponse) Render(w http.ResponseWriter, r *http.Request) error { 21 | return nil 22 | } 23 | 24 | func QuizHistoryResponse(list database.HistoryList) []render.Renderer { 25 | result := []render.Renderer{} 26 | for _, item := range list { 27 | result = append(result, item) 28 | } 29 | return result 30 | } 31 | 32 | func GetQuiz(w http.ResponseWriter, r *http.Request) { 33 | appState := ctx.GetContextVar[*config.AppState](r.Context(), ctx.StateKey) 34 | if appState.Ended { 35 | http.Error(w, http.StatusText(http.StatusGone), http.StatusGone) 36 | return 37 | } 38 | err := render.Render(w, r, &QuizListResponse{ 39 | List: appState.QuizList, 40 | Date: time.Now().Add(time.Hour * 24 * time.Duration(appState.QuizCounter)).Format(database.SimpleDateFormat), 41 | }) 42 | if err != nil { 43 | log.Error().Err(err) 44 | } 45 | } 46 | 47 | func GetHistory(w http.ResponseWriter, r *http.Request) { 48 | appState := ctx.GetContextVar[*config.AppState](r.Context(), ctx.StateKey) 49 | err := render.RenderList(w, r, QuizHistoryResponse(database.GetHistoryDB(appState.DBConn))) 50 | if err != nil { 51 | log.Error().Err(err) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /api/pkg/server/server.go: -------------------------------------------------------------------------------- 1 | package server 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | "time" 8 | 9 | chiprometheus "github.com/766b/chi-prometheus" 10 | "github.com/dyrector-io/xor/api/internal/config" 11 | "github.com/dyrector-io/xor/api/internal/ctx" 12 | "github.com/dyrector-io/xor/api/pkg/database" 13 | "github.com/dyrector-io/xor/api/pkg/game" 14 | "github.com/go-chi/chi" 15 | "github.com/go-chi/chi/middleware" 16 | "github.com/go-chi/cors" 17 | "github.com/go-chi/httprate" 18 | "github.com/go-co-op/gocron" 19 | "github.com/prometheus/client_golang/prometheus/promhttp" 20 | "github.com/rs/zerolog/log" 21 | "gorm.io/gorm" 22 | ) 23 | 24 | const ( 25 | HTTPReadHeaderTimeout = 3 * time.Second 26 | HTTPTimeout = 60 * time.Second 27 | RateLimitPerMin = 100 28 | ) 29 | 30 | type LogWriter struct { 31 | http.ResponseWriter 32 | } 33 | 34 | func (w LogWriter) Write(p []byte) { 35 | _, err := w.ResponseWriter.Write(p) 36 | if err != nil { 37 | log.Error().Err(err).Msgf("write failed: %v", err) 38 | } 39 | } 40 | 41 | func GetChi(appConfig *config.AppConfig) *http.Server { 42 | r := chi.NewRouter() 43 | 44 | r.Use(middleware.RequestID) 45 | r.Use(middleware.RealIP) 46 | r.Use(middleware.Logger) 47 | r.Use(middleware.Recoverer) 48 | 49 | m := chiprometheus.NewMiddleware("xor-quiz-api") 50 | r.Use(m) 51 | origins := []string{} 52 | if appConfig.Debug { 53 | origins = append(origins, "http://*", "https://*") 54 | } 55 | if appConfig.AllowedOrigins != "" { 56 | origins = append(origins, strings.Split(appConfig.AllowedOrigins, ",")...) 57 | } 58 | log.Info().Msgf("allowed origins: %v", origins) 59 | r.Use(cors.Handler(cors.Options{ 60 | AllowedOrigins: origins, 61 | AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, 62 | AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"}, 63 | ExposedHeaders: []string{"Link"}, 64 | AllowCredentials: false, 65 | MaxAge: 300, 66 | })) 67 | 68 | var db *gorm.DB 69 | if appConfig.DSN != "" { 70 | db = database.InitPostgres(appConfig) 71 | } 72 | 73 | appState := &config.AppState{ 74 | AppConfig: appConfig, 75 | DBConn: db, 76 | } 77 | 78 | if appState.AppConfig.Method == "" { 79 | game.SelectAQuiz(appState) 80 | } 81 | 82 | r.Use(func(next http.Handler) http.Handler { 83 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 84 | next.ServeHTTP(w, r.WithContext(ctx.SetContextVar(r.Context(), ctx.StateKey, appState))) 85 | }) 86 | }) 87 | 88 | if appState.AppConfig.Freq == "request" { 89 | r.Use(ResetQuiz) 90 | } 91 | 92 | r.Use(httprate.Limit( 93 | RateLimitPerMin, 94 | 1*time.Minute, 95 | httprate.WithKeyFuncs(httprate.KeyByRealIP, httprate.KeyByEndpoint), 96 | )) 97 | 98 | r.Use(middleware.Timeout(HTTPTimeout)) 99 | 100 | r.Handle("/metrics", promhttp.Handler()) 101 | r.Get("/", func(w http.ResponseWriter, r *http.Request) { 102 | LogWriter{w}.WriteHeader(http.StatusOK) 103 | }) 104 | 105 | r.Get("/quiz", GetQuiz) 106 | 107 | r.Get("/history", GetHistory) 108 | 109 | r.Get("/ping", func(w http.ResponseWriter, r *http.Request) { 110 | LogWriter{w}.Write([]byte("pong")) 111 | }) 112 | 113 | r.Get("/panic", func(w http.ResponseWriter, r *http.Request) { 114 | panic("test") 115 | }) 116 | 117 | server := &http.Server{ 118 | Addr: fmt.Sprintf(":%v", appConfig.Port), 119 | ReadHeaderTimeout: HTTPReadHeaderTimeout, 120 | Handler: r, 121 | } 122 | 123 | s := gocron.NewScheduler(time.UTC) 124 | _, err := s.Every(1).Day().At("00:01").Do(game.SelectAQuiz, appState) 125 | if err != nil { 126 | log.Error().Err(err).Msg("daily quiz gen cron is not ok") 127 | } 128 | s.StartAsync() 129 | 130 | return server 131 | } 132 | -------------------------------------------------------------------------------- /docker-compose-db.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | postgres: 5 | container_name: postgres 6 | image: postgres 7 | environment: 8 | POSTGRES_USER: ${POSTGRES_USER:-postgres} 9 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} 10 | PGDATA: /data/postgres 11 | volumes: 12 | - postgres:/data/postgres 13 | ports: 14 | - "5432:5432" 15 | 16 | volumes: 17 | postgres: 18 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | postgres: 5 | container_name: postgres 6 | image: postgres 7 | environment: 8 | POSTGRES_USER: ${POSTGRES_USER:-postgres} 9 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password} 10 | PGDATA: /data/postgres 11 | volumes: 12 | - postgres:/data/postgres 13 | restart: unless-stopped 14 | api: 15 | depends_on: 16 | - "postgres" 17 | container_name: xor-api 18 | image: ghcr.io/dyrector-io/xor/api:2 19 | restart: unless-stopped 20 | user: "1000" 21 | build: 22 | context: api 23 | expose: 24 | - "3333" 25 | ports: 26 | - "3333:3333" 27 | labels: 28 | - "traefik.enable=true" 29 | - "traefik.http.routers.xor-api.rule=Host(`js.xor.dyrectorio.com`) && PathPrefix(`/api`)" 30 | - "traefik.http.routers.xor-api.entrypoints=websecure" 31 | - "traefik.http.routers.xor-api.tls.certresolver=le" 32 | - "traefik.http.middlewares.xor-strip.stripprefix.prefixes=/api" 33 | - "traefik.http.routers.xor-api.middlewares=xor-strip" 34 | environment: 35 | DSN: ${DSN:-host=172.17.0.1 user=postgres password=password dbname=postgres port=5432 sslmode=disable} 36 | ALLOWED_ORIGINS: ${ALLOWED_ORIGINS:-http://*, https://*"} 37 | FREQ: ${FREQ} 38 | METHOD: ${METHOD} 39 | 40 | ui: 41 | depends_on: 42 | - "api" 43 | container_name: xor-ui 44 | image: ghcr.io/dyrector-io/xor/ui:2 45 | restart: unless-stopped 46 | user: "1000" 47 | # volumes: 48 | # - "./web/nginx/ui.conf:/etc/nginx/conf.d/ui.conf" 49 | build: 50 | context: web 51 | labels: 52 | - "traefik.enable=true" 53 | - "traefik.http.routers.xor-ui.rule=Host(`js.xor.dyrectorio.com`) && PathPrefix(`/`)" 54 | - "traefik.http.routers.xor-ui.entrypoints=websecure" 55 | - "traefik.http.routers.xor-ui.tls.certresolver=le" 56 | 57 | volumes: 58 | postgres: 59 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/dyrector-io/xor 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8 7 | github.com/go-chi/chi v1.5.4 8 | github.com/go-chi/cors v1.2.1 9 | github.com/go-chi/httprate v0.7.0 10 | github.com/go-co-op/gocron v1.18.0 11 | github.com/ilyakaznacheev/cleanenv v1.4.2 12 | github.com/prometheus/client_golang v1.14.0 13 | github.com/proullon/ramsql v0.0.0-20220719091513-bf3c20043516 14 | github.com/rs/zerolog v1.28.0 15 | github.com/stretchr/testify v1.8.1 16 | ) 17 | 18 | require ( 19 | github.com/ajg/form v1.5.1 // indirect 20 | github.com/beorn7/perks v1.0.1 // indirect 21 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 22 | github.com/davecgh/go-spew v1.1.1 // indirect 23 | github.com/golang/protobuf v1.5.2 // indirect 24 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 25 | github.com/jackc/pgconn v1.13.0 // indirect 26 | github.com/jackc/pgio v1.0.0 // indirect 27 | github.com/jackc/pgpassfile v1.0.0 // indirect 28 | github.com/jackc/pgproto3/v2 v2.3.1 // indirect 29 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect 30 | github.com/jackc/pgtype v1.12.0 // indirect 31 | github.com/jackc/pgx/v4 v4.17.2 // indirect 32 | github.com/jinzhu/inflection v1.0.0 // indirect 33 | github.com/jinzhu/now v1.1.4 // indirect 34 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 35 | github.com/pmezard/go-difflib v1.0.0 // indirect 36 | github.com/prometheus/client_model v0.3.0 // indirect 37 | github.com/prometheus/common v0.37.0 // indirect 38 | github.com/prometheus/procfs v0.8.0 // indirect 39 | github.com/robfig/cron/v3 v3.0.1 // indirect 40 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect 41 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect 42 | golang.org/x/text v0.3.7 // indirect 43 | google.golang.org/protobuf v1.28.1 // indirect 44 | ) 45 | 46 | require ( 47 | github.com/BurntSushi/toml v1.1.0 // indirect 48 | github.com/go-chi/render v1.0.2 49 | github.com/joho/godotenv v1.4.0 // indirect 50 | github.com/mattn/go-colorable v0.1.13 // indirect 51 | github.com/mattn/go-isatty v0.0.16 // indirect 52 | golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 53 | golang.org/x/sys v0.3.0 // indirect 54 | gopkg.in/yaml.v3 v3.0.1 // indirect 55 | gorm.io/driver/postgres v1.4.5 56 | gorm.io/gorm v1.24.2 57 | olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect 58 | ) 59 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 17 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 18 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 19 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 20 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 21 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 22 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 23 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 24 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 25 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 26 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 27 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 28 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 29 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 30 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 31 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 32 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 33 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 34 | github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8 h1:hK1G69lDhhrGqJbRA5i1rmT2KI/W77MSdr7hEGHqWdQ= 35 | github.com/766b/chi-prometheus v0.0.0-20211217152057-87afa9aa2ca8/go.mod h1:X/LhbmoBoRu8TxoGIOIraVNhfz3hhikJoaelrOuhdPY= 36 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 37 | github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= 38 | github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 39 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 40 | github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= 41 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 42 | github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= 43 | github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= 44 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 45 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 46 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 47 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 48 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 49 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 50 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 51 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 52 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 53 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 54 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 55 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 56 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 57 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 58 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 59 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 60 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 61 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 62 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= 63 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 64 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 65 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 66 | github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 67 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 68 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 69 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 70 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 71 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 72 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 73 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 74 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 75 | github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= 76 | github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= 77 | github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= 78 | github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= 79 | github.com/go-chi/httprate v0.7.0 h1:8W0dF7Xa2Duz2p8ncGaehIphrxQGNlOtoGY0+NRRfjQ= 80 | github.com/go-chi/httprate v0.7.0/go.mod h1:6GOYBSwnpra4CQfAKXu8sQZg+nZ0M1g9QnyFvxrAB8A= 81 | github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= 82 | github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= 83 | github.com/go-co-op/gocron v1.18.0 h1:SxTyJ5xnSN4byCq7b10LmmszFdxQlSQJod8s3gbnXxA= 84 | github.com/go-co-op/gocron v1.18.0/go.mod h1:sD/a0Aadtw5CpflUJ/lpP9Vfdk979Wl1Sg33HPHg0FY= 85 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 86 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 87 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 88 | github.com/go-gorp/gorp v2.0.0+incompatible h1:dIQPsBtl6/H1MjVseWuWPXa7ET4p6Dve4j3Hg+UjqYw= 89 | github.com/go-gorp/gorp v2.0.0+incompatible/go.mod h1:7IfkAQnO7jfT/9IQ3R9wL1dFhukN6aQxzKTHnkxzA/E= 90 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 91 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 92 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 93 | github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 94 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 95 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 96 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 97 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 98 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 99 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 100 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 101 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 102 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 103 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 104 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 105 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 106 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 107 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 108 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 109 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 110 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 111 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 112 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 113 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 114 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 115 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 116 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 117 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 118 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 119 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 120 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 121 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 122 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 123 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 124 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 125 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 126 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 127 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 128 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 129 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 130 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 131 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 132 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 133 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 134 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 135 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 136 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 137 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 138 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 139 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 140 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 141 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 142 | github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= 143 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 144 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 145 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 146 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 147 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 148 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 149 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 150 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 151 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 152 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 153 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 154 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 155 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 156 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 157 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 158 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 159 | github.com/ilyakaznacheev/cleanenv v1.4.2 h1:nRqiriLMAC7tz7GzjzUTBHfzdzw6SQ7XvTagkFqe/zU= 160 | github.com/ilyakaznacheev/cleanenv v1.4.2/go.mod h1:i0owW+HDxeGKE0/JPREJOdSCPIyOnmh6C0xhWAkF/xA= 161 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 162 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 163 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= 164 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 165 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 166 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 167 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 168 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 169 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 170 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 171 | github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= 172 | github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= 173 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= 174 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 175 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 176 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 177 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= 178 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 179 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 180 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 181 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 182 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 183 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 184 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 185 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 186 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 187 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 188 | github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= 189 | github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 190 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= 191 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 192 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 193 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 194 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 195 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 196 | github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= 197 | github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 198 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 199 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 200 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 201 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 202 | github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= 203 | github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= 204 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 205 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 206 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 207 | github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 208 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 209 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 210 | github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas= 211 | github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 212 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= 213 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 214 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 215 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 216 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 217 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 218 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 219 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 220 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 221 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 222 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 223 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 224 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 225 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 226 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 227 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 228 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 229 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 230 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 231 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 232 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 233 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 234 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 235 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 236 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 237 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 238 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 239 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 240 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 241 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 242 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 243 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 244 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 245 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 246 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 247 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 248 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 249 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 250 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 251 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 252 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 253 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 254 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 255 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 256 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 257 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 258 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 259 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 260 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 261 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 262 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 263 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 264 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 265 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 266 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 267 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 268 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 269 | github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= 270 | github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= 271 | github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= 272 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 273 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 274 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 275 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 276 | github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= 277 | github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 278 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 279 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 280 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 281 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 282 | github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= 283 | github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= 284 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 285 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 286 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 287 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 288 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 289 | github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= 290 | github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= 291 | github.com/proullon/ramsql v0.0.0-20220719091513-bf3c20043516 h1:bw5nFFzU6D6ksVYJX+oOt06qiJRWuEVB/OL3PwQIzz8= 292 | github.com/proullon/ramsql v0.0.0-20220719091513-bf3c20043516/go.mod h1:jG8oAQG0ZPHPyxg5QlMERS31airDC+ZuqiAe8DUvFVo= 293 | github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= 294 | github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= 295 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 296 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 297 | github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 298 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 299 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 300 | github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= 301 | github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= 302 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 303 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 304 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 305 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 306 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 307 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 308 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 309 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 310 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 311 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 312 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 313 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 314 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 315 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 316 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 317 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 318 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 319 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 320 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 321 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 322 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 323 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 324 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 325 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 326 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 327 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 328 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 329 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 330 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 331 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 332 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 333 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 334 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 335 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 336 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 337 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 338 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 339 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 340 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 341 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 342 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 343 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 344 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 345 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 346 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 347 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 348 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 349 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 350 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 351 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 352 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 353 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= 354 | golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 355 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 356 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 357 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 358 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 359 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 360 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 361 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 362 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 363 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 364 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 365 | golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15 h1:5oN1Pz/eDhCpbMbLstvIPa0b/BEQo6g6nwV3pLjfM6w= 366 | golang.org/x/exp v0.0.0-20221217163422-3c43f8badb15/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 367 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 368 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 369 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 370 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 371 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 372 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 373 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 374 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 375 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 376 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 377 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 378 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 379 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 380 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 381 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 382 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 383 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 384 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 385 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 386 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 387 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 388 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 389 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 390 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 391 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 392 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 393 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 394 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 395 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 396 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 397 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 398 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 399 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 400 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 401 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 402 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 403 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 404 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 405 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 406 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 407 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 408 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 409 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 410 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 411 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 412 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 413 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 414 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 415 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 416 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 417 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 418 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 419 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 420 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 421 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 422 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 423 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 424 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 425 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 426 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 427 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 428 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 429 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 430 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 431 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 432 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 433 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 434 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 435 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 436 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 437 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= 438 | golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 439 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 440 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 441 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 442 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 443 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 444 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 445 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 446 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 447 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 448 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 449 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 450 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 451 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 452 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 453 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 454 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 455 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 456 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 457 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 458 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 459 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 460 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 461 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 462 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 463 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 464 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 465 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 466 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 467 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 468 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 469 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 470 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 471 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 472 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 473 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 474 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 475 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 476 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 477 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 478 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 479 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 480 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 481 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 482 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 483 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 484 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 485 | golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= 486 | golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 487 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 488 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 489 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 490 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 491 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 492 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 493 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 494 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 495 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 496 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 497 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 498 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 499 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 500 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 501 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 502 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 503 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 504 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 505 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 506 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 507 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 508 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 509 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 510 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 511 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 512 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 513 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 514 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 515 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 516 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 517 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 518 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 519 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 520 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 521 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 522 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 523 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 524 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 525 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 526 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 527 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 528 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 529 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 530 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 531 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 532 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 533 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 534 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 535 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 536 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 537 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 538 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 539 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 540 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 541 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 542 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 543 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 544 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 545 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 546 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 547 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 548 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 549 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 550 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 551 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 552 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 553 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 554 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 555 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 556 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 557 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 558 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 559 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 560 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 561 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 562 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 563 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 564 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 565 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 566 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 567 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 568 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 569 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 570 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 571 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 572 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 573 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 574 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 575 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 576 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 577 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 578 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 579 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 580 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 581 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 582 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 583 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 584 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 585 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 586 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 587 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 588 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 589 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 590 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 591 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 592 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 593 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 594 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 595 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 596 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 597 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 598 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 599 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 600 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 601 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 602 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 603 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 604 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 605 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 606 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 607 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 608 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 609 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 610 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 611 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 612 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 613 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 614 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 615 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 616 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 617 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 618 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 619 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 620 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 621 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 622 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 623 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 624 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 625 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 626 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 627 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 628 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 629 | google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 630 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 631 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 632 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 633 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 634 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 635 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 636 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 637 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 638 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 639 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 640 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 641 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 642 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 643 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 644 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 645 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 646 | gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc= 647 | gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg= 648 | gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= 649 | gorm.io/gorm v1.24.2 h1:9wR6CFD+G8nOusLdvkZelOEhpJVwwHzpQOUM+REd6U0= 650 | gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA= 651 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 652 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 653 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 654 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 655 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 656 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 657 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 658 | olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ= 659 | olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3/go.mod h1:oVgVk4OWVDi43qWBEyGhXgYxt7+ED4iYNpTngSLX2Iw= 660 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 661 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 662 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 663 | -------------------------------------------------------------------------------- /web/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .eslint* 3 | .prettier 4 | .git* 5 | public 6 | .svelte-kit 7 | build -------------------------------------------------------------------------------- /web/.env.example: -------------------------------------------------------------------------------- 1 | PUBLIC_API_PATH=http://localhost:3333 -------------------------------------------------------------------------------- /web/.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /web/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /web/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /web/.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /web/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine as BUILDER 2 | WORKDIR /app 3 | COPY ./ /app/ 4 | RUN npm install && npm run build 5 | 6 | FROM nginxinc/nginx-unprivileged:1.23-alpine 7 | #COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf 8 | COPY ./nginx/ui.conf /etc/nginx/conf.d/default.conf 9 | COPY --from=BUILDER --chown=101:101 /app/build/ /usr/share/nginx/html -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /web/nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | 2 | # Number of worker processes. The optimial value depends on many things: 3 | # number of CPU cores, number of storage drives, etc. Setting it to a total 4 | # number of CPU cores is good starting point, or just leave it to `auto`. 5 | # Max number of connections = worker_processes * worker_connections 6 | worker_processes auto; 7 | 8 | # Max number of open files (RLIMIT_NOFILE) for worker processes. 9 | # Should be > worker_connections. 10 | worker_rlimit_nofile 8192; 11 | 12 | # Default loging location and level. 13 | error_log /etc/nginx/logs/error.log error; 14 | 15 | events { 16 | # Max number of simultaneous connections that can be opened by the worker 17 | # processes. The simultaneous connections cannot exceed the maximum 18 | # number of open files, thus: worker_connections < worker_rlimit_nofile. 19 | worker_connections 8000; 20 | } 21 | 22 | http { 23 | # Enable or disable emitting nginx version on response's header. 24 | server_tokens off; 25 | 26 | # Max size & bucket size for the server names hash table. 27 | server_names_hash_max_size 1024; 28 | server_names_hash_bucket_size 32; 29 | 30 | # Max size & bucket size for the mime types hash table. 31 | types_hash_max_size 2048; 32 | types_hash_bucket_size 32; 33 | 34 | # Speed up static file transfers by using the sendfile() rather than the 35 | # read() and write() combination. sendfile() has the ability to transfer 36 | # data from the file descriptor. 37 | sendfile on; 38 | 39 | # Optimize the amount of data that is being sent at once. Prevent Nginx 40 | # from sending a partial frame. As a result it will increases the 41 | # throughput, since TCP frames will be filled up before being sent out. 42 | # You also need to activate the `sendfile` option. 43 | tcp_nopush on; 44 | 45 | # By default, the TCP stack implements a mechanism to delay sending the 46 | # data up to 200ms. To force a socket to send the data in its buffer 47 | # immediately we can turn this option on. 48 | tcp_nodelay on; 49 | 50 | # A timeout of which a keep-alive connection will stay open. Longer 51 | # duration are better for client, especially on SSL, the downside is the 52 | # worker connection is occupied longer. 53 | keepalive_timeout 20s; 54 | 55 | # Mime types. 56 | include mime.types; 57 | default_type application/octet-stream; 58 | 59 | # Update the charset to match the updated mime.types. 60 | # By efault the `text/html` is always included by the charset module. 61 | charset_types 62 | text/css 63 | text/plain 64 | text/vnd.wap.wml 65 | application/javascript 66 | application/json 67 | application/rss+xml 68 | application/xml; 69 | 70 | # Request log format. 71 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 72 | '$status $body_bytes_sent "$http_referer" ' 73 | '"$http_user_agent" "$http_x_forwarded_for"'; 74 | 75 | # The request log file path. 76 | access_log /etc/nginx/logs/access.log main; 77 | 78 | # Enable gzip compression. 79 | gzip on; 80 | 81 | # Gzip compression level (1-9). 82 | # 5 is a perfect compromise between size and CPU usage, offering about 83 | # 75% reduction for most ASCII files (almost identical to level 9). 84 | gzip_comp_level 5; 85 | 86 | # Don't compress a small file that is unlikely to shrink much. The small 87 | # file is also usually ended up in larger file sizes after gzipping. 88 | gzip_min_length 256; 89 | 90 | # Compress data even for a proxied connection. 91 | gzip_proxied any; 92 | 93 | # Cache both the regular and the gzipped versions of a resource whenever 94 | # client's Accept-Encoding capabilities header varies. 95 | gzip_vary on; 96 | 97 | # Compress all of the following mime-types, `text/html` is always 98 | # compressed. 99 | gzip_types 100 | application/atom+xml 101 | application/javascript 102 | application/json 103 | application/ld+json 104 | application/manifest+json 105 | application/rss+xml 106 | application/vnd.geo+json 107 | application/vnd.ms-fontobject 108 | application/x-font-ttf 109 | application/x-web-app-manifest+json 110 | application/xhtml+xml 111 | application/xml 112 | font/opentype 113 | image/bmp 114 | image/svg+xml 115 | image/x-icon 116 | text/cache-manifest 117 | text/css 118 | text/plain 119 | text/vcard 120 | text/vnd.rim.location.xloc 121 | text/vtt 122 | text/x-component 123 | text/x-cross-domain-policy; 124 | 125 | # Include other custom configurations. 126 | include conf.d/*.conf; 127 | 128 | # Include site configurations. 129 | include sites-enabled/*; 130 | } -------------------------------------------------------------------------------- /web/nginx/ui.conf: -------------------------------------------------------------------------------- 1 | server { 2 | root /usr/share/nginx/html; 3 | listen 8080; 4 | 5 | gzip on; 6 | gzip_min_length 1000; 7 | gzip_types text/plain text/xml application/javascript text/css; 8 | 9 | location ~ \.(js|css|png|ico)$ { 10 | try_files $uri $uri/ =404; 11 | } 12 | 13 | 14 | 15 | location /api/ { 16 | proxy_pass http://api:3333; 17 | proxy_http_version 1.1; 18 | proxy_set_header Upgrade $http_upgrade; 19 | proxy_set_header Connection "upgrade"; 20 | proxy_set_header X-Real-IP $remote_addr; 21 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 22 | proxy_set_header Host $http_host; 23 | proxy_read_timeout 86400; 24 | } 25 | 26 | location / { 27 | try_files $uri $uri/ $uri/index.html /index.html; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "vite dev", 7 | "dev": "vite dev", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 12 | "build-image": "docker build -t ", 13 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 14 | "format": "prettier --plugin-search-dir . --write ." 15 | }, 16 | "devDependencies": { 17 | "@sveltejs/adapter-auto": "^1.0.0", 18 | "@sveltejs/kit": "^1.0.0", 19 | "@typescript-eslint/eslint-plugin": "^5.45.0", 20 | "@typescript-eslint/parser": "^5.45.0", 21 | "autoprefixer": "^10.4.13", 22 | "eslint": "^8.28.0", 23 | "eslint-config-prettier": "^8.5.0", 24 | "eslint-plugin-svelte3": "^4.0.0", 25 | "fuzzyset.js": "^1.0.7", 26 | "postcss": "^8.4.20", 27 | "prettier": "^2.8.0", 28 | "prettier-plugin-svelte": "^2.8.1", 29 | "svelte": "^3.54.0", 30 | "svelte-check": "^2.9.2", 31 | "tailwindcss": "^3.2.4", 32 | "tslib": "^2.4.1", 33 | "typescript": "^4.9.3", 34 | "vite": "^4.0.0" 35 | }, 36 | "type": "module", 37 | "dependencies": { 38 | "@sveltejs/adapter-static": "^1.0.0", 39 | "highlight.js": "^11.7.0", 40 | "svelte-local-storage-store": "^0.3.2", 41 | "svelte-markdown": "^0.2.3" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /web/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /web/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .highlight { 6 | background-color: rgba(0, 138, 69, 0.5); 7 | } 8 | -------------------------------------------------------------------------------- /web/src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | // and what to do when importing types 4 | declare namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface Platform {} 9 | } 10 | -------------------------------------------------------------------------------- /web/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | XOR Quiz 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 19 | %sveltekit.head% 20 | 21 | 22 |
%sveltekit.body%
23 | 24 | 25 | -------------------------------------------------------------------------------- /web/src/components/Button.svelte: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /web/src/components/Code.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
{codeContent}
7 | 8 | 17 | -------------------------------------------------------------------------------- /web/src/components/Modal.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 46 | 47 | 53 | -------------------------------------------------------------------------------- /web/src/components/Question.svelte: -------------------------------------------------------------------------------- 1 | 67 | 68 |
69 |
70 | 71 | Question: 72 | {index + 1}/5 73 | Attempts: 74 | {$guessNumber}/3 75 |
76 | 77 | 78 |

Description: {question.Description}

79 |

Random fact: {question.RandomFact}

80 |

81 | Code example:
82 | 91 |

92 |

93 | GitHub Stars: 94 | {question.GithubStars.toLocaleString('en-US')} / Weekly npm downloads: 95 | {question.WeeklyDownloads.toLocaleString('en-US')} 96 |

97 |
98 | 99 |
100 | 108 | {#if index < 4} 109 | 110 | 111 | {:else} 112 | {#if $guessNumber === 2} 113 | 114 | {:else} 115 | 116 | {/if} 117 | 118 | {/if} 119 |
120 | 121 | {#if isAnswered} 122 | {#if !isCorrect} 123 |
124 | Wrong! Try harder! 125 |
126 | {/if} 127 | {/if} 128 | 129 |
130 | Your result: {$score.join('')} 131 |
132 | 133 | 142 | -------------------------------------------------------------------------------- /web/src/lib/results.ts: -------------------------------------------------------------------------------- 1 | import type { ResultItem } from 'src/types/result.type'; 2 | import { writable } from 'svelte-local-storage-store'; 3 | 4 | // First param `preferences` is the local storage key. 5 | // Second param is the initial value. 6 | export const resultStore = writable('results', new Array()); 7 | -------------------------------------------------------------------------------- /web/src/lib/store.ts: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | 3 | export const score = writable(['⚪', '⚪', '⚪', '⚪', '⚪']); 4 | 5 | export const questionNumber = writable(0); 6 | export const hintNumber = writable(0); 7 | export const guessNumber = writable(0); 8 | -------------------------------------------------------------------------------- /web/src/routes/+error.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |

ERROR {$page.status}: {$page.error.message}

6 | -------------------------------------------------------------------------------- /web/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 |
10 | 16 |
17 | 18 |
19 | 20 |
21 | 22 | 25 |
26 | 27 | 41 | -------------------------------------------------------------------------------- /web/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 |
24 |

Home

25 |
26 | 32 | 33 | 38 | 44 | 45 |

46 | contact: hello@dyrector.io 49 | / repository: 50 | dyrector-io/xor 53 |

54 |
55 |
56 | -------------------------------------------------------------------------------- /web/src/routes/history/+page.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
16 |

History

17 |

Take a look at previously included projects.

18 |
19 | {#each history as item} 20 |
  • {item.Date}: {item.Projects}
  • 21 | {/each} 22 |
    23 |
    24 | -------------------------------------------------------------------------------- /web/src/routes/quiz/+page.svelte: -------------------------------------------------------------------------------- 1 | 80 | 81 |

    XOR Quiz

    82 | 83 | {#if gone} 84 |
    85 | The quiz is ended. Please come back later or visit the repository for more information. 90 |
    91 | {:else if filledForToday} 92 |
    93 | You are done with the today quiz. Check your results here. 96 | 97 |

    Today solutions:

    98 | {#each quiz.List as question, index} 99 |
  • #{index + 1} {question.Name}
  • 100 | {/each} 101 |
    102 | {:else} 103 |
    104 | {#each quiz.List as question, index} 105 | {#if index === $questionNumber} 106 | 107 | {/if} 108 | {/each} 109 |
    110 | {/if} 111 | 112 | {#if quiz.Date && filledForToday && !closed && todayResult} 113 | 114 | {/if} 115 | -------------------------------------------------------------------------------- /web/src/routes/result/+page.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
    18 |

    Results

    19 | 20 | {#if resultsHistory.length === 0} 21 |
    Empty.
    22 | {:else} 23 | {#each resultsHistory as result} 24 |
  • {result.date}: {result.points.join('')}
  • 25 | {/each} 26 | {/if} 27 |
    28 | -------------------------------------------------------------------------------- /web/src/types/history.type.ts: -------------------------------------------------------------------------------- 1 | export type HistoryItem = { 2 | Date: string; 3 | Projects: string; 4 | }; 5 | 6 | export type HistoryResponse = { 7 | result: Array; 8 | }; 9 | -------------------------------------------------------------------------------- /web/src/types/quiz.type.ts: -------------------------------------------------------------------------------- 1 | export type QuizItem = { 2 | Name: string; 3 | CrunchbaseDescription: string; 4 | GithubDescription: string; 5 | Logo: string; 6 | Category: string; 7 | Subcategory: string; 8 | GithubStars: number; 9 | GithubContributorsCount: number; 10 | }; 11 | 12 | export type JavascriptQuizItem = { 13 | Name: string; 14 | Description: string; 15 | CodeExample: string; 16 | RandomFact: string; 17 | GitHubLink: string; 18 | GithubStars: number; 19 | WeeklyDownloads: number; 20 | }; 21 | 22 | export type QuizResponse = { 23 | List: Array; 24 | Date: string; 25 | }; 26 | -------------------------------------------------------------------------------- /web/src/types/result.type.ts: -------------------------------------------------------------------------------- 1 | export type ResultItem = { 2 | date: string; 3 | points: string[]; 4 | }; 5 | -------------------------------------------------------------------------------- /web/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyrector-io/xor/6cb3d192f000811de972fb8e32ed8204294ab235/web/static/favicon.png -------------------------------------------------------------------------------- /web/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | import { vitePreprocess } from '@sveltejs/kit/vite'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | adapter: adapter({ 12 | fallback: "index.html", 13 | }), 14 | prerender: { 15 | entries: ["*"], 16 | } 17 | }, 18 | }; 19 | 20 | export default config; 21 | -------------------------------------------------------------------------------- /web/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./src/**/*.{html,js,svelte,ts}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | } 9 | -------------------------------------------------------------------------------- /web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true 12 | } 13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 14 | // 15 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /web/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | 3 | /** @type {import('vite').UserConfig} */ 4 | const config = { 5 | plugins: [sveltekit()] 6 | }; 7 | 8 | export default config; 9 | --------------------------------------------------------------------------------