Add Pit Scouting Tab

Signed-off-by: Emily Markova <emily.markova@gmail.com>
Change-Id: Iede446546e20f2915bb53e134050b5025976da36
diff --git a/.bazelignore b/.bazelignore
index 2409a99..3665125 100644
--- a/.bazelignore
+++ b/.bazelignore
@@ -9,3 +9,4 @@
 scouting/www/rpc/node_modules
 scouting/www/shift_schedule/node_modules
 scouting/www/view/node_modules
+scouting/www/pit_scouting/node_modules
diff --git a/BUILD b/BUILD
index 5427fd5..eea9edb 100644
--- a/BUILD
+++ b/BUILD
@@ -71,6 +71,10 @@
 # gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response //scouting/webserver/requests/messages:submit_driver_ranking_response_go_fbs
 # gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2023_data_scouting //scouting/webserver/requests/messages:delete_2023_data_scouting_go_fbs
 # gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/delete_2023_data_scouting_response //scouting/webserver/requests/messages:delete_2023_data_scouting_response_go_fbs
+# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image //scouting/webserver/requests/messages:submit_pit_image_go_fbs
+# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response //scouting/webserver/requests/messages:submit_pit_image_response_go_fbs
+# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images //scouting/webserver/requests/messages:request_pit_images_go_fbs
+# gazelle:resolve go github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response //scouting/webserver/requests/messages:request_pit_images_response_go_fbs
 
 gazelle(
     name = "gazelle",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 10c6288..d844678 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -36,8 +36,8 @@
       '@angular/core': 15.1.5_rxjs@7.5.7+zone.js@0.11.8
       '@angular/forms': 15.1.5_kkteiffnjutwxhimrtvkwyrg3a
       '@angular/platform-browser': 15.1.5_s7kwnqxnlkypgp4vtemlnxkbmi
-      '@babel/cli': 7.20.7_@babel+core@7.20.12
-      '@babel/core': 7.20.12
+      '@babel/cli': 7.22.5_@babel+core@7.22.5
+      '@babel/core': 7.22.5
       '@rollup/plugin-node-resolve': 13.1.3_rollup@3.17.2
       '@types/flatbuffers': 1.10.0
       '@types/jasmine': 3.10.3
@@ -86,6 +86,12 @@
     dependencies:
       '@angular/forms': 15.1.5
 
+  scouting/www/pit_scouting:
+    specifiers:
+      '@angular/forms': 15.1.5
+    dependencies:
+      '@angular/forms': 15.1.5
+
   scouting/www/rpc:
     specifiers: {}
 
@@ -103,12 +109,12 @@
 
 packages:
 
-  /@ampproject/remapping/2.2.0:
-    resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
+  /@ampproject/remapping/2.2.1:
+    resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
     engines: {node: '>=6.0.0'}
     dependencies:
-      '@jridgewell/gen-mapping': 0.1.1
-      '@jridgewell/trace-mapping': 0.3.17
+      '@jridgewell/gen-mapping': 0.3.3
+      '@jridgewell/trace-mapping': 0.3.18
     dev: true
 
   /@angular-devkit/architect/0.1501.5:
@@ -157,7 +163,7 @@
       '@angular/core': 15.1.5
     dependencies:
       '@angular/core': 15.1.5_rxjs@7.5.7+zone.js@0.11.8
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
 
   /@angular/cli/15.1.5:
@@ -198,7 +204,7 @@
     dependencies:
       '@angular/core': 15.1.5_rxjs@7.5.7+zone.js@0.11.8
       rxjs: 7.5.7
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
 
   /@angular/compiler-cli/15.1.5_4dhd3kzleoe6yecgeixihz776m:
@@ -211,16 +217,16 @@
     dependencies:
       '@angular/compiler': 15.1.5_@angular+core@15.1.5
       '@babel/core': 7.19.3
-      '@jridgewell/sourcemap-codec': 1.4.14
+      '@jridgewell/sourcemap-codec': 1.4.15
       chokidar: 3.5.3
       convert-source-map: 1.9.0
       dependency-graph: 0.11.0
       magic-string: 0.27.0
       reflect-metadata: 0.1.13
-      semver: 7.3.8
-      tslib: 2.4.1
+      semver: 7.5.3
+      tslib: 2.6.0
       typescript: 4.8.4
-      yargs: 17.6.2
+      yargs: 17.7.2
     transitivePeerDependencies:
       - supports-color
     dev: true
@@ -235,7 +241,7 @@
         optional: true
     dependencies:
       '@angular/core': 15.1.5_rxjs@7.5.7+zone.js@0.11.8
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
 
   /@angular/core/15.1.5_rxjs@7.5.7+zone.js@0.11.8:
@@ -246,7 +252,7 @@
       zone.js: ~0.11.4 || ~0.12.0
     dependencies:
       rxjs: 7.5.7
-      tslib: 2.4.1
+      tslib: 2.6.0
       zone.js: 0.11.8
     dev: true
 
@@ -259,7 +265,7 @@
       '@angular/platform-browser': 15.1.5
       rxjs: ^6.5.3 || ^7.4.0
     dependencies:
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: false
 
   /@angular/forms/15.1.5_kkteiffnjutwxhimrtvkwyrg3a:
@@ -275,7 +281,7 @@
       '@angular/core': 15.1.5_rxjs@7.5.7+zone.js@0.11.8
       '@angular/platform-browser': 15.1.5_s7kwnqxnlkypgp4vtemlnxkbmi
       rxjs: 7.5.7
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
 
   /@angular/platform-browser/15.1.5_s7kwnqxnlkypgp4vtemlnxkbmi:
@@ -292,18 +298,18 @@
       '@angular/animations': 15.1.5_@angular+core@15.1.5
       '@angular/common': 15.1.5_w2a4ar2ssyezibn6c65i4snjzu
       '@angular/core': 15.1.5_rxjs@7.5.7+zone.js@0.11.8
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
 
-  /@babel/cli/7.20.7_@babel+core@7.20.12:
-    resolution: {integrity: sha512-WylgcELHB66WwQqItxNILsMlaTd8/SO6SgTTjMp4uCI7P4QyH1r3nqgFmO3BfM4AtfniHgFMH3EpYFj/zynBkQ==}
+  /@babel/cli/7.22.5_@babel+core@7.22.5:
+    resolution: {integrity: sha512-N5d7MjzwsQ2wppwjhrsicVDhJSqF9labEP/swYiHhio4Ca2XjEehpgPmerjnLQl7BPE59BLud0PTWGYwqFl/cQ==}
     engines: {node: '>=6.9.0'}
     hasBin: true
     peerDependencies:
       '@babel/core': ^7.0.0-0
     dependencies:
-      '@babel/core': 7.20.12
-      '@jridgewell/trace-mapping': 0.3.17
+      '@babel/core': 7.22.5
+      '@jridgewell/trace-mapping': 0.3.18
       commander: 4.1.1
       convert-source-map: 1.9.0
       fs-readdir-recursive: 1.1.0
@@ -315,15 +321,15 @@
       chokidar: 3.5.3
     dev: true
 
-  /@babel/code-frame/7.18.6:
-    resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
+  /@babel/code-frame/7.22.5:
+    resolution: {integrity: sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/highlight': 7.18.6
+      '@babel/highlight': 7.22.5
     dev: true
 
-  /@babel/compat-data/7.20.10:
-    resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==}
+  /@babel/compat-data/7.22.5:
+    resolution: {integrity: sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==}
     engines: {node: '>=6.9.0'}
     dev: true
 
@@ -331,16 +337,16 @@
     resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@ampproject/remapping': 2.2.0
-      '@babel/code-frame': 7.18.6
-      '@babel/generator': 7.20.7
-      '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.19.3
-      '@babel/helper-module-transforms': 7.20.11
-      '@babel/helpers': 7.20.7
-      '@babel/parser': 7.20.7
-      '@babel/template': 7.20.7
-      '@babel/traverse': 7.20.12
-      '@babel/types': 7.20.7
+      '@ampproject/remapping': 2.2.1
+      '@babel/code-frame': 7.22.5
+      '@babel/generator': 7.22.5
+      '@babel/helper-compilation-targets': 7.22.5_@babel+core@7.19.3
+      '@babel/helper-module-transforms': 7.22.5
+      '@babel/helpers': 7.22.5
+      '@babel/parser': 7.22.5
+      '@babel/template': 7.22.5
+      '@babel/traverse': 7.22.5
+      '@babel/types': 7.22.5
       convert-source-map: 1.9.0
       debug: 4.3.4
       gensync: 1.0.0-beta.2
@@ -350,20 +356,20 @@
       - supports-color
     dev: true
 
-  /@babel/core/7.20.12:
-    resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==}
+  /@babel/core/7.22.5:
+    resolution: {integrity: sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@ampproject/remapping': 2.2.0
-      '@babel/code-frame': 7.18.6
-      '@babel/generator': 7.20.7
-      '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.20.12
-      '@babel/helper-module-transforms': 7.20.11
-      '@babel/helpers': 7.20.7
-      '@babel/parser': 7.20.7
-      '@babel/template': 7.20.7
-      '@babel/traverse': 7.20.12
-      '@babel/types': 7.20.7
+      '@ampproject/remapping': 2.2.1
+      '@babel/code-frame': 7.22.5
+      '@babel/generator': 7.22.5
+      '@babel/helper-compilation-targets': 7.22.5_@babel+core@7.22.5
+      '@babel/helper-module-transforms': 7.22.5
+      '@babel/helpers': 7.22.5
+      '@babel/parser': 7.22.5
+      '@babel/template': 7.22.5
+      '@babel/traverse': 7.22.5
+      '@babel/types': 7.22.5
       convert-source-map: 1.9.0
       debug: 4.3.4
       gensync: 1.0.0-beta.2
@@ -373,176 +379,177 @@
       - supports-color
     dev: true
 
-  /@babel/generator/7.20.7:
-    resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==}
+  /@babel/generator/7.22.5:
+    resolution: {integrity: sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
-      '@jridgewell/gen-mapping': 0.3.2
+      '@babel/types': 7.22.5
+      '@jridgewell/gen-mapping': 0.3.3
+      '@jridgewell/trace-mapping': 0.3.18
       jsesc: 2.5.2
     dev: true
 
-  /@babel/helper-compilation-targets/7.20.7_@babel+core@7.19.3:
-    resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==}
+  /@babel/helper-compilation-targets/7.22.5_@babel+core@7.19.3:
+    resolution: {integrity: sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/compat-data': 7.20.10
+      '@babel/compat-data': 7.22.5
       '@babel/core': 7.19.3
-      '@babel/helper-validator-option': 7.18.6
-      browserslist: 4.21.4
+      '@babel/helper-validator-option': 7.22.5
+      browserslist: 4.21.9
       lru-cache: 5.1.1
       semver: 6.3.0
     dev: true
 
-  /@babel/helper-compilation-targets/7.20.7_@babel+core@7.20.12:
-    resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==}
+  /@babel/helper-compilation-targets/7.22.5_@babel+core@7.22.5:
+    resolution: {integrity: sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==}
     engines: {node: '>=6.9.0'}
     peerDependencies:
       '@babel/core': ^7.0.0
     dependencies:
-      '@babel/compat-data': 7.20.10
-      '@babel/core': 7.20.12
-      '@babel/helper-validator-option': 7.18.6
-      browserslist: 4.21.4
+      '@babel/compat-data': 7.22.5
+      '@babel/core': 7.22.5
+      '@babel/helper-validator-option': 7.22.5
+      browserslist: 4.21.9
       lru-cache: 5.1.1
       semver: 6.3.0
     dev: true
 
-  /@babel/helper-environment-visitor/7.18.9:
-    resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
+  /@babel/helper-environment-visitor/7.22.5:
+    resolution: {integrity: sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==}
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helper-function-name/7.19.0:
-    resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==}
+  /@babel/helper-function-name/7.22.5:
+    resolution: {integrity: sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/template': 7.20.7
-      '@babel/types': 7.20.7
+      '@babel/template': 7.22.5
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/helper-hoist-variables/7.18.6:
-    resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
+  /@babel/helper-hoist-variables/7.22.5:
+    resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/helper-module-imports/7.18.6:
-    resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
+  /@babel/helper-module-imports/7.22.5:
+    resolution: {integrity: sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/helper-module-transforms/7.20.11:
-    resolution: {integrity: sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==}
+  /@babel/helper-module-transforms/7.22.5:
+    resolution: {integrity: sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/helper-environment-visitor': 7.18.9
-      '@babel/helper-module-imports': 7.18.6
-      '@babel/helper-simple-access': 7.20.2
-      '@babel/helper-split-export-declaration': 7.18.6
-      '@babel/helper-validator-identifier': 7.19.1
-      '@babel/template': 7.20.7
-      '@babel/traverse': 7.20.12
-      '@babel/types': 7.20.7
+      '@babel/helper-environment-visitor': 7.22.5
+      '@babel/helper-module-imports': 7.22.5
+      '@babel/helper-simple-access': 7.22.5
+      '@babel/helper-split-export-declaration': 7.22.5
+      '@babel/helper-validator-identifier': 7.22.5
+      '@babel/template': 7.22.5
+      '@babel/traverse': 7.22.5
+      '@babel/types': 7.22.5
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@babel/helper-simple-access/7.20.2:
-    resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==}
+  /@babel/helper-simple-access/7.22.5:
+    resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/helper-split-export-declaration/7.18.6:
-    resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
+  /@babel/helper-split-export-declaration/7.22.5:
+    resolution: {integrity: sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/helper-string-parser/7.19.4:
-    resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
+  /@babel/helper-string-parser/7.22.5:
+    resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==}
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helper-validator-identifier/7.19.1:
-    resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==}
+  /@babel/helper-validator-identifier/7.22.5:
+    resolution: {integrity: sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==}
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helper-validator-option/7.18.6:
-    resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==}
+  /@babel/helper-validator-option/7.22.5:
+    resolution: {integrity: sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==}
     engines: {node: '>=6.9.0'}
     dev: true
 
-  /@babel/helpers/7.20.7:
-    resolution: {integrity: sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==}
+  /@babel/helpers/7.22.5:
+    resolution: {integrity: sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/template': 7.20.7
-      '@babel/traverse': 7.20.12
-      '@babel/types': 7.20.7
+      '@babel/template': 7.22.5
+      '@babel/traverse': 7.22.5
+      '@babel/types': 7.22.5
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@babel/highlight/7.18.6:
-    resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
+  /@babel/highlight/7.22.5:
+    resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/helper-validator-identifier': 7.19.1
+      '@babel/helper-validator-identifier': 7.22.5
       chalk: 2.4.2
       js-tokens: 4.0.0
     dev: true
 
-  /@babel/parser/7.20.7:
-    resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==}
+  /@babel/parser/7.22.5:
+    resolution: {integrity: sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==}
     engines: {node: '>=6.0.0'}
     hasBin: true
     dependencies:
-      '@babel/types': 7.20.7
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/template/7.20.7:
-    resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==}
+  /@babel/template/7.22.5:
+    resolution: {integrity: sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/code-frame': 7.18.6
-      '@babel/parser': 7.20.7
-      '@babel/types': 7.20.7
+      '@babel/code-frame': 7.22.5
+      '@babel/parser': 7.22.5
+      '@babel/types': 7.22.5
     dev: true
 
-  /@babel/traverse/7.20.12:
-    resolution: {integrity: sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==}
+  /@babel/traverse/7.22.5:
+    resolution: {integrity: sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/code-frame': 7.18.6
-      '@babel/generator': 7.20.7
-      '@babel/helper-environment-visitor': 7.18.9
-      '@babel/helper-function-name': 7.19.0
-      '@babel/helper-hoist-variables': 7.18.6
-      '@babel/helper-split-export-declaration': 7.18.6
-      '@babel/parser': 7.20.7
-      '@babel/types': 7.20.7
+      '@babel/code-frame': 7.22.5
+      '@babel/generator': 7.22.5
+      '@babel/helper-environment-visitor': 7.22.5
+      '@babel/helper-function-name': 7.22.5
+      '@babel/helper-hoist-variables': 7.22.5
+      '@babel/helper-split-export-declaration': 7.22.5
+      '@babel/parser': 7.22.5
+      '@babel/types': 7.22.5
       debug: 4.3.4
       globals: 11.12.0
     transitivePeerDependencies:
       - supports-color
     dev: true
 
-  /@babel/types/7.20.7:
-    resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==}
+  /@babel/types/7.22.5:
+    resolution: {integrity: sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==}
     engines: {node: '>=6.9.0'}
     dependencies:
-      '@babel/helper-string-parser': 7.19.4
-      '@babel/helper-validator-identifier': 7.19.1
+      '@babel/helper-string-parser': 7.22.5
+      '@babel/helper-validator-identifier': 7.22.5
       to-fast-properties: 2.0.0
     dev: true
 
@@ -586,25 +593,25 @@
       - supports-color
     dev: true
 
-  /@gar/promisify/1.1.3:
-    resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
+  /@isaacs/cliui/8.0.2:
+    resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
+    engines: {node: '>=12'}
+    dependencies:
+      string-width: 5.1.2
+      string-width-cjs: /string-width/4.2.3
+      strip-ansi: 7.1.0
+      strip-ansi-cjs: /strip-ansi/6.0.1
+      wrap-ansi: 8.1.0
+      wrap-ansi-cjs: /wrap-ansi/7.0.0
     dev: true
 
-  /@jridgewell/gen-mapping/0.1.1:
-    resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
+  /@jridgewell/gen-mapping/0.3.3:
+    resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
     engines: {node: '>=6.0.0'}
     dependencies:
       '@jridgewell/set-array': 1.1.2
-      '@jridgewell/sourcemap-codec': 1.4.14
-    dev: true
-
-  /@jridgewell/gen-mapping/0.3.2:
-    resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
-    engines: {node: '>=6.0.0'}
-    dependencies:
-      '@jridgewell/set-array': 1.1.2
-      '@jridgewell/sourcemap-codec': 1.4.14
-      '@jridgewell/trace-mapping': 0.3.17
+      '@jridgewell/sourcemap-codec': 1.4.15
+      '@jridgewell/trace-mapping': 0.3.18
     dev: true
 
   /@jridgewell/resolve-uri/3.1.0:
@@ -617,19 +624,20 @@
     engines: {node: '>=6.0.0'}
     dev: true
 
-  /@jridgewell/source-map/0.3.2:
-    resolution: {integrity: sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==}
-    dependencies:
-      '@jridgewell/gen-mapping': 0.3.2
-      '@jridgewell/trace-mapping': 0.3.17
+  /@jridgewell/source-map/0.3.4:
+    resolution: {integrity: sha512-KE/SxsDqNs3rrWwFHcRh15ZLVFrI0YoZtgAdIyIq9k5hUNmiWRXXThPomIxHuL20sLdgzbDFyvkUMna14bvtrw==}
     dev: true
 
   /@jridgewell/sourcemap-codec/1.4.14:
     resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
     dev: true
 
-  /@jridgewell/trace-mapping/0.3.17:
-    resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
+  /@jridgewell/sourcemap-codec/1.4.15:
+    resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
+    dev: true
+
+  /@jridgewell/trace-mapping/0.3.18:
+    resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
     dependencies:
       '@jridgewell/resolve-uri': 3.1.0
       '@jridgewell/sourcemap-codec': 1.4.14
@@ -641,14 +649,6 @@
     dev: true
     optional: true
 
-  /@npmcli/fs/2.1.2:
-    resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      '@gar/promisify': 1.1.3
-      semver: 7.3.8
-    dev: true
-
   /@npmcli/fs/3.1.0:
     resolution: {integrity: sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -656,39 +656,29 @@
       semver: 7.3.8
     dev: true
 
-  /@npmcli/git/4.0.3:
-    resolution: {integrity: sha512-8cXNkDIbnXPVbhXMmQ7/bklCAjtmPaXfI9aEM4iH+xSuEHINLMHhlfESvVwdqmHJRJkR48vNJTSUvoF6GRPSFA==}
+  /@npmcli/git/4.1.0:
+    resolution: {integrity: sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
       '@npmcli/promise-spawn': 6.0.2
-      lru-cache: 7.14.1
-      mkdirp: 1.0.4
+      lru-cache: 7.18.3
       npm-pick-manifest: 8.0.1
       proc-log: 3.0.0
       promise-inflight: 1.0.1
       promise-retry: 2.0.1
       semver: 7.3.8
-      which: 3.0.0
+      which: 3.0.1
     transitivePeerDependencies:
       - bluebird
     dev: true
 
-  /@npmcli/installed-package-contents/2.0.1:
-    resolution: {integrity: sha512-GIykAFdOVK31Q1/zAtT5MbxqQL2vyl9mvFJv+OGu01zxbhL3p0xc8gJjdNGX1mWmUT43aEKVO2L6V/2j4TOsAA==}
+  /@npmcli/installed-package-contents/2.0.2:
+    resolution: {integrity: sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     hasBin: true
     dependencies:
       npm-bundled: 3.0.0
-      npm-normalize-package-bin: 3.0.0
-    dev: true
-
-  /@npmcli/move-file/2.0.1:
-    resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    deprecated: This functionality has been moved to @npmcli/fs
-    dependencies:
-      mkdirp: 1.0.4
-      rimraf: 3.0.2
+      npm-normalize-package-bin: 3.0.1
     dev: true
 
   /@npmcli/node-gyp/3.0.0:
@@ -700,23 +690,29 @@
     resolution: {integrity: sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      which: 3.0.0
+      which: 3.0.1
     dev: true
 
-  /@npmcli/run-script/6.0.0:
-    resolution: {integrity: sha512-ql+AbRur1TeOdl1FY+RAwGW9fcr4ZwiVKabdvm93mujGREVuVLbdkXRJDrkTXSdCjaxYydr1wlA2v67jxWG5BQ==}
+  /@npmcli/run-script/6.0.2:
+    resolution: {integrity: sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
       '@npmcli/node-gyp': 3.0.0
       '@npmcli/promise-spawn': 6.0.2
-      node-gyp: 9.3.1
+      node-gyp: 9.4.0
       read-package-json-fast: 3.0.2
-      which: 3.0.0
+      which: 3.0.1
     transitivePeerDependencies:
-      - bluebird
       - supports-color
     dev: true
 
+  /@pkgjs/parseargs/0.11.0:
+    resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
+    engines: {node: '>=14'}
+    requiresBuild: true
+    dev: true
+    optional: true
+
   /@rollup/plugin-node-resolve/13.1.3_rollup@3.17.2:
     resolution: {integrity: sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==}
     engines: {node: '>= 10.0.0'}
@@ -726,9 +722,9 @@
       '@rollup/pluginutils': 3.1.0_rollup@3.17.2
       '@types/resolve': 1.17.1
       builtin-modules: 3.3.0
-      deepmerge: 4.2.2
+      deepmerge: 4.3.1
       is-module: 1.0.0
-      resolve: 1.22.1
+      resolve: 1.22.2
       rollup: 3.17.2
     dev: true
 
@@ -772,8 +768,8 @@
     resolution: {integrity: sha512-SWyMrjgdAUHNQmutvDcKablrJhkDLy4wunTme8oYLjKp41GnHGxMRXr2MQMvy/qy8H3LdzwQk9gH4hZ6T++H8g==}
     dev: true
 
-  /@types/node/14.18.36:
-    resolution: {integrity: sha512-FXKWbsJ6a1hIrRxv+FoukuHnGTgEzKYGi7kilfMae96AL9UNkPFNWJEEYWzdRI9ooIkbr4AKldyuSTLql06vLQ==}
+  /@types/node/14.18.53:
+    resolution: {integrity: sha512-soGmOpVBUq+gaBMwom1M+krC/NNbWlosh4AtGA03SyWNDiqSKtwp7OulO1M6+mg8YkHMvJ/y0AkCeO8d1hNb7A==}
     dev: true
 
   /@types/node/17.0.21:
@@ -810,8 +806,8 @@
     resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
     dev: true
 
-  /acorn/8.8.1:
-    resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==}
+  /acorn/8.9.0:
+    resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==}
     engines: {node: '>=0.4.0'}
     hasBin: true
     dev: true
@@ -825,12 +821,12 @@
       - supports-color
     dev: true
 
-  /agentkeepalive/4.2.1:
-    resolution: {integrity: sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==}
+  /agentkeepalive/4.3.0:
+    resolution: {integrity: sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==}
     engines: {node: '>= 8.0.0'}
     dependencies:
       debug: 4.3.4
-      depd: 1.1.2
+      depd: 2.0.0
       humanize-ms: 1.2.1
     transitivePeerDependencies:
       - supports-color
@@ -879,6 +875,11 @@
     engines: {node: '>=8'}
     dev: true
 
+  /ansi-regex/6.0.1:
+    resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+    engines: {node: '>=12'}
+    dev: true
+
   /ansi-styles/3.2.1:
     resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
     engines: {node: '>=4'}
@@ -893,6 +894,11 @@
       color-convert: 2.0.1
     dev: true
 
+  /ansi-styles/6.2.1:
+    resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
+    engines: {node: '>=12'}
+    dev: true
+
   /anymatch/3.1.3:
     resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
     engines: {node: '>= 8'}
@@ -914,7 +920,7 @@
     engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
     dependencies:
       delegates: 1.0.0
-      readable-stream: 3.6.0
+      readable-stream: 3.6.2
     dev: true
 
   /asn1/0.2.6:
@@ -978,7 +984,7 @@
     dependencies:
       buffer: 5.7.1
       inherits: 2.0.4
-      readable-stream: 3.6.0
+      readable-stream: 3.6.2
     dev: true
 
   /blob-util/2.0.2:
@@ -1009,15 +1015,15 @@
       fill-range: 7.0.1
     dev: true
 
-  /browserslist/4.21.4:
-    resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==}
+  /browserslist/4.21.9:
+    resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
     hasBin: true
     dependencies:
-      caniuse-lite: 1.0.30001445
-      electron-to-chromium: 1.4.284
-      node-releases: 2.0.8
-      update-browserslist-db: 1.0.10_browserslist@4.21.4
+      caniuse-lite: 1.0.30001509
+      electron-to-chromium: 1.4.447
+      node-releases: 2.0.12
+      update-browserslist-db: 1.0.11_browserslist@4.21.9
     dev: true
 
   /buffer-crc32/0.2.13:
@@ -1046,51 +1052,22 @@
       semver: 7.3.8
     dev: true
 
-  /cacache/16.1.3:
-    resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      '@npmcli/fs': 2.1.2
-      '@npmcli/move-file': 2.0.1
-      chownr: 2.0.0
-      fs-minipass: 2.1.0
-      glob: 8.1.0
-      infer-owner: 1.0.4
-      lru-cache: 7.14.1
-      minipass: 3.3.6
-      minipass-collect: 1.0.2
-      minipass-flush: 1.0.5
-      minipass-pipeline: 1.2.4
-      mkdirp: 1.0.4
-      p-map: 4.0.0
-      promise-inflight: 1.0.1
-      rimraf: 3.0.2
-      ssri: 9.0.1
-      tar: 6.1.13
-      unique-filename: 2.0.1
-    transitivePeerDependencies:
-      - bluebird
-    dev: true
-
-  /cacache/17.0.4:
-    resolution: {integrity: sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==}
+  /cacache/17.1.3:
+    resolution: {integrity: sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
       '@npmcli/fs': 3.1.0
-      fs-minipass: 3.0.0
-      glob: 8.1.0
-      lru-cache: 7.14.1
-      minipass: 4.0.0
+      fs-minipass: 3.0.2
+      glob: 10.3.1
+      lru-cache: 7.18.3
+      minipass: 5.0.0
       minipass-collect: 1.0.2
       minipass-flush: 1.0.5
       minipass-pipeline: 1.2.4
       p-map: 4.0.0
-      promise-inflight: 1.0.1
-      ssri: 10.0.1
-      tar: 6.1.13
+      ssri: 10.0.4
+      tar: 6.1.15
       unique-filename: 3.0.0
-    transitivePeerDependencies:
-      - bluebird
     dev: true
 
   /cachedir/2.3.0:
@@ -1102,11 +1079,11 @@
     resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
     dependencies:
       function-bind: 1.1.1
-      get-intrinsic: 1.1.3
+      get-intrinsic: 1.2.1
     dev: true
 
-  /caniuse-lite/1.0.30001445:
-    resolution: {integrity: sha512-8sdQIdMztYmzfTMO6KfLny878Ln9c2M0fc7EH60IjlP4Dc4PiCy7K2Vl3ITmWgOyPgVQKa5x+UP/KqFsxj4mBg==}
+  /caniuse-lite/1.0.30001509:
+    resolution: {integrity: sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==}
     dev: true
 
   /caseless/0.12.0:
@@ -1159,8 +1136,8 @@
     engines: {node: '>=10'}
     dev: true
 
-  /ci-info/3.7.1:
-    resolution: {integrity: sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==}
+  /ci-info/3.8.0:
+    resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==}
     engines: {node: '>=8'}
     dev: true
 
@@ -1176,8 +1153,8 @@
       restore-cursor: 3.1.0
     dev: true
 
-  /cli-spinners/2.7.0:
-    resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
+  /cli-spinners/2.9.0:
+    resolution: {integrity: sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==}
     engines: {node: '>=6'}
     dev: true
 
@@ -1243,8 +1220,8 @@
     hasBin: true
     dev: true
 
-  /colorette/2.0.19:
-    resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
+  /colorette/2.0.20:
+    resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
     dev: true
 
   /combined-stream/1.0.8:
@@ -1306,7 +1283,7 @@
     dependencies:
       '@cypress/request': 2.88.11
       '@cypress/xvfb': 1.2.4_supports-color@8.1.1
-      '@types/node': 14.18.36
+      '@types/node': 14.18.53
       '@types/sinonjs__fake-timers': 8.1.1
       '@types/sizzle': 2.3.3
       arch: 2.2.0
@@ -1320,7 +1297,7 @@
       cli-table3: 0.6.3
       commander: 5.1.0
       common-tags: 1.8.2
-      dayjs: 1.11.7
+      dayjs: 1.11.9
       debug: 4.3.4_supports-color@8.1.1
       enquirer: 2.3.6
       eventemitter2: 6.4.7
@@ -1336,12 +1313,12 @@
       listr2: 3.14.0_enquirer@2.3.6
       lodash: 4.17.21
       log-symbols: 4.1.0
-      minimist: 1.2.7
+      minimist: 1.2.8
       ospath: 1.2.2
       pretty-bytes: 5.6.0
       proxy-from-env: 1.0.0
       request-progress: 3.0.0
-      semver: 7.3.8
+      semver: 7.5.3
       supports-color: 8.1.1
       tmp: 0.2.1
       untildify: 4.0.0
@@ -1355,8 +1332,8 @@
       assert-plus: 1.0.0
     dev: true
 
-  /dayjs/1.11.7:
-    resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==}
+  /dayjs/1.11.9:
+    resolution: {integrity: sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==}
     dev: true
 
   /debug/3.2.7_supports-color@8.1.1:
@@ -1396,8 +1373,8 @@
       supports-color: 8.1.1
     dev: true
 
-  /deepmerge/4.2.2:
-    resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
+  /deepmerge/4.3.1:
+    resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
     engines: {node: '>=0.10.0'}
     dev: true
 
@@ -1421,9 +1398,9 @@
     resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
     dev: true
 
-  /depd/1.1.2:
-    resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}
-    engines: {node: '>= 0.6'}
+  /depd/2.0.0:
+    resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
+    engines: {node: '>= 0.8'}
     dev: true
 
   /dependency-graph/0.11.0:
@@ -1431,6 +1408,10 @@
     engines: {node: '>= 0.6.0'}
     dev: true
 
+  /eastasianwidth/0.2.0:
+    resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+    dev: true
+
   /ecc-jsbn/0.1.2:
     resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
     dependencies:
@@ -1438,14 +1419,18 @@
       safer-buffer: 2.1.2
     dev: true
 
-  /electron-to-chromium/1.4.284:
-    resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
+  /electron-to-chromium/1.4.447:
+    resolution: {integrity: sha512-sxX0LXh+uL41hSJsujAN86PjhrV/6c79XmpY0TvjZStV6VxIgarf8SRkUoUTuYmFcZQTemsoqo8qXOGw5npWfw==}
     dev: true
 
   /emoji-regex/8.0.0:
     resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
     dev: true
 
+  /emoji-regex/9.2.2:
+    resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+    dev: true
+
   /encoding/0.1.13:
     resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==}
     requiresBuild: true
@@ -1516,6 +1501,10 @@
       pify: 2.3.0
     dev: true
 
+  /exponential-backoff/3.1.1:
+    resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==}
+    dev: true
+
   /extend/3.0.2:
     resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
     dev: true
@@ -1572,6 +1561,14 @@
       to-regex-range: 5.0.1
     dev: true
 
+  /foreground-child/3.1.1:
+    resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
+    engines: {node: '>=14'}
+    dependencies:
+      cross-spawn: 7.0.3
+      signal-exit: 4.0.2
+    dev: true
+
   /forever-agent/0.6.1:
     resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
     dev: true
@@ -1590,7 +1587,7 @@
     engines: {node: '>=10'}
     dependencies:
       at-least-node: 1.0.0
-      graceful-fs: 4.2.10
+      graceful-fs: 4.2.11
       jsonfile: 6.1.0
       universalify: 2.0.0
     dev: true
@@ -1602,11 +1599,11 @@
       minipass: 3.3.6
     dev: true
 
-  /fs-minipass/3.0.0:
-    resolution: {integrity: sha512-EUojgQaSPy6sxcqcZgQv6TVF6jiKvurji3AxhAivs/Ep4O1UpS8TusaxpybfFHZ2skRhLqzk6WR8nqNYIMMDeA==}
+  /fs-minipass/3.0.2:
+    resolution: {integrity: sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      minipass: 4.0.0
+      minipass: 5.0.0
     dev: true
 
   /fs-readdir-recursive/1.1.0:
@@ -1653,11 +1650,12 @@
     engines: {node: 6.* || 8.* || >= 10.*}
     dev: true
 
-  /get-intrinsic/1.1.3:
-    resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==}
+  /get-intrinsic/1.2.1:
+    resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
     dependencies:
       function-bind: 1.1.1
       has: 1.0.3
+      has-proto: 1.0.1
       has-symbols: 1.0.3
     dev: true
 
@@ -1687,6 +1685,18 @@
       is-glob: 4.0.3
     dev: true
 
+  /glob/10.3.1:
+    resolution: {integrity: sha512-9BKYcEeIs7QwlCYs+Y3GBvqAMISufUS0i2ELd11zpZjxI5V9iyRj0HgzB5/cLf2NY4vcYBTYzJ7GIui7j/4DOw==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    hasBin: true
+    dependencies:
+      foreground-child: 3.1.1
+      jackspeak: 2.2.1
+      minimatch: 9.0.2
+      minipass: 5.0.0
+      path-scurry: 1.10.0
+    dev: true
+
   /glob/7.2.3:
     resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
     dependencies:
@@ -1698,17 +1708,6 @@
       path-is-absolute: 1.0.1
     dev: true
 
-  /glob/8.1.0:
-    resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
-    engines: {node: '>=12'}
-    dependencies:
-      fs.realpath: 1.0.0
-      inflight: 1.0.6
-      inherits: 2.0.4
-      minimatch: 5.1.4
-      once: 1.4.0
-    dev: true
-
   /global-dirs/3.0.1:
     resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==}
     engines: {node: '>=10'}
@@ -1721,8 +1720,8 @@
     engines: {node: '>=4'}
     dev: true
 
-  /graceful-fs/4.2.10:
-    resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
+  /graceful-fs/4.2.11:
+    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
     dev: true
 
   /has-flag/3.0.0:
@@ -1735,6 +1734,11 @@
     engines: {node: '>=8'}
     dev: true
 
+  /has-proto/1.0.1:
+    resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
+    engines: {node: '>= 0.4'}
+    dev: true
+
   /has-symbols/1.0.3:
     resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
     engines: {node: '>= 0.4'}
@@ -1755,7 +1759,7 @@
     resolution: {integrity: sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      lru-cache: 7.14.1
+      lru-cache: 7.18.3
     dev: true
 
   /html-insert-assets/0.14.3:
@@ -1766,8 +1770,8 @@
       parse5: 6.0.1
     dev: true
 
-  /http-cache-semantics/4.1.0:
-    resolution: {integrity: sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==}
+  /http-cache-semantics/4.1.1:
+    resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
     dev: true
 
   /http-proxy-agent/5.0.0:
@@ -1830,11 +1834,11 @@
     resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
     dev: true
 
-  /ignore-walk/6.0.0:
-    resolution: {integrity: sha512-bTf9UWe/UP1yxG3QUrj/KOvEhTAUWPcv+WvbFZ28LcqznXabp7Xu6o9y1JEC18+oqODuS7VhTpekV5XvFwsxJg==}
+  /ignore-walk/6.0.3:
+    resolution: {integrity: sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      minimatch: 5.1.4
+      minimatch: 9.0.2
     dev: true
 
   /imurmurhash/0.1.4:
@@ -1847,10 +1851,6 @@
     engines: {node: '>=8'}
     dev: true
 
-  /infer-owner/1.0.4:
-    resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
-    dev: true
-
   /inflight/1.0.6:
     resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
     dependencies:
@@ -1908,11 +1908,11 @@
     resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
     hasBin: true
     dependencies:
-      ci-info: 3.7.1
+      ci-info: 3.8.0
     dev: true
 
-  /is-core-module/2.11.0:
-    resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
+  /is-core-module/2.12.1:
+    resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
     dependencies:
       has: 1.0.3
     dev: true
@@ -2000,6 +2000,15 @@
     resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
     dev: true
 
+  /jackspeak/2.2.1:
+    resolution: {integrity: sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==}
+    engines: {node: '>=14'}
+    dependencies:
+      '@isaacs/cliui': 8.0.2
+    optionalDependencies:
+      '@pkgjs/parseargs': 0.11.0
+    dev: true
+
   /js-tokens/4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
     dev: true
@@ -2046,7 +2055,7 @@
     dependencies:
       universalify: 2.0.0
     optionalDependencies:
-      graceful-fs: 4.2.10
+      graceful-fs: 4.2.11
     dev: true
 
   /jsonparse/1.3.1:
@@ -2079,7 +2088,7 @@
         optional: true
     dependencies:
       cli-truncate: 2.1.0
-      colorette: 2.0.19
+      colorette: 2.0.20
       enquirer: 2.3.6
       log-update: 4.0.0
       p-map: 4.0.0
@@ -2115,6 +2124,11 @@
       wrap-ansi: 6.2.0
     dev: true
 
+  /lru-cache/10.0.0:
+    resolution: {integrity: sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==}
+    engines: {node: 14 || >=16.14}
+    dev: true
+
   /lru-cache/5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
     dependencies:
@@ -2128,8 +2142,8 @@
       yallist: 4.0.0
     dev: true
 
-  /lru-cache/7.14.1:
-    resolution: {integrity: sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==}
+  /lru-cache/7.18.3:
+    resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
     engines: {node: '>=12'}
     dev: true
 
@@ -2137,7 +2151,7 @@
     resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
     engines: {node: '>=12'}
     dependencies:
-      '@jridgewell/sourcemap-codec': 1.4.14
+      '@jridgewell/sourcemap-codec': 1.4.15
     dev: true
 
   /make-dir/2.1.0:
@@ -2148,53 +2162,26 @@
       semver: 5.7.1
     dev: true
 
-  /make-fetch-happen/10.2.1:
-    resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      agentkeepalive: 4.2.1
-      cacache: 16.1.3
-      http-cache-semantics: 4.1.0
-      http-proxy-agent: 5.0.0
-      https-proxy-agent: 5.0.1
-      is-lambda: 1.0.1
-      lru-cache: 7.14.1
-      minipass: 3.3.6
-      minipass-collect: 1.0.2
-      minipass-fetch: 2.1.2
-      minipass-flush: 1.0.5
-      minipass-pipeline: 1.2.4
-      negotiator: 0.6.3
-      promise-retry: 2.0.1
-      socks-proxy-agent: 7.0.0
-      ssri: 9.0.1
-    transitivePeerDependencies:
-      - bluebird
-      - supports-color
-    dev: true
-
-  /make-fetch-happen/11.0.2:
-    resolution: {integrity: sha512-5n/Pq41w/uZghpdlXAY5kIM85RgJThtTH/NYBRAZ9VUOBWV90USaQjwGrw76fZP3Lj5hl/VZjpVvOaRBMoL/2w==}
+  /make-fetch-happen/11.1.1:
+    resolution: {integrity: sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      agentkeepalive: 4.2.1
-      cacache: 17.0.4
-      http-cache-semantics: 4.1.0
+      agentkeepalive: 4.3.0
+      cacache: 17.1.3
+      http-cache-semantics: 4.1.1
       http-proxy-agent: 5.0.0
       https-proxy-agent: 5.0.1
       is-lambda: 1.0.1
-      lru-cache: 7.14.1
-      minipass: 4.0.0
-      minipass-collect: 1.0.2
-      minipass-fetch: 3.0.1
+      lru-cache: 7.18.3
+      minipass: 5.0.0
+      minipass-fetch: 3.0.3
       minipass-flush: 1.0.5
       minipass-pipeline: 1.2.4
       negotiator: 0.6.3
       promise-retry: 2.0.1
       socks-proxy-agent: 7.0.0
-      ssri: 10.0.1
+      ssri: 10.0.4
     transitivePeerDependencies:
-      - bluebird
       - supports-color
     dev: true
 
@@ -2225,15 +2212,15 @@
       brace-expansion: 1.1.11
     dev: true
 
-  /minimatch/5.1.4:
-    resolution: {integrity: sha512-U0iNYXt9wALljzfnGkhFSy5sAC6/SCR3JrHrlsdJz4kF8MvhTRQNiC59iUi1iqsitV7abrNAJWElVL9pdnoUgw==}
-    engines: {node: '>=10'}
+  /minimatch/9.0.2:
+    resolution: {integrity: sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==}
+    engines: {node: '>=16 || 14 >=14.17'}
     dependencies:
       brace-expansion: 2.0.1
     dev: true
 
-  /minimist/1.2.7:
-    resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
+  /minimist/1.2.8:
+    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
     dev: true
 
   /minipass-collect/1.0.2:
@@ -2243,22 +2230,11 @@
       minipass: 3.3.6
     dev: true
 
-  /minipass-fetch/2.1.2:
-    resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      minipass: 3.3.6
-      minipass-sized: 1.0.3
-      minizlib: 2.1.2
-    optionalDependencies:
-      encoding: 0.1.13
-    dev: true
-
-  /minipass-fetch/3.0.1:
-    resolution: {integrity: sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==}
+  /minipass-fetch/3.0.3:
+    resolution: {integrity: sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      minipass: 4.0.0
+      minipass: 5.0.0
       minipass-sized: 1.0.3
       minizlib: 2.1.2
     optionalDependencies:
@@ -2300,11 +2276,14 @@
       yallist: 4.0.0
     dev: true
 
-  /minipass/4.0.0:
-    resolution: {integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==}
+  /minipass/4.2.8:
+    resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==}
     engines: {node: '>=8'}
-    dependencies:
-      yallist: 4.0.0
+    dev: true
+
+  /minipass/5.0.0:
+    resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
+    engines: {node: '>=8'}
     dev: true
 
   /minizlib/2.1.2:
@@ -2338,28 +2317,28 @@
     engines: {node: '>= 0.6'}
     dev: true
 
-  /node-gyp/9.3.1:
-    resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==}
+  /node-gyp/9.4.0:
+    resolution: {integrity: sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==}
     engines: {node: ^12.13 || ^14.13 || >=16}
     hasBin: true
     dependencies:
       env-paths: 2.2.1
+      exponential-backoff: 3.1.1
       glob: 7.2.3
-      graceful-fs: 4.2.10
-      make-fetch-happen: 10.2.1
+      graceful-fs: 4.2.11
+      make-fetch-happen: 11.1.1
       nopt: 6.0.0
       npmlog: 6.0.2
       rimraf: 3.0.2
       semver: 7.3.8
-      tar: 6.1.13
+      tar: 6.1.15
       which: 2.0.2
     transitivePeerDependencies:
-      - bluebird
       - supports-color
     dev: true
 
-  /node-releases/2.0.8:
-    resolution: {integrity: sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==}
+  /node-releases/2.0.12:
+    resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==}
     dev: true
 
   /nopt/6.0.0:
@@ -2375,7 +2354,7 @@
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
       hosted-git-info: 6.1.1
-      is-core-module: 2.11.0
+      is-core-module: 2.12.1
       semver: 7.3.8
       validate-npm-package-license: 3.0.4
     dev: true
@@ -2389,18 +2368,18 @@
     resolution: {integrity: sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      npm-normalize-package-bin: 3.0.0
+      npm-normalize-package-bin: 3.0.1
     dev: true
 
-  /npm-install-checks/6.0.0:
-    resolution: {integrity: sha512-SBU9oFglRVZnfElwAtF14NivyulDqF1VKqqwNsFW9HDcbHMAPHpRSsVFgKuwFGq/hVvWZExz62Th0kvxn/XE7Q==}
+  /npm-install-checks/6.1.1:
+    resolution: {integrity: sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
       semver: 7.3.8
     dev: true
 
-  /npm-normalize-package-bin/3.0.0:
-    resolution: {integrity: sha512-g+DPQSkusnk7HYXr75NtzkIP4+N81i3RPsGFidF3DzHd9MT9wWngmqoeg/fnHFz5MNdtG4w03s+QnhewSLTT2Q==}
+  /npm-normalize-package-bin/3.0.1:
+    resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dev: true
 
@@ -2418,32 +2397,31 @@
     resolution: {integrity: sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      ignore-walk: 6.0.0
+      ignore-walk: 6.0.3
     dev: true
 
   /npm-pick-manifest/8.0.1:
     resolution: {integrity: sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      npm-install-checks: 6.0.0
-      npm-normalize-package-bin: 3.0.0
+      npm-install-checks: 6.1.1
+      npm-normalize-package-bin: 3.0.1
       npm-package-arg: 10.1.0
       semver: 7.3.8
     dev: true
 
-  /npm-registry-fetch/14.0.3:
-    resolution: {integrity: sha512-YaeRbVNpnWvsGOjX2wk5s85XJ7l1qQBGAp724h8e2CZFFhMSuw9enom7K1mWVUtvXO1uUSFIAPofQK0pPN0ZcA==}
+  /npm-registry-fetch/14.0.5:
+    resolution: {integrity: sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      make-fetch-happen: 11.0.2
-      minipass: 4.0.0
-      minipass-fetch: 3.0.1
+      make-fetch-happen: 11.1.1
+      minipass: 5.0.0
+      minipass-fetch: 3.0.3
       minipass-json-stream: 1.0.1
       minizlib: 2.1.2
       npm-package-arg: 10.1.0
       proc-log: 3.0.0
     transitivePeerDependencies:
-      - bluebird
       - supports-color
     dev: true
 
@@ -2497,7 +2475,7 @@
       bl: 4.1.0
       chalk: 4.1.2
       cli-cursor: 3.1.0
-      cli-spinners: 2.7.0
+      cli-spinners: 2.9.0
       is-interactive: 1.0.0
       is-unicode-supported: 0.1.0
       log-symbols: 4.1.0
@@ -2526,23 +2504,23 @@
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     hasBin: true
     dependencies:
-      '@npmcli/git': 4.0.3
-      '@npmcli/installed-package-contents': 2.0.1
+      '@npmcli/git': 4.1.0
+      '@npmcli/installed-package-contents': 2.0.2
       '@npmcli/promise-spawn': 6.0.2
-      '@npmcli/run-script': 6.0.0
-      cacache: 17.0.4
-      fs-minipass: 3.0.0
-      minipass: 4.0.0
+      '@npmcli/run-script': 6.0.2
+      cacache: 17.1.3
+      fs-minipass: 3.0.2
+      minipass: 4.2.8
       npm-package-arg: 10.1.0
       npm-packlist: 7.0.4
       npm-pick-manifest: 8.0.1
-      npm-registry-fetch: 14.0.3
+      npm-registry-fetch: 14.0.5
       proc-log: 3.0.0
       promise-retry: 2.0.1
-      read-package-json: 6.0.0
+      read-package-json: 6.0.4
       read-package-json-fast: 3.0.2
-      ssri: 10.0.1
-      tar: 6.1.13
+      ssri: 10.0.4
+      tar: 6.1.15
     transitivePeerDependencies:
       - bluebird
       - supports-color
@@ -2566,6 +2544,14 @@
     resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
     dev: true
 
+  /path-scurry/1.10.0:
+    resolution: {integrity: sha512-tZFEaRQbMLjwrsmidsGJ6wDMv0iazJWk6SfIKnY4Xru8auXgmJkOBa5DUbYFcFD2Rzk2+KDlIiF0GVXNCbgC7g==}
+    engines: {node: '>=16 || 14 >=14.17'}
+    dependencies:
+      lru-cache: 10.0.0
+      minipass: 5.0.0
+    dev: true
+
   /pend/1.2.0:
     resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==}
     dev: true
@@ -2641,8 +2627,8 @@
       once: 1.4.0
     dev: true
 
-  /punycode/2.2.0:
-    resolution: {integrity: sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==}
+  /punycode/2.3.0:
+    resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
     engines: {node: '>=6'}
     dev: true
 
@@ -2658,21 +2644,21 @@
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
       json-parse-even-better-errors: 3.0.0
-      npm-normalize-package-bin: 3.0.0
+      npm-normalize-package-bin: 3.0.1
     dev: true
 
-  /read-package-json/6.0.0:
-    resolution: {integrity: sha512-b/9jxWJ8EwogJPpv99ma+QwtqB7FSl3+V6UXS7Aaay8/5VwMY50oIFooY1UKXMWpfNCM6T/PoGqa5GD1g9xf9w==}
+  /read-package-json/6.0.4:
+    resolution: {integrity: sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      glob: 8.1.0
+      glob: 10.3.1
       json-parse-even-better-errors: 3.0.0
       normalize-package-data: 5.0.0
-      npm-normalize-package-bin: 3.0.0
+      npm-normalize-package-bin: 3.0.1
     dev: true
 
-  /readable-stream/3.6.0:
-    resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
+  /readable-stream/3.6.2:
+    resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
     engines: {node: '>= 6'}
     dependencies:
       inherits: 2.0.4
@@ -2717,7 +2703,16 @@
     resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
     hasBin: true
     dependencies:
-      is-core-module: 2.11.0
+      is-core-module: 2.12.1
+      path-parse: 1.0.7
+      supports-preserve-symlinks-flag: 1.0.0
+    dev: true
+
+  /resolve/1.22.2:
+    resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
+    hasBin: true
+    dependencies:
+      is-core-module: 2.12.1
       path-parse: 1.0.7
       supports-preserve-symlinks-flag: 1.0.0
     dev: true
@@ -2769,7 +2764,7 @@
   /rxjs/7.5.7:
     resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==}
     dependencies:
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
 
   /safe-buffer/5.2.1:
@@ -2798,6 +2793,14 @@
       lru-cache: 6.0.0
     dev: true
 
+  /semver/7.5.3:
+    resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==}
+    engines: {node: '>=10'}
+    hasBin: true
+    dependencies:
+      lru-cache: 6.0.0
+    dev: true
+
   /set-blocking/2.0.0:
     resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
     dev: true
@@ -2818,7 +2821,7 @@
     resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
     dependencies:
       call-bind: 1.0.2
-      get-intrinsic: 1.1.3
+      get-intrinsic: 1.2.1
       object-inspect: 1.12.3
     dev: true
 
@@ -2826,6 +2829,11 @@
     resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
     dev: true
 
+  /signal-exit/4.0.2:
+    resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==}
+    engines: {node: '>=14'}
+    dev: true
+
   /slash/2.0.0:
     resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==}
     engines: {node: '>=6'}
@@ -2890,11 +2898,11 @@
     engines: {node: '>= 8'}
     dev: true
 
-  /spdx-correct/3.1.1:
-    resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==}
+  /spdx-correct/3.2.0:
+    resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}
     dependencies:
       spdx-expression-parse: 3.0.1
-      spdx-license-ids: 3.0.12
+      spdx-license-ids: 3.0.13
     dev: true
 
   /spdx-exceptions/2.3.0:
@@ -2905,11 +2913,11 @@
     resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
     dependencies:
       spdx-exceptions: 2.3.0
-      spdx-license-ids: 3.0.12
+      spdx-license-ids: 3.0.13
     dev: true
 
-  /spdx-license-ids/3.0.12:
-    resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==}
+  /spdx-license-ids/3.0.13:
+    resolution: {integrity: sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==}
     dev: true
 
   /sshpk/1.17.0:
@@ -2928,18 +2936,11 @@
       tweetnacl: 0.14.5
     dev: true
 
-  /ssri/10.0.1:
-    resolution: {integrity: sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==}
+  /ssri/10.0.4:
+    resolution: {integrity: sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     dependencies:
-      minipass: 4.0.0
-    dev: true
-
-  /ssri/9.0.1:
-    resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      minipass: 3.3.6
+      minipass: 5.0.0
     dev: true
 
   /string-width/4.2.3:
@@ -2951,6 +2952,15 @@
       strip-ansi: 6.0.1
     dev: true
 
+  /string-width/5.1.2:
+    resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
+    engines: {node: '>=12'}
+    dependencies:
+      eastasianwidth: 0.2.0
+      emoji-regex: 9.2.2
+      strip-ansi: 7.1.0
+    dev: true
+
   /string_decoder/1.3.0:
     resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
     dependencies:
@@ -2964,6 +2974,13 @@
       ansi-regex: 5.0.1
     dev: true
 
+  /strip-ansi/7.1.0:
+    resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-regex: 6.0.1
+    dev: true
+
   /strip-final-newline/2.0.0:
     resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
     engines: {node: '>=6'}
@@ -3000,13 +3017,13 @@
     engines: {node: '>=0.10'}
     dev: true
 
-  /tar/6.1.13:
-    resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
+  /tar/6.1.15:
+    resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==}
     engines: {node: '>=10'}
     dependencies:
       chownr: 2.0.0
       fs-minipass: 2.1.0
-      minipass: 4.0.0
+      minipass: 5.0.0
       minizlib: 2.1.2
       mkdirp: 1.0.4
       yallist: 4.0.0
@@ -3017,8 +3034,8 @@
     engines: {node: '>=10'}
     hasBin: true
     dependencies:
-      '@jridgewell/source-map': 0.3.2
-      acorn: 8.8.1
+      '@jridgewell/source-map': 0.3.4
+      acorn: 8.9.0
       commander: 2.20.3
       source-map-support: 0.5.21
     dev: true
@@ -3062,15 +3079,15 @@
     engines: {node: '>=0.8'}
     dependencies:
       psl: 1.9.0
-      punycode: 2.2.0
+      punycode: 2.3.0
     dev: true
 
   /tslib/1.14.1:
     resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
     dev: true
 
-  /tslib/2.4.1:
-    resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==}
+  /tslib/2.6.0:
+    resolution: {integrity: sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==}
 
   /tunnel-agent/0.6.0:
     resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
@@ -3093,13 +3110,6 @@
     hasBin: true
     dev: true
 
-  /unique-filename/2.0.1:
-    resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      unique-slug: 3.0.0
-    dev: true
-
   /unique-filename/3.0.0:
     resolution: {integrity: sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -3107,13 +3117,6 @@
       unique-slug: 4.0.0
     dev: true
 
-  /unique-slug/3.0.0:
-    resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==}
-    engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
-    dependencies:
-      imurmurhash: 0.1.4
-    dev: true
-
   /unique-slug/4.0.0:
     resolution: {integrity: sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -3131,13 +3134,13 @@
     engines: {node: '>=8'}
     dev: true
 
-  /update-browserslist-db/1.0.10_browserslist@4.21.4:
-    resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
+  /update-browserslist-db/1.0.11_browserslist@4.21.9:
+    resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
     hasBin: true
     peerDependencies:
       browserslist: '>= 4.21.0'
     dependencies:
-      browserslist: 4.21.4
+      browserslist: 4.21.9
       escalade: 3.1.1
       picocolors: 1.0.0
     dev: true
@@ -3145,7 +3148,7 @@
   /uri-js/4.4.1:
     resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
     dependencies:
-      punycode: 2.2.0
+      punycode: 2.3.0
     dev: true
 
   /util-deprecate/1.0.2:
@@ -3160,7 +3163,7 @@
   /validate-npm-package-license/3.0.4:
     resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
     dependencies:
-      spdx-correct: 3.1.1
+      spdx-correct: 3.2.0
       spdx-expression-parse: 3.0.1
     dev: true
 
@@ -3194,8 +3197,8 @@
       isexe: 2.0.0
     dev: true
 
-  /which/3.0.0:
-    resolution: {integrity: sha512-nla//68K9NU6yRiwDY/Q8aU6siKlSs64aEC7+IV56QoAuyQT2ovsJcgGYGyqMOmI/CGN1BOR6mM5EN0FBO+zyQ==}
+  /which/3.0.1:
+    resolution: {integrity: sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
     hasBin: true
     dependencies:
@@ -3226,6 +3229,15 @@
       strip-ansi: 6.0.1
     dev: true
 
+  /wrap-ansi/8.1.0:
+    resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
+    engines: {node: '>=12'}
+    dependencies:
+      ansi-styles: 6.2.1
+      string-width: 5.1.2
+      strip-ansi: 7.1.0
+    dev: true
+
   /wrappy/1.0.2:
     resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
     dev: true
@@ -3261,6 +3273,19 @@
       yargs-parser: 21.1.1
     dev: true
 
+  /yargs/17.7.2:
+    resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
+    engines: {node: '>=12'}
+    dependencies:
+      cliui: 8.0.1
+      escalade: 3.1.1
+      get-caller-file: 2.0.5
+      require-directory: 2.1.1
+      string-width: 4.2.3
+      y18n: 5.0.8
+      yargs-parser: 21.1.1
+    dev: true
+
   /yauzl/2.10.0:
     resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==}
     dependencies:
@@ -3271,5 +3296,5 @@
   /zone.js/0.11.8:
     resolution: {integrity: sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==}
     dependencies:
-      tslib: 2.4.1
+      tslib: 2.6.0
     dev: true
diff --git a/scouting/db/BUILD b/scouting/db/BUILD
index 154cab6..9447a5f 100644
--- a/scouting/db/BUILD
+++ b/scouting/db/BUILD
@@ -18,9 +18,7 @@
     name = "db_test",
     size = "small",
     srcs = ["db_test.go"],
-    data = [
-        "//scouting/db/testdb_server",
-    ],
+    data = ["//scouting/db/testdb_server"],
     embed = [":db"],
     target_compatible_with = ["@platforms//cpu:x86_64"],
     deps = ["@com_github_davecgh_go_spew//spew"],
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 1a43634..578edb6 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -1,6 +1,7 @@
 package db
 
 import (
+	"crypto/sha256"
 	"errors"
 	"fmt"
 	"gorm.io/driver/postgres"
@@ -27,6 +28,19 @@
 	R1scouter, R2scouter, R3scouter, B1scouter, B2scouter, B3scouter string
 }
 
+type PitImage struct {
+	TeamNumber string `gorm:"primaryKey"`
+	CheckSum   string `gorm:"primaryKey"`
+	ImagePath  string
+	ImageData  []byte
+}
+
+type RequestedPitImage struct {
+	TeamNumber string
+	CheckSum   string `gorm:"primaryKey"`
+	ImagePath  string
+}
+
 type Stats2023 struct {
 	// This is set to `true` for "pre-scouted" matches. This means that the
 	// match information is unlikely to correspond with an entry in the
@@ -125,7 +139,7 @@
 		return nil, errors.New(fmt.Sprint("Failed to connect to postgres: ", err))
 	}
 
-	err = database.AutoMigrate(&TeamMatch{}, &Shift{}, &Stats2023{}, &Action{}, &NotesData{}, &Ranking{}, &DriverRankingData{}, &ParsedDriverRankingData{})
+	err = database.AutoMigrate(&TeamMatch{}, &Shift{}, &Stats2023{}, &Action{}, &PitImage{}, &NotesData{}, &Ranking{}, &DriverRankingData{}, &ParsedDriverRankingData{})
 	if err != nil {
 		database.Delete()
 		return nil, errors.New(fmt.Sprint("Failed to create/migrate tables: ", err))
@@ -167,6 +181,11 @@
 	return result.Error
 }
 
+func (database *Database) AddPitImage(p PitImage) error {
+	result := database.Create(&p)
+	return result.Error
+}
+
 func (database *Database) AddToStats2023(s Stats2023) error {
 	if !s.PreScouting {
 		matches, err := database.QueryMatchesString(s.TeamNumber)
@@ -250,6 +269,12 @@
 	return actions, result.Error
 }
 
+func (database *Database) ReturnPitImages() ([]PitImage, error) {
+	var images []PitImage
+	result := database.Find(&images)
+	return images, result.Error
+}
+
 func (database *Database) ReturnStats2023() ([]Stats2023, error) {
 	var stats2023 []Stats2023
 	result := database.Find(&stats2023)
@@ -279,6 +304,28 @@
 	return matches, result.Error
 }
 
+func (database *Database) QueryPitImages(teamNumber_ string) ([]RequestedPitImage, error) {
+	var requestedPitImages []RequestedPitImage
+	result := database.Model(&PitImage{}).
+		Where("team_number = $1", teamNumber_).
+		Find(&requestedPitImages)
+
+	return requestedPitImages, result.Error
+}
+
+func (database *Database) QueryPitImageByChecksum(checksum_ string) (PitImage, error) {
+	var pitImage PitImage
+	result := database.
+		Where("check_sum = $1", checksum_).
+		Find(&pitImage)
+	return pitImage, result.Error
+}
+
+func ComputeSha256FromByteArray(arr []byte) string {
+	sum := sha256.Sum256(arr)
+	return fmt.Sprintf("%x", sum)
+}
+
 func (database *Database) QueryMatchesString(teamNumber_ string) ([]TeamMatch, error) {
 	var matches []TeamMatch
 	result := database.
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index d49e649..94dce7e 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -609,6 +609,82 @@
 	}
 }
 
+func TestQueryPitImages(t *testing.T) {
+	fixture := createDatabase(t)
+	defer fixture.TearDown()
+
+	testDatabase := []PitImage{
+		PitImage{
+			TeamNumber: "723", CheckSum: "8be8h9829hf98wp",
+			ImagePath: "image1.jpg", ImageData: []byte{14, 15, 32, 54},
+		},
+		PitImage{
+			TeamNumber: "237", CheckSum: "br78232b6r7iaa",
+			ImagePath: "bot.png", ImageData: []byte{32, 54, 23, 00},
+		},
+		PitImage{
+			TeamNumber: "125A", CheckSum: "b63c728bqiq8a73",
+			ImagePath: "file123.jpeg", ImageData: []byte{32, 05, 01, 28},
+		},
+	}
+
+	for i := 0; i < len(testDatabase); i++ {
+		err := fixture.db.AddPitImage(testDatabase[i])
+		check(t, err, fmt.Sprint("Failed to add pit image", i))
+	}
+
+	correct := []RequestedPitImage{
+		RequestedPitImage{
+			TeamNumber: "723", CheckSum: "8be8h9829hf98wp",
+			ImagePath: "image1.jpg",
+		},
+	}
+
+	got, err := fixture.db.QueryPitImages("723")
+	check(t, err, "Failed to query shift for team 723")
+
+	if !reflect.DeepEqual(correct, got) {
+		t.Fatalf("Got %#v,\nbut expected %#v.", got, correct)
+	}
+}
+
+func TestQueryPitImageByChecksum(t *testing.T) {
+	fixture := createDatabase(t)
+	defer fixture.TearDown()
+
+	testDatabase := []PitImage{
+		PitImage{
+			TeamNumber: "723", CheckSum: "8be8h9829hf98wp",
+			ImagePath: "image1.jpg", ImageData: []byte{05, 32, 00, 74, 28},
+		},
+		PitImage{
+			TeamNumber: "237", CheckSum: "br78232b6r7iaa",
+			ImagePath: "bot.png", ImageData: []byte{32, 54, 23, 00},
+		},
+		PitImage{
+			TeamNumber: "125A", CheckSum: "b63c728bqiq8a73",
+			ImagePath: "file123.jpeg", ImageData: []byte{32, 05, 01, 28},
+		},
+	}
+
+	for i := 0; i < len(testDatabase); i++ {
+		err := fixture.db.AddPitImage(testDatabase[i])
+		check(t, err, fmt.Sprint("Failed to add pit image", i))
+	}
+
+	correctPitImage := PitImage{
+		TeamNumber: "125A", CheckSum: "b63c728bqiq8a73",
+		ImagePath: "file123.jpeg", ImageData: []byte{32, 05, 01, 28},
+	}
+
+	got, err := fixture.db.QueryPitImageByChecksum("b63c728bqiq8a73")
+	check(t, err, "Failed to query shift for checksum 'b63c728bqiq8a73'")
+
+	if !reflect.DeepEqual(correctPitImage, got) {
+		t.Fatalf("Got %#v,\nbut expected %#v.", got, correctPitImage)
+	}
+}
+
 func TestQueryRankingsDB(t *testing.T) {
 	fixture := createDatabase(t)
 	defer fixture.TearDown()
diff --git a/scouting/webserver/main.go b/scouting/webserver/main.go
index c5bed2c..d655708 100644
--- a/scouting/webserver/main.go
+++ b/scouting/webserver/main.go
@@ -133,7 +133,7 @@
 	defer database.Delete()
 
 	scoutingServer := server.NewScoutingServer()
-	static.ServePages(scoutingServer, *dirPtr)
+	static.ServePages(scoutingServer, *dirPtr, database)
 	requests.HandleRequests(database, scoutingServer)
 	scoutingServer.Start(*portPtr)
 	fmt.Println("Serving", *dirPtr, "on port", *portPtr)
diff --git a/scouting/webserver/requests/BUILD b/scouting/webserver/requests/BUILD
index 795d0ee..a7593e7 100644
--- a/scouting/webserver/requests/BUILD
+++ b/scouting/webserver/requests/BUILD
@@ -21,6 +21,8 @@
         "//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
         "//scouting/webserver/requests/messages:request_notes_for_team_go_fbs",
         "//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_pit_images_go_fbs",
+        "//scouting/webserver/requests/messages:request_pit_images_response_go_fbs",
         "//scouting/webserver/requests/messages:request_shift_schedule_go_fbs",
         "//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_actions_go_fbs",
@@ -29,6 +31,8 @@
         "//scouting/webserver/requests/messages:submit_driver_ranking_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_notes_go_fbs",
         "//scouting/webserver/requests/messages:submit_notes_response_go_fbs",
+        "//scouting/webserver/requests/messages:submit_pit_image_go_fbs",
+        "//scouting/webserver/requests/messages:submit_pit_image_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_shift_schedule_go_fbs",
         "//scouting/webserver/requests/messages:submit_shift_schedule_response_go_fbs",
         "//scouting/webserver/server",
@@ -54,11 +58,14 @@
         "//scouting/webserver/requests/messages:request_all_notes_go_fbs",
         "//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
         "//scouting/webserver/requests/messages:request_notes_for_team_go_fbs",
+        "//scouting/webserver/requests/messages:request_pit_images_go_fbs",
+        "//scouting/webserver/requests/messages:request_pit_images_response_go_fbs",
         "//scouting/webserver/requests/messages:request_shift_schedule_go_fbs",
         "//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_actions_go_fbs",
         "//scouting/webserver/requests/messages:submit_driver_ranking_go_fbs",
         "//scouting/webserver/requests/messages:submit_notes_go_fbs",
+        "//scouting/webserver/requests/messages:submit_pit_image_go_fbs",
         "//scouting/webserver/requests/messages:submit_shift_schedule_go_fbs",
         "//scouting/webserver/server",
         "@com_github_google_flatbuffers//go:go_default_library",
diff --git a/scouting/webserver/requests/debug/BUILD b/scouting/webserver/requests/debug/BUILD
index ef14e5a..11311d2 100644
--- a/scouting/webserver/requests/debug/BUILD
+++ b/scouting/webserver/requests/debug/BUILD
@@ -14,10 +14,12 @@
         "//scouting/webserver/requests/messages:request_all_matches_response_go_fbs",
         "//scouting/webserver/requests/messages:request_all_notes_response_go_fbs",
         "//scouting/webserver/requests/messages:request_notes_for_team_response_go_fbs",
+        "//scouting/webserver/requests/messages:request_pit_images_response_go_fbs",
         "//scouting/webserver/requests/messages:request_shift_schedule_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_actions_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_driver_ranking_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_notes_response_go_fbs",
+        "//scouting/webserver/requests/messages:submit_pit_image_response_go_fbs",
         "//scouting/webserver/requests/messages:submit_shift_schedule_response_go_fbs",
         "@com_github_google_flatbuffers//go:go_default_library",
     ],
diff --git a/scouting/webserver/requests/debug/debug.go b/scouting/webserver/requests/debug/debug.go
index 4837cfe..3e5b4f9 100644
--- a/scouting/webserver/requests/debug/debug.go
+++ b/scouting/webserver/requests/debug/debug.go
@@ -16,10 +16,12 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_matches_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
 	flatbuffers "github.com/google/flatbuffers/go"
 )
@@ -136,6 +138,12 @@
 		request_notes_for_team_response.GetRootAsRequestNotesForTeamResponse)
 }
 
+func RequestPitImages(server string, requestBytes []byte) (*request_pit_images_response.RequestPitImagesResponseT, error) {
+	return sendMessage[request_pit_images_response.RequestPitImagesResponseT](
+		server+"/requests/request/pit_images", requestBytes,
+		request_pit_images_response.GetRootAsRequestPitImagesResponse)
+}
+
 func RequestAllNotes(server string, requestBytes []byte) (*request_all_notes_response.RequestAllNotesResponseT, error) {
 	return sendMessage[request_all_notes_response.RequestAllNotesResponseT](
 		server+"/requests/request/all_notes", requestBytes,
@@ -166,6 +174,12 @@
 		submit_actions_response.GetRootAsSubmitActionsResponse)
 }
 
+func SubmitPitImage(server string, requestBytes []byte) (*submit_pit_image_response.SubmitPitImageResponseT, error) {
+	return sendMessage[submit_pit_image_response.SubmitPitImageResponseT](
+		server+"/requests/submit/submit_pit_image", requestBytes,
+		submit_pit_image_response.GetRootAsSubmitPitImageResponse)
+}
+
 func Delete2023DataScouting(server string, requestBytes []byte) (*delete_2023_data_scouting_response.Delete2023DataScoutingResponseT, error) {
 	return sendMessage[delete_2023_data_scouting_response.Delete2023DataScoutingResponseT](
 		server+"/requests/delete/delete_2023_data_scouting", requestBytes,
diff --git a/scouting/webserver/requests/messages/BUILD b/scouting/webserver/requests/messages/BUILD
index db422ed..13fdc45 100644
--- a/scouting/webserver/requests/messages/BUILD
+++ b/scouting/webserver/requests/messages/BUILD
@@ -15,6 +15,10 @@
     "submit_notes_response",
     "request_notes_for_team",
     "request_notes_for_team_response",
+    "submit_pit_image",
+    "submit_pit_image_response",
+    "request_pit_images",
+    "request_pit_images_response",
     "request_shift_schedule",
     "request_shift_schedule_response",
     "submit_shift_schedule",
diff --git a/scouting/webserver/requests/messages/request_pit_images.fbs b/scouting/webserver/requests/messages/request_pit_images.fbs
new file mode 100644
index 0000000..b28f0a8
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_pit_images.fbs
@@ -0,0 +1,7 @@
+namespace scouting.webserver.requests;
+
+table RequestPitImages {
+    team_number:string (id: 0);
+}
+
+root_type RequestPitImages;
diff --git a/scouting/webserver/requests/messages/request_pit_images_response.fbs b/scouting/webserver/requests/messages/request_pit_images_response.fbs
new file mode 100644
index 0000000..d9bb2cc
--- /dev/null
+++ b/scouting/webserver/requests/messages/request_pit_images_response.fbs
@@ -0,0 +1,13 @@
+namespace scouting.webserver.requests;
+
+table PitImage {
+	team_number:string (id:0);
+	check_sum:string (id:1);
+	image_path:string (id:2);
+}
+
+table RequestPitImagesResponse {
+	pit_image_list: [PitImage] (id:0);
+}
+
+root_type RequestPitImagesResponse;
diff --git a/scouting/webserver/requests/messages/submit_pit_image.fbs b/scouting/webserver/requests/messages/submit_pit_image.fbs
new file mode 100644
index 0000000..ffbaca2
--- /dev/null
+++ b/scouting/webserver/requests/messages/submit_pit_image.fbs
@@ -0,0 +1,9 @@
+namespace scouting.webserver.requests;
+
+table SubmitPitImage {
+	team_number:string (id:0);
+	image_path:string (id:1);
+	image_data:[ubyte] (id:2);
+}
+
+root_type SubmitPitImage;
diff --git a/scouting/webserver/requests/messages/submit_pit_image_response.fbs b/scouting/webserver/requests/messages/submit_pit_image_response.fbs
new file mode 100644
index 0000000..0b9d907
--- /dev/null
+++ b/scouting/webserver/requests/messages/submit_pit_image_response.fbs
@@ -0,0 +1,7 @@
+namespace scouting.webserver.requests;
+
+table SubmitPitImageResponse {
+    // empty response
+}
+
+root_type SubmitPitImageResponse;
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 533959c..51612ff 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -25,6 +25,8 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team_response"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions"
@@ -33,6 +35,8 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes_response"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/server"
@@ -49,6 +53,10 @@
 type Request2023DataScoutingResponseT = request_2023_data_scouting_response.Request2023DataScoutingResponseT
 type SubmitNotes = submit_notes.SubmitNotes
 type SubmitNotesResponseT = submit_notes_response.SubmitNotesResponseT
+type SubmitPitImage = submit_pit_image.SubmitPitImage
+type SubmitPitImageResponseT = submit_pit_image_response.SubmitPitImageResponseT
+type RequestPitImages = request_pit_images.RequestPitImages
+type RequestPitImagesResponseT = request_pit_images_response.RequestPitImagesResponseT
 type RequestNotesForTeam = request_notes_for_team.RequestNotesForTeam
 type RequestNotesForTeamResponseT = request_notes_for_team_response.RequestNotesForTeamResponseT
 type RequestShiftSchedule = request_shift_schedule.RequestShiftSchedule
@@ -77,7 +85,9 @@
 	ReturnStats2023ForTeam(teamNumber string, matchNumber int32, setNumber int32, compLevel string, preScouting bool) ([]db.Stats2023, error)
 	QueryAllShifts(int) ([]db.Shift, error)
 	QueryNotes(int32) ([]string, error)
+	QueryPitImages(string) ([]db.RequestedPitImage, error)
 	AddNotes(db.NotesData) error
+	AddPitImage(db.PitImage) error
 	AddDriverRanking(db.DriverRankingData) error
 	AddAction(db.Action) error
 	DeleteFromStats(string, int32, int32, string) error
@@ -378,6 +388,39 @@
 	w.Write(builder.FinishedBytes())
 }
 
+type submitPitImageScoutingHandler struct {
+	db Database
+}
+
+func (handler submitPitImageScoutingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	requestBytes, err := io.ReadAll(req.Body)
+	if err != nil {
+		respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+		return
+	}
+
+	request, success := parseRequest(w, requestBytes, "SubmitPitImage", submit_pit_image.GetRootAsSubmitPitImage)
+	if !success {
+		return
+	}
+
+	err = handler.db.AddPitImage(db.PitImage{
+		TeamNumber: string(request.TeamNumber()),
+		CheckSum:   db.ComputeSha256FromByteArray(request.ImageDataBytes()),
+		ImagePath:  string(request.ImagePath()),
+		ImageData:  request.ImageDataBytes(),
+	})
+	if err != nil {
+		respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to insert notes: %v", err))
+		return
+	}
+
+	var response SubmitPitImageResponseT
+	builder := flatbuffers.NewBuilder(10)
+	builder.Finish((&response).Pack(builder))
+	w.Write(builder.FinishedBytes())
+}
+
 func ConvertActionsToStat(submitActions *submit_actions.SubmitActions) (db.Stats2023, error) {
 	overall_time := int64(0)
 	cycles := int64(0)
@@ -576,6 +619,42 @@
 	w.Write(builder.FinishedBytes())
 }
 
+type requestPitImagesHandler struct {
+	db Database
+}
+
+func (handler requestPitImagesHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+	requestBytes, err := io.ReadAll(req.Body)
+	if err != nil {
+		respondWithError(w, http.StatusBadRequest, fmt.Sprint("Failed to read request bytes:", err))
+		return
+	}
+
+	request, success := parseRequest(w, requestBytes, "RequestPitImages", request_pit_images.GetRootAsRequestPitImages)
+	if !success {
+		return
+	}
+
+	images, err := handler.db.QueryPitImages(string(request.TeamNumber()))
+	if err != nil {
+		respondWithError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to query pit images: %v", err))
+		return
+	}
+
+	var response RequestPitImagesResponseT
+	for _, data := range images {
+		response.PitImageList = append(response.PitImageList, &request_pit_images_response.PitImageT{
+			TeamNumber: data.TeamNumber,
+			ImagePath:  data.ImagePath,
+			CheckSum:   data.CheckSum,
+		})
+	}
+
+	builder := flatbuffers.NewBuilder(1024)
+	builder.Finish((&response).Pack(builder))
+	w.Write(builder.FinishedBytes())
+}
+
 type requestNotesForTeamHandler struct {
 	db Database
 }
@@ -928,6 +1007,8 @@
 	scoutingServer.Handle("/requests/request/all_driver_rankings", requestAllDriverRankingsHandler{db})
 	scoutingServer.Handle("/requests/request/2023_data_scouting", request2023DataScoutingHandler{db})
 	scoutingServer.Handle("/requests/submit/submit_notes", submitNoteScoutingHandler{db})
+	scoutingServer.Handle("/requests/submit/submit_pit_image", submitPitImageScoutingHandler{db})
+	scoutingServer.Handle("/requests/request/pit_images", requestPitImagesHandler{db})
 	scoutingServer.Handle("/requests/request/notes_for_team", requestNotesForTeamHandler{db})
 	scoutingServer.Handle("/requests/submit/shift_schedule", submitShiftScheduleHandler{db})
 	scoutingServer.Handle("/requests/request/shift_schedule", requestShiftScheduleHandler{db})
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index 20a63ca..e50583b 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -17,11 +17,14 @@
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_all_notes_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_notes_for_team"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_pit_images_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/request_shift_schedule_response"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_actions"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_driver_ranking"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_notes"
+	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_pit_image"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/requests/messages/submit_shift_schedule"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/server"
 	flatbuffers "github.com/google/flatbuffers/go"
@@ -514,6 +517,86 @@
 	}
 }
 
+func TestSubmitPitImage(t *testing.T) {
+	database := MockDatabase{}
+	scoutingServer := server.NewScoutingServer()
+	HandleRequests(&database, scoutingServer)
+	scoutingServer.Start(8080)
+	defer scoutingServer.Stop()
+
+	builder := flatbuffers.NewBuilder(1024)
+	builder.Finish((&submit_pit_image.SubmitPitImageT{
+		TeamNumber: "483A", ImagePath: "483Arobot.jpg",
+		ImageData: []byte{12, 43, 54, 34, 98},
+	}).Pack(builder))
+
+	_, err := debug.SubmitPitImage("http://localhost:8080", builder.FinishedBytes())
+	if err != nil {
+		t.Fatal("Failed to submit pit image: ", err)
+	}
+
+	expected := []db.PitImage{
+		{
+			TeamNumber: "483A", CheckSum: "177d9dc52bc25f391232e82521259c378964c068832a9178d73448ba4ac5e0b1",
+			ImagePath: "483Arobot.jpg", ImageData: []byte{12, 43, 54, 34, 98},
+		},
+	}
+
+	if !reflect.DeepEqual(database.images, expected) {
+		t.Fatal("Submitted image did not match", expected, database.images)
+	}
+}
+
+func TestRequestPitImages(t *testing.T) {
+	db := MockDatabase{
+		images: []db.PitImage{
+			{
+				TeamNumber: "932", ImagePath: "pitimage.jpg",
+				ImageData: []byte{3, 34, 44, 65}, CheckSum: "abcdf",
+			},
+			{
+				TeamNumber: "234", ImagePath: "234robot.png",
+				ImageData: []byte{64, 54, 21, 21, 76, 32}, CheckSum: "egrfd",
+			},
+			{
+				TeamNumber: "93A", ImagePath: "abcd.jpg",
+				ImageData: []byte{92, 94, 10, 30, 57, 32, 32}, CheckSum: "rgegfd",
+			},
+		},
+	}
+
+	scoutingServer := server.NewScoutingServer()
+	HandleRequests(&db, scoutingServer)
+	scoutingServer.Start(8080)
+	defer scoutingServer.Stop()
+
+	builder := flatbuffers.NewBuilder(1024)
+	builder.Finish((&request_pit_images.RequestPitImagesT{"932"}).Pack(builder))
+
+	response, err := debug.RequestPitImages("http://localhost:8080", builder.FinishedBytes())
+	if err != nil {
+		t.Fatal("Failed to request pit images: ", err)
+	}
+
+	expected := request_pit_images_response.RequestPitImagesResponseT{
+		PitImageList: []*request_pit_images_response.PitImageT{
+			{
+				TeamNumber: "932", ImagePath: "pitimage.jpg", CheckSum: "abcdf",
+			},
+		},
+	}
+
+	if len(expected.PitImageList) != len(response.PitImageList) {
+		t.Fatal("Expected ", expected, ", but got ", *response)
+	}
+
+	for i, pit_image := range expected.PitImageList {
+		if !reflect.DeepEqual(*pit_image, *response.PitImageList[i]) {
+			t.Fatal("Expected for pit image", i, ":", *pit_image, ", but got:", *response.PitImageList[i])
+		}
+	}
+}
+
 func TestRequestShiftSchedule(t *testing.T) {
 	db := MockDatabase{
 		shiftSchedule: []db.Shift{
@@ -1024,6 +1107,7 @@
 	driver_ranking []db.DriverRankingData
 	stats2023      []db.Stats2023
 	actions        []db.Action
+	images         []db.PitImage
 }
 
 func (database *MockDatabase) AddToMatch(match db.TeamMatch) error {
@@ -1085,6 +1169,20 @@
 	return []db.Shift{}, nil
 }
 
+func (database *MockDatabase) QueryPitImages(requestedTeam string) ([]db.RequestedPitImage, error) {
+	var results []db.RequestedPitImage
+	for _, data := range database.images {
+		if data.TeamNumber == requestedTeam {
+			results = append(results, db.RequestedPitImage{
+				TeamNumber: data.TeamNumber,
+				ImagePath:  data.ImagePath,
+				CheckSum:   data.CheckSum,
+			})
+		}
+	}
+	return results, nil
+}
+
 func (database *MockDatabase) AddDriverRanking(data db.DriverRankingData) error {
 	database.driver_ranking = append(database.driver_ranking, data)
 	return nil
@@ -1099,6 +1197,11 @@
 	return nil
 }
 
+func (database *MockDatabase) AddPitImage(pitImage db.PitImage) error {
+	database.images = append(database.images, pitImage)
+	return nil
+}
+
 func (database *MockDatabase) ReturnActions() ([]db.Action, error) {
 	return database.actions, nil
 }
diff --git a/scouting/webserver/static/BUILD b/scouting/webserver/static/BUILD
index 0cf22f3..4b40c76 100644
--- a/scouting/webserver/static/BUILD
+++ b/scouting/webserver/static/BUILD
@@ -6,7 +6,10 @@
     importpath = "github.com/frc971/971-Robot-Code/scouting/webserver/static",
     target_compatible_with = ["@platforms//cpu:x86_64"],
     visibility = ["//visibility:public"],
-    deps = ["//scouting/webserver/server"],
+    deps = [
+        "//scouting/db",
+        "//scouting/webserver/server",
+    ],
 )
 
 go_test(
@@ -19,5 +22,8 @@
     ],
     embed = [":static"],
     target_compatible_with = ["@platforms//cpu:x86_64"],
-    deps = ["//scouting/webserver/server"],
+    deps = [
+        "//scouting/db",
+        "//scouting/webserver/server",
+    ],
 )
diff --git a/scouting/webserver/static/static.go b/scouting/webserver/static/static.go
index fbad476..8e2e400 100644
--- a/scouting/webserver/static/static.go
+++ b/scouting/webserver/static/static.go
@@ -7,12 +7,14 @@
 	"fmt"
 	"io"
 	"log"
+	"mime"
 	"net/http"
 	"os"
 	"path/filepath"
 	"strings"
 	"time"
 
+	"github.com/frc971/971-Robot-Code/scouting/db"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/server"
 )
 
@@ -28,6 +30,10 @@
 	"X-Accel-Expires": "0",
 }
 
+type ScoutingDatabase interface {
+	QueryPitImageByChecksum(checksum string) (db.PitImage, error)
+}
+
 func MaybeNoCache(h http.Handler) http.Handler {
 	fn := func(w http.ResponseWriter, r *http.Request) {
 		// We force the browser not to cache index.html so that
@@ -98,7 +104,7 @@
 	return shaSums
 }
 
-func HandleShaUrl(directory string, h http.Handler) http.Handler {
+func HandleShaUrl(directory string, h http.Handler, scoutingDatabase ScoutingDatabase) http.Handler {
 	shaSums := findAllFileShas(directory)
 
 	fn := func(w http.ResponseWriter, r *http.Request) {
@@ -132,9 +138,20 @@
 			// We found a file with this checksum. Serve that file.
 			r.URL.Path = path
 		} else {
-			// No file with this checksum found.
-			w.WriteHeader(http.StatusNotFound)
-			return
+			pitImage, err := scoutingDatabase.QueryPitImageByChecksum(hash)
+			if err == nil {
+				if parts[3] != pitImage.ImagePath {
+					log.Println("Got ", parts[3], "expected", pitImage.ImagePath)
+					w.WriteHeader(http.StatusBadRequest)
+					return
+				}
+				w.Header().Add("Content-Type", mime.TypeByExtension(pitImage.ImagePath))
+				w.Write(pitImage.ImageData)
+				return
+			} else { // No file with this checksum found.
+				w.WriteHeader(http.StatusNotFound)
+				return
+			}
 		}
 
 		h.ServeHTTP(w, r)
@@ -143,11 +160,10 @@
 	return http.HandlerFunc(fn)
 }
 
-// Serve pages in the specified directory.
-func ServePages(scoutingServer server.ScoutingServer, directory string) {
+func ServePages(scoutingServer server.ScoutingServer, directory string, scoutingDatabase ScoutingDatabase) {
 	// Serve the / endpoint given a folder of pages.
 	scoutingServer.Handle("/", MaybeNoCache(http.FileServer(http.Dir(directory))))
 
 	// Also serve files in a checksum-addressable manner.
-	scoutingServer.Handle("/sha256/", HandleShaUrl(directory, http.FileServer(http.Dir(directory))))
+	scoutingServer.Handle("/sha256/", HandleShaUrl(directory, http.FileServer(http.Dir(directory)), scoutingDatabase))
 }
diff --git a/scouting/webserver/static/static_test.go b/scouting/webserver/static/static_test.go
index 1d036a0..a68d973 100644
--- a/scouting/webserver/static/static_test.go
+++ b/scouting/webserver/static/static_test.go
@@ -1,14 +1,30 @@
 package static
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"net/http"
 	"testing"
 
+	"github.com/frc971/971-Robot-Code/scouting/db"
 	"github.com/frc971/971-Robot-Code/scouting/webserver/server"
 )
 
+type MockDatabase struct {
+	images []db.PitImage
+}
+
+func (database *MockDatabase) QueryPitImageByChecksum(checksum string) (db.PitImage, error) {
+	for _, data := range database.images {
+		if data.CheckSum == checksum {
+			return data, nil
+		}
+	}
+
+	return db.PitImage{}, errors.New("Could not find pit image")
+}
+
 func expectEqual(t *testing.T, actual string, expected string) {
 	if actual != expected {
 		t.Error("Expected ", actual, " to equal ", expected)
@@ -16,6 +32,15 @@
 }
 
 func TestServing(t *testing.T) {
+	database := MockDatabase{
+		images: []db.PitImage{
+			{
+				TeamNumber: "971", CheckSum: "3yi32rhewd23",
+				ImagePath: "abc.png", ImageData: []byte("hello"),
+			},
+		},
+	}
+
 	cases := []struct {
 		// The path to request from the server.
 		path string
@@ -26,10 +51,11 @@
 		{"/", "<h1>This is the index</h1>\n"},
 		{"/root.txt", "Hello, this is the root page!"},
 		{"/page.txt", "Hello from a page!"},
+		{"/sha256/3yi32rhewd23/abc.png", "hello"},
 	}
 
 	scoutingServer := server.NewScoutingServer()
-	ServePages(scoutingServer, "test_pages")
+	ServePages(scoutingServer, "test_pages", &database)
 	scoutingServer.Start(8080)
 	defer scoutingServer.Stop()
 
@@ -43,8 +69,9 @@
 // Makes sure that requesting / sets the proper headers so it doesn't get
 // cached.
 func TestDisallowedCache(t *testing.T) {
+	database := MockDatabase{}
 	scoutingServer := server.NewScoutingServer()
-	ServePages(scoutingServer, "test_pages")
+	ServePages(scoutingServer, "test_pages", &database)
 	scoutingServer.Start(8080)
 	defer scoutingServer.Stop()
 
@@ -61,8 +88,9 @@
 // Makes sure that requesting anything other than / doesn't set the "do not
 // cache" headers.
 func TestAllowedCache(t *testing.T) {
+	database := MockDatabase{}
 	scoutingServer := server.NewScoutingServer()
-	ServePages(scoutingServer, "test_pages")
+	ServePages(scoutingServer, "test_pages", &database)
 	scoutingServer.Start(8080)
 	defer scoutingServer.Stop()
 
@@ -77,11 +105,23 @@
 }
 
 func TestSha256(t *testing.T) {
+	database := MockDatabase{
+		images: []db.PitImage{
+			{
+				TeamNumber: "971", CheckSum: "3yi32rhewd23",
+				ImagePath: "abc.png", ImageData: []byte{32, 54, 23, 00},
+			},
+		},
+	}
 	scoutingServer := server.NewScoutingServer()
-	ServePages(scoutingServer, "test_pages")
+	ServePages(scoutingServer, "test_pages", &database)
 	scoutingServer.Start(8080)
 	defer scoutingServer.Stop()
 
+	//Validate receiving the correct byte sequence from image request.
+	byteDataReceived := getData("sha256/3yi32rhewd23/abc.png", t)
+	expectEqual(t, string(byteDataReceived), string([]byte{32, 54, 23, 00}))
+
 	// Validate a valid checksum.
 	dataReceived := getData("sha256/553b9b29647a112136986cf93c57b988d1f12dc43d3b774f14a24e58d272dbff/root.txt", t)
 	expectEqual(t, dataReceived, "Hello, this is the root page!")
diff --git a/scouting/www/BUILD b/scouting/www/BUILD
index 6ecad54..55e9a8f 100644
--- a/scouting/www/BUILD
+++ b/scouting/www/BUILD
@@ -19,6 +19,7 @@
         "//scouting/www/entry",
         "//scouting/www/match_list",
         "//scouting/www/notes",
+        "//scouting/www/pit_scouting",
         "//scouting/www/shift_schedule",
         "//scouting/www/view",
     ],
diff --git a/scouting/www/app/app.module.ts b/scouting/www/app/app.module.ts
index 7b200d0..bf393e4 100644
--- a/scouting/www/app/app.module.ts
+++ b/scouting/www/app/app.module.ts
@@ -9,6 +9,7 @@
 import {ShiftScheduleModule} from '../shift_schedule';
 import {ViewModule} from '../view';
 import {DriverRankingModule} from '../driver_ranking';
+import {PitScoutingModule} from '../pit_scouting';
 
 @NgModule({
   declarations: [App],
@@ -21,6 +22,7 @@
     ShiftScheduleModule,
     DriverRankingModule,
     ViewModule,
+    PitScoutingModule,
   ],
   exports: [App],
   bootstrap: [App],
diff --git a/scouting/www/app/app.ng.html b/scouting/www/app/app.ng.html
index b7f1873..5f7ea9f 100644
--- a/scouting/www/app/app.ng.html
+++ b/scouting/www/app/app.ng.html
@@ -64,6 +64,15 @@
       View
     </a>
   </li>
+  <li class="nav-item">
+    <a
+      class="nav-link"
+      [class.active]="tabIs('Pit')"
+      (click)="switchTabToGuarded('Pit')"
+    >
+      Pit
+    </a>
+  </li>
 </ul>
 
 <ng-container [ngSwitch]="tab">
@@ -83,4 +92,5 @@
   <app-driver-ranking *ngSwitchCase="'DriverRanking'"></app-driver-ranking>
   <shift-schedule *ngSwitchCase="'ShiftSchedule'"></shift-schedule>
   <app-view *ngSwitchCase="'View'"></app-view>
+  <app-pit-scouting *ngSwitchCase="'Pit'"></app-pit-scouting>
 </ng-container>
diff --git a/scouting/www/app/app.ts b/scouting/www/app/app.ts
index c19895a..16e3197 100644
--- a/scouting/www/app/app.ts
+++ b/scouting/www/app/app.ts
@@ -6,7 +6,8 @@
   | 'Entry'
   | 'DriverRanking'
   | 'ShiftSchedule'
-  | 'View';
+  | 'View'
+  | 'Pit';
 
 // Ignore the guard for tabs that don't require the user to enter any data.
 const unguardedTabs: Tab[] = ['MatchList'];
diff --git a/scouting/www/pit_scouting/BUILD b/scouting/www/pit_scouting/BUILD
new file mode 100644
index 0000000..740dee1
--- /dev/null
+++ b/scouting/www/pit_scouting/BUILD
@@ -0,0 +1,18 @@
+load("@npm//:defs.bzl", "npm_link_all_packages")
+load("//tools/build_rules:js.bzl", "ng_pkg")
+
+npm_link_all_packages(name = "node_modules")
+
+ng_pkg(
+    name = "pit_scouting",
+    extra_srcs = [
+        "//scouting/www:app_common_css",
+    ],
+    deps = [
+        ":node_modules/@angular/forms",
+        "//scouting/webserver/requests/messages:error_response_ts_fbs",
+        "//scouting/webserver/requests/messages:submit_pit_image_response_ts_fbs",
+        "//scouting/webserver/requests/messages:submit_pit_image_ts_fbs",
+        "@com_github_google_flatbuffers//ts:flatbuffers_ts",
+    ],
+)
diff --git a/scouting/www/pit_scouting/package.json b/scouting/www/pit_scouting/package.json
new file mode 100644
index 0000000..e58fc51
--- /dev/null
+++ b/scouting/www/pit_scouting/package.json
@@ -0,0 +1,7 @@
+{
+	"name": "@org_frc971/scouting/www/pit_scouting",
+	"private": true,
+	"dependencies": {
+			"@angular/forms": "15.1.5"
+	}
+}
diff --git a/scouting/www/pit_scouting/pit_scouting.component.css b/scouting/www/pit_scouting/pit_scouting.component.css
new file mode 100644
index 0000000..b224d73
--- /dev/null
+++ b/scouting/www/pit_scouting/pit_scouting.component.css
@@ -0,0 +1,8 @@
+* {
+  padding: 10px;
+}
+
+button {
+  touch-action: manipulation;
+  margin-top: 1vh;
+}
diff --git a/scouting/www/pit_scouting/pit_scouting.component.ts b/scouting/www/pit_scouting/pit_scouting.component.ts
new file mode 100644
index 0000000..b74c119
--- /dev/null
+++ b/scouting/www/pit_scouting/pit_scouting.component.ts
@@ -0,0 +1,75 @@
+import {Component} from '@angular/core';
+import {Builder, ByteBuffer} from 'flatbuffers';
+import {ErrorResponse} from '../../webserver/requests/messages/error_response_generated';
+import {SubmitPitImage} from '../../webserver/requests/messages/submit_pit_image_generated';
+
+type Section = 'TeamSelection' | 'Data';
+
+interface Input {
+  teamNumber: number;
+  pitImage: HTMLImageElement;
+}
+
+@Component({
+  selector: 'app-pit-scouting',
+  templateUrl: './pit_scouting.ng.html',
+  styleUrls: ['../app/common.css', './pit_scouting.component.css'],
+})
+export class PitScoutingComponent {
+  section: Section = 'Data';
+
+  errorMessage = '';
+  teamNumber: number = 971;
+  pitImage: string = '';
+
+  async readFile(file): Promise<ArrayBuffer> {
+    return new Promise((resolve, reject) => {
+      let reader = new FileReader();
+      reader.addEventListener('loadend', (e) =>
+        resolve(e.target.result as ArrayBuffer)
+      );
+      reader.addEventListener('error', reject);
+      reader.readAsArrayBuffer(file);
+    });
+  }
+
+  async getImageData() {
+    const selectedFile = (<HTMLInputElement>document.getElementById('pitImage'))
+      .files[0];
+    return new Uint8Array(await this.readFile(selectedFile));
+  }
+
+  async submitData() {
+    const builder = new Builder();
+    const teamNumber = builder.createString(this.teamNumber.toString());
+    const pitImage = builder.createString(this.pitImage.toString());
+    const imageData = SubmitPitImage.createImageDataVector(
+      builder,
+      await this.getImageData()
+    );
+    builder.finish(
+      SubmitPitImage.createSubmitPitImage(
+        builder,
+        teamNumber,
+        pitImage,
+        imageData
+      )
+    );
+
+    const buffer = builder.asUint8Array();
+    const res = await fetch('/requests/submit/submit_pit_image', {
+      method: 'POST',
+      body: buffer,
+    });
+    if (!res.ok) {
+      const resBuffer = await res.arrayBuffer();
+      const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
+      const parsedResponse = ErrorResponse.getRootAsErrorResponse(fbBuffer);
+
+      const errorMessage = parsedResponse.errorMessage();
+      this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
+    }
+    this.section = 'TeamSelection';
+    this.pitImage = '';
+  }
+}
diff --git a/scouting/www/pit_scouting/pit_scouting.module.ts b/scouting/www/pit_scouting/pit_scouting.module.ts
new file mode 100644
index 0000000..7d92f6c
--- /dev/null
+++ b/scouting/www/pit_scouting/pit_scouting.module.ts
@@ -0,0 +1,11 @@
+import {NgModule} from '@angular/core';
+import {CommonModule} from '@angular/common';
+import {FormsModule} from '@angular/forms';
+import {PitScoutingComponent} from './pit_scouting.component';
+
+@NgModule({
+  declarations: [PitScoutingComponent],
+  exports: [PitScoutingComponent],
+  imports: [CommonModule, FormsModule],
+})
+export class PitScoutingModule {}
diff --git a/scouting/www/pit_scouting/pit_scouting.ng.html b/scouting/www/pit_scouting/pit_scouting.ng.html
new file mode 100644
index 0000000..98aa313
--- /dev/null
+++ b/scouting/www/pit_scouting/pit_scouting.ng.html
@@ -0,0 +1,30 @@
+<div class="header">
+  <h2>Pit Scouting</h2>
+</div>
+<ng-container [ngSwitch]="section">
+  <div *ngSwitchCase="'Data'" id="pitImageSelection" class="container-fluid">
+    <label for="teamNumber">Team Number</label>
+    <input
+      [(ngModel)]="teamNumber"
+      type="string"
+      id="teamNumber"
+      min="1"
+      max="9999"
+    />
+    <form action="setPitImage()">
+      <label for="pitImage">Select pit image:</label>
+      <br />
+      <input
+        id="pitImage"
+        [(ngModel)]="pitImage"
+        type="file"
+        accept="image/*"
+      />
+    </form>
+    <button id="submit-button" class="btn btn-success" (click)="submitData()">
+      Submit
+    </button>
+  </div>
+
+  <span class="error_message" role="alert">{{ errorMessage }}</span>
+</ng-container>