From 1af4d33b95fccb1de43e4170a27f620d87715de3 Mon Sep 17 00:00:00 2001 From: Matt McCoy <59743922+MattCMcCoy@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:20:47 -0500 Subject: [PATCH] feat: start to full stack dev code (#10) * feat: full stack dev code config files, db setup, BE connection to FE, swagger, github workflow, pull request template BREAKING CHANGE: * refactor: folder structure, file simplification, and tons of readme stuffs * docs: readme badge fix * test: db test now uses connect database function and pings that connection * ci: various clean up things with ci * refactor: remove go/prettier precommit hooks so go can go into backend * ci: fix lint * ci: updates to work better with windows * ci: fix build task failing * ci: add configuration env file support for ngrok domain name * style: rename types folder to models in the be, put the env file setup in a before running section in readme * docs: mention commitizen installation in readme --- .github/pull_request_template.md | 19 ++ .github/workflows/CI.yml | 121 ++++++++++ .gitignore | 23 ++ .pre-commit-config.yaml | 17 ++ .prettierrc | 10 + README.md | 114 +++++++++- Taskfile.yaml | 52 +++++ backend/configuration/config.go | 62 +++++ backend/configuration/github.yaml | 7 + backend/configuration/local.yaml | 7 + backend/db/db.go | 38 ++++ backend/db/db_test.go | 31 +++ backend/db/migrations/init.sql | 16 ++ backend/docs/docs.go | 70 ++++++ backend/docs/swagger.json | 45 ++++ backend/docs/swagger.yaml | 29 +++ backend/go.mod | 73 ++++++ backend/go.sum | 226 +++++++++++++++++++ backend/main.go | 48 ++++ backend/models/medication.go | 6 + backend/schema/medication/medication_test.go | 81 +++++++ backend/schema/medication/routes.go | 39 ++++ backend/schema/medication/transactions.go | 36 +++ client/App.tsx | 21 ++ client/app.json | 28 +++ client/assets/adaptive-icon.png | Bin 0 -> 17547 bytes client/assets/favicon.png | Bin 0 -> 1466 bytes client/assets/icon.png | Bin 0 -> 22380 bytes client/assets/splash.png | Bin 0 -> 47346 bytes client/babel.config.js | 7 + client/metro.config.js | 6 + client/nativewind.d.ts | 1 + client/package.json | 32 +++ client/services/api-links.ts | 1 + client/services/medication.ts | 7 + client/tailwind.config.js | 8 + client/tsconfig.json | 7 + client/types/app.d.ts | 4 + docker-compose.yaml | 20 ++ 39 files changed, 1311 insertions(+), 1 deletion(-) create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/CI.yml create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 .prettierrc create mode 100644 Taskfile.yaml create mode 100644 backend/configuration/config.go create mode 100644 backend/configuration/github.yaml create mode 100644 backend/configuration/local.yaml create mode 100644 backend/db/db.go create mode 100644 backend/db/db_test.go create mode 100644 backend/db/migrations/init.sql create mode 100644 backend/docs/docs.go create mode 100644 backend/docs/swagger.json create mode 100644 backend/docs/swagger.yaml create mode 100644 backend/go.mod create mode 100644 backend/go.sum create mode 100644 backend/main.go create mode 100644 backend/models/medication.go create mode 100644 backend/schema/medication/medication_test.go create mode 100644 backend/schema/medication/routes.go create mode 100644 backend/schema/medication/transactions.go create mode 100644 client/App.tsx create mode 100644 client/app.json create mode 100644 client/assets/adaptive-icon.png create mode 100644 client/assets/favicon.png create mode 100644 client/assets/icon.png create mode 100644 client/assets/splash.png create mode 100644 client/babel.config.js create mode 100644 client/metro.config.js create mode 100644 client/nativewind.d.ts create mode 100644 client/package.json create mode 100644 client/services/api-links.ts create mode 100644 client/services/medication.ts create mode 100644 client/tailwind.config.js create mode 100644 client/tsconfig.json create mode 100644 client/types/app.d.ts create mode 100644 docker-compose.yaml diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..00c55e2 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,19 @@ +# Description + +[Link to Ticket](insert the link to your ticket inside the parenthesis here) + +Please include a summary of the changes and the related issue. Please also +include relevant motivation, context, and images! + +# How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. If they are unit +tests, provide the file name the tests are in. If they are not unit tests, +describe how you tested the change. + +# Checklist + +- [ ] I have performed a self-review of my code +- [ ] I have reached out to another developer to review my code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] New and existing unit tests pass locally with my changes diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..4ca54da --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,121 @@ +name: CI (Linting, Testing, Building) + +on: + push: + branches: ['main'] + pull_request: + branches: ['main'] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + go-version: [1.21.x] + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + + - name: Set up Node + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + - name: Lint Go code + run: | + cd backend + go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest + golangci-lint run ./... + + - name: Format Frontend + run: | + cd client + npm install + npm run format + + test: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + go-version: [1.21.x] + container: node:latest + + services: + postgres: + image: postgres:latest + env: + POSTGRES_PASSWORD: pwd + POSTGRES_USER: user + POSTGRES_DB: carewallet + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready --health-interval 10s --health-timeout 5s + --health-retries 5 + steps: + - name: Install PostgreSQL client + run: | + apt-get update + apt-get install --yes postgresql-client + - name: Check out repository code + uses: actions/checkout@v4 + + - name: Import DB seed data + run: + psql -d postgresql://user:pwd@172.17.0.1:5432/carewallet -f init.sql + working-directory: ./backend/db/migrations + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run Go tests + run: | + task test-all + + build: + name: Build + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20.x] + go-version: [1.21.x] + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + + - name: Set up Node + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + + - name: Install Task + uses: arduino/setup-task@v1 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Build app + run: | + task build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b73f19b --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Go workspace file +go.work + +*.DS_Store +*package-lock.json +vendor +*.expo +*node_modules + +*.env diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5805b47 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,17 @@ +default_stages: [commit, push] +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-added-large-files + - id: check-merge-conflict + - id: end-of-file-fixer + exclude: 'backend/docs/' + - id: trailing-whitespace + - id: no-commit-to-branch + args: ['--branch', 'main'] + - repo: https://github.com/commitizen-tools/commitizen + rev: v3.13.0 + hooks: + - id: commitizen + stages: [commit-msg] diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..77991e0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "semi": true, + "trailingComma": "none", + "singleQuote": true, + "printWidth": 80, + "tabWidth": 2, + "endOfLine": "auto", + "bracketSpacing": true, + "proseWrap": "always" +} diff --git a/README.md b/README.md index dca47d1..847b2d5 100644 --- a/README.md +++ b/README.md @@ -1 +1,113 @@ -# CareWallet \ No newline at end of file +
+ +## Set Up Your Development Environment + +First, understand the tech stack: + +- The database is [PostGreSQL](https://www.postgresql.org/) and will be + containerized using [Docker](https://www.docker.com/). +- The backend is [Golang](https://go.dev/) +- The frontend is [TypeScript](https://www.typescriptlang.org/) with + [ReactNative](https://reactnative.dev/) and + [NativeWind](https://www.nativewind.dev) and uses [Expo](https://expo.dev/) as + a build tool + +Before compiling and running our application, we need to install/setup several +languages, package managers, and various tools. The installation process can +vary, so follow the instructions for each item below! + +- [Go](https://go.dev/doc/install) - our primary backend language +- [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) - our + package manager in the frontend +- [Docker Desktop](https://www.docker.com/products/docker-desktop/) - useful for + running docker +- [ngrok](https://ngrok.com/docs/getting-started/) - Allows us to easily connect + the frontend to backend code +- [expo-go](https://docs.expo.dev/get-started/expo-go/) - Expo allows mobile + devices to scan a QR code and view the code running on a mobile device + +If you wish to simulate a phone from your computer either below will work: + +- [xcode](https://docs.expo.dev/workflow/ios-simulator/) - A simulator to view + the code on an iphone from a laptop +- [android studio](https://docs.expo.dev/workflow/android-studio-emulator/) - An + emulator to view the code on an android device from a laptop + +If everything was successful, you can now compile and run the project! + +Next, understand the development tools that will make our lives easier: + +- [Pre-commit](https://pre-commit.com) - standardizing code style and commits +- [Swagger](https://github.com/swaggo/swag) - visualizing the api and return + types of requests from the database +- [Task](https://taskfile.dev) - speeding up development by running long + commands in quick phrases + +Before committing anything, we need to install several tools. The installation +process can vary, so follow the instructions for each item below! + +- [pre-commit](https://pre-commit.com/#installation) - our development tool to + standardize development and ensure every file follows the same styling + guidelines. +- [commitizen](https://commitizen-tools.github.io/commitizen/#installation) - + This allows us to organize commits! By typing `cz c` instead of + `git commit -m ""`, we can organize each of our commits into one of nine + categories: + - **fix**: A bug fix. Correlates with PATCH in SemVer + - **feat**: A new feature. Correlates with MINOR in SemVer + - **docs**: Documentation only changes + - **style**: Changes that do not affect the meaning of the code (white-space, + formatting, missing semi-colons, etc) + - **refactor**: A code change that neither fixes a bug nor adds a feature + - **perf**: A code change that improves performance + - **test**: Adding missing or correcting existing tests + - **build**: Changes that affect the build system or external dependencies + (example scopes: pip, docker, npm) + - **ci**: Changes to our CI configuration files and scripts (example scopes: + GitLabCI) +- [Task](https://taskfile.dev/installation/) - our development tool to quickly + run commands that run, test, and clean files. + +## Before Running + +1. Create a .env file in the root directory with a single line: + `EXPO_PUBLIC_API_DOMAIN=your-ngrok-static-domain-here` + - this will be used by the frontend services as well as the task file to + launch ngrok! + +## Running the project + +1. Launch Docker Desktop +2. In the base of the repo: run `task start-docker` + + - This will run `docker-compose down` then `docker-compose up` + +3. To build all of the dependencies of the project: run `task build` + + - This will install both frontend and backend dependencies + +4. Then, open a new tab to run commands in: run `task start-backend` + + - This will generate the swagger docs as well as start the backend + - You can now view swagger: http://localhost:8080/swagger/index.html + +5. Next, in a new tab run `task start-ngrok` + +6. Finally, open one last new tab: run `task start-frontend` + + - This will start the frontend + +7. From here follow the prompt in step 6 to launch the frontend on your device + of choice diff --git a/Taskfile.yaml b/Taskfile.yaml new file mode 100644 index 0000000..394fb79 --- /dev/null +++ b/Taskfile.yaml @@ -0,0 +1,52 @@ +version: '3' +dotenv: ['.env'] +tasks: + build: + - | + cd client + npm install + cd ../backend + go mod tidy + go install . + + format: + - | + cd client + npm run format + cd ../backend + go fmt + go vet + swag f + + start-backend: + - | + cd backend + swag i --parseDependency + go run main.go + + start-frontend: + - | + cd client + npm start + + start-ngrok: + dotenv: ['.env'] + cmds: + - | + cd backend + ngrok http --domain=$EXPO_PUBLIC_API_DOMAIN 8080 + + start-docker: + - | + docker-compose down + docker-compose up + + test-all: + - | + cd backend + go test -count=1 carewallet/... + + pre-commit: + - | + pre-commit install + pre-commit run --all-files diff --git a/backend/configuration/config.go b/backend/configuration/config.go new file mode 100644 index 0000000..87db10e --- /dev/null +++ b/backend/configuration/config.go @@ -0,0 +1,62 @@ +package configuration + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + + "github.com/spf13/viper" +) + +type Settings struct { + Database DatabaseSettings `yaml:"database"` +} + +type DatabaseSettings struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + Port uint16 `yaml:"port"` + Host string `yaml:"host"` + DatabaseName string `yaml:"databasename"` + RequireSSL bool `yaml:"requiressl"` +} + +type Environment string + +const ( + EnvironmentLocal Environment = "local" + EnvironmentGitHub Environment = "github" +) + +var ( + _, b, _, _ = runtime.Caller(0) + basepath = filepath.Dir(b) +) + +func GetConfiguration() (Settings, error) { + v := viper.New() + v.SetConfigType("yaml") + v.AddConfigPath(basepath) + + var settings Settings + + var environment Environment + if env := os.Getenv("GITHUB_ACTIONS"); env != "" { + environment = EnvironmentGitHub + } else { + environment = EnvironmentLocal + } + + v.SetConfigName(string(environment)) + + if err := v.ReadInConfig(); err != nil { + return settings, fmt.Errorf("failed to read %s configuration: %w", environment, err) + } + + if err := v.Unmarshal(&settings); err != nil { + return settings, fmt.Errorf("failed to unmarshal configuration: %w", err) + } + + return settings, nil +} diff --git a/backend/configuration/github.yaml b/backend/configuration/github.yaml new file mode 100644 index 0000000..ec353c1 --- /dev/null +++ b/backend/configuration/github.yaml @@ -0,0 +1,7 @@ +database: + host: '172.17.0.1' + port: 5432 + username: 'user' + password: 'pwd' + databasename: 'carewallet' + requiressl: false diff --git a/backend/configuration/local.yaml b/backend/configuration/local.yaml new file mode 100644 index 0000000..fbdd411 --- /dev/null +++ b/backend/configuration/local.yaml @@ -0,0 +1,7 @@ +database: + host: 'localhost' + port: 5434 + username: 'user' + password: 'pwd' + databasename: 'carewallet' + requiressl: false diff --git a/backend/db/db.go b/backend/db/db.go new file mode 100644 index 0000000..9eaef0f --- /dev/null +++ b/backend/db/db.go @@ -0,0 +1,38 @@ +package db + +import ( + "carewallet/configuration" + "fmt" + "os" + + "github.com/jackc/pgx" +) + +func ConnectPosgresDatabase(settings configuration.Settings) *pgx.Conn { + db_url, exists := os.LookupEnv("DATABASE_URL") + + cfg := pgx.ConnConfig{ + User: settings.Database.Username, + Database: settings.Database.DatabaseName, + Password: settings.Database.Password, + Host: settings.Database.Host, + Port: settings.Database.Port, + } + + var err error + if exists { + cfg, err = pgx.ParseConnectionString(db_url) + + if err != nil { + panic(err) + } + } + + conn, err := pgx.Connect(cfg) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err) + os.Exit(1) + } + + return conn +} diff --git a/backend/db/db_test.go b/backend/db/db_test.go new file mode 100644 index 0000000..b53e945 --- /dev/null +++ b/backend/db/db_test.go @@ -0,0 +1,31 @@ +package db + +import ( + "carewallet/configuration" + "context" + "fmt" + "os" + "testing" + + _ "github.com/lib/pq" +) + +func TestDBConnection(t *testing.T) { + config, err := configuration.GetConfiguration() + + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to retreive configuration file: %v\n", err) + os.Exit(1) + } + + t.Run("TestConnectPosgresDatabase", func(t *testing.T) { + conn := ConnectPosgresDatabase(config) + defer conn.Close() + + err = conn.Ping(context.Background()) + + if err != nil { + t.Error("Failed to connect to the Database") + } + }) +} diff --git a/backend/db/migrations/init.sql b/backend/db/migrations/init.sql new file mode 100644 index 0000000..f599e7e --- /dev/null +++ b/backend/db/migrations/init.sql @@ -0,0 +1,16 @@ +DROP TABLE IF EXISTS medication; + +CREATE TABLE IF NOT EXISTS medication ( + medication_id integer NOT NULL UNIQUE, + medication_name varchar NOT NULL, + PRIMARY KEY (medication_id) +); + +-- Insert sample data into "medication" table +INSERT INTO medication (medication_id, medication_name) +VALUES + (1, 'Medication A'), + (2, 'Medication B'), + (3, 'Medication C'), + (4, 'Medication D'), + (5, 'Medication E') diff --git a/backend/docs/docs.go b/backend/docs/docs.go new file mode 100644 index 0000000..bc5db06 --- /dev/null +++ b/backend/docs/docs.go @@ -0,0 +1,70 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/medications": { + "get": { + "description": "get all user medications", + "tags": [ + "medications" + ], + "summary": "Get All Meds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Medication" + } + } + } + } + } + } + }, + "definitions": { + "models.Medication": { + "type": "object", + "properties": { + "medication_id": { + "type": "integer" + }, + "medication_name": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "/", + Schemes: []string{}, + Title: "Care-Wallet API", + Description: "This is an API for the Care-Wallet App.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/backend/docs/swagger.json b/backend/docs/swagger.json new file mode 100644 index 0000000..0c33bef --- /dev/null +++ b/backend/docs/swagger.json @@ -0,0 +1,45 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is an API for the Care-Wallet App.", + "title": "Care-Wallet API", + "contact": {}, + "version": "1.0" + }, + "basePath": "/", + "paths": { + "/medications": { + "get": { + "description": "get all user medications", + "tags": [ + "medications" + ], + "summary": "Get All Meds", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Medication" + } + } + } + } + } + } + }, + "definitions": { + "models.Medication": { + "type": "object", + "properties": { + "medication_id": { + "type": "integer" + }, + "medication_name": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/backend/docs/swagger.yaml b/backend/docs/swagger.yaml new file mode 100644 index 0000000..d782391 --- /dev/null +++ b/backend/docs/swagger.yaml @@ -0,0 +1,29 @@ +basePath: / +definitions: + models.Medication: + properties: + medication_id: + type: integer + medication_name: + type: string + type: object +info: + contact: {} + description: This is an API for the Care-Wallet App. + title: Care-Wallet API + version: "1.0" +paths: + /medications: + get: + description: get all user medications + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.Medication' + type: array + summary: Get All Meds + tags: + - medications +swagger: "2.0" diff --git a/backend/go.mod b/backend/go.mod new file mode 100644 index 0000000..9ab9e9f --- /dev/null +++ b/backend/go.mod @@ -0,0 +1,73 @@ +module carewallet + +go 1.21.5 + +require ( + github.com/gin-contrib/cors v1.5.0 + github.com/gin-gonic/gin v1.9.1 + github.com/jackc/pgx v3.6.2+incompatible + github.com/lib/pq v1.10.9 + github.com/spf13/viper v1.18.2 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.2 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/bytedance/sonic v1.10.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect + github.com/cockroachdb/apd v1.1.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/gofrs/uuid v4.4.0+incompatible // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/shopspring/decimal v1.3.1 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/arch v0.5.0 // indirect + golang.org/x/crypto v0.16.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/net v0.19.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.13.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/backend/go.sum b/backend/go.sum new file mode 100644 index 0000000..82ef267 --- /dev/null +++ b/backend/go.sum @@ -0,0 +1,226 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.1 h1:7a1wuFXL1cMy7a3f7/VFcEtriuXQnUBhtoVfOZiaysc= +github.com/bytedance/sonic v1.10.1/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24= +github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= +github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= +github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.5.0 h1:jpGode6huXQxcskEIpOCvrU+tzo81b6+oFLUYXWtH/Y= +golang.org/x/arch v0.5.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/backend/main.go b/backend/main.go new file mode 100644 index 0000000..8f9aaa5 --- /dev/null +++ b/backend/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "carewallet/configuration" + "carewallet/db" + _ "carewallet/docs" + "carewallet/schema/medication" + "fmt" + "os" + + "github.com/gin-gonic/gin" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" +) + +// Care-Wallet API godoc +// +// @title Care-Wallet API +// @version 1.0 +// @description This is an API for the Care-Wallet App. +// @BasePath / +func main() { + config, err := configuration.GetConfiguration() + + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to retreive configuration file: %v\n", err) + os.Exit(1) + } + + conn := db.ConnectPosgresDatabase(config) + + defer conn.Close() + + r := gin.Default() + + v1 := r.Group("/") + { + medication.GetMedicationGroup(v1, &medication.PgModel{Conn: conn}) + } + + r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + err = r.Run(":8080") + + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + os.Exit(1) + } +} diff --git a/backend/models/medication.go b/backend/models/medication.go new file mode 100644 index 0000000..3806606 --- /dev/null +++ b/backend/models/medication.go @@ -0,0 +1,6 @@ +package models + +type Medication struct { + MedicationID int `json:"medication_id"` + MedicationName string `json:"medication_name"` +} diff --git a/backend/schema/medication/medication_test.go b/backend/schema/medication/medication_test.go new file mode 100644 index 0000000..58bfd20 --- /dev/null +++ b/backend/schema/medication/medication_test.go @@ -0,0 +1,81 @@ +package medication + +import ( + "carewallet/configuration" + "carewallet/db" + "carewallet/models" + "fmt" + "os" + "slices" + "testing" + + "encoding/json" + "net/http" + "net/http/httptest" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" + _ "github.com/lib/pq" +) + +func TestGetMedication(t *testing.T) { + config, err := configuration.GetConfiguration() + + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to retreive configuration file: %v\n", err) + os.Exit(1) + } + + conn := db.ConnectPosgresDatabase(config) + + defer conn.Close() + + controller := PgModel{Conn: conn} + + router := gin.Default() + + router.Use(cors.Default()) + + v1 := router.Group("/") + { + GetMedicationGroup(v1, &controller) + } + + t.Run("TestGetMedication", func(t *testing.T) { + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/medications", nil) + router.ServeHTTP(w, req) + + // Check for HTTP Status OK (200) + if http.StatusOK != w.Code { + t.Error("Failed to retrieve medications.") + } + + var responseMedication []models.Medication + err := json.Unmarshal(w.Body.Bytes(), &responseMedication) + + if err != nil { + t.Error("Failed to unmarshal json") + } + + // Define the expected medication data + expectedMedication := []models.Medication{ + {MedicationID: 1, + MedicationName: "Medication A"}, + {MedicationID: 2, + MedicationName: "Medication B"}, + {MedicationID: 3, + MedicationName: "Medication C"}, + {MedicationID: 4, + MedicationName: "Medication D"}, + {MedicationID: 5, + MedicationName: "Medication E"}, + } + + if !slices.Equal(expectedMedication, responseMedication) { + t.Error("Result was not correct") + } + + }) + +} diff --git a/backend/schema/medication/routes.go b/backend/schema/medication/routes.go new file mode 100644 index 0000000..5f7f3f0 --- /dev/null +++ b/backend/schema/medication/routes.go @@ -0,0 +1,39 @@ +package medication + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/jackc/pgx" +) + +type PgModel struct { + Conn *pgx.Conn +} + +func GetMedicationGroup(v1 *gin.RouterGroup, c *PgModel) *gin.RouterGroup { + + medications := v1.Group("medications") + { + medications.GET("", c.GetMedications) + } + + return medications +} + +// GetMedications godoc +// +// @summary Get All Meds +// @description get all user medications +// @tags medications +// @success 200 {array} models.Medication +// @router /medications [get] +func (pg *PgModel) GetMedications(c *gin.Context) { + med, err := GetAllMedsFromDB(pg.Conn) + + if err != nil { + panic(err) + } + + c.JSON(http.StatusOK, med) +} diff --git a/backend/schema/medication/transactions.go b/backend/schema/medication/transactions.go new file mode 100644 index 0000000..a90471d --- /dev/null +++ b/backend/schema/medication/transactions.go @@ -0,0 +1,36 @@ +package medication + +import ( + "carewallet/models" + + "github.com/jackc/pgx" +) + +func GetAllMedsFromDB(pool *pgx.Conn) ([]models.Medication, error) { + rows, err := pool.Query("SELECT medication_id, medication_name FROM medication;") + + if err != nil { + print(err, "from transactions err ") + + return nil, err + } + + defer rows.Close() + + var results []models.Medication + + for rows.Next() { + med := models.Medication{} + err := rows.Scan(&med.MedicationID, &med.MedicationName) + + if err != nil { + print(err, "from transactions err2 ") + + return nil, err + } + + results = append(results, med) + } + + return results, nil +} diff --git a/client/App.tsx b/client/App.tsx new file mode 100644 index 0000000..b10d304 --- /dev/null +++ b/client/App.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import { View, Text } from 'react-native'; +import { getAllMedications } from './services/medication'; + +export default function App() { + const [medications, setMedications] = React.useStategk(*nG6_q=^VO{)x0`lqq2GV~}@c!>8{Rh%N*#!Md
zcK;8gf67wupJn>jNdIgNpZR|v@cIA03H<+(hK<+%dm4_({I~3;yCGk?+3uu{%&A)1
zP|cr?l KFzaTY@vvKH7%3fMd5>K7Hf1!``V7EA{
z1wfp4Pd!A;Kstvm^z=AAQ1*5zEXWGy2d _m_Cz!aI|OA~=>rP h%0{}|+DPWgk|($2LaYkVi1EqD))Ngy$!?Ey_Khw=N$
z0*>LrfiNG=fipoI@PGEb=ZJztU+<|21z=DLF=KlMJ2zm4_5;FT06CGWu2!NR2eAwR
zbOz1gYQ0;g)<1&;g4q~H!I!3*&s`CKwL$eom8B(_m6ZJICl14gPoJ8jl?}@^^A^>C
z$e~861#yJ}%zF{{H>1(kb7
z4)}@b!KeU2)@MzR_YE%3o4g*xJG?EcRK5kXSbz@E+m@qx9_R7a^9cb
UB)$2x>!>nfd_<&42MzO_oU^Cuw3W1U>C8k4Z-;I)Hwz}clprW*1#cN9Eb
zc+)>qHS%7}9^t&jOjsczIIrb)IhH|7_FvnJ#3iry6`pc8JS^|zdc`sIrW~1v44uAu
z4cXW$3L?~kE9>1tR}nrfv_T83-xr!;EgYul%$1fy>9C%r0(M(5`Ww>Z8eY8jc)$22
z79&%(H(PfzKGg~3+n=o
f0^4m~AUeAv={cet7m*{2|~6vVAM=vpL?8r|>+7ZfuT;*FKMLJGNyc
z)!M?FJlzd>mzyrCJi3SQM$eUS@xCJioofaUwqrzeQ%S|R`Aa6u$h3~pn3ge8H;U0%
z+Z~w$tX*TF3?Bia(5OK1--uI#gzJ;b5uLoH{ZFw&E0w}REn0XA!4#HLjdvE}GHCBT
zMj7g$9;PwAHTUKI5ZL0?jTRutws}W@-^ZQvY+I`RRUq^H(;hro2sF&qX0$Sn8yjq1
zS-XgbgdmyQukGKXhM9c#5rJ(q^!e2^A|dvfiB5oGPSLeAt5%D5*PeG3-*&*guZuuC
zJBU$e7TQYCv=P5Uu*IQUHW?0y%33xDZpbd98PO};2E)HxOQKujAq3if83>i5Pu
zYMyimE!m+Pmb_Cldje-6xU_|0Y~>W12^QzJUQ%KCfn-h(j9E~e3Rza5+0iCjw=GkR
zllb*}Z;86cW~@;2#H$^c?SJZ&~V2j?k
zG|`DtuOZxpw-AY`^ORuoHM0{}8K&Q|>4z}_GxXGN26MhH(*yL)Wh#Wq)~aU7Y+-t>
z2Gi$X&&c{>T-F`5Id&^R_U(!2wJTKOCLLzNOV-BSUQ;j8Q_q&Bo)TCfrbifrN`A(C
zsH8<9&qKAN7yoI|fj4+LZmmi
8H<#Jdj6-1?y&;5J~8X2
zz7CuJk}fVIaFPY~et#fWJ{T*j#nWee)9-McpR-W6OkCGj*gu<&Tv=bu3J1H0#ve0mwiSZ6
zR0Vwj+-m(w-WooXk=Hkl)m~qjKbT<&y0h$2gl8Qr#(JfoEZLZWVuB->i=`_OmFHed!L&*^B0azpeu!a9XuMHX{b&M!monL+>QR!DW>6J%bs#d@QG;{2YEo5Y(^V;Uy
z_b_1qCEf|3;9iHmuGY95K{bnX7xa3=-`mF=o3?L4=9R3>c=4mL>B#bz{#SeUWZv?0
z=KN~};zrBgYL+nvThul&KZEWEVP|W-y}cPR2_$}&STL(mApmvKJ<~J$X4q5Hs;B)<
z2zC8XG(ZSDGCX}5fI+FWsbTyn4H4;{n*E!X?ij*{AgF!A%UUgV1oP)^=;?8qoFDcd
z#g?mHMJx1268mZ>*8tZI!nW1e(wyt0RIhQq))G}VpHbmv9WmDVzbjCy6uC=K50C!o
zxBqxI8B1Eug2U