diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml
new file mode 100644
index 0000000..c473e32
--- /dev/null
+++ b/.forgejo/workflows/build+release.yml
@@ -0,0 +1,91 @@
+name: 'Build and Release Binary File'
+author: 'Neshura'
+
+on: 
+    push:
+        tags:
+            - '[0-9]+.[0-9]+.[0-9]+'
+            - '[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
+jobs:
+    test:
+        runs-on: docker
+        steps:
+            -
+                name: Checking Out Repository Code
+                uses: https://code.forgejo.org/actions/checkout@v3
+            -
+                name: Placeholder
+                run: echo Placeholder Job
+            -
+                name: Check if Version in Cargo.toml matches Tag
+                run: |
+                    VERSION=$(cat Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ")
+                    if test $VERSION != "${{  github.ref_name }}"; then 
+                        echo "Expected Version is: '${{  github.ref_name }}' actual Version is: '$VERSION'"; 
+                        exit 1
+                    else 
+                        echo "Version is: '$VERSION'"; 
+                    fi
+
+    build:
+        needs: test
+        if: success()
+        runs-on: docker
+        container: rust:latest
+        steps: 
+            -
+                name: Installing Node
+                run: apt update && apt install -y nodejs
+            -
+                name: Checking Out Repository Code
+                uses: https://code.forgejo.org/actions/checkout@v3
+            -
+                name: Preparing Environment
+                run: |
+                    echo DATABASE_URL=${{ secrets.DATABASE_URL }} >> .env
+                    echo MACHINE_GROUP_ID=${{ vars.MACHINE_GROUP_ID }} >> .env
+                    echo UPTIME_KUMA_URL= >> .env
+            -
+                name: Compiling To Linux Target
+                run: |
+                    cargo build -r
+                    mv target/release/chellaris-rust-api chellaris-rust-api-linux-amd64                    
+            -
+                name: Uploading Build Artifact
+                uses: actions/upload-artifact@v3
+                with:
+                    name: chellaris-rust-api-linux-amd64
+                    path: chellaris-rust-api-linux-amd64
+                    if-no-files-found: error
+
+    upload-release:
+        needs: build
+        if: success()
+        runs-on: docker
+        steps:
+            -
+                name: Downloading All Build Artifacts
+                uses: actions/download-artifact@v3
+            -
+                name: Rearrange Artifact Paths
+                run: |
+                    mkdir release
+                    mv chellaris-rust-api-linux-amd64/chellaris-rust-api-linux-amd64 release/chellaris-rust-api-linux-amd64                    
+            -
+                name: Upload Artifacts As Generic Packages
+                run: |
+                    echo 'curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
+                    --upload-file release/chellaris-rust-api-linux-amd64 \
+                    https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{  github.ref_name }}/chellaris-rust-api-linux-amd64'
+                    curl -v --user ${{ secrets.FORGEJO_USERNAME }}:${{ secrets.FORGEJO_TOKEN }} \
+                    --upload-file release/chellaris-rust-api-linux-amd64 \
+                    https://forgejo.neshweb.net/api/packages/${{ secrets.FORGEJO_USERNAME }}/generic/${{ github.event.repository.name }}/${{  github.ref_name }}/chellaris-rust-api-linux-amd64                    
+            -
+                name: Release New Version
+                uses: actions/forgejo-release@v1
+                with:
+                    direction: upload
+                    url: https://forgejo.neshweb.net
+                    release-dir: release
+                    token: ${{ secrets.FORGEJO_TOKEN }}
+                    tag: ${{  github.ref_name }}
diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml
new file mode 100644
index 0000000..637f42a
--- /dev/null
+++ b/.forgejo/workflows/test.yml
@@ -0,0 +1,16 @@
+name: 'Run Tests on Code'
+author: 'Neshura'
+
+on: 
+    push:
+        tags-ignore:
+            - '**'
+        branches:
+            - '**'
+jobs:
+    run-tests:
+        runs-on: docker
+        steps:
+            -
+                name: Placeholder
+                run: echo Placeholder Job
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ecdc5b9..14602bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
 /target
+/.vscode
+/.idea
 
 config.toml
 
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index 20c400c..0000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-image: 3.10.8-slim-buster
-
-variables:
-  PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/linux/$CI_COMMIT_TAG/"
-
-.deploy:
-  rules:
-    # Regex magic copied from Neshura/page-test, only deploys on x.y.z or higher (x.y) Tags
-    - if: $CI_COMMIT_TAG =~ /^((([\d])+\.){1,2}[\d]+)\s*$/ && $CI_COMMIT_TAG
-
-stages:          
-  - build
-  - upload
-  - release
-
-## Docker steps
-
-build:
-  image: rust:latest
-  stage: build
-
-  variables:
-    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_BRANCH
-    CACHING: 
-  script:
-    - echo "Compiling the code..."
-    - cargo build -r
-    - echo "Compile complete."
-  after_script:
-    - echo JOB_ID=$CI_JOB_ID >> job.env
-    - mkdir ./artifacts
-    - cp /builds/Neshura/chellaris-rust-api/target/release/chellaris-rust-api ./artifacts/
-  artifacts:
-    paths:
-      - ./artifacts/
-    reports:
-      dotenv: job.env
-  rules:
-    - !reference [.deploy, rules]
-
-upload:
-  needs: 
-  - job: build
-    artifacts: true
-  image: curlimages/curl:latest
-  stage: upload
-  script:
-    - |
-      curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" --upload-file artifacts/chellaris-rust-api "${PACKAGE_REGISTRY_URL}/chellaris-rust-api"
-  rules:
-    - !reference [.deploy, rules]
-
-
-Tag Release:
-  stage: release
-  image: registry.gitlab.com/gitlab-org/release-cli:latest
-  rules:
-    - !reference [.deploy, rules]  
-  script:
-    - apk add curl
-    - echo "running Release Job, attaching Artifact from Job $JOB_ID"
-  release:
-    tag_name: '$CI_COMMIT_TAG'
-    description: '$CI_COMMIT_TAG'
-    assets:
-      links:
-        - name: "chellaris-rust-api"
-          url: "${PACKAGE_REGISTRY_URL}/chellaris-rust-api"
diff --git a/Cargo.lock b/Cargo.lock
index 93c78fa..ca617a4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -21,17 +21,17 @@ dependencies = [
 
 [[package]]
 name = "actix-http"
-version = "3.3.1"
+version = "3.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74"
+checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9"
 dependencies = [
  "actix-codec",
  "actix-rt",
  "actix-service",
  "actix-utils",
- "ahash 0.8.3",
+ "ahash",
  "base64",
- "bitflags 1.3.2",
+ "bitflags 2.4.0",
  "brotli",
  "bytes",
  "bytestring",
@@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
 dependencies = [
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "actix-web"
-version = "4.3.1"
+version = "4.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96"
+checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9"
 dependencies = [
  "actix-codec",
  "actix-http",
@@ -145,7 +145,7 @@ dependencies = [
  "actix-service",
  "actix-utils",
  "actix-web-codegen",
- "ahash 0.7.6",
+ "ahash",
  "bytes",
  "bytestring",
  "cfg-if",
@@ -154,7 +154,6 @@ dependencies = [
  "encoding_rs",
  "futures-core",
  "futures-util",
- "http",
  "itoa",
  "language-tags",
  "log",
@@ -166,8 +165,8 @@ dependencies = [
  "serde_json",
  "serde_urlencoded",
  "smallvec",
- "socket2 0.4.9",
- "time 0.3.27",
+ "socket2 0.5.5",
+ "time",
  "url",
 ]
 
@@ -200,25 +199,15 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
 name = "ahash"
-version = "0.7.6"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "ahash"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
 dependencies = [
  "cfg-if",
  "getrandom",
  "once_cell",
  "version_check",
+ "zerocopy",
 ]
 
 [[package]]
@@ -275,6 +264,16 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "atomic-write-file"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
+dependencies = [
+ "nix",
+ "rand",
+]
+
 [[package]]
 name = "autocfg"
 version = "1.1.0"
@@ -398,37 +397,39 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chellaris-rust-api"
-version = "0.1.0"
+version = "1.2.4"
 dependencies = [
  "actix-web",
  "chrono",
  "ctrlc",
- "dotenv",
- "dotenv_codegen",
+ "dotenvy",
+ "dotenvy_macro",
  "env_logger",
+ "rand",
+ "reqwest",
  "schemars",
  "serde",
  "serde_json",
  "sqlx",
  "tokio",
  "toml",
+ "url",
  "utoipa",
  "utoipa-swagger-ui",
 ]
 
 [[package]]
 name = "chrono"
-version = "0.4.26"
+version = "0.4.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
+checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
- "time 0.1.45",
  "wasm-bindgen",
- "winapi",
+ "windows-targets",
 ]
 
 [[package]]
@@ -450,10 +451,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
 dependencies = [
  "percent-encoding",
- "time 0.3.27",
+ "time",
  "version_check",
 ]
 
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.4"
@@ -524,9 +535,9 @@ dependencies = [
 
 [[package]]
 name = "ctrlc"
-version = "3.4.0"
+version = "3.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e"
+checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
 dependencies = [
  "nix",
  "windows-sys",
@@ -594,41 +605,24 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "dotenv"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
-
-[[package]]
-name = "dotenv_codegen"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56966279c10e4f8ee8c22123a15ed74e7c8150b658b26c619c53f4a56eb4a8aa"
-dependencies = [
- "dotenv_codegen_implementation",
- "proc-macro-hack",
-]
-
-[[package]]
-name = "dotenv_codegen_implementation"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53e737a3522cd45f6adc19b644ce43ef53e1e9045f2d2de425c1f468abd4cf33"
-dependencies = [
- "dotenv",
- "proc-macro-hack",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
 [[package]]
 name = "dotenvy"
 version = "0.15.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
 
+[[package]]
+name = "dotenvy_macro"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb0235d912a8c749f4e0c9f18ca253b4c28cfefc1d2518096016d6e3230b6424"
+dependencies = [
+ "dotenvy",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "dyn-clone"
 version = "1.0.13"
@@ -655,9 +649,9 @@ dependencies = [
 
 [[package]]
 name = "env_logger"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
+checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
 dependencies = [
  "humantime",
  "is-terminal",
@@ -728,13 +722,12 @@ dependencies = [
 
 [[package]]
 name = "flume"
-version = "0.10.14"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
+checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
 dependencies = [
  "futures-core",
  "futures-sink",
- "pin-project",
  "spin 0.9.8",
 ]
 
@@ -745,10 +738,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
-name = "form_urlencoded"
-version = "1.2.0"
+name = "foreign-types"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -843,7 +851,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
 ]
 
 [[package]]
@@ -883,7 +891,7 @@ version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
 dependencies = [
- "ahash 0.8.3",
+ "ahash",
  "allocator-api2",
 ]
 
@@ -955,6 +963,17 @@ dependencies = [
  "itoa",
 ]
 
+[[package]]
+name = "http-body"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+dependencies = [
+ "bytes",
+ "http",
+ "pin-project-lite",
+]
+
 [[package]]
 name = "httparse"
 version = "1.8.0"
@@ -973,6 +992,43 @@ version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
+[[package]]
+name = "hyper"
+version = "0.14.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "pin-project-lite",
+ "socket2 0.4.9",
+ "tokio",
+ "tower-service",
+ "tracing",
+ "want",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
+dependencies = [
+ "bytes",
+ "hyper",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+]
+
 [[package]]
 name = "iana-time-zone"
 version = "0.1.57"
@@ -998,9 +1054,9 @@ dependencies = [
 
 [[package]]
 name = "idna"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -1027,6 +1083,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "ipnet"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
+
 [[package]]
 name = "is-terminal"
 version = "0.4.9"
@@ -1088,9 +1150,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.147"
+version = "0.2.151"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
 
 [[package]]
 name = "libm"
@@ -1100,9 +1162,9 @@ checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
 
 [[package]]
 name = "libsqlite3-sys"
-version = "0.26.0"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc22eff61b133b115c6e8c74e818c628d6d5e7a502afea6f64dee076dd94326"
+checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716"
 dependencies = [
  "cc",
  "pkg-config",
@@ -1197,26 +1259,43 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.8"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
 dependencies = [
  "libc",
  "log",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
  "windows-sys",
 ]
 
 [[package]]
-name = "nix"
-version = "0.26.2"
+name = "native-tls"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a"
+checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
 dependencies = [
- "bitflags 1.3.2",
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
+[[package]]
+name = "nix"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+dependencies = [
+ "bitflags 2.4.0",
  "cfg-if",
  "libc",
- "static_assertions",
 ]
 
 [[package]]
@@ -1302,6 +1381,50 @@ version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
+[[package]]
+name = "openssl"
+version = "0.10.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
+dependencies = [
+ "bitflags 2.4.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "parking_lot"
 version = "0.12.1"
@@ -1342,29 +1465,9 @@ dependencies = [
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
-
-[[package]]
-name = "pin-project"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.29",
-]
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pin-project-lite"
@@ -1435,12 +1538,6 @@ dependencies = [
  "version_check",
 ]
 
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.20+deprecated"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
-
 [[package]]
 name = "proc-macro2"
 version = "1.0.66"
@@ -1547,6 +1644,44 @@ version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
 
+[[package]]
+name = "reqwest"
+version = "0.11.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2",
+ "http",
+ "http-body",
+ "hyper",
+ "hyper-tls",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winreg",
+]
+
 [[package]]
 name = "rsa"
 version = "0.9.2"
@@ -1571,9 +1706,9 @@ dependencies = [
 
 [[package]]
 name = "rust-embed"
-version = "6.8.1"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a36224c3276f8c4ebc8c20f158eca7ca4359c8db89991c4925132aaaf6702661"
+checksum = "810294a8a4a0853d4118e3b94bb079905f2107c7fe979d8f0faae98765eb6378"
 dependencies = [
  "rust-embed-impl",
  "rust-embed-utils",
@@ -1582,23 +1717,23 @@ dependencies = [
 
 [[package]]
 name = "rust-embed-impl"
-version = "6.8.1"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac"
+checksum = "bfc144a1273124a67b8c1d7cd19f5695d1878b31569c0512f6086f0f4676604e"
 dependencies = [
  "proc-macro2",
  "quote",
  "rust-embed-utils",
  "shellexpand",
- "syn 2.0.29",
+ "syn 2.0.32",
  "walkdir",
 ]
 
 [[package]]
 name = "rust-embed-utils"
-version = "7.8.1"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d38ff6bf570dc3bb7100fce9f7b60c33fa71d80e88da3f2580df4ff2bdded74"
+checksum = "816ccd4875431253d6bb54b804bcff4369cbde9bae33defde25fdf6c2ef91d40"
 dependencies = [
  "sha2",
  "walkdir",
@@ -1648,10 +1783,19 @@ dependencies = [
 ]
 
 [[package]]
-name = "schemars"
-version = "0.8.12"
+name = "schannel"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f"
+checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "schemars"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29"
 dependencies = [
  "dyn-clone",
  "schemars_derive",
@@ -1661,9 +1805,9 @@ dependencies = [
 
 [[package]]
 name = "schemars_derive"
-version = "0.8.12"
+version = "0.8.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c"
+checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1677,6 +1821,29 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
+[[package]]
+name = "security-framework"
+version = "2.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "semver"
 version = "1.0.18"
@@ -1685,22 +1852,22 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
 
 [[package]]
 name = "serde"
-version = "1.0.185"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.185"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc59dfdcbad1437773485e0367fea4b090a2e0a16d9ffc46af47764536a298ec"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -1716,9 +1883,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.105"
+version = "1.0.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
 dependencies = [
  "itoa",
  "ryu",
@@ -1727,9 +1894,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.3"
+version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
 dependencies = [
  "serde",
 ]
@@ -1770,9 +1937,9 @@ dependencies = [
 
 [[package]]
 name = "shellexpand"
-version = "2.1.2"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
+checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
 dependencies = [
  "dirs",
 ]
@@ -1823,9 +1990,9 @@ dependencies = [
 
 [[package]]
 name = "socket2"
-version = "0.5.3"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
  "windows-sys",
@@ -1869,9 +2036,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e58421b6bc416714d5115a2ca953718f6c621a51b68e4f4922aea5a4391a721"
+checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
 dependencies = [
  "sqlx-core",
  "sqlx-macros",
@@ -1882,11 +2049,11 @@ dependencies = [
 
 [[package]]
 name = "sqlx-core"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53"
+checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
 dependencies = [
- "ahash 0.8.3",
+ "ahash",
  "atoi",
  "byteorder",
  "bytes",
@@ -1922,9 +2089,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-macros"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "208e3165167afd7f3881b16c1ef3f2af69fa75980897aac8874a0696516d12c2"
+checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1935,10 +2102,11 @@ dependencies = [
 
 [[package]]
 name = "sqlx-macros-core"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a4a8336d278c62231d87f24e8a7a74898156e34c1c18942857be2acb29c7dfc"
+checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
 dependencies = [
+ "atomic-write-file",
  "dotenvy",
  "either",
  "heck",
@@ -1961,9 +2129,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-mysql"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482"
+checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
 dependencies = [
  "atoi",
  "base64",
@@ -2003,9 +2171,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-postgres"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e"
+checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
 dependencies = [
  "atoi",
  "base64",
@@ -2042,9 +2210,9 @@ dependencies = [
 
 [[package]]
 name = "sqlx-sqlite"
-version = "0.7.1"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2"
+checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
 dependencies = [
  "atoi",
  "flume",
@@ -2060,14 +2228,9 @@ dependencies = [
  "sqlx-core",
  "tracing",
  "url",
+ "urlencoding",
 ]
 
-[[package]]
-name = "static_assertions"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
-
 [[package]]
 name = "stringprep"
 version = "0.1.3"
@@ -2097,15 +2260,36 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.29"
+version = "2.0.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "system-configuration"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "tempfile"
 version = "3.8.0"
@@ -2145,18 +2329,7 @@ checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
-]
-
-[[package]]
-name = "time"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
-dependencies = [
- "libc",
- "wasi 0.10.0+wasi-snapshot-preview1",
- "winapi",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -2204,21 +2377,44 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.32.0"
+version = "1.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
+checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c"
 dependencies = [
  "backtrace",
  "bytes",
  "libc",
  "mio",
+ "num_cpus",
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.3",
+ "socket2 0.5.5",
+ "tokio-macros",
  "windows-sys",
 ]
 
+[[package]]
+name = "tokio-macros"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
 [[package]]
 name = "tokio-stream"
 version = "0.1.14"
@@ -2246,9 +2442,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.7.6"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
+checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2258,18 +2454,18 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.19.14"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
+checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
 dependencies = [
  "indexmap 2.0.0",
  "serde",
@@ -2278,6 +2474,12 @@ dependencies = [
  "winnow",
 ]
 
+[[package]]
+name = "tower-service"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
+
 [[package]]
 name = "tracing"
 version = "0.1.37"
@@ -2299,7 +2501,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
@@ -2311,6 +2513,12 @@ dependencies = [
  "once_cell",
 ]
 
+[[package]]
+name = "try-lock"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+
 [[package]]
 name = "typenum"
 version = "1.16.0"
@@ -2361,9 +2569,9 @@ checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
 
 [[package]]
 name = "url"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -2371,10 +2579,16 @@ dependencies = [
 ]
 
 [[package]]
-name = "utoipa"
-version = "3.5.0"
+name = "urlencoding"
+version = "2.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d82b1bc5417102a73e8464c686eef947bdfb99fcdfc0a4f228e81afa9526470a"
+checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
+
+[[package]]
+name = "utoipa"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ff05e3bac2c9428f57ade702667753ca3f5cf085e2011fe697de5bfd49aa72d"
 dependencies = [
  "indexmap 2.0.0",
  "serde",
@@ -2384,22 +2598,22 @@ dependencies = [
 
 [[package]]
 name = "utoipa-gen"
-version = "3.5.0"
+version = "4.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d96dcd6fc96f3df9b3280ef480770af1b7c5d14bc55192baa9b067976d920c"
+checksum = "5f0b6f4667edd64be0e820d6631a60433a269710b6ee89ac39525b872b76d61d"
 dependencies = [
  "proc-macro-error",
  "proc-macro2",
  "quote",
  "regex",
- "syn 2.0.29",
+ "syn 2.0.32",
 ]
 
 [[package]]
 name = "utoipa-swagger-ui"
-version = "3.1.5"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84614caa239fb25b2bb373a52859ffd94605ceb256eeb1d63436325cf81e3653"
+checksum = "f839caa8e09dddc3ff1c3112a91ef7da0601075ba5025d9f33ae99c4cb9b6e51"
 dependencies = [
  "actix-web",
  "mime_guess",
@@ -2434,10 +2648,13 @@ dependencies = [
 ]
 
 [[package]]
-name = "wasi"
-version = "0.10.0+wasi-snapshot-preview1"
+name = "want"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
 
 [[package]]
 name = "wasi"
@@ -2466,10 +2683,22 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
  "wasm-bindgen-shared",
 ]
 
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.87"
@@ -2488,7 +2717,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.29",
+ "syn 2.0.32",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -2499,6 +2728,16 @@ version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
+[[package]]
+name = "web-sys"
+version = "0.3.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "whoami"
 version = "1.4.1"
@@ -2620,6 +2859,36 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "winreg"
+version = "0.50.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
+dependencies = [
+ "cfg-if",
+ "windows-sys",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "306dca4455518f1f31635ec308b6b3e4eb1b11758cefafc782827d0aa7acb5c7"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be912bf68235a88fbefd1b73415cb218405958d1655b2ece9035a19920bdf6ba"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.32",
+]
+
 [[package]]
 name = "zeroize"
 version = "1.6.0"
diff --git a/Cargo.toml b/Cargo.toml
index 4d071ee..f901372 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,22 +1,25 @@
 [package]
 name = "chellaris-rust-api"
-version = "0.1.0"
+version = "1.2.4"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-actix-web = "4.3.1"
-chrono = "0.4.26"
-ctrlc = "3.4.0"
-dotenv = "0.15.0"
-dotenv_codegen = "0.15.0"
-env_logger = "0.10.0"
-schemars = "0.8.10"
-serde = { version = "1.0.185", features = ["derive"] }
-serde_json = "1.0.105"
-sqlx = { version = "0.7.1", features = ["postgres", "runtime-tokio"] }
-tokio = { version = "1.32.0", features = ["rt"] }
-toml = "0.7.6"
-utoipa = { version = "3.5.0", features = ["actix_extras", "non_strict_integers"] }
-utoipa-swagger-ui = { version = "3.1.5", features = ["actix-web"] }
+actix-web = "4.4.0"
+chrono = "0.4.31"
+ctrlc = "3.4.1"
+dotenvy = "0.15.7"
+dotenvy_macro = "0.15.7"
+env_logger = "0.10.1"
+reqwest = "0.11.22"
+schemars = "0.8.16"
+serde = { version = "1.0.193", features = ["derive"] }
+serde_json = "1.0.108"
+sqlx = { version = "0.7.3", features = ["postgres", "runtime-tokio"] }
+tokio = { version = "1.35.0", features = ["rt", "rt-multi-thread", "macros", "time"] }
+toml = "0.8.8"
+utoipa = { version = "4.1.0", features = ["actix_extras", "non_strict_integers"] }
+utoipa-swagger-ui = { version = "5.0.0", features = ["actix-web"] }
+rand = "0.8.5"
+url = "2.5.0"
diff --git a/package.json b/package.json
deleted file mode 100644
index 2bb8783..0000000
--- a/package.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "dependencies": {
-    "sqlx": "^4.3.2"
-  }
-}
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 7c8e632..0f2302c 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -1,5 +1 @@
-use std::error::Error;
-
-use sqlx::{Postgres, postgres::PgConnectOptions, PgPool, Pool};
-
 pub(crate) mod schemas;
\ No newline at end of file
diff --git a/src/db/schemas.rs b/src/db/schemas.rs
index 88525ad..9604b78 100644
--- a/src/db/schemas.rs
+++ b/src/db/schemas.rs
@@ -33,7 +33,7 @@ pub struct GameGroup {
 pub struct Ethic {
     pub id: i32,
     pub name: String,
-    pub machine_ethic: bool,
+    pub gestalt_ethic: bool,
 }
 
 #[derive(Serialize, ToSchema, Debug, FromRow)]
@@ -42,10 +42,15 @@ pub struct Empire {
     pub group_id: i32,
     pub game_id: i32,
     pub name: String,
-    pub discord_user: Option<String>,
     pub gestalt: bool,
     pub portrait_id: i32,
     pub portrait_group_id: i32,
+    pub backstory: String,
+    pub goals: String,
+    pub interactions: String,
+    pub available: bool,
+    pub approval_status: Option<bool>,
+    pub users_id: i32,
 }
 
 #[derive(Serialize, ToSchema, Debug, FromRow)]
@@ -55,3 +60,15 @@ pub struct EmpireEthic {
     pub ethics_id: i32,
     pub fanatic: bool,
 }
+
+#[derive(Serialize, ToSchema, Debug, FromRow)]
+pub struct User {
+    pub id: i32,
+    pub token: String,
+    pub discord_id: Option<String>,
+    pub picture_url: Option<String>,
+    pub game_permissions: bool,
+    pub empire_permissions: bool,
+    pub data_permissions: bool,
+    pub user_permissions: bool,
+}
diff --git a/src/main.rs b/src/main.rs
index d8da6f8..6a3a574 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,21 +1,24 @@
 #[macro_use]
-extern crate dotenv_codegen;
-extern crate dotenv;
+extern crate dotenvy_macro;
+extern crate dotenvy;
 
-use dotenv::dotenv;
+use dotenvy::dotenv;
 use tokio::time::sleep;
 
-use std::{env, error::Error, fs, net::Ipv4Addr, net::Ipv6Addr, thread, time::Duration, sync::{Mutex, Arc, atomic::{AtomicBool, Ordering}}};
+use std::{env, fs, net::Ipv4Addr, net::Ipv6Addr, time::Duration, sync::{Arc, atomic::{AtomicBool, Ordering}}};
+use std::process::abort;
 
 use chrono::Local;
 
-use actix_web::{middleware::Logger, web, App, HttpServer, Result};
+use actix_web::{middleware::Logger, web, App, HttpServer};
 use serde::{Deserialize, Serialize};
 use sqlx::{PgPool, Pool, Postgres, Connection};
+use tokio::signal::unix::SignalKind;
 use utoipa::{OpenApi, openapi::security::{SecurityScheme, ApiKey, ApiKeyValue}, Modify};
 use utoipa_swagger_ui::{Config, SwaggerUi, Url};
 
 mod db;
+mod v1;
 mod v2;
 mod v3;
 
@@ -25,21 +28,33 @@ macro_rules! api_base {
     };
 }
 
+macro_rules! api_base_1 {
+    () => {
+        "/api/v1"
+    };
+}
+
 macro_rules! api_base_2 {
     () => {
-        "/api/v2"
+        "/api/v2-l"
     };
 }
 
 macro_rules! api_base_3 {
     () => {
-        "/api/v3"
+        "/api/v3-l"
     };
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
 pub(crate) struct ConfigToml {
     auth: AuthenticationTokens,
+    port: PortConfig,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub(crate) struct PortConfig {
+    default: u16,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -53,11 +68,8 @@ pub struct AppState {
     auth_tokens: AuthenticationTokens,
 }
 
-async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Arc<AtomicBool>) {
-    loop {
-        if shutdown.load(Ordering::Relaxed) {
-            break;
-        }
+async fn postgres_watchdog(pool: PgPool, shutdown: Arc<AtomicBool>) {
+    while !shutdown.load(Ordering::Relaxed) {
         let start = Local::now();
 
         let mut conn = match pool.acquire().await {
@@ -70,27 +82,32 @@ async fn postgres_watchdog(pool: PgPool, is_alive: Arc<AtomicBool>, shutdown: Ar
             Err(_) => {println!("Error pinging Server"); break;},
         };
 
-        let passed = (Local::now() - start).to_std().expect(&format!("Unable to get Time Difference for '{}' and '{}'", start, Local::now()));
+        let url = dotenvy::var("UPTIME_KUMA_URL").unwrap_or("".to_string());
+        if url != "" {
+            match reqwest::get(
+                url,
+            ).await {
+                Ok(_) => {}
+                Err(err) => println!("{}", err),
+            };
+        }
+        else {
+            println!("No Uptime Kuma URL provided!");
+        }
         
-        sleep(Duration::from_secs(15) - passed).await;
+        while Local::now() - start < chrono::Duration::seconds(15) {
+            sleep(Duration::from_millis(100)).await;
+        }
     }
-    is_alive.store(false, Ordering::Relaxed);
 }
 
 #[actix_web::main]
-async fn main() -> Result<()> {
+async fn main() {
     env_logger::init();
     dotenv().ok();
 
     let shutdown: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
 
-    let shutdown_clone = Arc::clone(&shutdown);
-    ctrlc::set_handler(move || {
-        eprintln!("Ctrl-C received");
-        shutdown_clone.store(true, Ordering::Relaxed)
-    })
-    .expect("Error setting Ctrl-C handler");
-
     let toml_str = fs::read_to_string("config.toml").expect("Failed to read config.toml");
 
     let config: ConfigToml = toml::from_str(&toml_str).expect("Failed to parse config.toml");
@@ -148,7 +165,9 @@ async fn main() -> Result<()> {
             v3::get_empire,
             v3::create_empire,
             v3::edit_empire,
-            v3::delete_empire
+            v3::delete_empire,
+            v3::get_ethics,
+            v3::get_phenotypes
         ), 
         components(schemas(
             v3::schemas::AuthReturn,
@@ -165,15 +184,17 @@ async fn main() -> Result<()> {
             v3::schemas::DeleteEmpireParams,
             v3::schemas::FullViewData,
             v3::schemas::Ethic,
+            v3::schemas::ChellarisEthics,
             v3::schemas::EmpireEthic,
             v3::schemas::EmpireEthicLegacy,
             v3::schemas::ChellarisGameLegacy,
             v3::schemas::ChellarisGameFlat,
             v3::schemas::ChellarisGame,
-            v3::schemas::Species,
+            v3::schemas::Phenotype,
+            v3::schemas::ChellarisPhenotypes,
             v3::schemas::ChellarisGameGroupLegacy,
             v3::schemas::ChellarisGroupFlat,
-            v3::schemas::Portrait,
+            v3::schemas::Species,
             v3::schemas::ChellarisEmpireLegacy,
             v3::schemas::ChellarisEmpireFlat,
             v3::schemas::ChellarisEmpire
@@ -182,27 +203,64 @@ async fn main() -> Result<()> {
     )]
     struct ApiDocV3;
 
-    let openapi_urls = vec![
-        Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
-        Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
-    ];
+    #[derive(OpenApi)]
+    #[openapi(
+        paths(
+            v1::get_user,
+            v1::create_user,
+            v1::update_user,
+            v1::delete_user
+        ),
+        components(schemas(
+            v1::schemas::GetUserParams,
+            v1::schemas::UpdateUserParams,
+            v1::schemas::DeleteUserParams,
+            v1::schemas::User
+        ))
+    )]
+    struct ApiDocV1;
 
-    let is_alive: Arc<AtomicBool> = Arc::new(AtomicBool::new(true));
+    let openapi_urls = vec![
+        Url::new("v1", concat!(api_base!(), "-docs/openapi1.json")),
+        Url::new("v2-L", concat!(api_base!(), "-docs/openapi2l.json")),
+        Url::new("v3-L", concat!(api_base!(), "-docs/openapi3l.json")),
+    ];
 
     loop {
         let db_auth_tokens = config.auth.clone();
         let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap();
+
         let pool_copy = pool.clone();
+        let shutdown_clone = shutdown.clone();
 
         let swagger_config = Config::new(openapi_urls.clone());
 
-        let mut openapi_v2 = ApiDocV2::openapi();
-        openapi_v2.info.title = "Chellaris Rust API".to_string();
-    
-        let mut openapi_v3 = ApiDocV3::openapi();
-        openapi_v3.info.title = "Chellaris Rust API".to_string();
+        let mut openapi_v1 = ApiDocV1::openapi();
+        openapi_v1.info.title = "Chellaris Rust API v1".to_string();
 
-        let server = HttpServer::new(move || {
+        let mut openapi_v2_l = ApiDocV2::openapi();
+        openapi_v2_l.info.title = "Legacy Chellaris Rust API v2".to_string();
+
+        let mut openapi_v3_l = ApiDocV3::openapi();
+        openapi_v3_l.info.title = "Legacy Chellaris Rust API v3".to_string();
+
+        println!("Serving API on: ");
+        println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080);
+        println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080);
+
+        let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone).await });
+        tokio::spawn(async move {
+            actix_web::rt::signal::unix::signal(SignalKind::terminate()).unwrap().recv().await;
+            println!("SIGTERM received, killing Server");
+            abort()
+        });
+        tokio::spawn(async move {
+            actix_web::rt::signal::unix::signal(SignalKind::interrupt()).unwrap().recv().await;
+            println!("SIGINT received, killing Server");
+            abort()
+        });
+
+        let _ = HttpServer::new(move || {
             App::new()
                 .app_data(web::Data::new(AppState { db: pool.clone(), auth_tokens: db_auth_tokens.clone() }))
                 .wrap(Logger::default())
@@ -229,56 +287,43 @@ async fn main() -> Result<()> {
                 .service(v3::create_empire)
                 .service(v3::edit_empire)
                 .service(v3::delete_empire)
+                .service(v3::get_ethics)
+                .service(v3::get_phenotypes)
+                // API v1 Endpoints
+                .service(v1::get_user)
+                .service(v1::create_user)
+                .service(v1::update_user)
+                .service(v1::delete_user)
                 // Swagger UI
                 .service(
                     SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}"))
                         .urls(vec![
                             (
-                                Url::new("v2", concat!(api_base_2!(), "/openapi.json")),
-                                openapi_v2.clone(),
+                                Url::new("v1", concat!(api_base!(), "-docs/openapi1.json")),
+                                openapi_v1.clone(),
                             ),
                             (
-                                Url::new("v3", concat!(api_base_3!(), "/openapi.json")),
-                                openapi_v3.clone(),
+                                Url::new("v2-l", concat!(api_base!(), "-docs/openapi2l.json")),
+                                openapi_v2_l.clone(),
+                            ),
+                            (
+                                Url::new("v3-l", concat!(api_base!(), "-docs/openapi3l.json")),
+                                openapi_v3_l.clone(),
                             ),
                         ])
                         .config(swagger_config.clone()),
                 )
         })
-        .bind((Ipv6Addr::UNSPECIFIED, 8080)).expect("Port or IP already occupied")
-        .run();
+            .bind((Ipv6Addr::UNSPECIFIED, config.port.default)).expect("Port or IP already occupied")
+            .run()
+            .await;
 
-        let server_thread = tokio::spawn(async {
-            println!("Awaiting server");
-            let _ = server.await;
-            println!("Stopped awaiting server");
-        });
+        watchdog_thread.abort();
 
-        println!("Started Serving API on: ");
-        println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080);
-        println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080);
+        sleep(Duration::from_secs(10)).await;
 
-        let is_alive_clone = Arc::clone(&is_alive);
-        let shutdown_clone = Arc::clone(&shutdown);
-        let _ = tokio::spawn(async move { postgres_watchdog(pool_copy, is_alive_clone, shutdown_clone).await });
-        
-        //watchdog_thread.await;
+        println!("Service crashed due to unexpected Error, restarting thread after wait...");
 
-        while is_alive.load(Ordering::Relaxed) {
-            let thread = tokio::spawn(async {
-                sleep(Duration::from_millis(100));
-            });
-
-            let _ = thread.await;
-        }
-
-        if shutdown.load(Ordering::Relaxed) {
-            break;
-        }
-
-        eprintln!("Connection died, restarting Server");
-        server_thread.abort();
+        sleep(Duration::from_secs(10)).await;
     }
-
-    Ok(())
 }
diff --git a/src/v1/mod.rs b/src/v1/mod.rs
new file mode 100644
index 0000000..4c0fb1b
--- /dev/null
+++ b/src/v1/mod.rs
@@ -0,0 +1,369 @@
+use crate::{db, AppState};
+use actix_web::{delete, get, post, put, web, HttpRequest, HttpResponse, Responder};
+use std::collections::HashMap;
+use std::ops::Deref;
+use rand::distributions::Alphanumeric;
+use rand::{Rng, thread_rng};
+use sqlx::QueryBuilder;
+
+pub(crate) mod schemas;
+
+fn get_auth_header(req: &HttpRequest) -> Option<&str> {
+    req.headers().get("x-api-key")?.to_str().ok()
+}
+
+async fn verify_user_auth(data: &web::Data<AppState>, auth_token: &str, user_token: &str, table: schemas::TablePermission, permissions_only: bool) -> bool {
+    let user: db::schemas::User = match sqlx::query_as!(
+        db::schemas::User,
+        "SELECT * FROM public.users WHERE token = $1",
+        auth_token
+    )
+        .fetch_one(&data.db)
+        .await
+    {
+        Ok(data) => data,
+        Err(_) => return false,
+    };
+
+    if user.token == user_token && !permissions_only {
+        return true;
+    }
+    else {
+        match table {
+            schemas::TablePermission::Game => {
+                return user.data_permissions;
+            },
+            schemas::TablePermission::Empire => {
+                return user.empire_permissions;
+            },
+            schemas::TablePermission::Data => {
+                return user.data_permissions;
+            },
+            schemas::TablePermission::User => {
+                return user.user_permissions;
+            },
+        }
+    }
+}
+
+// User Endpoints
+#[utoipa::path(
+    request_body = GetUserParams,
+    responses(
+        (status = 200, description = "OK", body = User),
+        (status = 403, description = "Unauthorized"),
+        (status = 500, description = "Internal Server Error")
+    ),
+    security(
+        ("api_key" = [])
+    ),
+)]
+#[post("/api/v1/user")]
+pub(crate) async fn get_user(
+    data: web::Data<AppState>,
+    params: web::Json<schemas::GetUserParams>,
+    req: HttpRequest,
+) -> impl Responder {
+    let auth_header = get_auth_header(&req);
+    let params = params.into_inner();
+
+    let auth_token: String;
+
+    match auth_header {
+        Some(token) => auth_token = token.to_string(),
+        None => return HttpResponse::Unauthorized().finish(),
+    };
+
+    let auth = verify_user_auth(&data, &auth_token, &params.user_token, schemas::TablePermission::User, false).await;
+
+    if auth {
+        let user: db::schemas::User = match sqlx::query_as!(
+        db::schemas::User,
+        "SELECT * FROM public.users WHERE token = $1",
+        params.user_token
+    )
+            .fetch_one(&data.db)
+            .await
+        {
+            Ok(data) => data,
+            Err(_) => return HttpResponse::InternalServerError().finish(),
+        };
+
+        let mut user_permissions: HashMap<String, bool> = HashMap::new();
+
+        user_permissions.insert("game_permissions".to_string(), user.game_permissions);
+        user_permissions.insert("empire_permissions".to_string(), user.empire_permissions);
+        user_permissions.insert("data_permissions".to_string(), user.data_permissions);
+        user_permissions.insert("user_permissions".to_string(), user.user_permissions);
+
+        let return_data = schemas::User {
+            user_token: user.token,
+            discord_handle: user.discord_id,
+            profile_picture: user.picture_url,
+            permissions: user_permissions
+        };
+
+        return HttpResponse::Ok().json(return_data);
+    }
+    else {
+        return HttpResponse::Unauthorized().finish();
+    }
+}
+
+#[utoipa::path(
+    responses(
+        (status = 200, description = "OK", body = User),
+        (status = 500, description = "Internal Server Error")
+    ),
+)]
+#[post("/api/v1/user/create")]
+pub(crate) async fn create_user(
+    data: web::Data<AppState>,
+) -> impl Responder {
+    let user: db::schemas::User;
+
+    let mut rng = thread_rng();
+
+    let user_tokens = match sqlx::query_scalar!(
+        "SELECT token FROM public.users"
+    )
+        .fetch_all(&data.db)
+        .await
+    {
+        Ok(data) => data,
+        Err(_) => return HttpResponse::InternalServerError().finish(),
+    };
+
+    let new_token: String;
+
+    loop {
+        let mut chars: String = (0..6).map(|_| rng.sample(Alphanumeric) as char).collect();
+        chars = chars.to_uppercase();
+        if !user_tokens.contains(&chars) {
+            new_token = chars;
+            break;
+        }
+        else {
+            println!("looping");
+        }
+    }
+
+    user = match sqlx::query_as!(
+        db::schemas::User,
+        "INSERT INTO public.users(token, game_permissions, empire_permissions, data_permissions, user_permissions) VALUES ($1, $2, $3, $4, $5) RETURNING * ",
+        new_token,
+        false,
+        false,
+        false,
+        false
+
+    )
+        .fetch_one(&data.db)
+        .await
+    {
+        Ok(data) => data,
+        Err(_) => return HttpResponse::InternalServerError().finish(),
+    };
+
+    return HttpResponse::Ok().json(user)
+}
+
+#[utoipa::path(
+    request_body = UpdateUserParams,
+    responses(
+        (status = 200, description = "OK"),
+        (status = 403, description = "Unauthorized"),
+        (status = 500, description = "Internal Server Error")
+    ),
+    security(
+        ("api_key" = [])
+    ),
+)]
+#[put("/api/v1/user")]
+pub(crate) async fn update_user(
+    data: web::Data<AppState>,
+    params: web::Json<schemas::UpdateUserParams>,
+    req: HttpRequest,
+) -> impl Responder {
+    let auth_header = get_auth_header(&req);
+    let params = params.into_inner();
+
+    let auth_token: String;
+
+    match auth_header {
+        Some(token) => auth_token = token.to_string(),
+        None => return HttpResponse::Unauthorized().finish(),
+    };
+
+    let mut user_permissions: HashMap<String, bool> = HashMap::new();
+    match params.permissions {
+        Some(data) => {user_permissions = data.clone()},
+        None => {},
+    }
+
+    let mut elevated_auth = false;
+    if user_permissions.len() != 0 {
+        if user_permissions["game_permissions"] || user_permissions["empire_permissions"] || user_permissions["data_permissions"] || user_permissions["user_permissions"] {
+            elevated_auth = true;
+        }
+    }
+
+    let auth = verify_user_auth(&data, &auth_token, &params.user_token, schemas::TablePermission::User, elevated_auth).await;
+
+    // SQL Queries
+    // TODO: Optimize by utilizing some SQL magic, for now this has to do
+    if auth {
+        let user: db::schemas::User;
+
+        let mut user_query = QueryBuilder::<sqlx::Postgres>::new("UPDATE public.users SET ");
+        let mut user_query_separated = user_query.separated(", ");
+        let mut any_param_present = false;
+
+        if let Some(discord_handle) = params.discord_handle {
+            user_query_separated.push(" discord_id = ").push_bind_unseparated(discord_handle);
+            any_param_present = true;
+        }
+
+        if let Some(profile_picture) = params.profile_picture {
+            user_query_separated.push(" picture_url = ");
+            match any_param_present {
+                true => user_query_separated.push_bind(profile_picture),
+                false => user_query_separated.push_bind_unseparated(profile_picture)
+            };
+            any_param_present = true;
+        }
+
+        if user_permissions.len() != 0 {
+            for (entry, value) in user_permissions.iter() {
+                match entry.deref() {
+                    "game_permissions" => {
+                        user_query_separated.push( " game_permissions = ");
+                        match any_param_present {
+                            true => user_query_separated.push_bind(value),
+                            false => user_query_separated.push_bind_unseparated(value)
+                        };
+                        any_param_present = true;
+                    },
+                    "empire_permissions" => {
+                        user_query_separated.push( " empire_permissions = ");
+                        match any_param_present {
+                            true => user_query_separated.push_bind(value),
+                            false => user_query_separated.push_bind_unseparated(value)
+                        };
+                        any_param_present = true;
+                    },
+                    "data_permissions" => {
+                        user_query_separated.push( " data_permissions = ");
+                        match any_param_present {
+                            true => user_query_separated.push_bind(value),
+                            false => user_query_separated.push_bind_unseparated(value)
+                        };
+                        any_param_present = true;
+                    },
+                    "user_permissions" => {
+                        user_query_separated.push( " user_permissions = ");
+                        match any_param_present {
+                            true => user_query_separated.push_bind(value),
+                            false => user_query_separated.push_bind_unseparated(value)
+                        };
+                        any_param_present = true;
+                    },
+                    _ => {}
+                }
+            }
+        }
+
+        if any_param_present {
+            user_query_separated.push_unseparated(" WHERE token = ").push_bind_unseparated(params.user_token);
+            user_query_separated.push_unseparated(" RETURNING *");
+
+            user = match user_query
+                .build_query_as::<db::schemas::User>()
+                .fetch_one(&data.db)
+                .await
+            {
+                Ok(data) => data,
+                Err(_) => return HttpResponse::InternalServerError().finish(),
+            };
+        } else {
+            user = match sqlx::query_as!(
+                db::schemas::User,
+                "SELECT * FROM public.users WHERE token = $1",
+                params.user_token
+            )
+                .fetch_one(&data.db)
+                .await
+            {
+                Ok(data) => data,
+                Err(_) => return HttpResponse::InternalServerError().finish(),
+            };
+        }
+
+        let mut user_permissions: HashMap<String, bool> = HashMap::new();
+        user_permissions.insert("game_permissions".to_string(), user.game_permissions);
+        user_permissions.insert("empire_permissions".to_string(), user.empire_permissions);
+        user_permissions.insert("data_permissions".to_string(), user.data_permissions);
+        user_permissions.insert("user_permissions".to_string(), user.user_permissions);
+
+        let return_data = schemas::User {
+            user_token: user.token,
+            discord_handle: user.discord_id,
+            profile_picture: user.picture_url,
+            permissions: user_permissions
+        };
+        return HttpResponse::Ok().json(return_data);
+    } else {
+        return HttpResponse::Unauthorized().finish();
+    }
+}
+
+#[utoipa::path(
+    request_body = DeleteUserParams,
+    responses(
+        (status = 200, description = "OK"),
+        (status = 403, description = "Unauthorized"),
+        (status = 500, description = "Internal Server Error")
+    ),
+    security(
+        ("api_key" = [])
+    ),
+)]
+#[delete("/api/v1/user")]
+pub(crate) async fn delete_user(
+    data: web::Data<AppState>,
+    params: web::Query<schemas::DeleteUserParams>,
+    req: HttpRequest,
+) -> impl Responder {
+    let auth_header = get_auth_header(&req);
+    let params = params.into_inner();
+
+    let auth_token: String;
+
+    match auth_header {
+        Some(token) => auth_token = token.to_string(),
+        None => return HttpResponse::Unauthorized().finish(),
+    };
+
+    let auth = verify_user_auth(&data, &auth_token, &params.user_token, schemas::TablePermission::User, false).await;
+
+    // SQL Queries
+    // TODO: Optimize by utilizing some SQL magic, for now this has to do
+    if auth {
+        match sqlx::query!(
+            "DELETE FROM public.users WHERE token = $1",
+            params.user_token
+        )
+            .execute(&data.db)
+            .await
+        {
+            Ok(_) => {}
+            Err(_) => {
+                return HttpResponse::InternalServerError().finish();
+            }
+        };
+
+        return HttpResponse::Ok().into();
+    } else {
+        return HttpResponse::Unauthorized().finish();
+    }
+}
diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs
new file mode 100644
index 0000000..81c23c3
--- /dev/null
+++ b/src/v1/schemas.rs
@@ -0,0 +1,64 @@
+use std::collections::HashMap;
+use serde::{Deserialize, Serialize};
+use utoipa::{IntoParams, ToSchema};
+
+// DB Permission Enums
+
+pub enum TablePermission {
+    Game,
+    Empire,
+    Data,
+    User
+}
+
+// User Structs
+
+#[derive(Serialize, ToSchema, Debug)]
+pub struct User {
+    #[schema(example = "abcdef")]
+    pub user_token: String,
+    #[schema(example = "discorduser")]
+    pub discord_handle: Option<String>,
+    #[schema(example = "/assets/avatars/124677612.png")]
+    pub profile_picture: Option<String>,
+    #[schema(example = "\
+    {\
+        [\"game_permissions\"]: true,
+        [\"empire_permissions\"]: true,
+        [\"data_permissions\"]: false,
+        [\"user_permissions\"]: false,
+    }\
+    ")]
+    pub permissions: HashMap<String, bool>,
+}
+
+#[derive(Serialize, Deserialize, ToSchema, Debug)]
+pub struct GetUserParams {
+    #[schema(example = "abcdef")]
+    pub user_token: String,
+}
+
+#[derive(Serialize, Deserialize, ToSchema, Debug)]
+pub struct UpdateUserParams {
+    #[schema(example = "abcdef")]
+    pub user_token: String,
+    #[schema(example = "discorduser")]
+    pub discord_handle: Option<String>,
+    #[schema(example = "/assets/avatars/124677612.png")]
+    pub profile_picture: Option<String>,
+    #[schema(example = "\
+    {\
+        [\"game_permissions\"]: true,
+        [\"empire_permissions\"]: true,
+        [\"data_permissions\"]: false,
+        [\"user_permissions\"]: false,
+    }\
+    ")]
+    pub permissions: Option<HashMap<String, bool>>,
+}
+
+#[derive(Serialize, Deserialize, ToSchema, Debug)]
+pub struct DeleteUserParams {
+    #[schema(example = "abcdef")]
+    pub user_token: String,
+}
\ No newline at end of file
diff --git a/src/v2/mod.rs b/src/v2/mod.rs
index 9f37731..1f1f07a 100644
--- a/src/v2/mod.rs
+++ b/src/v2/mod.rs
@@ -78,7 +78,7 @@ pub(crate) async fn empires(
 
         if let Some(auth_token) = params.token.clone() {
             if  auth_token == data.auth_tokens.admin || auth_token == data.auth_tokens.moderator {
-                new_data.discord_user = entry.discord_user.clone();
+                new_data.discord_user = Some("deprecated".to_string());
             }
         }
 
@@ -112,7 +112,7 @@ pub(crate) async fn ethics(
     db_data.iter().for_each(|entry| {
         let new_data = schemas::Ethic {
             id: entry.id,
-            machine_ethic: entry.machine_ethic,
+            gestalt_ethic: entry.gestalt_ethic,
             name: entry.name.clone()
         };
 
diff --git a/src/v2/schemas.rs b/src/v2/schemas.rs
index e575885..69897e0 100644
--- a/src/v2/schemas.rs
+++ b/src/v2/schemas.rs
@@ -38,7 +38,7 @@ pub struct GameGroup {
 pub struct Ethic {
     pub id: i32,
     pub name: String,
-    pub machine_ethic: bool,
+    pub gestalt_ethic: bool,
 }
 
 #[derive(Serialize, ToSchema, Debug, FromRow)]
diff --git a/src/v3/mod.rs b/src/v3/mod.rs
index 980e772..f1c414c 100644
--- a/src/v3/mod.rs
+++ b/src/v3/mod.rs
@@ -5,12 +5,11 @@ use actix_web::{
     web::{self, Json},
     HttpRequest, HttpResponse, Responder,
 };
-use sqlx::{Execute, QueryBuilder};
+use sqlx::QueryBuilder;
 
-use crate::{
-    db::{self, schemas::EmpireEthic},
-    AppState,
-};
+use dotenvy;
+
+use crate::{db, AppState};
 
 pub(crate) mod schemas;
 
@@ -32,7 +31,7 @@ fn verify_auth(token: Option<&str>, data: &AppState) -> schemas::AuthReturn {
     return auth_return;
 }
 
-fn get_auth_header<'a>(req: &'a HttpRequest) -> Option<&'a str> {
+fn get_auth_header(req: &HttpRequest) -> Option<&str> {
     req.headers().get("x-api-key")?.to_str().ok()
 }
 
@@ -110,37 +109,37 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
     let mut parsed_data: schemas::FullViewData = schemas::FullViewData {
         games: HashMap::new(),
         ethics: HashMap::new(),
-        species: HashMap::new(),
+        phenotypes: HashMap::new(),
     };
 
     // Data processing
     // Species Vector
     db_portrait_groups.iter().for_each(|species| {
-        let new_data = schemas::Species {
+        let new_data = schemas::Phenotype {
             id: species.id,
             display: species.name.clone(),
-            portraits: HashMap::new(),
+            species: HashMap::new(),
         };
 
         parsed_data
-            .species
+            .phenotypes
             .entry(species.id)
             .and_modify(|d| *d = new_data.clone())
             .or_insert(new_data);
     });
 
     db_portraits.iter().for_each(|portrait| {
-        let new_data = schemas::Portrait {
+        let new_data = schemas::Species {
             id: portrait.id,
             hires: portrait.hires.clone(),
-            lores: Some(portrait.lores.clone()),
+            lores: portrait.lores.clone(),
         };
 
         parsed_data
-            .species
+            .phenotypes
             .get_mut(&portrait.group_id)
             .unwrap()
-            .portraits
+            .species
             .entry(portrait.id)
             .and_modify(|d| *d = new_data.clone())
             .or_insert(new_data);
@@ -182,10 +181,10 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let new_data = schemas::ChellarisEmpireLegacy {
             id: empire.id,
             gestalt: empire.gestalt,
-            machine: false,
+            machine: empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
             group: empire.group_id,
-            empire_portrait: empire.portrait_id,
-            empire_portrait_group: empire.portrait_group_id,
+            portrait_id: empire.portrait_id,
+            portrait_group_id: empire.portrait_group_id,
             discord_user: None,
             ethics: HashMap::new(),
         };
@@ -205,7 +204,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let new_data = schemas::Ethic {
             id: ethic.id,
             display: ethic.name.clone(),
-            machine: ethic.machine_ethic,
+            gestalt: ethic.gestalt_ethic,
         };
 
         parsed_data
@@ -220,13 +219,13 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
         let id = empire_ethic.empire_id;
 
         let new_data = schemas::EmpireEthicLegacy {
-            id: empire_ethic.ethics_id,
+            ethic_id: empire_ethic.ethics_id,
             display: parsed_data.ethics[&empire_ethic.ethics_id].display.clone(),
-            machine: parsed_data.ethics[&empire_ethic.ethics_id].machine,
+            gestalt: parsed_data.ethics[&empire_ethic.ethics_id].gestalt,
             fanatic: empire_ethic.fanatic,
         };
 
-        if new_data.machine {
+        if new_data.gestalt {
             parsed_data
                 .games
                 .get_mut(&game_id)
@@ -234,7 +233,7 @@ pub(crate) async fn full_view_data(data: web::Data<AppState>) -> impl Responder
                 .empires
                 .get_mut(&id)
                 .unwrap()
-                .machine = true;
+                .gestalt = true;
         }
 
         parsed_data
@@ -368,7 +367,7 @@ pub(crate) async fn get_game_data(
                 "[REDACTED]".to_string()
             },
             discord_user: if user_auth.moderator || user_auth.admin {
-                empire.discord_user.clone()
+                Some("deprecated".to_string())
             } else {
                 None
             },
@@ -808,7 +807,8 @@ pub(crate) async fn get_empire(
             group: db_empire.group_id,
             game: db_empire.game_id,
             name: db_empire.name,
-            discord_user: db_empire.discord_user,
+            discord_user: Some("deprecated".to_string()),
+            machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
             gestalt: db_empire.gestalt,
             portrait_id: db_empire.portrait_id,
             portrait_group_id: db_empire.portrait_group_id,
@@ -941,7 +941,8 @@ pub(crate) async fn create_empire(
                 group: db_empire.group_id,
                 game: db_empire.game_id,
                 name: db_empire.name,
-                discord_user: db_empire.discord_user,
+                discord_user: Some("deprecated".to_string()),
+                machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
                 gestalt: db_empire.gestalt,
                 portrait_id: db_empire.portrait_id,
                 portrait_group_id: db_empire.portrait_group_id,
@@ -987,12 +988,10 @@ pub(crate) async fn edit_empire(
         let mut db_empire_query = QueryBuilder::<sqlx::Postgres>::new("UPDATE public.empires SET ");
         let mut db_empire_separated = db_empire_query.separated(", ");
 
-        if let Some(new_game) = params.game_id {
-            any_param_present = true;
-            db_empire_separated
-                .push(" game_id = ")
-                .push_bind_unseparated(new_game);
-        }
+        // More often than not does nothing but is required to ensure data is handled properly
+        db_empire_separated
+            .push(" game_id = ")
+            .push_bind_unseparated(params.game_id);
 
         if let Some(new_group) = params.group_id {
             any_param_present = true;
@@ -1038,6 +1037,12 @@ pub(crate) async fn edit_empire(
                     .push(" discord_user = ")
                     .push_bind_unseparated(new_discord_user);
             }
+            else {
+                any_param_present = true;
+                let val: Option<String> = None;
+                db_empire_separated
+                    .push(" discord_user = ").push_bind_unseparated(val);
+            }
         }
 
         let db_empire: db::schemas::Empire;
@@ -1046,9 +1051,6 @@ pub(crate) async fn edit_empire(
             db_empire_separated
                 .push_unseparated(" WHERE id = ")
                 .push_bind_unseparated(params.empire_id);
-            db_empire_separated
-                .push_unseparated(" AND group_id = ")
-                .push_bind_unseparated(params.group_id);
             db_empire_separated
                 .push_unseparated(" AND game_id = ")
                 .push_bind_unseparated(params.game_id);
@@ -1071,9 +1073,6 @@ pub(crate) async fn edit_empire(
             db_empire_separated
                 .push_unseparated(" WHERE id = ")
                 .push_bind_unseparated(params.empire_id);
-            db_empire_separated
-                .push_unseparated(" AND group_id = ")
-                .push_bind_unseparated(params.group_id);
             db_empire_separated
                 .push_unseparated(" AND game_id = ")
                 .push_bind_unseparated(params.game_id);
@@ -1175,7 +1174,8 @@ pub(crate) async fn edit_empire(
                 group: db_empire.group_id,
                 game: db_empire.game_id,
                 name: db_empire.name,
-                discord_user: db_empire.discord_user,
+                discord_user: Some("deprecated".to_string()),
+                machine: db_empire.portrait_group_id.to_string() == dotenvy::var("MACHINE_GROUP_ID").unwrap_or("12".to_string()),
                 gestalt: db_empire.gestalt,
                 portrait_id: db_empire.portrait_id,
                 portrait_group_id: db_empire.portrait_group_id,
@@ -1235,9 +1235,110 @@ pub(crate) async fn delete_empire(
     }
 }
 
-// Data Manipulation Endpoints
+// Ethics Endpoints
+// Data Manipulation Admin Only
 
-// Admin
-// Add/Update/Remove Portrait
-// Add/Update/Remove Species
-// Add/Update/Remove Ethics
+#[utoipa::path(
+    responses(
+        (status = 200, description = "OK", body = ChellarisEthics),
+    ),
+)]
+#[get("/api/v3/ethics")]
+pub(crate) async fn get_ethics(data: web::Data<AppState>) -> impl Responder {
+    // SQL Queries
+    // TODO: Optimize by utilizing some SQL magic, for now this has to do
+    let mut db_ethics: HashMap<i32, schemas::Ethic> = HashMap::new();
+
+    let mut db_ethic_query = QueryBuilder::<sqlx::Postgres>::new("SELECT * FROM public.ethics");
+
+    match db_ethic_query
+        .build_query_as::<db::schemas::Ethic>()
+        .fetch_all(&data.db)
+        .await
+    {
+        Ok(data) => {
+            for ethic in data {
+                db_ethics.insert(
+                    ethic.id,
+                    schemas::Ethic {
+                        id: ethic.id,
+                        gestalt: ethic.gestalt_ethic,
+                        display: ethic.name,
+                    },
+                );
+            }
+        }
+        Err(e) => return HttpResponse::UnprocessableEntity().body(format!("{:#?}", e.to_string())),
+    };
+
+    // Empire Ethic Creation
+    let parsed_data: schemas::ChellarisEthics = schemas::ChellarisEthics { ethics: db_ethics };
+
+    return HttpResponse::Ok().json(parsed_data);
+}
+
+// Species & Portrait Endpoints
+// Data Manipulation Admin Only
+
+#[utoipa::path(
+    responses(
+        (status = 200, description = "OK", body = ChellarisPhenotypes),
+    ),
+)]
+#[get("/api/v3/phenotypes")]
+pub(crate) async fn get_phenotypes(data: web::Data<AppState>) -> impl Responder {
+    // SQL Queries
+    // TODO: Optimize by utilizing some SQL magic, for now this has to do
+    let mut db_phenotypes: HashMap<i32, schemas::Phenotype> = HashMap::new();
+
+    let mut db_phenotype_query = QueryBuilder::<sqlx::Postgres>::new("SELECT * FROM public.portrait_groups");
+
+    match db_phenotype_query
+        .build_query_as::<db::schemas::PortraitGroup>()
+        .fetch_all(&data.db)
+        .await
+    {
+        Ok(data) => {
+            for phenotype in data {
+                db_phenotypes.insert(
+                    phenotype.id,
+                    schemas::Phenotype {
+                        id: phenotype.id,
+                        display: phenotype.name,
+                        species: HashMap::new(),
+                    },
+                );
+            }
+        }
+        Err(e) => return HttpResponse::UnprocessableEntity().body(format!("{:#?}", e.to_string())),
+    };
+
+    let mut db_species_query = QueryBuilder::<sqlx::Postgres>::new("SELECT * FROM public.portraits");
+
+    match db_species_query
+        .build_query_as::<db::schemas::Portrait>()
+        .fetch_all(&data.db)
+        .await
+    {
+        Ok(data) => {
+            for species in data {
+                if let Some(phenotype) = db_phenotypes.get_mut(&species.group_id) {
+                    phenotype.species.insert(
+                        species.id,
+                        schemas::Species {
+                            id: species.id,
+                            hires: species.hires,
+                            lores: species.lores
+                        }
+                    );
+                }
+            }
+        }
+        Err(e) => return HttpResponse::UnprocessableEntity().body(format!("{:#?}", e.to_string())),
+    };
+
+    // Empire Ethic Creation
+    let parsed_data: schemas::ChellarisPhenotypes = schemas::ChellarisPhenotypes { phenotypes: db_phenotypes };
+
+    return HttpResponse::Ok().json(parsed_data);
+}
diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs
index 2a25b96..709a7b2 100644
--- a/src/v3/schemas.rs
+++ b/src/v3/schemas.rs
@@ -43,7 +43,7 @@ pub struct DeleteGameParam {
 pub struct FullViewData {
     pub games: HashMap<i32, ChellarisGameLegacy>,
     pub ethics: HashMap<i32, Ethic>,
-    pub species: HashMap<i32, Species>,
+    pub phenotypes: HashMap<i32, Phenotype>,
 }
 
 #[derive(Serialize, ToSchema, Debug, Clone)]
@@ -147,7 +147,7 @@ pub struct UpdateEmpireParams {
     #[schema(example = 1)]
     pub empire_id: i32,
     #[schema(example = 1)]
-    pub game_id: Option<i32>,
+    pub game_id: i32,
     #[schema(example = 1)]
     pub group_id: Option<i32>,
     #[schema(example = "Example Empire")]
@@ -195,6 +195,7 @@ pub struct ChellarisEmpire {
     pub game: i32,
     pub name: String,
     pub discord_user: Option<String>,
+    pub machine: bool,
     pub gestalt: bool,
     pub portrait_id: i32,
     pub portrait_group_id: i32,
@@ -207,17 +208,19 @@ pub struct ChellarisEmpireLegacy {
     pub group: i32,
     pub gestalt: bool,
     pub machine: bool,
-    pub empire_portrait: i32,
-    pub empire_portrait_group: i32,
+    pub portrait_id: i32,
+    pub portrait_group_id: i32,
     pub discord_user: Option<String>,
     pub ethics: HashMap<i32, EmpireEthicLegacy>,
 }
 
+// Ethics Structs
+
 #[derive(Serialize, ToSchema, Debug, Clone)]
 pub struct Ethic {
     pub id: i32,
     pub display: String,
-    pub machine: bool,
+    pub gestalt: bool,
 }
 
 #[derive(Serialize, Deserialize, ToSchema, Debug, Clone)]
@@ -230,23 +233,35 @@ pub struct EmpireEthic {
 
 #[derive(Serialize, ToSchema, Debug, Clone)]
 pub struct EmpireEthicLegacy {
+    pub ethic_id: i32,
+    pub display: String,
+    pub gestalt: bool,
+    pub fanatic: bool,
+}
+
+#[derive(Serialize, ToSchema, Debug, Clone)]
+pub struct ChellarisEthics {
+    pub ethics: HashMap<i32, Ethic>,
+}
+
+// Species Structs
+
+#[derive(Serialize, ToSchema, Debug, Clone)]
+pub struct Phenotype {
     pub id: i32,
     pub display: String,
-    pub machine: bool,
-    pub fanatic: bool,
+    pub species: HashMap<i32, Species>,
+}
+
+#[derive(Serialize, ToSchema, Debug, Clone)]
+pub struct ChellarisPhenotypes {
+    pub phenotypes: HashMap<i32, Phenotype>
 }
 
 #[derive(Serialize, ToSchema, Debug, Clone)]
 pub struct Species {
-    pub id: i32,
-    pub display: String,
-    pub portraits: HashMap<i32, Portrait>,
-}
-
-#[derive(Serialize, ToSchema, Debug, Clone)]
-pub struct Portrait {
     pub id: i32,
     pub hires: String,
-    pub lores: Option<String>,
+    pub lores: String,
 }
 
diff --git a/yarn.lock b/yarn.lock
deleted file mode 100644
index a2e0510..0000000
--- a/yarn.lock
+++ /dev/null
@@ -1,314 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-ajv@^6.1.1:
-  version "6.12.6"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
-  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
-  dependencies:
-    fast-deep-equal "^3.1.1"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.4.1"
-    uri-js "^4.2.2"
-
-async@^2.0.1:
-  version "2.6.4"
-  resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
-  integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==
-  dependencies:
-    lodash "^4.17.14"
-
-bignumber.js@9.0.0:
-  version "9.0.0"
-  resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075"
-  integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==
-
-bson@~1.0.4:
-  version "1.0.9"
-  resolved "https://registry.yarnpkg.com/bson/-/bson-1.0.9.tgz#12319f8323b1254739b7c6bef8d3e89ae05a2f57"
-  integrity sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg==
-
-buffer-shims@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
-  integrity sha512-Zy8ZXMyxIT6RMTeY7OP/bDndfj6bwCan7SS98CEndS6deHwWPpseeHlwarNcBim+etXnF9HBc1non5JgDaJU1g==
-
-core-util-is@~1.0.0:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
-  integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
-
-debug@*:
-  version "4.3.4"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
-  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
-  dependencies:
-    ms "2.1.2"
-
-debug@^2.2.0:
-  version "2.6.9"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
-  integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
-  dependencies:
-    ms "2.0.0"
-
-double-ended-queue@^2.1.0-0:
-  version "2.1.0-0"
-  resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
-  integrity sha512-+BNfZ+deCo8hMNpDqDnvT+c0XpJ5cUa6mqYq89bho2Ifze4URTqRkcwR399hWoTrTkbZ/XJYDgP6rc7pRgffEQ==
-
-es6-promise@3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.2.1.tgz#ec56233868032909207170c39448e24449dd1fc4"
-  integrity sha512-oj4jOSXvWglTsc3wrw86iom3LDPOx1nbipQk+jaG3dy+sMRM6ReSgVr/VlmBuF6lXUrflN9DCcQHeSbAwGUl4g==
-
-fast-deep-equal@^3.1.1:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
-  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-
-fast-json-stable-stringify@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
-  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
-
-inherits@~2.0.1, inherits@~2.0.3:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
-  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-isarray@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
-  integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
-
-json-schema-traverse@^0.4.1:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
-  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
-
-lodash@^4.17.14, lodash@^4.17.4:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
-  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-mongo-sql@^2.7.5:
-  version "2.7.8"
-  resolved "https://registry.yarnpkg.com/mongo-sql/-/mongo-sql-2.7.8.tgz#f50184aaadc1be530db69e301ba35b01afd402d9"
-  integrity sha512-fJ4Tsn/G5QimXPRyoT0tnDhYdrPa/UJZY6FCJ4e9CYZgYH84w1qQrlednrpqgD9qK0oXtrLv78j1V+I5Yt/a6A==
-
-mongodb-core@2.1.20:
-  version "2.1.20"
-  resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.20.tgz#fece8dd76b59ee7d7f2d313b65322c160492d8f1"
-  integrity sha512-IN57CX5/Q1bhDq6ShAR6gIv4koFsZP7L8WOK1S0lR0pVDQaScffSMV5jxubLsmZ7J+UdqmykKw4r9hG3XQEGgQ==
-  dependencies:
-    bson "~1.0.4"
-    require_optional "~1.0.0"
-
-mongodb@^2.1.18:
-  version "2.2.36"
-  resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.36.tgz#1c573680b2849fb0f47acbba3dc5fa228de975f5"
-  integrity sha512-P2SBLQ8Z0PVx71ngoXwo12+FiSfbNfGOClAao03/bant5DgLNkOPAck5IaJcEk4gKlQhDEURzfR3xuBG1/B+IA==
-  dependencies:
-    es6-promise "3.2.1"
-    mongodb-core "2.1.20"
-    readable-stream "2.2.7"
-
-monk-middleware-cast-ids@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/monk-middleware-cast-ids/-/monk-middleware-cast-ids-0.2.1.tgz#40c40e5a6cb33ccedc289220943275ee8861c529"
-  integrity sha512-Hp9gwjXo+inSPhXUlsV1u3DyZh2cXT3Osij/1gSNCJQCgacAF1lfmnTj6bKmlf1Et4dvLhwUL0PquxdZRIofkA==
-
-monk-middleware-fields@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/monk-middleware-fields/-/monk-middleware-fields-0.2.0.tgz#ff637af35f5948879ccb2be15a91360911bea6c1"
-  integrity sha512-pp+k0JeBX+HkIKnCisrtsW/QM2WGkOVG1Bd1qKLSanuBCf1l5khpdHrEullfko0HO6tCjCJMp//MsR16gd5tAw==
-
-monk-middleware-handle-callback@^0.2.0:
-  version "0.2.2"
-  resolved "https://registry.yarnpkg.com/monk-middleware-handle-callback/-/monk-middleware-handle-callback-0.2.2.tgz#47de6cc1248726c72a2be0c81bc4e68310c32146"
-  integrity sha512-5hBynb7asZ2uw9XVze7C3XH0zXT51yFDvYydk/5HnWWzh2NLglDSiKDcX0yLKPHzFgiq+5Z4Laq5fFVnFsmm8w==
-
-monk-middleware-options@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/monk-middleware-options/-/monk-middleware-options-0.2.1.tgz#58dae1c518d46636ebdff506fadfc773bb442886"
-  integrity sha512-ypE0wGC8n5ARvOq2tlERr1uyu1edckeDRkheQLaXPRm9LoW7kr9P7xMGEjW2vmBh7IxnkpONVc7555X8x+34hQ==
-
-monk-middleware-query@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/monk-middleware-query/-/monk-middleware-query-0.2.0.tgz#a926c677d4a5620c62151b0a56d0c0c151675874"
-  integrity sha512-BApd5HBiczJl1eVy65c9/NBVLtygBePFxuoHgar/LeMWCjWP9odSJk3vsnbxTnsOT1CMJ+hFysbaosLzDsxvtA==
-
-monk-middleware-wait-for-connection@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/monk-middleware-wait-for-connection/-/monk-middleware-wait-for-connection-0.2.0.tgz#312958d30e588b57d09754dd7c97b4843316835a"
-  integrity sha512-jSTz73B/+pGTTvhu5Ym8xsG6+QqaWab53UXnXdNNlTijTdLvcHABCLJXudQiJxob5N1Mzr5EOSx5ziwn2sihPQ==
-
-monk@^6.0.5:
-  version "6.0.6"
-  resolved "https://registry.yarnpkg.com/monk/-/monk-6.0.6.tgz#2ff1cd57f001bba0fea73d1eea3952a7d35450c5"
-  integrity sha512-bSuADQGwIxBcRzCzQaMoGmiGl30Dr+0iB1FQAQb3VwWwAKbtpDN2wkVHCjthzw/jXhPHWxTQFUtlSt/nSagojQ==
-  dependencies:
-    debug "*"
-    mongodb "^2.1.18"
-    monk-middleware-cast-ids "^0.2.1"
-    monk-middleware-fields "^0.2.0"
-    monk-middleware-handle-callback "^0.2.0"
-    monk-middleware-options "^0.2.1"
-    monk-middleware-query "^0.2.0"
-    monk-middleware-wait-for-connection "^0.2.0"
-    object-assign "^4.1.1"
-
-ms@2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
-  integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
-
-ms@2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
-  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-mysql@^2.11.1:
-  version "2.18.1"
-  resolved "https://registry.yarnpkg.com/mysql/-/mysql-2.18.1.tgz#2254143855c5a8c73825e4522baf2ea021766717"
-  integrity sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==
-  dependencies:
-    bignumber.js "9.0.0"
-    readable-stream "2.3.7"
-    safe-buffer "5.1.2"
-    sqlstring "2.3.1"
-
-object-assign@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
-  integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
-
-process-nextick-args@~1.0.6:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
-  integrity sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==
-
-process-nextick-args@~2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
-  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-
-punycode@^2.1.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
-  integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
-
-readable-stream@2.2.7:
-  version "2.2.7"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.7.tgz#07057acbe2467b22042d36f98c5ad507054e95b1"
-  integrity sha512-a6ibcfWFhgihuTw/chl+u3fB5ykBZFmnvpyZHebY0MCQE4vvYcsCLpCeaQ1BkH7HdJYavNSqF0WDLeo4IPHQaQ==
-  dependencies:
-    buffer-shims "~1.0.0"
-    core-util-is "~1.0.0"
-    inherits "~2.0.1"
-    isarray "~1.0.0"
-    process-nextick-args "~1.0.6"
-    string_decoder "~1.0.0"
-    util-deprecate "~1.0.1"
-
-readable-stream@2.3.7:
-  version "2.3.7"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
-  integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
-  dependencies:
-    core-util-is "~1.0.0"
-    inherits "~2.0.3"
-    isarray "~1.0.0"
-    process-nextick-args "~2.0.0"
-    safe-buffer "~5.1.1"
-    string_decoder "~1.1.1"
-    util-deprecate "~1.0.1"
-
-redis-commands@^1.2.0:
-  version "1.7.0"
-  resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89"
-  integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==
-
-redis-parser@^2.6.0:
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b"
-  integrity sha512-9Hdw19gwXFBJdN8ENUoNVJFRyMDFrE/ZBClPicKYDPwNPJ4ST1TedAHYNSiGKElwh2vrmRGMoJYbVdJd+WQXIw==
-
-redis@^2.8.0:
-  version "2.8.0"
-  resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02"
-  integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==
-  dependencies:
-    double-ended-queue "^2.1.0-0"
-    redis-commands "^1.2.0"
-    redis-parser "^2.6.0"
-
-require_optional@~1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
-  integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==
-  dependencies:
-    resolve-from "^2.0.0"
-    semver "^5.1.0"
-
-resolve-from@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
-  integrity sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==
-
-safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
-  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-semver@^5.1.0:
-  version "5.7.2"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
-  integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
-
-sqlstring@2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40"
-  integrity sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==
-
-sqlx@^4.3.2:
-  version "4.3.2"
-  resolved "https://registry.yarnpkg.com/sqlx/-/sqlx-4.3.2.tgz#e00e9c01543e776639b3622beee0b51f2e005b76"
-  integrity sha512-cKXn3T0fDhnX69F7556K0weGUYaBsmmtcIjTlj9OPQNxR56Lvil89pk5WntRR+h4IFFkrmKDg0yzl0YVsSDgbQ==
-  dependencies:
-    ajv "^6.1.1"
-    async "^2.0.1"
-    debug "^2.2.0"
-    lodash "^4.17.4"
-    mongo-sql "^2.7.5"
-    monk "^6.0.5"
-    mysql "^2.11.1"
-    redis "^2.8.0"
-
-string_decoder@~1.0.0:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab"
-  integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==
-  dependencies:
-    safe-buffer "~5.1.0"
-
-string_decoder@~1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
-  integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
-  dependencies:
-    safe-buffer "~5.1.0"
-
-uri-js@^4.2.2:
-  version "4.4.1"
-  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
-  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
-  dependencies:
-    punycode "^2.1.0"
-
-util-deprecate@~1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
-  integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==