From f691c86954cf6dbf2f432345dedf4015c9700b09 Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 2 May 2024 13:41:28 +0200 Subject: [PATCH 01/30] refactor: update dependencies --- .isort.cfg | 2 + .pre-commit-config.yaml | 48 ++ api/Pipfile | 4 +- api/Pipfile.lock | 1061 +++++++++++++++++++++++++++++---------- 4 files changed, 857 insertions(+), 258 deletions(-) create mode 100644 .isort.cfg create mode 100644 .pre-commit-config.yaml diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 0000000..95a5f9d --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +known_third_party = firebase_admin,flask,flask_cors,loguru,psycopg2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b09c780 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,48 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks + +fail_fast: true +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: mixed-line-ending + args: [--fix=lf] + +- repo: https://github.com/asottile/pyupgrade + rev: v3.15.0 + hooks: + - id: pyupgrade + args: [--py310-plus] +- repo: https://github.com/hadialqattan/pycln + rev: v2.3.0 + hooks: + - id: pycln +- repo: https://github.com/asottile/seed-isort-config + rev: v2.2.0 + hooks: + - id: seed-isort-config +- repo: https://github.com/PyCQA/isort + rev: 5.13.2 + hooks: + - id: isort + args: [--profile, black] +- repo: https://github.com/psf/black + rev: 23.10.1 + hooks: + - id: black + language_version: python3.10 +- repo: https://github.com/asottile/blacken-docs + rev: 1.16.0 + hooks: + - id: blacken-docs + additional_dependencies: [black==24.4.2] +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.10.0 + hooks: + - id: mypy + additional_dependencies: [types-all] diff --git a/api/Pipfile b/api/Pipfile index 5c7179b..aa64ed2 100644 --- a/api/Pipfile +++ b/api/Pipfile @@ -5,12 +5,14 @@ name = "pypi" [packages] flask = "*" -psycopg2 = "*" flask-cors = "*" gunicorn = "*" loguru = "*" +firebase-admin = "*" +psycopg = {extras = ["c"], version = "*"} [dev-packages] +pre-commit = "*" [requires] python_version = "3.10" diff --git a/api/Pipfile.lock b/api/Pipfile.lock index 0c4ea49..7e30d00 100644 --- a/api/Pipfile.lock +++ b/api/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9bd7ac630a482a5dba34bd1147d9b0115c0d38f4d039546c2b2f53e29f0c1c13" + "sha256": "7c177b9c2e7a349f999118a16486e6f20ad9322632475682f472b35f0f46dbb1" }, "pipfile-spec": 6, "requires": { @@ -16,372 +16,919 @@ ] }, "default": { + "blinker": { + "hashes": [ + "sha256:5f1cdeff423b77c31b89de0565cd03e5275a03028f44b2b15f912632a58cced6", + "sha256:da44ec748222dcd0105ef975eed946da197d5bdf8bafb6aa92f5bc89da63fa25" + ], + "markers": "python_version >= '3.8'", + "version": "==1.8.1" + }, + "cachecontrol": { + "hashes": [ + "sha256:7db1195b41c81f8274a7bbd97c956f44e8348265a1bc7641c37dfebc39f0c938", + "sha256:f5bf3f0620c38db2e5122c0726bdebb0d16869de966ea6a2befe92470b740ea0" + ], + "markers": "python_version >= '3.7'", + "version": "==0.14.0" + }, "cachetools": { "hashes": [ - "sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757", - "sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db" + "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945", + "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105" ], - "markers": "python_version ~= '3.7'", - "version": "==5.2.0" + "markers": "python_version >= '3.7'", + "version": "==5.3.3" }, "certifi": { "hashes": [ - "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14", - "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382" + "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", + "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" ], "markers": "python_version >= '3.6'", - "version": "==2022.9.24" + "version": "==2024.2.2" }, "cffi": { "hashes": [ - "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5", - "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef", - "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104", - "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426", - "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405", - "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375", - "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a", - "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e", - "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc", - "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf", - "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185", - "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497", - "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3", - "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35", - "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c", - "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83", - "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21", - "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca", - "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984", - "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac", - "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd", - "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee", - "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a", - "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2", - "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192", - "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7", - "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585", - "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f", - "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e", - "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27", - "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b", - "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e", - "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e", - "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d", - "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c", - "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415", - "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82", - "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02", - "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314", - "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325", - "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c", - "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3", - "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914", - "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045", - "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d", - "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9", - "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5", - "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2", - "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c", - "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3", - "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2", - "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8", - "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d", - "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d", - "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9", - "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162", - "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76", - "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4", - "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e", - "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9", - "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6", - "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b", - "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01", - "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0" - ], - "version": "==1.15.1" + "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", + "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", + "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", + "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", + "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", + "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", + "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", + "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", + "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", + "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", + "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", + "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", + "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", + "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", + "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", + "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", + "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", + "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", + "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", + "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", + "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", + "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", + "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", + "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", + "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", + "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", + "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", + "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", + "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", + "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", + "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", + "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", + "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", + "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", + "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", + "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", + "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", + "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", + "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", + "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", + "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", + "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", + "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", + "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", + "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", + "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", + "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", + "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", + "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", + "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", + "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.16.0" }, "charset-normalizer": { "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" + "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", + "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", + "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", + "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", + "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", + "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", + "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", + "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", + "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", + "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", + "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", + "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", + "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", + "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", + "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", + "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", + "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", + "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", + "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", + "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", + "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", + "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", + "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", + "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", + "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", + "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", + "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", + "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", + "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", + "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", + "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", + "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", + "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", + "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", + "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", + "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", + "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", + "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", + "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", + "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", + "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", + "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", + "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", + "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", + "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", + "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", + "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", + "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", + "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", + "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", + "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", + "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", + "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", + "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", + "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", + "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", + "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", + "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", + "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", + "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", + "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", + "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", + "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", + "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", + "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", + "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", + "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", + "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", + "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", + "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", + "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", + "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", + "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", + "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", + "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", + "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", + "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", + "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", + "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", + "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", + "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", + "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", + "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", + "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", + "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", + "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", + "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", + "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", + "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", + "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" ], - "markers": "python_full_version >= '3.6.0'", - "version": "==2.1.1" + "markers": "python_full_version >= '3.7.0'", + "version": "==3.3.2" }, "click": { "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" + "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" ], "markers": "python_version >= '3.7'", - "version": "==8.1.3" + "version": "==8.1.7" }, "cryptography": { "hashes": [ - "sha256:0297ffc478bdd237f5ca3a7dc96fc0d315670bfa099c04dc3a4a2172008a405a", - "sha256:10d1f29d6292fc95acb597bacefd5b9e812099d75a6469004fd38ba5471a977f", - "sha256:16fa61e7481f4b77ef53991075de29fc5bacb582a1244046d2e8b4bb72ef66d0", - "sha256:194044c6b89a2f9f169df475cc167f6157eb9151cc69af8a2a163481d45cc407", - "sha256:1db3d807a14931fa317f96435695d9ec386be7b84b618cc61cfa5d08b0ae33d7", - "sha256:3261725c0ef84e7592597606f6583385fed2a5ec3909f43bc475ade9729a41d6", - "sha256:3b72c360427889b40f36dc214630e688c2fe03e16c162ef0aa41da7ab1455153", - "sha256:3e3a2599e640927089f932295a9a247fc40a5bdf69b0484532f530471a382750", - "sha256:3fc26e22840b77326a764ceb5f02ca2d342305fba08f002a8c1f139540cdfaad", - "sha256:5067ee7f2bce36b11d0e334abcd1ccf8c541fc0bbdaf57cdd511fdee53e879b6", - "sha256:52e7bee800ec869b4031093875279f1ff2ed12c1e2f74923e8f49c916afd1d3b", - "sha256:64760ba5331e3f1794d0bcaabc0d0c39e8c60bf67d09c93dc0e54189dfd7cfe5", - "sha256:765fa194a0f3372d83005ab83ab35d7c5526c4e22951e46059b8ac678b44fa5a", - "sha256:79473cf8a5cbc471979bd9378c9f425384980fcf2ab6534b18ed7d0d9843987d", - "sha256:896dd3a66959d3a5ddcfc140a53391f69ff1e8f25d93f0e2e7830c6de90ceb9d", - "sha256:89ed49784ba88c221756ff4d4755dbc03b3c8d2c5103f6d6b4f83a0fb1e85294", - "sha256:ac7e48f7e7261207d750fa7e55eac2d45f720027d5703cd9007e9b37bbb59ac0", - "sha256:ad7353f6ddf285aeadfaf79e5a6829110106ff8189391704c1d8801aa0bae45a", - "sha256:b0163a849b6f315bf52815e238bc2b2346604413fa7c1601eea84bcddb5fb9ac", - "sha256:b6c9b706316d7b5a137c35e14f4103e2115b088c412140fdbd5f87c73284df61", - "sha256:c2e5856248a416767322c8668ef1845ad46ee62629266f84a8f007a317141013", - "sha256:ca9f6784ea96b55ff41708b92c3f6aeaebde4c560308e5fbbd3173fbc466e94e", - "sha256:d1a5bd52d684e49a36582193e0b89ff267704cd4025abefb9e26803adeb3e5fb", - "sha256:d3971e2749a723e9084dd507584e2a2761f78ad2c638aa31e80bc7a15c9db4f9", - "sha256:d4ef6cc305394ed669d4d9eebf10d3a101059bdcf2669c366ec1d14e4fb227bd", - "sha256:d9e69ae01f99abe6ad646947bba8941e896cb3aa805be2597a0400e0764b5818" + "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", + "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", + "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", + "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", + "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", + "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", + "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", + "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", + "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", + "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", + "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", + "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", + "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", + "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", + "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", + "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", + "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", + "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", + "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", + "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", + "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", + "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", + "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", + "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", + "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", + "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", + "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", + "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", + "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", + "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", + "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", + "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" ], "markers": "python_version >= '3.6'", - "version": "==38.0.1" + "version": "==42.0.5" + }, + "firebase-admin": { + "hashes": [ + "sha256:e716dde1447f0a1cd1523be76ff872df33c4e1a3c079564ace033b2ad60bcc4f", + "sha256:fe34ee3ca0e625c5156b3931ca4b4b69b5fc344dbe51bba9706ff674ce277898" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==6.5.0" }, "flask": { "hashes": [ - "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b", - "sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526" + "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3", + "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842" ], "index": "pypi", - "version": "==2.2.2" + "markers": "python_version >= '3.8'", + "version": "==3.0.3" }, "flask-cors": { "hashes": [ - "sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438", - "sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de" + "sha256:bc3492bfd6368d27cfe79c7821df5a8a319e1a6d5eab277a3794be19bdc51783", + "sha256:f268522fcb2f73e2ecdde1ef45e2fd5c71cc48fe03cffb4b441c6d1b40684eb0" ], "index": "pypi", - "version": "==3.0.10" + "version": "==4.0.0" + }, + "google-api-core": { + "extras": [ + "grpc" + ], + "hashes": [ + "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251", + "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==2.19.0" + }, + "google-api-python-client": { + "hashes": [ + "sha256:bbb51b0fbccdf40e536c26341e372d7800f09afebb53103bbcc94e08f14b523b", + "sha256:d01c70c7840ec37888aa02b1aea5d9baba4c1701e268d1a0251640afd56e5e90" + ], + "markers": "python_version >= '3.7'", + "version": "==2.127.0" }, "google-auth": { "hashes": [ - "sha256:98f601773978c969e1769f97265e732a81a8e598da3263895023958d456ee625", - "sha256:f12d86502ce0f2c0174e2e70ecc8d36c69593817e67e1d9c5e34489120422e4b" + "sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360", + "sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415" ], - "index": "pypi", - "version": "==2.12.0" + "markers": "python_version >= '3.7'", + "version": "==2.29.0" }, - "google-oauth": { + "google-auth-httplib2": { "hashes": [ - "sha256:5d26c0d995aafd5f4884424159146c81569b9762ed9516d9fd13c7d6c11cc5aa" + "sha256:38aa7badf48f974f1eb9861794e9c0cb2a0511a4ec0679b1f886d108f5640e05", + "sha256:b65a0a2123300dd71281a7bf6e64d65a0759287df52729bdd1ae2e47dc311a3d" ], - "index": "pypi", - "version": "==1.0.1" + "version": "==0.2.0" + }, + "google-cloud-core": { + "hashes": [ + "sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073", + "sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61" + ], + "markers": "python_version >= '3.7'", + "version": "==2.4.1" + }, + "google-cloud-firestore": { + "hashes": [ + "sha256:3347ac38346c2702134d4c81f652a5e3451c840a6237f28b844501bd528e5fd8", + "sha256:e61ae70229a6e532e439c8d16447a32024447f2ee4a2303fc4d054c258d6877f" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==2.16.0" + }, + "google-cloud-storage": { + "hashes": [ + "sha256:91a06b96fb79cf9cdfb4e759f178ce11ea885c79938f89590344d079305f5852", + "sha256:dda485fa503710a828d01246bd16ce9db0823dc51bbca742ce96a6817d58669f" + ], + "markers": "python_version >= '3.7'", + "version": "==2.16.0" + }, + "google-crc32c": { + "hashes": [ + "sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a", + "sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876", + "sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c", + "sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289", + "sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298", + "sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02", + "sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f", + "sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2", + "sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a", + "sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb", + "sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210", + "sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5", + "sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee", + "sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c", + "sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a", + "sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314", + "sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd", + "sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65", + "sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37", + "sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4", + "sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13", + "sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894", + "sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31", + "sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e", + "sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709", + "sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740", + "sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc", + "sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d", + "sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c", + "sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c", + "sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d", + "sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906", + "sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61", + "sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57", + "sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c", + "sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a", + "sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438", + "sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946", + "sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7", + "sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96", + "sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091", + "sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae", + "sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d", + "sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88", + "sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2", + "sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd", + "sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541", + "sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728", + "sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178", + "sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968", + "sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346", + "sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8", + "sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93", + "sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7", + "sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273", + "sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462", + "sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94", + "sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd", + "sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e", + "sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57", + "sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b", + "sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9", + "sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a", + "sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100", + "sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325", + "sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183", + "sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556", + "sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4" + ], + "markers": "python_version >= '3.7'", + "version": "==1.5.0" + }, + "google-resumable-media": { + "hashes": [ + "sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b", + "sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08" + ], + "markers": "python_version >= '3.7'", + "version": "==2.7.0" + }, + "googleapis-common-protos": { + "hashes": [ + "sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e", + "sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632" + ], + "markers": "python_version >= '3.7'", + "version": "==1.63.0" + }, + "grpcio": { + "hashes": [ + "sha256:01799e8649f9e94ba7db1aeb3452188048b0019dc37696b0f5ce212c87c560c3", + "sha256:0697563d1d84d6985e40ec5ec596ff41b52abb3fd91ec240e8cb44a63b895094", + "sha256:08e1559fd3b3b4468486b26b0af64a3904a8dbc78d8d936af9c1cf9636eb3e8b", + "sha256:166e5c460e5d7d4656ff9e63b13e1f6029b122104c1633d5f37eaea348d7356d", + "sha256:1ff737cf29b5b801619f10e59b581869e32f400159e8b12d7a97e7e3bdeee6a2", + "sha256:219bb1848cd2c90348c79ed0a6b0ea51866bc7e72fa6e205e459fedab5770172", + "sha256:259e11932230d70ef24a21b9fb5bb947eb4703f57865a404054400ee92f42f5d", + "sha256:2e93aca840c29d4ab5db93f94ed0a0ca899e241f2e8aec6334ab3575dc46125c", + "sha256:3a6d1f9ea965e750db7b4ee6f9fdef5fdf135abe8a249e75d84b0a3e0c668a1b", + "sha256:50344663068041b34a992c19c600236e7abb42d6ec32567916b87b4c8b8833b3", + "sha256:56cdf96ff82e3cc90dbe8bac260352993f23e8e256e063c327b6cf9c88daf7a9", + "sha256:5c039ef01516039fa39da8a8a43a95b64e288f79f42a17e6c2904a02a319b357", + "sha256:6426e1fb92d006e47476d42b8f240c1d916a6d4423c5258ccc5b105e43438f61", + "sha256:65bf975639a1f93bee63ca60d2e4951f1b543f498d581869922910a476ead2f5", + "sha256:6a1a3642d76f887aa4009d92f71eb37809abceb3b7b5a1eec9c554a246f20e3a", + "sha256:6ef0ad92873672a2a3767cb827b64741c363ebaa27e7f21659e4e31f4d750280", + "sha256:756fed02dacd24e8f488f295a913f250b56b98fb793f41d5b2de6c44fb762434", + "sha256:75f701ff645858a2b16bc8c9fc68af215a8bb2d5a9b647448129de6e85d52bce", + "sha256:8064d986d3a64ba21e498b9a376cbc5d6ab2e8ab0e288d39f266f0fca169b90d", + "sha256:878b1d88d0137df60e6b09b74cdb73db123f9579232c8456f53e9abc4f62eb3c", + "sha256:8f3f6883ce54a7a5f47db43289a0a4c776487912de1a0e2cc83fdaec9685cc9f", + "sha256:91b73d3f1340fefa1e1716c8c1ec9930c676d6b10a3513ab6c26004cb02d8b3f", + "sha256:93a46794cc96c3a674cdfb59ef9ce84d46185fe9421baf2268ccb556f8f81f57", + "sha256:93f45f27f516548e23e4ec3fbab21b060416007dbe768a111fc4611464cc773f", + "sha256:9e350cb096e5c67832e9b6e018cf8a0d2a53b2a958f6251615173165269a91b0", + "sha256:a2d60cd1d58817bc5985fae6168d8b5655c4981d448d0f5b6194bbcc038090d2", + "sha256:a3abfe0b0f6798dedd2e9e92e881d9acd0fdb62ae27dcbbfa7654a57e24060c0", + "sha256:a44624aad77bf8ca198c55af811fd28f2b3eaf0a50ec5b57b06c034416ef2d0a", + "sha256:a7b19dfc74d0be7032ca1eda0ed545e582ee46cd65c162f9e9fc6b26ef827dc6", + "sha256:ad2ac8903b2eae071055a927ef74121ed52d69468e91d9bcbd028bd0e554be6d", + "sha256:b005292369d9c1f80bf70c1db1c17c6c342da7576f1c689e8eee4fb0c256af85", + "sha256:b2e44f59316716532a993ca2966636df6fbe7be4ab6f099de6815570ebe4383a", + "sha256:b3afbd9d6827fa6f475a4f91db55e441113f6d3eb9b7ebb8fb806e5bb6d6bd0d", + "sha256:b416252ac5588d9dfb8a30a191451adbf534e9ce5f56bb02cd193f12d8845b7f", + "sha256:b5194775fec7dc3dbd6a935102bb156cd2c35efe1685b0a46c67b927c74f0cfb", + "sha256:cacdef0348a08e475a721967f48206a2254a1b26ee7637638d9e081761a5ba86", + "sha256:cd1e68776262dd44dedd7381b1a0ad09d9930ffb405f737d64f505eb7f77d6c7", + "sha256:cdcda1156dcc41e042d1e899ba1f5c2e9f3cd7625b3d6ebfa619806a4c1aadda", + "sha256:cf8dae9cc0412cb86c8de5a8f3be395c5119a370f3ce2e69c8b7d46bb9872c8d", + "sha256:d2497769895bb03efe3187fb1888fc20e98a5f18b3d14b606167dacda5789434", + "sha256:e3b77eaefc74d7eb861d3ffbdf91b50a1bb1639514ebe764c47773b833fa2d91", + "sha256:e48cee31bc5f5a31fb2f3b573764bd563aaa5472342860edcc7039525b53e46a", + "sha256:e4cbb2100ee46d024c45920d16e888ee5d3cf47c66e316210bc236d5bebc42b3", + "sha256:f28f8b2db7b86c77916829d64ab21ff49a9d8289ea1564a2b2a3a8ed9ffcccd3", + "sha256:f3023e14805c61bc439fb40ca545ac3d5740ce66120a678a3c6c2c55b70343d1", + "sha256:fdf348ae69c6ff484402cfdb14e18c1b0054ac2420079d575c53a60b9b2853ae" + ], + "version": "==1.63.0" + }, + "grpcio-status": { + "hashes": [ + "sha256:206ddf0eb36bc99b033f03b2c8e95d319f0044defae9b41ae21408e7e0cda48f", + "sha256:62e1bfcb02025a1cd73732a2d33672d3e9d0df4d21c12c51e0bbcaf09bab742a" + ], + "version": "==1.62.2" }, "gunicorn": { "hashes": [ - "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", - "sha256:e0a968b5ba15f8a328fdfd7ab1fcb5af4470c28aaf7e55df02a99bc13138e6e8" + "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9", + "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63" ], "index": "pypi", - "version": "==20.1.0" + "markers": "python_version >= '3.7'", + "version": "==22.0.0" + }, + "httplib2": { + "hashes": [ + "sha256:14ae0a53c1ba8f3d37e9e27cf37eabb0fb9980f435ba405d546948b009dd64dc", + "sha256:d7a10bc5ef5ab08322488bde8c726eeee5c8618723fdb399597ec58f3d82df81" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.22.0" }, "idna": { "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.4" + "version": "==3.7" }, "itsdangerous": { "hashes": [ - "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", - "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a" + "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", + "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173" ], - "markers": "python_version >= '3.7'", - "version": "==2.1.2" + "markers": "python_version >= '3.8'", + "version": "==2.2.0" }, "jinja2": { "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" + "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", + "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" ], "markers": "python_version >= '3.7'", - "version": "==3.1.2" + "version": "==3.1.3" }, "loguru": { "hashes": [ - "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c", - "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3" + "sha256:003d71e3d3ed35f0f8984898359d65b79e5b21943f78af86aa5491210429b8eb", + "sha256:e671a53522515f34fd406340ee968cb9ecafbc4b36c679da03c18fd8d0bd51ac" ], "index": "pypi", - "version": "==0.6.0" + "markers": "python_version >= '3.5'", + "version": "==0.7.2" }, "markupsafe": { "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a", + "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68" ], "markers": "python_version >= '3.7'", - "version": "==2.1.1" - }, - "psycopg2": { - "hashes": [ - "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c", - "sha256:0762c27d018edbcb2d34d51596e4346c983bd27c330218c56c4dc25ef7e819bf", - "sha256:083707a696e5e1c330af2508d8fab36f9700b26621ccbcb538abe22e15485362", - "sha256:34b33e0162cfcaad151f249c2649fd1030010c16f4bbc40a604c1cb77173dcf7", - "sha256:4295093a6ae3434d33ec6baab4ca5512a5082cc43c0505293087b8a46d108461", - "sha256:8cf3878353cc04b053822896bc4922b194792df9df2f1ad8da01fb3043602126", - "sha256:8e841d1bf3434da985cc5ef13e6f75c8981ced601fd70cc6bf33351b91562981", - "sha256:9572e08b50aed176ef6d66f15a21d823bb6f6d23152d35e8451d7d2d18fdac56", - "sha256:a81e3866f99382dfe8c15a151f1ca5fde5815fde879348fe5a9884a7c092a305", - "sha256:cb10d44e6694d763fa1078a26f7f6137d69f555a78ec85dc2ef716c37447e4b2", - "sha256:d3ca6421b942f60c008f81a3541e8faf6865a28d5a9b48544b0ee4f40cac7fca" + "version": "==2.1.5" + }, + "msgpack": { + "hashes": [ + "sha256:00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982", + "sha256:0726c282d188e204281ebd8de31724b7d749adebc086873a59efb8cf7ae27df3", + "sha256:0ceea77719d45c839fd73abcb190b8390412a890df2f83fb8cf49b2a4b5c2f40", + "sha256:114be227f5213ef8b215c22dde19532f5da9652e56e8ce969bf0a26d7c419fee", + "sha256:13577ec9e247f8741c84d06b9ece5f654920d8365a4b636ce0e44f15e07ec693", + "sha256:1876b0b653a808fcd50123b953af170c535027bf1d053b59790eebb0aeb38950", + "sha256:1ab0bbcd4d1f7b6991ee7c753655b481c50084294218de69365f8f1970d4c151", + "sha256:1cce488457370ffd1f953846f82323cb6b2ad2190987cd4d70b2713e17268d24", + "sha256:26ee97a8261e6e35885c2ecd2fd4a6d38252246f94a2aec23665a4e66d066305", + "sha256:3528807cbbb7f315bb81959d5961855e7ba52aa60a3097151cb21956fbc7502b", + "sha256:374a8e88ddab84b9ada695d255679fb99c53513c0a51778796fcf0944d6c789c", + "sha256:376081f471a2ef24828b83a641a02c575d6103a3ad7fd7dade5486cad10ea659", + "sha256:3923a1778f7e5ef31865893fdca12a8d7dc03a44b33e2a5f3295416314c09f5d", + "sha256:4916727e31c28be8beaf11cf117d6f6f188dcc36daae4e851fee88646f5b6b18", + "sha256:493c5c5e44b06d6c9268ce21b302c9ca055c1fd3484c25ba41d34476c76ee746", + "sha256:505fe3d03856ac7d215dbe005414bc28505d26f0c128906037e66d98c4e95868", + "sha256:5845fdf5e5d5b78a49b826fcdc0eb2e2aa7191980e3d2cfd2a30303a74f212e2", + "sha256:5c330eace3dd100bdb54b5653b966de7f51c26ec4a7d4e87132d9b4f738220ba", + "sha256:5dbf059fb4b7c240c873c1245ee112505be27497e90f7c6591261c7d3c3a8228", + "sha256:5e390971d082dba073c05dbd56322427d3280b7cc8b53484c9377adfbae67dc2", + "sha256:5fbb160554e319f7b22ecf530a80a3ff496d38e8e07ae763b9e82fadfe96f273", + "sha256:64d0fcd436c5683fdd7c907eeae5e2cbb5eb872fafbc03a43609d7941840995c", + "sha256:69284049d07fce531c17404fcba2bb1df472bc2dcdac642ae71a2d079d950653", + "sha256:6a0e76621f6e1f908ae52860bdcb58e1ca85231a9b0545e64509c931dd34275a", + "sha256:73ee792784d48aa338bba28063e19a27e8d989344f34aad14ea6e1b9bd83f596", + "sha256:74398a4cf19de42e1498368c36eed45d9528f5fd0155241e82c4082b7e16cffd", + "sha256:7938111ed1358f536daf311be244f34df7bf3cdedb3ed883787aca97778b28d8", + "sha256:82d92c773fbc6942a7a8b520d22c11cfc8fd83bba86116bfcf962c2f5c2ecdaa", + "sha256:83b5c044f3eff2a6534768ccfd50425939e7a8b5cf9a7261c385de1e20dcfc85", + "sha256:8db8e423192303ed77cff4dce3a4b88dbfaf43979d280181558af5e2c3c71afc", + "sha256:9517004e21664f2b5a5fd6333b0731b9cf0817403a941b393d89a2f1dc2bd836", + "sha256:95c02b0e27e706e48d0e5426d1710ca78e0f0628d6e89d5b5a5b91a5f12274f3", + "sha256:99881222f4a8c2f641f25703963a5cefb076adffd959e0558dc9f803a52d6a58", + "sha256:9ee32dcb8e531adae1f1ca568822e9b3a738369b3b686d1477cbc643c4a9c128", + "sha256:a22e47578b30a3e199ab067a4d43d790249b3c0587d9a771921f86250c8435db", + "sha256:b5505774ea2a73a86ea176e8a9a4a7c8bf5d521050f0f6f8426afe798689243f", + "sha256:bd739c9251d01e0279ce729e37b39d49a08c0420d3fee7f2a4968c0576678f77", + "sha256:d16a786905034e7e34098634b184a7d81f91d4c3d246edc6bd7aefb2fd8ea6ad", + "sha256:d3420522057ebab1728b21ad473aa950026d07cb09da41103f8e597dfbfaeb13", + "sha256:d56fd9f1f1cdc8227d7b7918f55091349741904d9520c65f0139a9755952c9e8", + "sha256:d661dc4785affa9d0edfdd1e59ec056a58b3dbb9f196fa43587f3ddac654ac7b", + "sha256:dfe1f0f0ed5785c187144c46a292b8c34c1295c01da12e10ccddfc16def4448a", + "sha256:e1dd7839443592d00e96db831eddb4111a2a81a46b028f0facd60a09ebbdd543", + "sha256:e2872993e209f7ed04d963e4b4fbae72d034844ec66bc4ca403329db2074377b", + "sha256:e2f879ab92ce502a1e65fce390eab619774dda6a6ff719718069ac94084098ce", + "sha256:e3aa7e51d738e0ec0afbed661261513b38b3014754c9459508399baf14ae0c9d", + "sha256:e532dbd6ddfe13946de050d7474e3f5fb6ec774fbb1a188aaf469b08cf04189a", + "sha256:e6b7842518a63a9f17107eb176320960ec095a8ee3b4420b5f688e24bf50c53c", + "sha256:e75753aeda0ddc4c28dce4c32ba2f6ec30b1b02f6c0b14e547841ba5b24f753f", + "sha256:eadb9f826c138e6cf3c49d6f8de88225a3c0ab181a9b4ba792e006e5292d150e", + "sha256:ed59dd52075f8fc91da6053b12e8c89e37aa043f8986efd89e61fae69dc1b011", + "sha256:ef254a06bcea461e65ff0373d8a0dd1ed3aa004af48839f002a0c994a6f72d04", + "sha256:f3709997b228685fe53e8c433e2df9f0cdb5f4542bd5114ed17ac3c0129b0480", + "sha256:f51bab98d52739c50c56658cc303f190785f9a2cd97b823357e7aeae54c8f68a", + "sha256:f9904e24646570539a8950400602d66d2b2c492b9010ea7e965025cb71d0c86d", + "sha256:f9af38a89b6a5c04b7d18c492c8ccf2aee7048aff1ce8437c4683bb5a1df893d" ], - "index": "pypi", - "version": "==2.9.3" + "markers": "python_version >= '3.8'", + "version": "==1.0.8" + }, + "packaging": { + "hashes": [ + "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", + "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + ], + "markers": "python_version >= '3.7'", + "version": "==24.0" + }, + "proto-plus": { + "hashes": [ + "sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2", + "sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c" + ], + "markers": "python_version >= '3.6'", + "version": "==1.23.0" + }, + "protobuf": { + "hashes": [ + "sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4", + "sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8", + "sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c", + "sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d", + "sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4", + "sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa", + "sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c", + "sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019", + "sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9", + "sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c", + "sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2" + ], + "markers": "python_version >= '3.8'", + "version": "==4.25.3" + }, + "psycopg": { + "extras": [ + "c" + ], + "hashes": [ + "sha256:31144d3fb4c17d78094d9e579826f047d4af1da6a10427d91dfcfb6ecdf6f12b", + "sha256:4d5a0a5a8590906daa58ebd5f3cfc34091377354a1acced269dd10faf55da60e" + ], + "markers": "python_version >= '3.7'", + "version": "==3.1.18" + }, + "psycopg-c": { + "hashes": [ + "sha256:ffff0c4a9c0e0b7aadb1acb7b61eb8f886365dd8ef00120ce14676235846ba73" + ], + "version": "==3.1.18" }, "pyasn1": { "hashes": [ - "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", - "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", - "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", - "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", - "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", - "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", - "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", - "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", - "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", - "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", - "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", - "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", - "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" - ], - "version": "==0.4.8" + "sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c", + "sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473" + ], + "markers": "python_version >= '3.8'", + "version": "==0.6.0" }, "pyasn1-modules": { "hashes": [ - "sha256:0845a5582f6a02bb3e1bde9ecfc4bfcae6ec3210dd270522fee602365430c3f8", - "sha256:0fe1b68d1e486a1ed5473f1302bd991c1611d319bba158e98b106ff86e1d7199", - "sha256:15b7c67fabc7fc240d87fb9aabf999cf82311a6d6fb2c70d00d3d0604878c811", - "sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed", - "sha256:65cebbaffc913f4fe9e4808735c95ea22d7a7775646ab690518c056784bc21b4", - "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", - "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74", - "sha256:a99324196732f53093a84c4369c996713eb8c89d360a496b599fb1a9c47fc3eb", - "sha256:b80486a6c77252ea3a3e9b1e360bc9cf28eaac41263d173c032581ad2f20fe45", - "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd", - "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0", - "sha256:f39edd8c4ecaa4556e989147ebf219227e2cd2e8a43c7e7fcb1f1c18c5fd6a3d", - "sha256:fe0644d9ab041506b62782e92b06b8c68cca799e1a9636ec398675459e031405" - ], - "version": "==0.2.8" + "sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6", + "sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b" + ], + "markers": "python_version >= '3.8'", + "version": "==0.4.0" }, "pycparser": { "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" ], - "version": "==2.21" + "markers": "python_version >= '3.8'", + "version": "==2.22" }, - "pyopenssl": { + "pyjwt": { + "extras": [ + "crypto" + ], "hashes": [ - "sha256:7a83b7b272dd595222d672f5ce29aa030f1fb837630ef229f62e72e395ce8968", - "sha256:b28437c9773bb6c6958628cf9c3bebe585de661dba6f63df17111966363dd15e" + "sha256:57e28d156e3d5c10088e0c68abb90bfac3df82b40a71bd0daa20c65ccd5c23de", + "sha256:59127c392cc44c2da5bb3192169a91f429924e17aff6534d70fdc02ab3e04320" ], - "markers": "python_version >= '3.6'", - "version": "==22.1.0" + "markers": "python_version >= '3.7'", + "version": "==2.8.0" + }, + "pyparsing": { + "hashes": [ + "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad", + "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742" + ], + "markers": "python_version >= '3.1'", + "version": "==3.1.2" }, "requests": { "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.28.1" + "markers": "python_version >= '3.7'", + "version": "==2.31.0" }, "rsa": { "hashes": [ "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21" ], - "markers": "python_version >= '3.6'", + "markers": "python_version >= '3.6' and python_version < '4'", "version": "==4.9" }, - "setuptools": { + "typing-extensions": { "hashes": [ - "sha256:1b6bdc6161661409c5f21508763dc63ab20a9ac2f8ba20029aaaa7fdb9118012", - "sha256:3050e338e5871e70c72983072fe34f6032ae1cdeeeb67338199c2f74e083a80e" + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" ], - "markers": "python_version >= '3.7'", - "version": "==65.4.1" + "markers": "python_version >= '3.8'", + "version": "==4.11.0" }, - "six": { + "uritemplate": { "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0", + "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.16.0" + "markers": "python_version >= '3.6'", + "version": "==4.1.1" }, "urllib3": { "hashes": [ - "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", - "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5' and python_version < '4'", - "version": "==1.26.12" + "markers": "python_version >= '3.8'", + "version": "==2.2.1" }, "werkzeug": { "hashes": [ - "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", - "sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5" + "sha256:3aac3f5da756f93030740bc235d3e09449efcf65f2f55e3602e1d851b8f48795", + "sha256:e39b645a6ac92822588e7b39a692e7828724ceae0b0d702ef96701f90e70128d" ], - "markers": "python_version >= '3.7'", - "version": "==2.2.2" + "markers": "python_version >= '3.8'", + "version": "==3.0.2" } }, - "develop": {} + "develop": { + "cfgv": { + "hashes": [ + "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", + "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" + ], + "markers": "python_version >= '3.8'", + "version": "==3.4.0" + }, + "distlib": { + "hashes": [ + "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", + "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64" + ], + "version": "==0.3.8" + }, + "filelock": { + "hashes": [ + "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f", + "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a" + ], + "markers": "python_version >= '3.8'", + "version": "==3.14.0" + }, + "identify": { + "hashes": [ + "sha256:37d93f380f4de590500d9dba7db359d0d3da95ffe7f9de1753faa159e71e7dfa", + "sha256:e5e00f54165f9047fbebeb4a560f9acfb8af4c88232be60a488e9b68d122745d" + ], + "markers": "python_version >= '3.8'", + "version": "==2.5.36" + }, + "nodeenv": { + "hashes": [ + "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2", + "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==1.8.0" + }, + "platformdirs": { + "hashes": [ + "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf", + "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1" + ], + "markers": "python_version >= '3.8'", + "version": "==4.2.1" + }, + "pre-commit": { + "hashes": [ + "sha256:5eae9e10c2b5ac51577c3452ec0a490455c45a0533f7960f993a0d01e59decab", + "sha256:e209d61b8acdcf742404408531f0c37d49d2c734fd7cff2d6076083d191cb060" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.7.0" + }, + "pyyaml": { + "hashes": [ + "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", + "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc", + "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df", + "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741", + "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206", + "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27", + "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595", + "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62", + "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98", + "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696", + "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290", + "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9", + "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d", + "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6", + "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867", + "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47", + "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486", + "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6", + "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3", + "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007", + "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938", + "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0", + "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c", + "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735", + "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d", + "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28", + "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4", + "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba", + "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8", + "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef", + "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5", + "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd", + "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3", + "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0", + "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515", + "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c", + "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c", + "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924", + "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34", + "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43", + "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859", + "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673", + "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54", + "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a", + "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b", + "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab", + "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa", + "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c", + "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585", + "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d", + "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f" + ], + "markers": "python_version >= '3.6'", + "version": "==6.0.1" + }, + "setuptools": { + "hashes": [ + "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987", + "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" + ], + "markers": "python_version >= '3.8'", + "version": "==69.5.1" + }, + "virtualenv": { + "hashes": [ + "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b", + "sha256:7aa9982a728ae5892558bff6a2839c00b9ed145523ece2274fad6f414690ae75" + ], + "markers": "python_version >= '3.7'", + "version": "==20.26.1" + } + } } From 115d4a6947028b45f51cd296cf14b19684e46033 Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 2 May 2024 13:42:54 +0200 Subject: [PATCH 02/30] refactor: update to psycopg3 --- .isort.cfg | 2 +- api/api.py | 52 +++++++++++++++++++++++++++++----------------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/.isort.cfg b/.isort.cfg index 95a5f9d..ef429f5 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,2 +1,2 @@ [settings] -known_third_party = firebase_admin,flask,flask_cors,loguru,psycopg2 +known_third_party = firebase_admin,flask,flask_cors,loguru,psycopg diff --git a/api/api.py b/api/api.py index 8ff53ef..99b305f 100644 --- a/api/api.py +++ b/api/api.py @@ -1,19 +1,18 @@ -from psycopg2 import sql -import psycopg2 -from psycopg2.extras import RealDictCursor -from flask import Flask, request, jsonify, abort, Response -from flask_cors import CORS import json -from functools import wraps +import math import os -from loguru import logger +import time from datetime import datetime -import math +from functools import wraps + import firebase_admin -from firebase_admin import credentials -from firebase_admin import auth -from firebase_admin import firestore -import time +import psycopg +from firebase_admin import auth, credentials, firestore +from flask import Flask, Response, jsonify, request +from flask_cors import CORS +from loguru import logger +from psycopg import sql +from psycopg.rows import dict_row cred = credentials.Certificate("service_account.json") firebase_app = firebase_admin.initialize_app(cred) @@ -45,7 +44,7 @@ def get_db_connection(): - conn = psycopg2.connect( + conn = psycopg.connect( database=os.environ.get("PG_DB"), host=os.environ.get("PG_HOST"), port=os.environ.get("PG_PORT"), @@ -59,14 +58,14 @@ def query_with_timing(query, conn=None): if conn is None: conn = get_db_connection() - cur = conn.cursor(cursor_factory=RealDictCursor) + cur = conn.cursor(row_factory=dict_row) cur.execute("SET SESSION statement_timeout = '100s';") t1 = datetime.now() try: cur.execute(query) - except psycopg2.errors.QueryCanceled: + except psycopg.errors.QueryCanceled: logger.warning("Request timed out") return Response(status=400) @@ -77,10 +76,11 @@ def query_with_timing(query, conn=None): t2 = datetime.now() for d in data: - d.pop('point_geom') + d.pop("point_geom") return (data, t2 - t1) + def get_user(request): token = None @@ -252,13 +252,19 @@ def get_intersection(): first_query = sql.SQL( "SELECT tags->'name' AS name, ST_Centroid(way) AS point_geom, way AS geom FROM {table}" ).format( - table=sql.SQL("planet_osm_line") - if first["type"] == "line" - else sql.SQL("planet_osm_polygon") - if first["type"] == "polygon" - else sql.SQL("planet_osm_point") - if first["type"] == "point" - else sql.SQL("planet_osm") + table=( + sql.SQL("planet_osm_line") + if first["type"] == "line" + else ( + sql.SQL("planet_osm_polygon") + if first["type"] == "polygon" + else ( + sql.SQL("planet_osm_point") + if first["type"] == "point" + else sql.SQL("planet_osm") + ) + ) + ) ) first_filter = make_filter_query(first) first_assembled = sql.SQL("{query} WHERE ({filter}) {bbox}").format( From c5794de7daf6792fcca9157859414a67bfdcefc8 Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 2 May 2024 15:24:48 +0200 Subject: [PATCH 03/30] feat: typing --- .isort.cfg | 2 +- .pre-commit-config.yaml | 2 +- api/Pipfile | 1 + api/Pipfile.lock | 104 ++++++++++++++++++++++- api/api.py | 177 +++++++++++++++++++++------------------- api/api_types.py | 58 +++++++++++++ 6 files changed, 259 insertions(+), 85 deletions(-) create mode 100644 api/api_types.py diff --git a/.isort.cfg b/.isort.cfg index ef429f5..60f021e 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,2 +1,2 @@ [settings] -known_third_party = firebase_admin,flask,flask_cors,loguru,psycopg +known_third_party = api_types,firebase_admin,flask,flask_cors,loguru,psycopg,pydantic diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b09c780..b4fccda 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,6 +31,7 @@ repos: hooks: - id: isort args: [--profile, black] + - repo: https://github.com/psf/black rev: 23.10.1 hooks: @@ -45,4 +46,3 @@ repos: rev: v1.10.0 hooks: - id: mypy - additional_dependencies: [types-all] diff --git a/api/Pipfile b/api/Pipfile index aa64ed2..91fd0a7 100644 --- a/api/Pipfile +++ b/api/Pipfile @@ -10,6 +10,7 @@ gunicorn = "*" loguru = "*" firebase-admin = "*" psycopg = {extras = ["c"], version = "*"} +pydantic = "*" [dev-packages] pre-commit = "*" diff --git a/api/Pipfile.lock b/api/Pipfile.lock index 7e30d00..1214112 100644 --- a/api/Pipfile.lock +++ b/api/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "7c177b9c2e7a349f999118a16486e6f20ad9322632475682f472b35f0f46dbb1" + "sha256": "df2709b0b1e25ed0db66f31b2a4d327d34e1395aced5cbff02d69588af428950" }, "pipfile-spec": 6, "requires": { @@ -16,6 +16,14 @@ ] }, "default": { + "annotated-types": { + "hashes": [ + "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", + "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" + ], + "markers": "python_version >= '3.8'", + "version": "==0.6.0" + }, "blinker": { "hashes": [ "sha256:5f1cdeff423b77c31b89de0565cd03e5275a03028f44b2b15f912632a58cced6", @@ -732,6 +740,100 @@ "markers": "python_version >= '3.8'", "version": "==2.22" }, + "pydantic": { + "hashes": [ + "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5", + "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.7.1" + }, + "pydantic-core": { + "hashes": [ + "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b", + "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a", + "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90", + "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d", + "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e", + "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d", + "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027", + "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804", + "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347", + "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400", + "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3", + "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399", + "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349", + "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd", + "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c", + "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e", + "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413", + "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3", + "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e", + "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3", + "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91", + "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce", + "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c", + "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb", + "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664", + "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6", + "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd", + "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3", + "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af", + "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043", + "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350", + "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7", + "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0", + "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563", + "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761", + "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72", + "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3", + "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb", + "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788", + "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b", + "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c", + "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038", + "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250", + "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec", + "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c", + "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74", + "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81", + "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439", + "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75", + "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0", + "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8", + "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150", + "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438", + "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae", + "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857", + "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038", + "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374", + "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f", + "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241", + "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592", + "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4", + "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d", + "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b", + "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b", + "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182", + "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e", + "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641", + "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70", + "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9", + "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a", + "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543", + "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b", + "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f", + "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38", + "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845", + "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2", + "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0", + "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4", + "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242" + ], + "markers": "python_version >= '3.8'", + "version": "==2.18.2" + }, "pyjwt": { "extras": [ "crypto" diff --git a/api/api.py b/api/api.py index 99b305f..e917c26 100644 --- a/api/api.py +++ b/api/api.py @@ -1,18 +1,20 @@ -import json import math import os import time -from datetime import datetime +from datetime import datetime, timedelta from functools import wraps +from typing import Literal import firebase_admin import psycopg +from api_types import Bbox, Filter, RequestParams, Timeout from firebase_admin import auth, credentials, firestore -from flask import Flask, Response, jsonify, request +from flask import Flask, Request, Response, jsonify, request from flask_cors import CORS from loguru import logger from psycopg import sql from psycopg.rows import dict_row +from pydantic import ValidationError cred = credentials.Certificate("service_account.json") firebase_app = firebase_admin.initialize_app(cred) @@ -43,7 +45,7 @@ ALLOWED_CASTS = ["integer", "float", "cast_to_int", "cast_to_float"] -def get_db_connection(): +def get_db_connection() -> psycopg.Connection: conn = psycopg.connect( database=os.environ.get("PG_DB"), host=os.environ.get("PG_HOST"), @@ -54,22 +56,24 @@ def get_db_connection(): return conn -def query_with_timing(query, conn=None): +def query_with_timing( + query, conn: psycopg.Connection | None = None +) -> tuple[list[dict], timedelta]: if conn is None: conn = get_db_connection() - cur = conn.cursor(row_factory=dict_row) + cur: psycopg.Cursor = conn.cursor(row_factory=dict_row) cur.execute("SET SESSION statement_timeout = '100s';") - t1 = datetime.now() + t1: datetime = datetime.now() try: cur.execute(query) except psycopg.errors.QueryCanceled: logger.warning("Request timed out") - return Response(status=400) + raise Timeout() - data = cur.fetchall() + data: list[dict] = cur.fetchall() cur.close() conn.close() @@ -81,7 +85,7 @@ def query_with_timing(query, conn=None): return (data, t2 - t1) -def get_user(request): +def get_user(request: Request): token = None if "Authorization" in request.headers: @@ -132,73 +136,73 @@ def decorated(*args, **kwargs): return decorated -def make_filter_query(filter): +def make_filter_query(filter: Filter): filter_query = sql.SQL("") i = 0 - for subfilter in filter["filters"]: - if subfilter["comparison"] not in ALLOWED_COMPARISONS: - logger.error(f"Invalid comparison {subfilter['comparison']}") + for subfilter in filter.filters: + if subfilter.comparison not in ALLOWED_COMPARISONS: + logger.error(f"Invalid comparison {subfilter.comparison}") break - if subfilter["comparison"] == "=": + if subfilter.comparison == "=": filter_query = sql.SQL("{filter_query} (tags @> {match})").format( filter_query=filter_query, - match=sql.Literal(subfilter["parameter"] + "=>" + subfilter["value"]), + match=sql.Literal(subfilter.parameter + "=>" + subfilter.value), ) - elif subfilter["comparison"] == "!=": + elif subfilter.comparison == "!=": filter_query = sql.SQL("{filter_query} NOT(tags @> {match})").format( filter_query=filter_query, - match=sql.Literal(subfilter["parameter"] + "=>" + subfilter["value"]), + match=sql.Literal(subfilter.parameter + "=>" + subfilter.value), ) - elif subfilter["comparison"] == "is null": + elif subfilter.comparison == "is null": filter_query = sql.SQL("{filter_query} NOT(tags?{parameter})").format( - filter_query=filter_query, parameter=sql.Literal(subfilter["parameter"]) + filter_query=filter_query, parameter=sql.Literal(subfilter.parameter) ) - elif subfilter["comparison"] == "is not null": + elif subfilter.comparison == "is not null": filter_query = sql.SQL("{filter_query} (tags?{parameter})").format( - filter_query=filter_query, parameter=sql.Literal(subfilter["parameter"]) + filter_query=filter_query, parameter=sql.Literal(subfilter.parameter) ) else: parameter = sql.SQL("tags->{parameter}").format( - parameter=sql.Literal(subfilter["parameter"]) + parameter=sql.Literal(subfilter.parameter) ) - if "cast" in subfilter and subfilter["cast"] in ALLOWED_CASTS: - if subfilter["cast"] == "cast_to_float": + if "cast" in subfilter and subfilter.cast in ALLOWED_CASTS: + if subfilter.cast == "cast_to_float": parameter = sql.SQL("cast_to_float({parameter}, 0.0)").format( parameter=parameter ) - elif subfilter["cast"] == "cast_to_int": + elif subfilter.cast == "cast_to_int": parameter = sql.SQL("cast_to_int({parameter}, 0)").format( parameter=parameter ) else: parameter = sql.SQL("CAST({parameter} AS {cast})").format( - parameter=parameter, cast=sql.SQL(subfilter["cast"]) + parameter=parameter, cast=sql.SQL(subfilter.cast) ) - if subfilter["comparison"] == "starts with": - subfilter["value"] = f"{subfilter['value']}%" - subfilter["comparison"] = "ILIKE" - elif subfilter["comparison"] == "ends with": - subfilter["value"] = f"%{subfilter['value']}" - subfilter["comparison"] = "ILIKE" - elif subfilter["comparison"] == "contains": - subfilter["value"] = f"%{subfilter['value']}%" - subfilter["comparison"] = "ILIKE" - elif subfilter["comparison"] == "does not contain": - subfilter["value"] = f"%{subfilter['value']}%" - subfilter["comparison"] = "NOT ILIKE" + if subfilter.comparison == "starts with": + subfilter.value = f"{subfilter.value}%" + subfilter.comparison = "ILIKE" + elif subfilter.comparison == "ends with": + subfilter.value = f"%{subfilter.value}" + subfilter.comparison = "ILIKE" + elif subfilter.comparison == "contains": + subfilter.value = f"%{subfilter.value}%" + subfilter.comparison = "ILIKE" + elif subfilter.comparison == "does not contain": + subfilter.value = f"%{subfilter.value}%" + subfilter.comparison = "NOT ILIKE" filter_query = sql.SQL( "{filter_query} ({parameter} {comparison} {value})" ).format( filter_query=filter_query, parameter=parameter, - comparison=sql.SQL(subfilter["comparison"]), - value=sql.Literal(subfilter["value"]), + comparison=sql.SQL(subfilter.comparison), + value=sql.Literal(subfilter.value), ) if i != len(filter["filters"]) - 1: @@ -213,24 +217,30 @@ def make_filter_query(filter): @app.route("/intersection") @token_required -def get_intersection(): - args = request.args - - buffer = int(args.get("buffer")) - filters = json.loads(args.get("filters")) +def get_intersection() -> tuple[Response, Literal[400]] | Response: + try: + params = RequestParams( + buffer=request.args.get("buffer"), + filters=request.args.get("filters"), + l=request.args.get("l"), + b=request.args.get("b"), + r=request.args.get("r"), + t=request.args.get("t"), + ) + except ValidationError as e: + # Handle errors in a way that fits your API design + return jsonify({"error": "Invalid data", "details": e.errors()}), 400 - l = float(args.get("l")) - b = float(args.get("b")) - r = float(args.get("r")) - t = float(args.get("t")) + buffer: int = params.buffer + filters: list[Filter] = params.filters - bbox = [l, b, r, t] + bbox: Bbox = Bbox(params.l, params.b, params.r, params.t) - area = ( + area: float = ( math.pow(6371, 2) * math.pi - * abs(math.sin(math.radians(t)) - math.sin(math.radians(b))) - * abs(r - l) + * abs(math.sin(math.radians(bbox.t)) - math.sin(math.radians(bbox.b))) + * abs(bbox.r - bbox.l) / 180 ) @@ -238,18 +248,18 @@ def get_intersection(): if area > 4e6: return Response(status=400) - bbox_filter = sql.SQL( + bbox_filter: sql.Composed = sql.SQL( "AND (way && ST_Transform(ST_MakeEnvelope({left}, {bottom}, {right}, {top}, 4326), 3857))" ).format( - left=sql.Literal(bbox[0]), - bottom=sql.Literal(bbox[1]), - right=sql.Literal(bbox[2]), - top=sql.Literal(bbox[3]), + left=sql.Literal(bbox.l), + bottom=sql.Literal(bbox.b), + right=sql.Literal(bbox.r), + top=sql.Literal(bbox.t), ) - first = filters[0] + first: Filter = filters[0] - first_query = sql.SQL( + first_query: sql.Composed = sql.SQL( "SELECT tags->'name' AS name, ST_Centroid(way) AS point_geom, way AS geom FROM {table}" ).format( table=( @@ -266,32 +276,32 @@ def get_intersection(): ) ) ) - first_filter = make_filter_query(first) - first_assembled = sql.SQL("{query} WHERE ({filter}) {bbox}").format( + first_filter: sql.Composed | sql.Sql = make_filter_query(first) + first_assembled: sql.Composed = sql.SQL("{query} WHERE ({filter}) {bbox}").format( query=first_query, filter=first_filter, bbox=bbox_filter ) - logger.info(f"Buffer: {buffer}\tFilters: {filters}\tBbox: [{l},{b},{r},{t}]") + logger.info(f"Buffer: {buffer}\tFilters: {filters}\tBbox: {str(bbox)}") - subqueries = [] + subqueries: list[sql.Composed] = [] for f in filters[1:]: filter = make_filter_query(f) - if f["type"] == "point": - query = sql.SQL("SELECT way AS geom FROM planet_osm_point") - elif f["type"] == "line": - query = sql.SQL("SELECT way AS geom FROM planet_osm_line") - elif f["type"] == "polygon": - query = sql.SQL("SELECT way AS geom FROM planet_osm_polygon") - elif f["type"] == "any": - query = sql.SQL("SELECT way AS geom FROM planet_osm") - - assembled = sql.SQL("{query} WHERE ({filter}) {bbox}").format( - query=query, filter=filter, bbox=bbox_filter + if f.type == "point": + source_query = sql.SQL("SELECT way AS geom FROM planet_osm_point") + elif f.type == "line": + source_query = sql.SQL("SELECT way AS geom FROM planet_osm_line") + elif f.type == "polygon": + source_query = sql.SQL("SELECT way AS geom FROM planet_osm_polygon") + elif f.type == "any": + source_query = sql.SQL("SELECT way AS geom FROM planet_osm") + + assembled: sql.Composed = sql.SQL("{query} WHERE ({filter}) {bbox}").format( + query=source_query, filter=filter, bbox=bbox_filter ) subqueries.append(assembled) - join_query = sql.SQL( + join_query: sql.Composed = sql.SQL( "SELECT DISTINCT point_geom, name, ST_Y(ST_Transform(point_geom, 4326)) AS lat, ST_X(ST_Transform(point_geom, 4326)) as lng FROM ({point}) point " ).format(point=first_assembled) @@ -309,21 +319,24 @@ def get_intersection(): join_query = sql.SQL("{join_query} LIMIT 100").format(join_query=join_query) - conn = get_db_connection() + conn: psycopg.Connection = get_db_connection() logger.info(f"Executing query: {join_query.as_string(conn)}") - timestamp = time.time_ns() + timestamp: int = time.time_ns() user = get_user(request) - data, tdiff = query_with_timing(join_query) + try: + data, tdiff = query_with_timing(join_query) + except Timeout: + return Response(status=408) log_data = { "timestamp": firestore.SERVER_TIMESTAMP, "query": join_query.as_string(conn), "user_uid": user["uid"], "user_email": user["email"], - "bbox": bbox, + "bbox": list(bbox), "filters": filters, "query_time": tdiff.total_seconds(), "query_nresults": len(data), @@ -338,7 +351,7 @@ def get_intersection(): @app.route("/robots.txt") -def robots(): +def robots() -> Response: return Response("User-agent: *\nDisallow: /", mimetype="text/plain") diff --git a/api/api_types.py b/api/api_types.py new file mode 100644 index 0000000..27dcb88 --- /dev/null +++ b/api/api_types.py @@ -0,0 +1,58 @@ +from dataclasses import dataclass +from typing import Literal + +from pydantic import BaseModel, Json + + +class Subfilter(BaseModel): + comparison: ( + str + | Literal[ + "=", + "!=", + ">", + "<", + ">=", + "<=", + "starts with", + "ends with", + "contains", + "does not contain", + "is null", + "is not null", + ] + ) + parameter: str + value: str + + +class Filter(BaseModel): + type: Literal["point", "line", "polygon", "any"] + filters: list[Subfilter] + + +class RequestParams(BaseModel): + buffer: int + filters: Json[list[Filter]] + l: float + b: float + r: float + t: float + + +@dataclass +class Bbox: + l: float + b: float + r: float + t: float + + def __str__(self) -> str: + return f"[{self.l}, {self.b}, {self.r}, {self.t}]" + + def __iter__(self): + return iter([self.l, self.b, self.r, self.t]) + + +class Timeout(Exception): + pass From 8a5f6d366828a0e6c179c0ef968f6b4a3a119994 Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 2 May 2024 15:37:28 +0200 Subject: [PATCH 04/30] refactor: restructure db config --- api/api.py | 14 +++++++------- api/api_types.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/api/api.py b/api/api.py index e917c26..b3d04f0 100644 --- a/api/api.py +++ b/api/api.py @@ -1,5 +1,4 @@ import math -import os import time from datetime import datetime, timedelta from functools import wraps @@ -7,7 +6,7 @@ import firebase_admin import psycopg -from api_types import Bbox, Filter, RequestParams, Timeout +from api_types import Bbox, Filter, PostgresConfig, RequestParams, Timeout from firebase_admin import auth, credentials, firestore from flask import Flask, Request, Response, jsonify, request from flask_cors import CORS @@ -46,12 +45,13 @@ def get_db_connection() -> psycopg.Connection: + db_config = PostgresConfig() conn = psycopg.connect( - database=os.environ.get("PG_DB"), - host=os.environ.get("PG_HOST"), - port=os.environ.get("PG_PORT"), - user=os.environ.get("PG_USER"), - password=os.environ.get("PG_PASSWORD"), + database=db_config.database, + host=db_config.host, + port=db_config.port, + user=db_config.user, + password=db_config.password, ) return conn diff --git a/api/api_types.py b/api/api_types.py index 27dcb88..0fbc9b4 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -1,3 +1,4 @@ +import os from dataclasses import dataclass from typing import Literal @@ -54,5 +55,19 @@ def __iter__(self): return iter([self.l, self.b, self.r, self.t]) +@dataclass +class PostgresConfig: + database: str = os.environ.get("PG_DB", "") + host: str = os.environ.get("PG_HOST", "") + port: str = os.environ.get("PG_PORT", "") + user: str = os.environ.get("PG_USER", "") + password: str = os.environ.get("PG_PASSWORD", "") + + def __post_init__(self): + for key, value in self.__dict__.items(): + if value is None: + raise ValueError(f"Missing environment variable: {key}") + + class Timeout(Exception): pass From dae50fa57b7253983478c80637908ceac13c41cb Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 2 May 2024 15:54:56 +0200 Subject: [PATCH 05/30] fix: support optional cast --- .pre-commit-config.yaml | 1 - api/.python-version | 1 + api/api.py | 2 +- api/api_types.py | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 api/.python-version diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b4fccda..29eab2c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,6 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks -fail_fast: true repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 diff --git a/api/.python-version b/api/.python-version new file mode 100644 index 0000000..871f80a --- /dev/null +++ b/api/.python-version @@ -0,0 +1 @@ +3.12.3 diff --git a/api/api.py b/api/api.py index b3d04f0..b04b54c 100644 --- a/api/api.py +++ b/api/api.py @@ -169,7 +169,7 @@ def make_filter_query(filter: Filter): parameter=sql.Literal(subfilter.parameter) ) - if "cast" in subfilter and subfilter.cast in ALLOWED_CASTS: + if subfilter.cast is not None and subfilter.cast in ALLOWED_CASTS: if subfilter.cast == "cast_to_float": parameter = sql.SQL("cast_to_float({parameter}, 0.0)").format( parameter=parameter diff --git a/api/api_types.py b/api/api_types.py index 0fbc9b4..c2d2b90 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -25,6 +25,7 @@ class Subfilter(BaseModel): ) parameter: str value: str + cast: str | None = None class Filter(BaseModel): From ef77a64269181dc2f6a5538ca8af9077a2745b18 Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 2 May 2024 16:37:25 +0200 Subject: [PATCH 06/30] feat: type response --- .isort.cfg | 2 +- api/api.py | 31 +++++++++++++++++-------------- api/api_types.py | 14 ++++++++++++-- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/.isort.cfg b/.isort.cfg index 60f021e..c2401b9 100644 --- a/.isort.cfg +++ b/.isort.cfg @@ -1,2 +1,2 @@ [settings] -known_third_party = api_types,firebase_admin,flask,flask_cors,loguru,psycopg,pydantic +known_third_party = api_types,firebase_admin,flask,flask_cors,loguru,psycopg,pydantic,typing_extensions diff --git a/api/api.py b/api/api.py index b04b54c..d7fcf34 100644 --- a/api/api.py +++ b/api/api.py @@ -6,7 +6,14 @@ import firebase_admin import psycopg -from api_types import Bbox, Filter, PostgresConfig, RequestParams, Timeout +from api_types import ( + Bbox, + Filter, + PostgresConfig, + RequestParams, + RetrievedData, + Timeout, +) from firebase_admin import auth, credentials, firestore from flask import Flask, Request, Response, jsonify, request from flask_cors import CORS @@ -47,18 +54,15 @@ def get_db_connection() -> psycopg.Connection: db_config = PostgresConfig() conn = psycopg.connect( - database=db_config.database, - host=db_config.host, - port=db_config.port, - user=db_config.user, - password=db_config.password, + f"dbname={db_config.database} user={db_config.user} password={db_config.password} host={db_config.host} port={db_config.port}" ) + return conn def query_with_timing( query, conn: psycopg.Connection | None = None -) -> tuple[list[dict], timedelta]: +) -> tuple[list[RetrievedData], timedelta]: if conn is None: conn = get_db_connection() @@ -73,14 +77,14 @@ def query_with_timing( logger.warning("Request timed out") raise Timeout() - data: list[dict] = cur.fetchall() + data: list[RetrievedData] = cur.fetchall() cur.close() conn.close() t2 = datetime.now() for d in data: - d.pop("point_geom") + del d["point_geom"] return (data, t2 - t1) @@ -205,7 +209,7 @@ def make_filter_query(filter: Filter): value=sql.Literal(subfilter.value), ) - if i != len(filter["filters"]) - 1: + if i != len(filter.filters) - 1: filter_query = sql.SQL("{filter_query} {method}").format( filter_query=filter_query, method=sql.SQL(filter["method"]) ) @@ -228,7 +232,6 @@ def get_intersection() -> tuple[Response, Literal[400]] | Response: t=request.args.get("t"), ) except ValidationError as e: - # Handle errors in a way that fits your API design return jsonify({"error": "Invalid data", "details": e.errors()}), 400 buffer: int = params.buffer @@ -264,13 +267,13 @@ def get_intersection() -> tuple[Response, Literal[400]] | Response: ).format( table=( sql.SQL("planet_osm_line") - if first["type"] == "line" + if first.type == "line" else ( sql.SQL("planet_osm_polygon") - if first["type"] == "polygon" + if first.type == "polygon" else ( sql.SQL("planet_osm_point") - if first["type"] == "point" + if first.type == "point" else sql.SQL("planet_osm") ) ) diff --git a/api/api_types.py b/api/api_types.py index c2d2b90..a3ef97b 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -1,8 +1,9 @@ import os from dataclasses import dataclass -from typing import Literal +from typing import Literal, TypedDict from pydantic import BaseModel, Json +from typing_extensions import NotRequired class Subfilter(BaseModel): @@ -24,11 +25,13 @@ class Subfilter(BaseModel): ] ) parameter: str - value: str + value: str = "" cast: str | None = None class Filter(BaseModel): + name: str + method: Literal["AND", "OR"] type: Literal["point", "line", "polygon", "any"] filters: list[Subfilter] @@ -72,3 +75,10 @@ def __post_init__(self): class Timeout(Exception): pass + + +class RetrievedData(TypedDict): + name: str + lat: float + lng: float + point_geom: NotRequired[str] From e5295130981bc28fddbf25a36e4650491597cc65 Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 00:08:35 +0200 Subject: [PATCH 07/30] refactor: optimize query --- api/Pipfile | 4 +- api/Pipfile.lock | 886 ++++++++++++++++++++++++++++++++++++++++++++++- api/api.py | 120 +++---- api/api_types.py | 36 +- 4 files changed, 966 insertions(+), 80 deletions(-) diff --git a/api/Pipfile b/api/Pipfile index 91fd0a7..9dbe212 100644 --- a/api/Pipfile +++ b/api/Pipfile @@ -9,11 +9,13 @@ flask-cors = "*" gunicorn = "*" loguru = "*" firebase-admin = "*" -psycopg = {extras = ["c"], version = "*"} +psycopg = {extras = ["c"] } pydantic = "*" [dev-packages] pre-commit = "*" +mypy = "*" +types-all = "*" [requires] python_version = "3.10" diff --git a/api/Pipfile.lock b/api/Pipfile.lock index 1214112..52dc973 100644 --- a/api/Pipfile.lock +++ b/api/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "df2709b0b1e25ed0db66f31b2a4d327d34e1395aced5cbff02d69588af428950" + "sha256": "216e7cdf661aceed5d49cc2cf37a657096ef48b4c65171de1f123e33fc4dd1be" }, "pipfile-spec": 6, "requires": { @@ -903,6 +903,64 @@ } }, "develop": { + "cffi": { + "hashes": [ + "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", + "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", + "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", + "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", + "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", + "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", + "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", + "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", + "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", + "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", + "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", + "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", + "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", + "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", + "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", + "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", + "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", + "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", + "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", + "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", + "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", + "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", + "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", + "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", + "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", + "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", + "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", + "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", + "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", + "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", + "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", + "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", + "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", + "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", + "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", + "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", + "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", + "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", + "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", + "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", + "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", + "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", + "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", + "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", + "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", + "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", + "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", + "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", + "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", + "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", + "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", + "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357" + ], + "markers": "platform_python_implementation != 'PyPy'", + "version": "==1.16.0" + }, "cfgv": { "hashes": [ "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", @@ -911,6 +969,44 @@ "markers": "python_version >= '3.8'", "version": "==3.4.0" }, + "cryptography": { + "hashes": [ + "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", + "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", + "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", + "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", + "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", + "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", + "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", + "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", + "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", + "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", + "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", + "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", + "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", + "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", + "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", + "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", + "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", + "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", + "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", + "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", + "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", + "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", + "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", + "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", + "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", + "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", + "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", + "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", + "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", + "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", + "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", + "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" + ], + "markers": "python_version >= '3.6'", + "version": "==42.0.5" + }, "distlib": { "hashes": [ "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784", @@ -934,6 +1030,48 @@ "markers": "python_version >= '3.8'", "version": "==2.5.36" }, + "mypy": { + "hashes": [ + "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061", + "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99", + "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de", + "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a", + "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9", + "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec", + "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1", + "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131", + "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f", + "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821", + "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5", + "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee", + "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e", + "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746", + "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2", + "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0", + "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b", + "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53", + "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30", + "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda", + "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051", + "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2", + "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7", + "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee", + "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727", + "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976", + "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.10.0" + }, + "mypy-extensions": { + "hashes": [ + "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", + "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.0" + }, "nodeenv": { "hashes": [ "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2", @@ -942,6 +1080,48 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", "version": "==1.8.0" }, + "numpy": { + "hashes": [ + "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b", + "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818", + "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", + "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0", + "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", + "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", + "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea", + "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c", + "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", + "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110", + "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be", + "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", + "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", + "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", + "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed", + "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd", + "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c", + "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", + "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0", + "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c", + "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", + "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b", + "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", + "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6", + "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", + "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a", + "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30", + "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218", + "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", + "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", + "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", + "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", + "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764", + "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", + "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3", + "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f" + ], + "markers": "python_version >= '3.9'", + "version": "==1.26.4" + }, "platformdirs": { "hashes": [ "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf", @@ -959,6 +1139,14 @@ "markers": "python_version >= '3.9'", "version": "==3.7.0" }, + "pycparser": { + "hashes": [ + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" + ], + "markers": "python_version >= '3.8'", + "version": "==2.22" + }, "pyyaml": { "hashes": [ "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5", @@ -1024,6 +1212,702 @@ "markers": "python_version >= '3.8'", "version": "==69.5.1" }, + "tomli": { + "hashes": [ + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + ], + "markers": "python_version < '3.11'", + "version": "==2.0.1" + }, + "types-aiofiles": { + "hashes": [ + "sha256:1ffcf8f5f72b81f71139f754ea2610ab0017f27ba4fd771e187b07840ee49c0f", + "sha256:adeeb4b999f19fda2dfe91c07857ff54701b6ee9b227b523a5a7be92125a2c5f" + ], + "markers": "python_version >= '3.8'", + "version": "==23.2.0.20240403" + }, + "types-all": { + "hashes": [ + "sha256:5de4a3c9f9c5687978fd05c3bc08e6b70b0c4c093a50e3ef866bbe50c5534a68", + "sha256:b61d204c31b733e4296e666399c0ecf829844ab7080d77e5404fa55ef1d7d972" + ], + "index": "pypi", + "markers": "python_full_version >= '3.6.1'", + "version": "==1.0.0" + }, + "types-annoy": { + "hashes": [ + "sha256:3cb135d7b5fdda0c87fea9bf5cbeb6eead3f7d880cc7c9e3e9fe7ab06d8f5a0b", + "sha256:73a6d3f93a8bfbd5e800635a6a59722818baeac9e1c2895c039aafe3b6a7d35a" + ], + "version": "==1.17.8.4" + }, + "types-atomicwrites": { + "hashes": [ + "sha256:2f1febbdc78b55453b189fa5b136dce34bab7d1d82319163d470e404aab55c83", + "sha256:9e9f0923ebf93524b28bcece5a23ac8c3820f39b060df29f671936d2e4bc04bc" + ], + "version": "==1.4.5.1" + }, + "types-backports": { + "hashes": [ + "sha256:dafcd61848081503e738a7768872d1dd6c018401b4d2a1cfb608ea87ec9864b9", + "sha256:f4b7206c073df88d6200891e3d27506185fd60cda66fb289737b2fa92c0010cf" + ], + "version": "==0.1.3" + }, + "types-backports-abc": { + "hashes": [ + "sha256:044266599faaaea85af6e8409cdc5894aa228885326ef5769c65dd45d96a9560", + "sha256:4c35baaafafe1f5a06d0a6b3b080553c274a79071dfeb30bc2dd5a8633f8b65d" + ], + "version": "==0.5.2" + }, + "types-bleach": { + "hashes": [ + "sha256:2ee858a84fb06fc2225ff56ba2f7f6c88b65638659efae0d7bfd6b24a1b5a524", + "sha256:399bc59bfd20a36a56595f13f805e56c8a08e5a5c07903e5cf6fafb5a5107dd4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.1.0.20240331" + }, + "types-boto": { + "hashes": [ + "sha256:6c7f3945e5759e1f8a760e2843adbeb1eea64f869f3a3070af7cfcfc25ea71bd", + "sha256:9873214ce37756a6145c165fb9beaf80cb4ac1df5a5967f6a0945109c8c4469a" + ], + "markers": "python_version >= '3.8'", + "version": "==2.49.18.20240205" + }, + "types-cachetools": { + "hashes": [ + "sha256:27c982cdb9cf3fead8b0089ee6b895715ecc99dac90ec29e2cab56eb1aaf4199", + "sha256:98c069dc7fc087b1b061703369c80751b0a0fc561f6fb072b554e5eee23773a0" + ], + "markers": "python_version >= '3.7'", + "version": "==5.3.0.7" + }, + "types-certifi": { + "hashes": [ + "sha256:72cf7798d165bc0b76e1c10dd1ea3097c7063c42c21d664523b928e88b554a4f", + "sha256:b2d1e325e69f71f7c78e5943d410e650b4707bb0ef32e4ddf3da37f54176e88a" + ], + "version": "==2021.10.8.3" + }, + "types-cffi": { + "hashes": [ + "sha256:a363e5ea54a4eb6a4a105d800685fde596bc318089b025b27dee09849fe41ff0", + "sha256:b8b20d23a2b89cfed5f8c5bc53b0cb8677c3aac6d970dbc771e28b9c698f5dee" + ], + "markers": "python_version >= '3.8'", + "version": "==1.16.0.20240331" + }, + "types-characteristic": { + "hashes": [ + "sha256:d49837535be1e336572d668fc794b2dab9df08e4477aa5ca37f874cd31503b87", + "sha256:de01956d96521389a9bc670b8fab49fd9602ed5def29af5744452455ef446bc7" + ], + "version": "==14.3.7" + }, + "types-chardet": { + "hashes": [ + "sha256:caf4c74cd13ccfd8b3313c314aba943b159de562a2573ed03137402b2bb37818", + "sha256:ea832d87e798abf1e4dfc73767807c2b7fee35d0003ae90348aea4ae00fb004d" + ], + "version": "==5.0.4.6" + }, + "types-click": { + "hashes": [ + "sha256:8cb030a669e2e927461be9827375f83c16b8178c365852c060a34e24871e7e81", + "sha256:b6604968be6401dc516311ca50708a0a28baa7a0cb840efd7412f0dbbff4e092" + ], + "version": "==7.1.8" + }, + "types-click-spinner": { + "hashes": [ + "sha256:b32e73aebee90f65190123d5bd58cd04f4eb2d2f4a2ce4eecb0d592d80dabf5b", + "sha256:f780cf995f615b2ab5119c81a7e30719da1ce33c61cad6d947cb1236d6d7e04e" + ], + "markers": "python_version >= '3.8'", + "version": "==0.1.13.20240311" + }, + "types-colorama": { + "hashes": [ + "sha256:6391de60ddc0db3f147e31ecb230006a6823e81e380862ffca1e4695c13a0b8e", + "sha256:a28e7f98d17d2b14fb9565d32388e419f4108f557a7d939a66319969b2b99c7a" + ], + "markers": "python_version >= '3.8'", + "version": "==0.4.15.20240311" + }, + "types-contextvars": { + "hashes": [ + "sha256:a15a1624c709d04974900ea4f8c4fc2676941bf7d4771a9c9c4ac3daa0e0060d", + "sha256:bcd8e97a5b58e76d20f5cc161ba39b29b60ac46dcc6edf3e23c1d33f99b34351" + ], + "version": "==2.4.7.3" + }, + "types-croniter": { + "hashes": [ + "sha256:30f8e4d7ff39c39a3cabc17bfc5186a49f6d4807d9c7177e5fa9b0c2cfe3b073", + "sha256:73c0e068c6ac5abc8ffed2d9828c8a38ebae9a2d32af8fcd6bc5c680c79b64b6" + ], + "markers": "python_version >= '3.8'", + "version": "==2.0.0.20240423" + }, + "types-cryptography": { + "hashes": [ + "sha256:09cc53f273dd4d8c29fa7ad11fefd9b734126d467960162397bc5e3e604dea75", + "sha256:b965d548f148f8e87f353ccf2b7bd92719fdf6c845ff7cedf2abb393a0643e4f" + ], + "version": "==3.3.23.2" + }, + "types-dataclasses": { + "hashes": [ + "sha256:4b5a2fcf8e568d5a1974cd69010e320e1af8251177ec968de7b9bb49aa49f7b9", + "sha256:a0a1ab5324ba30363a15c9daa0f053ae4fff914812a1ebd8ad84a08e5349574d" + ], + "version": "==0.6.6" + }, + "types-dateparser": { + "hashes": [ + "sha256:8f813ddf5ef41b32cabe6167138ae833ada10c22811e42220a1e38a0be7adbdc", + "sha256:bf3695ddfbadfdfc875064895a51d926fd80b04da1a44364c6c1a9703db7b194" + ], + "markers": "python_version >= '3.8'", + "version": "==1.2.0.20240420" + }, + "types-datetimerange": { + "hashes": [ + "sha256:767990370f571d6a6da89ea47a43a9bc78ec891deb20f06190be3e6f6408b36c", + "sha256:a173c317691f0c98f4d86a8e2c9691550994be9c598ed7d8b8a6c6057a7e754c" + ], + "version": "==2.0.0.6" + }, + "types-decorator": { + "hashes": [ + "sha256:3af75dc38f5baf65b9b53ea6661ce2056c5ca7d70d620d0b1f620285c1242757", + "sha256:52e316b03783886a8a2abdc228f7071680ba65894545cd2085ebe3cf88684a0e" + ], + "markers": "python_version >= '3.8'", + "version": "==5.1.8.20240310" + }, + "types-deprecated": { + "hashes": [ + "sha256:0680e89989a8142707de8103f15d182445a533c1047fd9b7e8c5459101e9b90a", + "sha256:d7793aaf32ff8f7e49a8ac781de4872248e0694c4b75a7a8a186c51167463f9d" + ], + "markers": "python_version >= '3.8'", + "version": "==1.2.9.20240311" + }, + "types-docopt": { + "hashes": [ + "sha256:694fc67fc3b15733b65d3f07aa1eefc08212a0e2515dd39535ca81f45d3ac3e3", + "sha256:991a64c1569310c2240ae734fd2c10627abb8a4afaf3be5ac6f4eff9a601f31a" + ], + "version": "==0.6.11.4" + }, + "types-docutils": { + "hashes": [ + "sha256:7716ec6c68b5179b7ba1738cace2f1326e64df9f44b7ab08d9904d32c23fc15f", + "sha256:7f6e84ba8fcd2454c5b8bb8d77384d091a901929cc2b31079316e10eb346580a" + ], + "markers": "python_version >= '3.8'", + "version": "==0.21.0.20240423" + }, + "types-emoji": { + "hashes": [ + "sha256:32fe5cf02c4834bb59579380f600a89d1471571fb56e36465cbd0c7d95f669ca", + "sha256:98ddb0ff5f48622550c431206e4dbfcbde8ca8bc03fcfbb9962a778d2049aa13" + ], + "version": "==2.1.0.3" + }, + "types-enum34": { + "hashes": [ + "sha256:05058c7a495f6bfaaca0be4aeac3cce5cdd80a2bad2aab01fd49a20bf4a0209d", + "sha256:6f9c769641d06d73a55e11c14d38ac76fcd37eb545ce79cebb6eec9d50a64110" + ], + "version": "==1.1.8" + }, + "types-fb303": { + "hashes": [ + "sha256:3492e36567729fdb487e7b4388f8cc66f8d9e55a8cc8dff3fe7d18ca3e7c4841", + "sha256:80f21d51c8075cf8d902b1048f2de6b8bc3dfd67c01d8c7b72984021293ff1b9" + ], + "version": "==1.0.0" + }, + "types-filelock": { + "hashes": [ + "sha256:0673a25b45725c5c45661fe3744c3d8058653a16e683f0ae4a74afb44a0cdef4", + "sha256:ee0ee2b4ec3d491ebe71f7343e21435c3a07f910881275a94788cac42acf4339" + ], + "version": "==3.2.7" + }, + "types-first": { + "hashes": [ + "sha256:342c2d99d3a2bf43c281b2de5d08f83c65ac1b2320af04b0f878ea2bc8ba390c", + "sha256:4115d28bdb52542531f70ccb1a044802f597d8fb3e4e55f65c23f522e1086d1f" + ], + "version": "==2.0.5.2" + }, + "types-flask": { + "hashes": [ + "sha256:6ab8a9a5e258b76539d652f6341408867298550b19b81f0e41e916825fc39087", + "sha256:aac777b3abfff9436e6b01f6d08171cf23ea6e5be71cbf773aaabb1c5763e9cf" + ], + "version": "==1.1.6" + }, + "types-freezegun": { + "hashes": [ + "sha256:cb3a2d2eee950eacbaac0673ab50499823365ceb8c655babb1544a41446409ec", + "sha256:fadebe72213e0674036153366205038e1f95c8ca96deb4ef9b71ddc15413543e" + ], + "version": "==1.1.10" + }, + "types-frozendict": { + "hashes": [ + "sha256:446b5f33125566c9885c31363e065d6416f8da6c81252af1e459a4e67a15487b", + "sha256:d4292ef14f87ddec575ab1d968102dcba2c8f1e490acc67945eee1fc7de24d08" + ], + "version": "==2.0.9" + }, + "types-futures": { + "hashes": [ + "sha256:6fe8ccc2c2af7ef2fdd9bf73eab6d617074f09f30ad7d373510b4043d39c42de", + "sha256:d6e97ec51d56b96debfbf1dea32ebec22c1687f16d2547ea0a34b48db45df205" + ], + "version": "==3.3.8" + }, + "types-geoip2": { + "hashes": [ + "sha256:75ce236f3d98529b44b2dddf91476178ff0d088f33414b206253594936613574", + "sha256:d79d7e261365575de12047e4ef8774c4b216e16e3b1f6dd45de6c7a2cb2e563c" + ], + "version": "==3.0.0" + }, + "types-html5lib": { + "hashes": [ + "sha256:22736b7299e605ec4ba539d48691e905fd0c61c3ea610acc59922232dc84cede", + "sha256:af5de0125cb0fe5667543b158db83849b22e25c0e36c9149836b095548bf1020" + ], + "markers": "python_version >= '3.8'", + "version": "==1.1.11.20240228" + }, + "types-ipaddress": { + "hashes": [ + "sha256:4933b74da157ba877b1a705d64f6fa7742745e9ffd65e51011f370c11ebedb55", + "sha256:a03df3be5935e50ba03fa843daabff539a041a28e73e0fce2c5705bee54d3841" + ], + "version": "==1.0.8" + }, + "types-itsdangerous": { + "hashes": [ + "sha256:21c6966c10e353a5d35d36c82aaa2c5598d3bc32ddc8e0591276da5ad2e3c638", + "sha256:aef2535c2fa0527dcce244ece0792b20ec02ee46533800735275f82a45a0244d" + ], + "version": "==1.1.6" + }, + "types-jack-client": { + "hashes": [ + "sha256:220514c2783575da88e8ea5a0f1b7b850c7ece2612214169cecff0f05dfb6dc8", + "sha256:7ae020b594c683ca7ad5f8b4f6355c2fc7c42f0bf947f60193bf40c8f6a46251" + ], + "markers": "python_version >= '3.8'", + "version": "==0.5.10.20240425" + }, + "types-jinja2": { + "hashes": [ + "sha256:60a1e21e8296979db32f9374d8a239af4cb541ff66447bb915d8ad398f9c63b2", + "sha256:dbdc74a40aba7aed520b7e4d89e8f0fe4286518494208b35123bcf084d4b8c81" + ], + "version": "==2.11.9" + }, + "types-kazoo": { + "hashes": [ + "sha256:885cb481b2af327f6ecae725c9e2770ece454c675b94ea5e367dbc76243e7418", + "sha256:97a3b95e2437fcc093506e822b009c1ee9e4db6906631b5320117f0d2be4aa4a" + ], + "version": "==0.1.3" + }, + "types-markdown": { + "hashes": [ + "sha256:d3ecd26a940781787c7b57a0e3c9d77c150db64e12989ef687059edc83dfd78a", + "sha256:de9fb84860b55b647b170ca576895fcca61b934a6ecdc65c31932c6795b440b8" + ], + "markers": "python_version >= '3.8'", + "version": "==3.6.0.20240316" + }, + "types-markupsafe": { + "hashes": [ + "sha256:85b3a872683d02aea3a5ac2a8ef590193c344092032f58457287fbf8e06711b1", + "sha256:ca2bee0f4faafc45250602567ef38d533e877d2ddca13003b319c551ff5b3cc5" + ], + "version": "==1.1.10" + }, + "types-maxminddb": { + "hashes": [ + "sha256:4bdcd434a6f12feefbe1fa569cc202b15556cb5a5aec38f1008446516a36dc36", + "sha256:9146df7098d834d5f584d2393af85ef9294c67a16ace991f1635a2aa331f7854" + ], + "version": "==1.5.0" + }, + "types-mock": { + "hashes": [ + "sha256:5281a645d72e827d70043e3cc144fe33b1c003db084f789dc203aa90e812a5a4", + "sha256:d586a01d39ad919d3ddcd73de6cde73ca7f3c69707219f722d1b8d7733641ad7" + ], + "markers": "python_version >= '3.8'", + "version": "==5.1.0.20240425" + }, + "types-mypy-extensions": { + "hashes": [ + "sha256:5bd57d5c6bf07b5a8db3c1b70df52c1570cab34a69a631e31d755c003d1a9da7", + "sha256:a482ec81320658aaf14600f7dd8e6e3bc76394cdae1a8f403c5fa36300068248" + ], + "markers": "python_version >= '3.8'", + "version": "==1.0.0.20240311" + }, + "types-nmap": { + "hashes": [ + "sha256:ed1f7f6bf280845e938549e70455a7a081cb8280e987b56caf93ddddd32317b8", + "sha256:fc4446bc3bcbf19839fbb5bc0ddd6248f02b46863818e701216a84ee5ab14320" + ], + "version": "==0.1.6" + }, + "types-openssl-python": { + "hashes": [ + "sha256:8f58ebae880550412f8aad619a7615e49471de2766dfc35aa7faa5609d01ffe5" + ], + "version": "==0.1.3" + }, + "types-orjson": { + "hashes": [ + "sha256:22ee9a79236b6b0bfb35a0684eded62ad930a88a56797fa3c449b026cf7dbfe4", + "sha256:cf9afcc79a86325c7aff251790338109ed6f6b1bab09d2d4262dd18c85a3c638" + ], + "version": "==3.6.2" + }, + "types-paramiko": { + "hashes": [ + "sha256:aaa98dda232c47886563d66743d3a8b66c432790c596bc3bdd3f17f91be2a8c1", + "sha256:c56e0d43399a1b909901b1e0375e0ff6ee62e16cd6e00695024abc2e9fe02035" + ], + "markers": "python_version >= '3.8'", + "version": "==3.4.0.20240423" + }, + "types-pathlib2": { + "hashes": [ + "sha256:996981d3c39a3dd592bac06b4d87257c623f1acc3eef672f823d85c528b7a6ed", + "sha256:c69db9ca95e4577ddbca19abbab5d387fa55f40d5475b45854bfa1c2d0604c37" + ], + "version": "==2.3.0" + }, + "types-pillow": { + "hashes": [ + "sha256:696e68b9b6a58548fc307a8669830469237c5b11809ddf978ac77fafa79251cd", + "sha256:bd12923093b96c91d523efcdb66967a307f1a843bcfaf2d5a529146c10a9ced3" + ], + "markers": "python_version >= '3.8'", + "version": "==10.2.0.20240423" + }, + "types-pkg-resources": { + "hashes": [ + "sha256:0cb9972cee992249f93fff1a491bf2dc3ce674e5a1926e27d4f0866f7d9b6d9c", + "sha256:834a9b8d3dbea343562fd99d5d3359a726f6bf9d3733bccd2b4f3096fbab9dae" + ], + "version": "==0.1.3" + }, + "types-polib": { + "hashes": [ + "sha256:8cf6746e87f652599f06ac755fdd61e4582c756e7714f393fc6a89a8e8a5b152", + "sha256:d86add535343c293d3f94a16caca6ec3110ccc194a144743769f146cef6fa30d" + ], + "markers": "python_version >= '3.8'", + "version": "==1.2.0.20240327" + }, + "types-protobuf": { + "hashes": [ + "sha256:e4dc2554d342501d5aebc3c71203868b51118340e105fc190e3a64ca1be43831", + "sha256:e6074178109f97efe9f0b20a035ba61d7c3b03e867eb47d254d2b2ab6a805e36" + ], + "markers": "python_version >= '3.8'", + "version": "==5.26.0.20240422" + }, + "types-pyaudio": { + "hashes": [ + "sha256:b6649ed7229ee201e5ac4955595dccfd5acb78d22f688646a389868ea7b56700", + "sha256:dbe096f18ebe289557ec40689e35d03558ab43be99686143286e3b0cd769584f" + ], + "markers": "python_version >= '3.8'", + "version": "==0.2.16.20240425" + }, + "types-pycurl": { + "hashes": [ + "sha256:0d5b3b9243e3940e26b782c1cdc0b2438d244ee2e8dcde09cf523635a42ff406", + "sha256:c20b56426cd67e4a80682d054391f6bab725d5fc31baae0c3eef9bbec00629c3" + ], + "markers": "python_version >= '3.8'", + "version": "==7.45.3.20240421" + }, + "types-pyfarmhash": { + "hashes": [ + "sha256:358b94bd2976fcc2eeb453d0ca69566ae2a797f85e5034c1d4c6fc8545bd815a", + "sha256:b3a377f1026831b6144ed3a5381c8009bcff870fb67cdbfad4cd22f63f221f2e" + ], + "markers": "python_version >= '3.8'", + "version": "==0.3.1.20240311" + }, + "types-pyjwt": { + "hashes": [ + "sha256:810112a84b6c060bb5bc1959a1d229830465eccffa91d8a68eeaac28fb7713ac", + "sha256:99c1a0d94d370951f9c6e57b1c369be280b2cbfab72c0f9c0998707490f015c9" + ], + "version": "==1.7.1" + }, + "types-pymssql": { + "hashes": [ + "sha256:3a531f46f559bbedf242bde7c8dbee18200c32e830522fcc4c67ebf96215a169", + "sha256:72e04114ce360a0606c3e78caab036636928ad52c4dd839e057932342774763e" + ], + "version": "==2.1.0" + }, + "types-pymysql": { + "hashes": [ + "sha256:32a472233de53b913e934695530a2d083146b81ed6de1669ecb845f76b6ddc15", + "sha256:afe24e8eba5f4851b729835530a1698b1b1645a93f9f9c83ae45228866ed31fc" + ], + "markers": "python_version >= '3.8'", + "version": "==1.1.0.20240425" + }, + "types-pyopenssl": { + "hashes": [ + "sha256:0a7e82626c1983dc8dc59292bf20654a51c3c3881bcbb9b337c1da6e32f0204e", + "sha256:f51a156835555dd2a1f025621e8c4fbe7493470331afeef96884d1d29bf3a473" + ], + "markers": "python_version >= '3.8'", + "version": "==24.1.0.20240425" + }, + "types-pyrfc3339": { + "hashes": [ + "sha256:713b106361aa1d72ea607bf9f91e3bbe76e228df2b9346c60fca434ac60ff389", + "sha256:e45e8f4d039bc0c7e32e1c19bb915a01e8c2768f776996f1a4763efc654d8c51" + ], + "version": "==1.1.1.5" + }, + "types-pysftp": { + "hashes": [ + "sha256:bc10840e16edbc4a3876628fda3c0cc7da94769b849896e0bf85d4f178261136", + "sha256:d3615ee38c8381ab415ca004223e12c8e36524d400a9911cb91504d875778323" + ], + "markers": "python_version >= '3.8'", + "version": "==0.2.17.20240106" + }, + "types-python-dateutil": { + "hashes": [ + "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202", + "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b" + ], + "markers": "python_version >= '3.8'", + "version": "==2.9.0.20240316" + }, + "types-python-gflags": { + "hashes": [ + "sha256:15b3d64a0095143433bc56d90d330e1c3c0e114daad3cd927f53ebecdfbffdf6", + "sha256:f5dafd8d47235b4a195333c8ee41994077f40dac1d1a9ac6fcf95b93a47caff5" + ], + "version": "==3.1.7.3" + }, + "types-python-slugify": { + "hashes": [ + "sha256:0efec18b802c69ebd22dcee55c91afaeaa80e1e40ddd66ccabf69fd42ce87b74", + "sha256:5157b508c7fed587520c70d77f62aea0fafdc6620893c2ec8972f13a1faf5560" + ], + "markers": "python_version >= '3.8'", + "version": "==8.0.2.20240310" + }, + "types-pytz": { + "hashes": [ + "sha256:6810c8a1f68f21fdf0f4f374a432487c77645a0ac0b31de4bf4690cf21ad3981", + "sha256:8335d443310e2db7b74e007414e74c4f53b67452c0cb0d228ca359ccfba59659" + ], + "markers": "python_version >= '3.8'", + "version": "==2024.1.0.20240417" + }, + "types-pyvmomi": { + "hashes": [ + "sha256:494114a0ff30fa9cfe80dbd940308757586c836717803d8cb8af90f4f3190932", + "sha256:f1d95b25ce460cef6c2169053dbacfdab3872a2d30d184f1c3b3b2f0ba94be73" + ], + "version": "==8.0.0.6" + }, + "types-pyyaml": { + "hashes": [ + "sha256:a9e0f0f88dc835739b0c1ca51ee90d04ca2a897a71af79de9aec5f38cb0a5342", + "sha256:b845b06a1c7e54b8e5b4c683043de0d9caf205e7434b3edc678ff2411979b8f6" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.12.20240311" + }, + "types-redis": { + "hashes": [ + "sha256:9402a10ee931d241fdfcc04592ebf7a661d7bb92a8dea631279f0d8acbcf3a22", + "sha256:ac5bc19e8f5997b9e76ad5d9cf15d0392d9f28cf5fc7746ea4a64b989c45c6a8" + ], + "markers": "python_version >= '3.8'", + "version": "==4.6.0.20240425" + }, + "types-requests": { + "hashes": [ + "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1", + "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5" + ], + "markers": "python_version >= '3.8'", + "version": "==2.31.0.20240406" + }, + "types-retry": { + "hashes": [ + "sha256:e4731dc684b56b875d9746459ad665d3bc281a56b530acdf1c97730167799941", + "sha256:f29760a9fe8b1fefe253e5fe6be7e4c0eba243932c600e0eccffb42a21d17765" + ], + "version": "==0.9.9.4" + }, + "types-routes": { + "hashes": [ + "sha256:9267c82633b8866bde9a1fa594c6040ca8fda29e7cc9a0e633a24b7900aa957e", + "sha256:df7ab143c02821a749a4ba7c26fc697c2482c8fcb8f3032c509eecfcaf6d5951" + ], + "version": "==2.5.0" + }, + "types-scribe": { + "hashes": [ + "sha256:8d8a4bff3d663af5de66fbbb30c5962acd242008dbdbcdb6e7e3d2781dc0584b", + "sha256:c302f6ae55a1d9a5f4c83754deccf85674cf6807683b2df5e66be41a1f2a2655" + ], + "version": "==2.0.0" + }, + "types-setuptools": { + "hashes": [ + "sha256:a4381e041510755a6c9210e26ad55b1629bc10237aeb9cb8b6bd24996b73db48", + "sha256:a7ba908f1746c4337d13f027fa0f4a5bcad6d1d92048219ba792b3295c58586d" + ], + "markers": "python_version >= '3.8'", + "version": "==69.5.0.20240423" + }, + "types-simplejson": { + "hashes": [ + "sha256:2831366f70d5d55832c3d978dff7c989575d55fb38621d086dbfee7a30c2b500", + "sha256:6f06d8e50112bc931863a40e2cf463a99223d55fe07f275826fa969962bb56a4" + ], + "markers": "python_version >= '3.8'", + "version": "==3.19.0.20240310" + }, + "types-singledispatch": { + "hashes": [ + "sha256:0b4cc46bb876a67263e807225b6542983f913e5d17cab45fdfc758854770a66f", + "sha256:93f113ea22d66290821c0b59f87028e65c64160a5a62f77c3e1a5a586bee72e5" + ], + "version": "==4.1.0.0" + }, + "types-six": { + "hashes": [ + "sha256:1e924f823cdc2142670c942527f71b49912e6954b3b85388cd0cc1259ad4bfcf", + "sha256:378f8baa5b693e4f8a284e8f7b0b34c682210848900816788e19ee4712de8f59" + ], + "markers": "python_version >= '3.8'", + "version": "==1.16.21.20240425" + }, + "types-tabulate": { + "hashes": [ + "sha256:0378b7b6fe0ccb4986299496d027a6d4c218298ecad67199bbd0e2d7e9d335a1", + "sha256:c9b6db10dd7fcf55bd1712dd3537f86ddce72a08fd62bb1af4338c7096ce947e" + ], + "markers": "python_version >= '3.8'", + "version": "==0.9.0.20240106" + }, + "types-termcolor": { + "hashes": [ + "sha256:44c4c762c54a90d99b5c1033ef008aaa5610056d31d5c66b9288a942682a64d7", + "sha256:d8f0f69cf5552cc59ce75aa5172937cec9b320c17453adefe4168b93d16daad6" + ], + "version": "==1.1.6.2" + }, + "types-toml": { + "hashes": [ + "sha256:3d41501302972436a6b8b239c850b26689657e25281b48ff0ec06345b8830331", + "sha256:627b47775d25fa29977d9c70dc0cbab3f314f32c8d8d0c012f2ef5de7aaec05d" + ], + "markers": "python_version >= '3.8'", + "version": "==0.10.8.20240310" + }, + "types-tornado": { + "hashes": [ + "sha256:331c0069ff527ddeab4c38e2ee2bb0738dbd5ce04d536d9c0209d4c6de25b359", + "sha256:69b603360db4e64453dcb932efa9a152d7fd99bf7553b67902c9a3ecf4ba57e7" + ], + "version": "==5.1.1" + }, + "types-typed-ast": { + "hashes": [ + "sha256:97bdd9b4228f96c6904a76e10a050305ddadb529bd35e4d8234711e09c41b543", + "sha256:f7795f6f9d597b35212314040b993f6613b51d81738edce3c1e3a3e9ef655124" + ], + "version": "==1.5.8.7" + }, + "types-tzlocal": { + "hashes": [ + "sha256:0302e8067c86936de8f7e0aaedc2cfbf240080802c603df0f80312fbd4efb926", + "sha256:b84a115c0c68f0d0fa9af1c57f0645eeef0e539147806faf1f95ac3ac01ce47b" + ], + "markers": "python_version >= '3.7'", + "version": "==5.1.0.1" + }, + "types-ujson": { + "hashes": [ + "sha256:7e7042454dc7cd7f31b09c420d7caf36b93d30bdf4b8db93791bd0561713d017", + "sha256:f274fa604ed6317effcd1c424ef4cf292c3b0689cb118fb3180689d40ed1f4ed" + ], + "markers": "python_version >= '3.7'", + "version": "==5.9.0.0" + }, + "types-waitress": { + "hashes": [ + "sha256:7e9f77a3bc3c20436b9b7ef93da88c8fe0d1e2205d5891ae7526cbd93554f5a4", + "sha256:ec3af592b5868ccf151645afc74d2e606cd5dec3ed326c9fd0259691b39430fe" + ], + "markers": "python_version >= '3.8'", + "version": "==3.0.0.20240423" + }, + "types-werkzeug": { + "hashes": [ + "sha256:194bd5715a13c598f05c63e8a739328657590943bce941e8a3619a6b5d4a54ec", + "sha256:5cc269604c400133d452a40cee6397655f878fc460e03fde291b9e3a5eaa518c" + ], + "version": "==1.0.9" + }, + "types-xxhash": { + "hashes": [ + "sha256:3e531728e168f64d7e8aa960a7633f4a6087e2875f349c2b962b2a66195eea50", + "sha256:99f27f0af146beba2f108677d2b7980afe8ddf7359b445181bfc7139db76482e" + ], + "version": "==3.0.5.2" + }, + "typing-extensions": { + "hashes": [ + "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0", + "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a" + ], + "markers": "python_version >= '3.8'", + "version": "==4.11.0" + }, + "urllib3": { + "hashes": [ + "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", + "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + ], + "markers": "python_version >= '3.8'", + "version": "==2.2.1" + }, "virtualenv": { "hashes": [ "sha256:604bfdceaeece392802e6ae48e69cec49168b9c5f4a44e483963f9242eb0e78b", diff --git a/api/api.py b/api/api.py index d7fcf34..dc74d6e 100644 --- a/api/api.py +++ b/api/api.py @@ -189,16 +189,16 @@ def make_filter_query(filter: Filter): if subfilter.comparison == "starts with": subfilter.value = f"{subfilter.value}%" - subfilter.comparison = "ILIKE" + subfilter.comparison = "ILIKE" # type: ignore elif subfilter.comparison == "ends with": subfilter.value = f"%{subfilter.value}" - subfilter.comparison = "ILIKE" + subfilter.comparison = "ILIKE" # type: ignore elif subfilter.comparison == "contains": subfilter.value = f"%{subfilter.value}%" - subfilter.comparison = "ILIKE" + subfilter.comparison = "ILIKE" # type: ignore elif subfilter.comparison == "does not contain": subfilter.value = f"%{subfilter.value}%" - subfilter.comparison = "NOT ILIKE" + subfilter.comparison = "NOT ILIKE" # type: ignore filter_query = sql.SQL( "{filter_query} ({parameter} {comparison} {value})" @@ -211,7 +211,7 @@ def make_filter_query(filter: Filter): if i != len(filter.filters) - 1: filter_query = sql.SQL("{filter_query} {method}").format( - filter_query=filter_query, method=sql.SQL(filter["method"]) + filter_query=filter_query, method=sql.SQL(filter.method) ) i += 1 @@ -260,83 +260,85 @@ def get_intersection() -> tuple[Response, Literal[400]] | Response: top=sql.Literal(bbox.t), ) - first: Filter = filters[0] - - first_query: sql.Composed = sql.SQL( - "SELECT tags->'name' AS name, ST_Centroid(way) AS point_geom, way AS geom FROM {table}" + envelope_cte: sql.Composed = sql.SQL( + "WITH envelope AS (SELECT ST_Transform(ST_MakeEnvelope({left}, {bottom}, {right}, {top}, 4326), 3857) AS geom)" ).format( - table=( - sql.SQL("planet_osm_line") - if first.type == "line" - else ( - sql.SQL("planet_osm_polygon") - if first.type == "polygon" - else ( - sql.SQL("planet_osm_point") - if first.type == "point" - else sql.SQL("planet_osm") - ) - ) - ) + left=sql.Literal(bbox.l), + bottom=sql.Literal(bbox.b), + right=sql.Literal(bbox.r), + top=sql.Literal(bbox.t), ) - first_filter: sql.Composed | sql.Sql = make_filter_query(first) - first_assembled: sql.Composed = sql.SQL("{query} WHERE ({filter}) {bbox}").format( - query=first_query, filter=first_filter, bbox=bbox_filter + + first: Filter = filters.pop(0) + match first.type: + case "point": + main_table = sql.SQL("planet_osm_point") + case "line": + main_table = sql.SQL("planet_osm_line") + case "polygon": + main_table = sql.SQL("planet_osm_polygon") + case "any": + main_table = sql.SQL("planet_osm") + + initial_subtable = sql.SQL( + """initial_table AS (SELECT tags->'name' AS name, ST_Transform(ST_Centroid(way), 4326) AS point_geom, way AS geom FROM {main_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" + ).format(main_table=main_table, filter=make_filter_query(first), bbox=bbox_filter) + + query = sql.SQL("{envelope_cte}, {initial_subtable}").format( + envelope_cte=envelope_cte, initial_subtable=initial_subtable ) logger.info(f"Buffer: {buffer}\tFilters: {filters}\tBbox: {str(bbox)}") - subqueries: list[sql.Composed] = [] - for f in filters[1:]: + for i, f in enumerate(filters): filter = make_filter_query(f) - if f.type == "point": - source_query = sql.SQL("SELECT way AS geom FROM planet_osm_point") - elif f.type == "line": - source_query = sql.SQL("SELECT way AS geom FROM planet_osm_line") - elif f.type == "polygon": - source_query = sql.SQL("SELECT way AS geom FROM planet_osm_polygon") - elif f.type == "any": - source_query = sql.SQL("SELECT way AS geom FROM planet_osm") - - assembled: sql.Composed = sql.SQL("{query} WHERE ({filter}) {bbox}").format( - query=source_query, filter=filter, bbox=bbox_filter - ) - subqueries.append(assembled) + match f.type: + case "point": + source_table = sql.SQL("planet_osm_point") + case "line": + source_table = sql.SQL("planet_osm_line") + case "polygon": + source_table = sql.SQL("planet_osm_polygon") + case "any": + source_table = sql.SQL("planet_osm") - join_query: sql.Composed = sql.SQL( - "SELECT DISTINCT point_geom, name, ST_Y(ST_Transform(point_geom, 4326)) AS lat, ST_X(ST_Transform(point_geom, 4326)) as lng FROM ({point}) point " - ).format(point=first_assembled) + assembled: sql.Composed = sql.SQL( + """subquery{index} AS (SELECT way AS geom FROM {source_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" + ).format(index=sql.SQL(str(i)), source_table=source_table, filter=filter) - i = 0 - for q in subqueries: - join_query = sql.SQL( - "{join_query} JOIN ({q}) {subindex} ON ST_DWithin(point.geom, {subindex}.geom, {buffer})" - ).format( - join_query=join_query, - q=q, - subindex=sql.SQL("subquery" + str(i)), - buffer=sql.Literal(buffer), - ) - i += 1 + query = sql.SQL("{query}, {assembled}").format(query=query, assembled=assembled) - join_query = sql.SQL("{join_query} LIMIT 100").format(join_query=join_query) + select_statement = sql.SQL( + "SELECT DISTINCT point_geom, name, ST_Y(point_geom) AS lat, ST_X(point_geom) AS lng FROM initial_table" + ) + query = sql.SQL("{query} {select_statement}").format( + query=query, select_statement=select_statement + ) + for i in range(len(filters)): + query = sql.SQL( + "{query} JOIN subquery{index} ON ST_DWithin(initial_table.geom, subquery{index}.geom, {buffer})" + ).format(query=query, index=sql.Literal(i), buffer=sql.Literal(buffer)) + + query = sql.SQL("{query} LIMIT {limit} OFFSET {offset}").format( + query=query, limit=sql.Literal(100) + ) conn: psycopg.Connection = get_db_connection() - logger.info(f"Executing query: {join_query.as_string(conn)}") + logger.info(f"Executing query: {query.as_string(conn)}") - timestamp: int = time.time_ns() + timestamp: int = time.time_ns() # type: ignore user = get_user(request) try: - data, tdiff = query_with_timing(join_query) + data, tdiff = query_with_timing(query) except Timeout: return Response(status=408) log_data = { "timestamp": firestore.SERVER_TIMESTAMP, - "query": join_query.as_string(conn), + "query": query.as_string(conn), "user_uid": user["uid"], "user_email": user["email"], "bbox": list(bbox), diff --git a/api/api_types.py b/api/api_types.py index a3ef97b..7f83b2a 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -2,29 +2,26 @@ from dataclasses import dataclass from typing import Literal, TypedDict -from pydantic import BaseModel, Json +from pydantic import BaseModel, Field, Json from typing_extensions import NotRequired class Subfilter(BaseModel): - comparison: ( - str - | Literal[ - "=", - "!=", - ">", - "<", - ">=", - "<=", - "starts with", - "ends with", - "contains", - "does not contain", - "is null", - "is not null", - ] - ) - parameter: str + comparison: Literal[ + "=", + "!=", + ">", + "<", + ">=", + "<=", + "starts with", + "ends with", + "contains", + "does not contain", + "is null", + "is not null", + ] + parameter: str = Field(default_factory=str, pattern=r"^[a-zA-Z0-9_:]+$") value: str = "" cast: str | None = None @@ -34,6 +31,7 @@ class Filter(BaseModel): method: Literal["AND", "OR"] type: Literal["point", "line", "polygon", "any"] filters: list[Subfilter] + unsavedCustomFeature: bool = False class RequestParams(BaseModel): From 303914afdd1effa82aa2158450ad92013fabfbd2 Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 00:11:40 +0200 Subject: [PATCH 08/30] ci: local mypy run --- .pre-commit-config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 29eab2c..10d6a60 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,3 +45,5 @@ repos: rev: v1.10.0 hooks: - id: mypy + language: system + entry: PIPENV_FILE=api/Pipenv.lock pipenv run mypy From 1f6ef5007e6763d94a892110fd40ff2fa87d344e Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 00:19:03 +0200 Subject: [PATCH 09/30] feat: add pagination support to API --- .pre-commit-config.yaml | 2 -- api/api.py | 2 +- api/api_types.py | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 10d6a60..29eab2c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,5 +45,3 @@ repos: rev: v1.10.0 hooks: - id: mypy - language: system - entry: PIPENV_FILE=api/Pipenv.lock pipenv run mypy diff --git a/api/api.py b/api/api.py index dc74d6e..8f4d8f6 100644 --- a/api/api.py +++ b/api/api.py @@ -321,7 +321,7 @@ def get_intersection() -> tuple[Response, Literal[400]] | Response: ).format(query=query, index=sql.Literal(i), buffer=sql.Literal(buffer)) query = sql.SQL("{query} LIMIT {limit} OFFSET {offset}").format( - query=query, limit=sql.Literal(100) + query=query, limit=sql.Literal(params.limit), offset=sql.Literal(params.offset) ) conn: psycopg.Connection = get_db_connection() diff --git a/api/api_types.py b/api/api_types.py index 7f83b2a..76a94dd 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -41,6 +41,8 @@ class RequestParams(BaseModel): b: float r: float t: float + limit: int = 100 + offset: int = 0 @dataclass From 5767f6b5fb992b7a0ff386ccc11cb0afb7f2385f Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 11:05:23 +0200 Subject: [PATCH 10/30] refactor: `get_intersection` --- api/api.py | 195 +++++++++++++++++++++++++++++------------------------ 1 file changed, 108 insertions(+), 87 deletions(-) diff --git a/api/api.py b/api/api.py index 8f4d8f6..1bb93ef 100644 --- a/api/api.py +++ b/api/api.py @@ -140,7 +140,7 @@ def decorated(*args, **kwargs): return decorated -def make_filter_query(filter: Filter): +def make_where_statement(filter: Filter): filter_query = sql.SQL("") i = 0 @@ -219,37 +219,32 @@ def make_filter_query(filter: Filter): return filter_query -@app.route("/intersection") -@token_required -def get_intersection() -> tuple[Response, Literal[400]] | Response: - try: - params = RequestParams( - buffer=request.args.get("buffer"), - filters=request.args.get("filters"), - l=request.args.get("l"), - b=request.args.get("b"), - r=request.args.get("r"), - t=request.args.get("t"), - ) - except ValidationError as e: - return jsonify({"error": "Invalid data", "details": e.errors()}), 400 +def get_table_name(f: Filter) -> sql.Composed: + match f.type: + case "point": + return sql.SQL("planet_osm_point") + case "line": + return sql.SQL("planet_osm_line") + case "polygon": + return sql.SQL("planet_osm_polygon") + case "any": + return sql.SQL("planet_osm") - buffer: int = params.buffer - filters: list[Filter] = params.filters - bbox: Bbox = Bbox(params.l, params.b, params.r, params.t) +def build_cte(f: Filter, index: int) -> sql.Composed: + source_table = get_table_name(f) + filter_query = make_where_statement(f) - area: float = ( - math.pow(6371, 2) - * math.pi - * abs(math.sin(math.radians(bbox.t)) - math.sin(math.radians(bbox.b))) - * abs(bbox.r - bbox.l) - / 180 - ) + assembled: sql.Composed = sql.SQL( + """subquery{index} AS (SELECT way AS geom FROM {source_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" + ).format(index=sql.SQL(str(index)), source_table=source_table, filter=filter_query) + return assembled - # reject queries that are too large - if area > 4e6: - return Response(status=400) + +def build_query( + filters: list[Filter], bbox: Bbox, buffer: int, limit: int, offset: int +) -> sql.Composed: + logger.info(f"Buffer: {buffer}\tFilters: {filters}\tBbox: {str(bbox)}") bbox_filter: sql.Composed = sql.SQL( "AND (way && ST_Transform(ST_MakeEnvelope({left}, {bottom}, {right}, {top}, 4326), 3857))" @@ -270,79 +265,59 @@ def get_intersection() -> tuple[Response, Literal[400]] | Response: ) first: Filter = filters.pop(0) - match first.type: - case "point": - main_table = sql.SQL("planet_osm_point") - case "line": - main_table = sql.SQL("planet_osm_line") - case "polygon": - main_table = sql.SQL("planet_osm_polygon") - case "any": - main_table = sql.SQL("planet_osm") - - initial_subtable = sql.SQL( + source_table = get_table_name(first) + initial_cte = sql.SQL( """initial_table AS (SELECT tags->'name' AS name, ST_Transform(ST_Centroid(way), 4326) AS point_geom, way AS geom FROM {main_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" - ).format(main_table=main_table, filter=make_filter_query(first), bbox=bbox_filter) - - query = sql.SQL("{envelope_cte}, {initial_subtable}").format( - envelope_cte=envelope_cte, initial_subtable=initial_subtable + ).format( + main_table=source_table, filter=make_where_statement(first), bbox=bbox_filter ) - logger.info(f"Buffer: {buffer}\tFilters: {filters}\tBbox: {str(bbox)}") - + additional_cte_list: list[sql.Composed] = [] for i, f in enumerate(filters): - filter = make_filter_query(f) - - match f.type: - case "point": - source_table = sql.SQL("planet_osm_point") - case "line": - source_table = sql.SQL("planet_osm_line") - case "polygon": - source_table = sql.SQL("planet_osm_polygon") - case "any": - source_table = sql.SQL("planet_osm") - - assembled: sql.Composed = sql.SQL( - """subquery{index} AS (SELECT way AS geom FROM {source_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" - ).format(index=sql.SQL(str(i)), source_table=source_table, filter=filter) - - query = sql.SQL("{query}, {assembled}").format(query=query, assembled=assembled) - - select_statement = sql.SQL( - "SELECT DISTINCT point_geom, name, ST_Y(point_geom) AS lat, ST_X(point_geom) AS lng FROM initial_table" - ) - query = sql.SQL("{query} {select_statement}").format( - query=query, select_statement=select_statement - ) - for i in range(len(filters)): - query = sql.SQL( - "{query} JOIN subquery{index} ON ST_DWithin(initial_table.geom, subquery{index}.geom, {buffer})" - ).format(query=query, index=sql.Literal(i), buffer=sql.Literal(buffer)) + additional_cte_list.append(build_cte(f, i)) - query = sql.SQL("{query} LIMIT {limit} OFFSET {offset}").format( - query=query, limit=sql.Literal(params.limit), offset=sql.Literal(params.offset) + query = sql.SQL( + "{envelope_cte}, {ctes} {select_statement} {join_staments} {pagination}" + ).format( + envelope_cte=envelope_cte, + ctes=sql.SQL(", ").join([initial_cte, *additional_cte_list]), + select_statement=sql.SQL( + "SELECT DISTINCT point_geom, name, ST_Y(point_geom) AS lat, ST_X(point_geom) AS lng FROM initial_table" + ), + join_staments=sql.SQL(" ").join( + [ + sql.SQL( + "JOIN subquery{index} ON ST_DWithin(initial_table.geom, subquery{index}.geom, {buffer})" + ).format(index=sql.Literal(i), buffer=sql.Literal(buffer)) + for i in range(len(filters)) + ] + ), + pagination=sql.SQL("LIMIT {limit} OFFSET {offset}").format( + limit=sql.Literal(limit), offset=sql.Literal(offset) + ), ) - conn: psycopg.Connection = get_db_connection() + return query - logger.info(f"Executing query: {query.as_string(conn)}") +def log_query( + request: Request, + query_string: str, + bbox: Bbox, + filters: list[Filter], + tdiff: timedelta, + data: list[RetrievedData], +): timestamp: int = time.time_ns() # type: ignore - user = get_user(request) - - try: - data, tdiff = query_with_timing(query) - except Timeout: - return Response(status=408) + user: dict | None = get_user(request) log_data = { "timestamp": firestore.SERVER_TIMESTAMP, - "query": query.as_string(conn), - "user_uid": user["uid"], - "user_email": user["email"], + "query": query_string, + "user_uid": user["uid"] if user else None, + "user_email": user["email"] if user else None, "bbox": list(bbox), - "filters": filters, + "filters": [dict(f) for f in filters], "query_time": tdiff.total_seconds(), "query_nresults": len(data), "query_results": data, @@ -350,6 +325,52 @@ def get_intersection() -> tuple[Response, Literal[400]] | Response: db.collection("searches").document(str(timestamp)).set(log_data) + +@app.route("/intersection") +@token_required +def get_intersection() -> tuple[Response, Literal[400]] | Response: + try: + params = RequestParams( + buffer=request.args.get("buffer"), + filters=request.args.get("filters"), + l=request.args.get("l"), + b=request.args.get("b"), + r=request.args.get("r"), + t=request.args.get("t"), + ) + except ValidationError as e: + return jsonify({"error": "Invalid data", "details": e.errors()}), 400 + + buffer: int = params.buffer + filters: list[Filter] = params.filters + + bbox: Bbox = Bbox(params.l, params.b, params.r, params.t) + + area: float = ( + math.pow(6371, 2) + * math.pi + * abs(math.sin(math.radians(bbox.t)) - math.sin(math.radians(bbox.b))) + * abs(bbox.r - bbox.l) + / 180 + ) + + # reject queries that are too large + if area > 4e6: + return Response(status=400) + + query = build_query(filters, bbox, buffer, params.limit, params.offset) + conn: psycopg.Connection = get_db_connection() + + query_string: str = query.as_string(conn) + logger.info(f"Executing query: {query_string}") + + try: + data, tdiff = query_with_timing(query, conn=conn) + except Timeout: + return Response(status=408) + + log_query(request, query_string, bbox, filters, tdiff, data) + logger.info(f"Found {len(data)} results in {tdiff} seconds") return jsonify(data) From cf7e7464076700aae02d550aaf2cd45c7297b6aa Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 11:08:51 +0200 Subject: [PATCH 11/30] fix: minor fixes --- .gitignore | 4 ++++ api/api.py | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index fd3b8b4..11462b9 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,7 @@ node_modules/ # dotenv environment variables file .env + +# Python cache +__pycache__ +.mypy_cache diff --git a/api/api.py b/api/api.py index 1bb93ef..643e14e 100644 --- a/api/api.py +++ b/api/api.py @@ -2,7 +2,6 @@ import time from datetime import datetime, timedelta from functools import wraps -from typing import Literal import firebase_admin import psycopg @@ -328,7 +327,7 @@ def log_query( @app.route("/intersection") @token_required -def get_intersection() -> tuple[Response, Literal[400]] | Response: +def get_intersection() -> tuple[Response, int] | Response: try: params = RequestParams( buffer=request.args.get("buffer"), From f57a536a3dc2dacc561089fd18c48bae579e1aee Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 15:37:09 +0200 Subject: [PATCH 12/30] refactor: reorder functions --- api/api.py | 248 +++++++++++++++++++++++++---------------------------- 1 file changed, 116 insertions(+), 132 deletions(-) diff --git a/api/api.py b/api/api.py index 643e14e..f69cab8 100644 --- a/api/api.py +++ b/api/api.py @@ -21,35 +21,71 @@ from psycopg.rows import dict_row from pydantic import ValidationError +# Firebase initialization cred = credentials.Certificate("service_account.json") firebase_app = firebase_admin.initialize_app(cred) db = firestore.client() +# Flask initialization app = Flask(__name__) app.config["TEMPLATES_AUTO_RELOAD"] = True CORS(app) -ALLOWED_COMPARISONS = [ - "=", - "!=", - ">", - "<", - ">=", - "<=", - "starts with", - "ends with", - "contains", - "does not contain", - "is null", - "is not null", -] - -ALLOWED_METHODS = ["OR", "AND"] - ALLOWED_CASTS = ["integer", "float", "cast_to_int", "cast_to_float"] +def token_required(f): + @wraps(f) + def decorated(*args, **kwargs): + token = None + + if "Authorization" in request.headers: + token = request.headers["Authorization"].split(" ")[1] + if not token: + logger.info("Request with missing authentication token.") + return { + "message": "Authentication Token is missing!", + "data": None, + "error": "Unauthorized", + }, 401 + try: + idinfo = auth.verify_id_token(token) + + if idinfo is None: + logger.warning(f"Invalid authentication token {token}") + return { + "message": "Invalid Authentication token!", + "data": None, + "error": "Unauthorized", + }, 403 + except Exception as e: + logger.warning(f"Other error {e}") + return { + "message": "Something went wrong", + "data": None, + "error": str(e), + }, 403 + + logger.info(f"Authenticated request by {idinfo['email']}") + return f(*args, **kwargs) + + return decorated + + +def get_user(request: Request): + token = None + + if "Authorization" in request.headers: + token = request.headers["Authorization"].split(" ")[1] + + if not token: + return None + + idinfo = auth.verify_id_token(token) + return idinfo + + def get_db_connection() -> psycopg.Connection: db_config = PostgresConfig() conn = psycopg.connect( @@ -88,67 +124,50 @@ def query_with_timing( return (data, t2 - t1) -def get_user(request: Request): - token = None - - if "Authorization" in request.headers: - token = request.headers["Authorization"].split(" ")[1] - - if not token: - return None - - idinfo = auth.verify_id_token(token) - return idinfo - - -def token_required(f): - @wraps(f) - def decorated(*args, **kwargs): - token = None +def log_query( + request: Request, + query_string: str, + bbox: Bbox, + filters: list[Filter], + tdiff: timedelta, + data: list[RetrievedData], +): + timestamp: int = time.time_ns() # type: ignore + user: dict | None = get_user(request) - if "Authorization" in request.headers: - token = request.headers["Authorization"].split(" ")[1] - if not token: - logger.info("Request with missing authentication token.") - return { - "message": "Authentication Token is missing!", - "data": None, - "error": "Unauthorized", - }, 401 - try: - idinfo = auth.verify_id_token(token) + log_data = { + "timestamp": firestore.SERVER_TIMESTAMP, + "query": query_string, + "user_uid": user["uid"] if user else None, + "user_email": user["email"] if user else None, + "bbox": list(bbox), + "filters": [dict(f) for f in filters], + "query_time": tdiff.total_seconds(), + "query_nresults": len(data), + "query_results": data, + } - if idinfo is None: - logger.warning(f"Invalid authentication token {token}") - return { - "message": "Invalid Authentication token!", - "data": None, - "error": "Unauthorized", - }, 403 - except Exception as e: - logger.warning(f"Other error {e}") - return { - "message": "Something went wrong", - "data": None, - "error": str(e), - }, 403 + db.collection("searches").document(str(timestamp)).set(log_data) - logger.info(f"Authenticated request by {idinfo['email']}") - return f(*args, **kwargs) - return decorated +def get_source_table(f: Filter) -> sql.Composed: + match f.type: + case "point": + return sql.SQL("planet_osm_point") + case "line": + return sql.SQL("planet_osm_line") + case "polygon": + return sql.SQL("planet_osm_polygon") + case "any": + return sql.SQL("planet_osm") -def make_where_statement(filter: Filter): +def build_where_statement(filter: Filter): filter_query = sql.SQL("") i = 0 for subfilter in filter.filters: - if subfilter.comparison not in ALLOWED_COMPARISONS: - logger.error(f"Invalid comparison {subfilter.comparison}") - break - if subfilter.comparison == "=": filter_query = sql.SQL("{filter_query} (tags @> {match})").format( filter_query=filter_query, @@ -218,25 +237,16 @@ def make_where_statement(filter: Filter): return filter_query -def get_table_name(f: Filter) -> sql.Composed: - match f.type: - case "point": - return sql.SQL("planet_osm_point") - case "line": - return sql.SQL("planet_osm_line") - case "polygon": - return sql.SQL("planet_osm_polygon") - case "any": - return sql.SQL("planet_osm") - - -def build_cte(f: Filter, index: int) -> sql.Composed: - source_table = get_table_name(f) - filter_query = make_where_statement(f) +def build_cte_from_filter(f: Filter, id: sql.SQL) -> sql.Composed: + source_table = get_source_table(f) + filter_query = build_where_statement(f) assembled: sql.Composed = sql.SQL( - """subquery{index} AS (SELECT way AS geom FROM {source_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" - ).format(index=sql.SQL(str(index)), source_table=source_table, filter=filter_query) + """{id} AS (SELECT + way AS geom + FROM {source_table}, envelope + WHERE ({filter}) AND (way && envelope.geom))""" + ).format(id=id, source_table=source_table, filter=filter_query) return assembled @@ -245,17 +255,10 @@ def build_query( ) -> sql.Composed: logger.info(f"Buffer: {buffer}\tFilters: {filters}\tBbox: {str(bbox)}") - bbox_filter: sql.Composed = sql.SQL( - "AND (way && ST_Transform(ST_MakeEnvelope({left}, {bottom}, {right}, {top}, 4326), 3857))" - ).format( - left=sql.Literal(bbox.l), - bottom=sql.Literal(bbox.b), - right=sql.Literal(bbox.r), - top=sql.Literal(bbox.t), - ) - envelope_cte: sql.Composed = sql.SQL( - "WITH envelope AS (SELECT ST_Transform(ST_MakeEnvelope({left}, {bottom}, {right}, {top}, 4326), 3857) AS geom)" + """WITH envelope AS ( + SELECT ST_Transform(ST_MakeEnvelope({left}, {bottom}, {right}, {top}, 4326), 3857) AS geom + )""" ).format( left=sql.Literal(bbox.l), bottom=sql.Literal(bbox.b), @@ -264,31 +267,38 @@ def build_query( ) first: Filter = filters.pop(0) - source_table = get_table_name(first) + source_table = get_source_table(first) initial_cte = sql.SQL( - """initial_table AS (SELECT tags->'name' AS name, ST_Transform(ST_Centroid(way), 4326) AS point_geom, way AS geom FROM {main_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" - ).format( - main_table=source_table, filter=make_where_statement(first), bbox=bbox_filter - ) - - additional_cte_list: list[sql.Composed] = [] + """initial_table AS ( + SELECT + tags->'name' AS name, + ST_Transform(ST_Centroid(way), 4326) AS point_geom, + way AS geom + FROM {main_table}, envelope + WHERE ({filter}) AND (way && envelope.geom))""" + ).format(main_table=source_table, filter=build_where_statement(first)) + + additional_cte_list: list[tuple[sql.Composed, sql.Composed]] = [] for i, f in enumerate(filters): - additional_cte_list.append(build_cte(f, i)) + cte_id = sql.SQL("subquery{index}").format(index=sql.SQL(str(i))) + additional_cte_list.append((cte_id, build_cte_from_filter(f, cte_id))) query = sql.SQL( "{envelope_cte}, {ctes} {select_statement} {join_staments} {pagination}" ).format( envelope_cte=envelope_cte, - ctes=sql.SQL(", ").join([initial_cte, *additional_cte_list]), + ctes=sql.SQL(", ").join( + [initial_cte, *[cte_sql for cte_id, cte_sql in additional_cte_list]] + ), select_statement=sql.SQL( "SELECT DISTINCT point_geom, name, ST_Y(point_geom) AS lat, ST_X(point_geom) AS lng FROM initial_table" ), join_staments=sql.SQL(" ").join( [ sql.SQL( - "JOIN subquery{index} ON ST_DWithin(initial_table.geom, subquery{index}.geom, {buffer})" - ).format(index=sql.Literal(i), buffer=sql.Literal(buffer)) - for i in range(len(filters)) + "JOIN {cte_id} ON ST_DWithin(initial_table.geom, {cte_id}.geom, {buffer})" + ).format(cte_id=cte_id, buffer=sql.Literal(buffer)) + for cte_id, cte_sql in additional_cte_list ] ), pagination=sql.SQL("LIMIT {limit} OFFSET {offset}").format( @@ -299,32 +309,6 @@ def build_query( return query -def log_query( - request: Request, - query_string: str, - bbox: Bbox, - filters: list[Filter], - tdiff: timedelta, - data: list[RetrievedData], -): - timestamp: int = time.time_ns() # type: ignore - user: dict | None = get_user(request) - - log_data = { - "timestamp": firestore.SERVER_TIMESTAMP, - "query": query_string, - "user_uid": user["uid"] if user else None, - "user_email": user["email"] if user else None, - "bbox": list(bbox), - "filters": [dict(f) for f in filters], - "query_time": tdiff.total_seconds(), - "query_nresults": len(data), - "query_results": data, - } - - db.collection("searches").document(str(timestamp)).set(log_data) - - @app.route("/intersection") @token_required def get_intersection() -> tuple[Response, int] | Response: From 3f11095f8fb612d018de54462a7428eae4e4ad50 Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 16:01:56 +0200 Subject: [PATCH 13/30] refactor: `build_where_statement` --- api/api.py | 69 ++++++++++++++++++++---------------------------- api/api_types.py | 2 +- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/api/api.py b/api/api.py index f69cab8..d7b3cce 100644 --- a/api/api.py +++ b/api/api.py @@ -32,8 +32,6 @@ CORS(app) -ALLOWED_CASTS = ["integer", "float", "cast_to_int", "cast_to_float"] - def token_required(f): @wraps(f) @@ -163,35 +161,30 @@ def get_source_table(f: Filter) -> sql.Composed: def build_where_statement(filter: Filter): - filter_query = sql.SQL("") - - i = 0 - + subfilters_list: list[Filter] = [] for subfilter in filter.filters: if subfilter.comparison == "=": - filter_query = sql.SQL("{filter_query} (tags @> {match})").format( - filter_query=filter_query, + filter_query = sql.SQL("(tags @> {match})").format( match=sql.Literal(subfilter.parameter + "=>" + subfilter.value), ) elif subfilter.comparison == "!=": - filter_query = sql.SQL("{filter_query} NOT(tags @> {match})").format( - filter_query=filter_query, + filter_query = sql.SQL("NOT(tags @> {match})").format( match=sql.Literal(subfilter.parameter + "=>" + subfilter.value), ) elif subfilter.comparison == "is null": - filter_query = sql.SQL("{filter_query} NOT(tags?{parameter})").format( - filter_query=filter_query, parameter=sql.Literal(subfilter.parameter) + filter_query = sql.SQL("NOT(tags?{parameter})").format( + parameter=sql.Literal(subfilter.parameter) ) elif subfilter.comparison == "is not null": - filter_query = sql.SQL("{filter_query} (tags?{parameter})").format( - filter_query=filter_query, parameter=sql.Literal(subfilter.parameter) + filter_query = sql.SQL("(tags?{parameter})").format( + parameter=sql.Literal(subfilter.parameter) ) else: parameter = sql.SQL("tags->{parameter}").format( parameter=sql.Literal(subfilter.parameter) ) - if subfilter.cast is not None and subfilter.cast in ALLOWED_CASTS: + if subfilter.cast is not None: if subfilter.cast == "cast_to_float": parameter = sql.SQL("cast_to_float({parameter}, 0.0)").format( parameter=parameter @@ -205,36 +198,32 @@ def build_where_statement(filter: Filter): parameter=parameter, cast=sql.SQL(subfilter.cast) ) - if subfilter.comparison == "starts with": - subfilter.value = f"{subfilter.value}%" - subfilter.comparison = "ILIKE" # type: ignore - elif subfilter.comparison == "ends with": - subfilter.value = f"%{subfilter.value}" - subfilter.comparison = "ILIKE" # type: ignore - elif subfilter.comparison == "contains": - subfilter.value = f"%{subfilter.value}%" - subfilter.comparison = "ILIKE" # type: ignore + if subfilter.comparison in ("starts with", "ends with", "contains"): + comparison = "ILIKE" elif subfilter.comparison == "does not contain": - subfilter.value = f"%{subfilter.value}%" - subfilter.comparison = "NOT ILIKE" # type: ignore - - filter_query = sql.SQL( - "{filter_query} ({parameter} {comparison} {value})" - ).format( - filter_query=filter_query, + comparison = "NOT ILIKE" + else: + comparison = subfilter.comparison + + match subfilter.comparison: + case "starts with": + value = f"{subfilter.value}%" + case "ends with": + value = f"%{subfilter.value}" + case "contains" | "does not contain": + value = f"%{subfilter.value}%" + case _: + value = subfilter.value + + filter_query = sql.SQL("({parameter} {comparison} {value})").format( parameter=parameter, - comparison=sql.SQL(subfilter.comparison), - value=sql.Literal(subfilter.value), - ) - - if i != len(filter.filters) - 1: - filter_query = sql.SQL("{filter_query} {method}").format( - filter_query=filter_query, method=sql.SQL(filter.method) + comparison=sql.SQL(comparison), + value=sql.Literal(value), ) - i += 1 + subfilters_list.append(filter_query) - return filter_query + return sql.SQL(" {method} ").format(method=filter.method).join(subfilters_list) def build_cte_from_filter(f: Filter, id: sql.SQL) -> sql.Composed: diff --git a/api/api_types.py b/api/api_types.py index 76a94dd..5ba9b35 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -23,7 +23,7 @@ class Subfilter(BaseModel): ] parameter: str = Field(default_factory=str, pattern=r"^[a-zA-Z0-9_:]+$") value: str = "" - cast: str | None = None + cast: Literal["integer", "float", "cast_to_int", "cast_to_float"] | None = None class Filter(BaseModel): From 7854c9cbd909d11ed237aad1541c67c7fed25860 Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 16:03:14 +0200 Subject: [PATCH 14/30] refactor: `build_where_stament` -> `build_filter_query` --- api/api.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/api.py b/api/api.py index d7b3cce..3cf6319 100644 --- a/api/api.py +++ b/api/api.py @@ -160,7 +160,7 @@ def get_source_table(f: Filter) -> sql.Composed: return sql.SQL("planet_osm") -def build_where_statement(filter: Filter): +def build_filter_query(filter: Filter): subfilters_list: list[Filter] = [] for subfilter in filter.filters: if subfilter.comparison == "=": @@ -228,7 +228,7 @@ def build_where_statement(filter: Filter): def build_cte_from_filter(f: Filter, id: sql.SQL) -> sql.Composed: source_table = get_source_table(f) - filter_query = build_where_statement(f) + filter_query = build_filter_query(f) assembled: sql.Composed = sql.SQL( """{id} AS (SELECT @@ -265,7 +265,7 @@ def build_query( way AS geom FROM {main_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" - ).format(main_table=source_table, filter=build_where_statement(first)) + ).format(main_table=source_table, filter=build_filter_query(first)) additional_cte_list: list[tuple[sql.Composed, sql.Composed]] = [] for i, f in enumerate(filters): From df4db14cbb488db71f76c503d45a0872d96788fc Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 3 May 2024 16:26:24 +0200 Subject: [PATCH 15/30] fix: `build_filter_query` --- api/api.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/api/api.py b/api/api.py index 3cf6319..a3711a2 100644 --- a/api/api.py +++ b/api/api.py @@ -223,7 +223,12 @@ def build_filter_query(filter: Filter): subfilters_list.append(filter_query) - return sql.SQL(" {method} ").format(method=filter.method).join(subfilters_list) + if filter.method == "AND": + joiner = sql.SQL(" AND ") + else: + joiner = sql.SQL(" OR ") + + return joiner.join(subfilters_list) def build_cte_from_filter(f: Filter, id: sql.SQL) -> sql.Composed: From 59b54ca6e486eebfd6cef8b8f27e9426c092069c Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 9 May 2024 00:39:47 +0200 Subject: [PATCH 16/30] feat: server-side pagination --- api/api.py | 24 +++-- api/api_types.py | 2 +- frontend/src/components/SearchResults.vue | 26 ++++-- frontend/src/services/bellingcat.service.js | 97 +++++++++++++++++++++ frontend/src/store/index.js | 75 ++++++++-------- 5 files changed, 170 insertions(+), 54 deletions(-) create mode 100644 frontend/src/services/bellingcat.service.js diff --git a/api/api.py b/api/api.py index a3711a2..b7813eb 100644 --- a/api/api.py +++ b/api/api.py @@ -25,7 +25,7 @@ cred = credentials.Certificate("service_account.json") firebase_app = firebase_admin.initialize_app(cred) db = firestore.client() - +# # Flask initialization app = Flask(__name__) app.config["TEMPLATES_AUTO_RELOAD"] = True @@ -71,7 +71,7 @@ def decorated(*args, **kwargs): return decorated -def get_user(request: Request): +def get_user(request: Request) -> dict | None: token = None if "Authorization" in request.headers: @@ -295,9 +295,9 @@ def build_query( for cte_id, cte_sql in additional_cte_list ] ), - pagination=sql.SQL("LIMIT {limit} OFFSET {offset}").format( - limit=sql.Literal(limit), offset=sql.Literal(offset) - ), + pagination=sql.SQL( + "ORDER BY point_geom, name, lat, lng LIMIT {limit} OFFSET {offset}" + ).format(limit=sql.Literal(limit + 1), offset=sql.Literal(offset)), ) return query @@ -314,6 +314,8 @@ def get_intersection() -> tuple[Response, int] | Response: b=request.args.get("b"), r=request.args.get("r"), t=request.args.get("t"), + limit=request.args.get("limit"), + page=request.args.get("page"), ) except ValidationError as e: return jsonify({"error": "Invalid data", "details": e.errors()}), 400 @@ -322,6 +324,8 @@ def get_intersection() -> tuple[Response, int] | Response: filters: list[Filter] = params.filters bbox: Bbox = Bbox(params.l, params.b, params.r, params.t) + limit = min(params.limit, 100) + offset = params.page * limit area: float = ( math.pow(6371, 2) @@ -335,7 +339,7 @@ def get_intersection() -> tuple[Response, int] | Response: if area > 4e6: return Response(status=400) - query = build_query(filters, bbox, buffer, params.limit, params.offset) + query = build_query(filters, bbox, buffer, limit, offset) conn: psycopg.Connection = get_db_connection() query_string: str = query.as_string(conn) @@ -350,7 +354,13 @@ def get_intersection() -> tuple[Response, int] | Response: logger.info(f"Found {len(data)} results in {tdiff} seconds") - return jsonify(data) + if len(data) == 0: + return jsonify({"message": "No results found", "data": []}) + + # We fetch one extra result to determine if there are more results + has_more = len(data) > limit + + return jsonify({"data": data[0 : min(len(data), limit)], "has_more": has_more}) @app.route("/robots.txt") diff --git a/api/api_types.py b/api/api_types.py index 5ba9b35..0d15013 100644 --- a/api/api_types.py +++ b/api/api_types.py @@ -42,7 +42,7 @@ class RequestParams(BaseModel): r: float t: float limit: int = 100 - offset: int = 0 + page: int = 0 @dataclass diff --git a/frontend/src/components/SearchResults.vue b/frontend/src/components/SearchResults.vue index 2c9711a..37ecb60 100644 --- a/frontend/src/components/SearchResults.vue +++ b/frontend/src/components/SearchResults.vue @@ -2,14 +2,18 @@ - {{ - $store.state.searchResults.length == 100 - ? "100 results of many" - : $store.state.searchResults.length + " total results" - }} + {{ "Page: " + ($store.state.page + 1) }} + {{ "Results: " + $store.state.searchResults.length }} {{ "in " + ($store.state.responseTime / 1000).toFixed(2) + " seconds" }} + + + mdi-arrow-left-bold + + + mdi-arrow-right-bold + @@ -58,8 +62,20 @@ export default { this.$store.commit("setMode", mode); }, }, + hasMore() { + return this.$store.getters["hasMore"]; + }, + canGoBack() { + return this.$store.getters["page"] > 0; + }, }, methods: { + previous() { + this.$store.dispatch("previousPage"); + }, + next() { + this.$store.dispatch("nextPage"); + }, kml() { let features = this.$store.state.searchResults.map((f) => ({ type: "Feature", diff --git a/frontend/src/services/bellingcat.service.js b/frontend/src/services/bellingcat.service.js new file mode 100644 index 0000000..3b55911 --- /dev/null +++ b/frontend/src/services/bellingcat.service.js @@ -0,0 +1,97 @@ +const PAGE_SIZE = 100; +//const OSM_SEARCH_API = "https://api.osm-search.bellingcat.com"; +const OSM_SEARCH_API = "http://localhost:5050"; + +class BellingCatService { + constructor() { + this.token = null; + this.lastRequest = null; + this.cache = new Map(); + } + + setToken(token) { + this.token = token; + } + + search({ bbox, range, filters, page = 0, prefetchNext = false }) { + // Check cache based on parameters and page + const requestKey = `${bbox[0][1]}_${bbox[0][0]}_${bbox[1][1]}_${bbox[1][0]}_${range}_${filters}`; + const cacheKey = `${requestKey}_${page}`; + + if (this.lastRequest && this.lastRequest != requestKey) { + this.cache.clear(); + } + this.lastRequest = requestKey; + + let cachedData = this.cache.get(cacheKey); + if (cachedData) { + if (prefetchNext) { + setTimeout(() => { + this.search({ bbox, range, filters, page: page + 1 }); + }, 1000); + } + return Promise.resolve(cachedData); + } + + const result = new Promise((resolve, reject) => { + let time1 = performance.now(); + + fetch( + `${OSM_SEARCH_API}/intersection?l=${bbox[0][1]}&b=${bbox[0][0]}&r=${bbox[1][1]}&t=${bbox[1][0]}&buffer=${range}&filters=${filters}&limit=${PAGE_SIZE}&page=${page}`, + { + headers: { + Authorization: "Bearer " + this.token, + }, + } + ) + .then((d) => { + if (d.status != 200) { + return Promise.reject(Error(d.status)); + } + return d.json(); + }) + .then(({ data, has_more }) => { + let time2 = performance.now(); + let responseTime = time2 - time1; + const response = { responseTime, data, hasMore: has_more }; + if (has_more && prefetchNext) { + setTimeout(() => { + this.search({ bbox, range, filters, page: page + 1 }); + }, 1000); + } + + resolve(response); + }) + .catch((e) => { + switch (e.message) { + case 400: + reject( + "Your search area is too large, or your search timed out. Zoom in on a smaller area or change your search parameters." + ); + break; + case 401: + reject("The data provided was invalid."); + break; + case 403: + reject("Your login has expired. Please log in again."); + break; + case 408: + reject("The request timed out."); + break; + case 500: + reject("The server encountered an error."); + break; + default: + reject( + "Search error. Check your custom features or email logan@bellingcat.com." + ); + } + }); + }); + + this.cache.set(cacheKey, result); + return result; + } +} + +export const bellingCatService = new BellingCatService(); diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 7c63d59..e9be79c 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -14,11 +14,10 @@ import { doc, } from "firebase/firestore"; import queries from "@/assets/queries"; +import { bellingCatService } from "@/services/bellingcat.service"; Vue.use(Vuex); -const OSM_SEARCH_API = "https://api.osm-search.bellingcat.com"; - export default new Vuex.Store({ state: { selected: [], @@ -39,6 +38,8 @@ export default new Vuex.Store({ user: null, presets: queries, customPresets: [], + page: 0, + hasMore: false, }, mutations: { setUser(state, user) { @@ -46,6 +47,7 @@ export default new Vuex.Store({ }, setToken(state, token) { state.token = token; + bellingCatService.setToken(token); }, updateSelected(state, value) { state.selected = [...value]; @@ -104,6 +106,12 @@ export default new Vuex.Store({ setCustomPresets(state, presets) { state.customPresets = presets; }, + setPage(state, page) { + state.page = page; + }, + setHasMore(state, hasMore) { + state.hasMore = hasMore; + }, }, actions: { async signout({ commit }) { @@ -119,6 +127,16 @@ export default new Vuex.Store({ } }, + nextPage({ commit, state, dispatch }) { + commit("setPage", state.page + 1); + dispatch("search"); + }, + + previousPage({ commit, state, dispatch }) { + commit("setPage", state.page - 1); + dispatch("search"); + }, + getKeys({ commit }) { fetch( "https://taginfo.openstreetmap.org/api/4/keys/all?page=1&rp=200&filter=in_wiki&sortname=count_all&sortorder=desc" @@ -160,53 +178,24 @@ export default new Vuex.Store({ }); }, search({ state, commit }) { - let bbox = state.bbox; - let range = state.range; - let filters = JSON.stringify(state.selected); + const bbox = state.bbox; + const range = state.range; + const filters = JSON.stringify(state.selected); + const page = state.page; commit("setLoading", true); - - let time1 = performance.now(); - - fetch( - `${OSM_SEARCH_API}/intersection?l=${bbox[0][1]}&b=${bbox[0][0]}&r=${bbox[1][1]}&t=${bbox[1][0]}&buffer=${range}&filters=${filters}`, - { - headers: { - Authorization: "Bearer " + state.token, - }, - } - ) - .then((d) => { - if (d.status != 200) { - return Promise.reject(Error(d.status)); - } - return d.json(); - }) - .then((data) => { - let time2 = performance.now(); - commit("setResponseTime", time2 - time1); + bellingCatService + .search({ bbox, range, filters, page, prefetchNext: true }) + .then(({ data, responseTime, hasMore }) => { + commit("setResponseTime", responseTime); commit("setSearchResults", data); + commit("setHasMore", hasMore); commit("setLoading", false); commit("setError", false); }) .catch((e) => { commit("setLoading", false); - if (e.message == 400) { - commit("setLoading", false); - commit( - "setError", - "Your search area is too large, or your search timed out. Zoom in on a smaller area or change your search parameters." - ); - } else if (e.message == 403) { - commit("setLoading", false); - commit("setError", "Your login has expired. Please log in again."); - } else { - commit("setLoading", false); - commit( - "setError", - "Search error. Check your custom features or email logan@bellingcat.com." - ); - } + commit("setError", e); }); }, @@ -277,5 +266,9 @@ export default new Vuex.Store({ dispatch("getCustomPresets"); }, }, + getters: { + page: (state) => state.page, + hasMore: (state) => state.hasMore, + }, modules: {}, }); From 99fddb403ef7f043dc451af126dfc77a51412ed1 Mon Sep 17 00:00:00 2001 From: zameji Date: Thu, 9 May 2024 01:05:12 +0200 Subject: [PATCH 17/30] fix: remove hardcoded localhost server --- frontend/src/services/bellingcat.service.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/services/bellingcat.service.js b/frontend/src/services/bellingcat.service.js index 3b55911..5c7573f 100644 --- a/frontend/src/services/bellingcat.service.js +++ b/frontend/src/services/bellingcat.service.js @@ -1,6 +1,5 @@ const PAGE_SIZE = 100; -//const OSM_SEARCH_API = "https://api.osm-search.bellingcat.com"; -const OSM_SEARCH_API = "http://localhost:5050"; +const OSM_SEARCH_API = "https://api.osm-search.bellingcat.com"; class BellingCatService { constructor() { From 82a1a9c45ba7bfd52d1dcacd4bfffb854fe8b389 Mon Sep 17 00:00:00 2001 From: zameji Date: Sun, 12 May 2024 22:51:52 +0200 Subject: [PATCH 18/30] refactor: initial commit --- frontend_v2/.browserslistrc | 4 + frontend_v2/.editorconfig | 5 + frontend_v2/.eslintrc-auto-import.json | 69 + frontend_v2/.eslintrc.js | 21 + frontend_v2/.gitignore | 22 + frontend_v2/.prettierrc.json | 1 + frontend_v2/README.md | 82 + frontend_v2/index.html | 14 + frontend_v2/package-lock.json | 6431 +++++++++++++++++ frontend_v2/package.json | 52 + frontend_v2/public/favicon.ico | Bin 0 -> 15406 bytes frontend_v2/src/App.vue | 66 + .../src/assets/fonts/GoogleSans-Regular.ttf | Bin 0 -> 119984 bytes frontend_v2/src/assets/queries.ts | 602 ++ frontend_v2/src/auto-imports.d.ts | 191 + frontend_v2/src/components.d.ts | 23 + frontend_v2/src/components/FeatureCustom.vue | 100 + .../src/components/FeatureSelector.vue | 156 + frontend_v2/src/components/FeatureView.vue | 111 + frontend_v2/src/components/FirebaseLogin.vue | 50 + frontend_v2/src/components/GoogleLogin.vue | 64 + frontend_v2/src/components/HelpCard.vue | 69 + frontend_v2/src/components/README.md | 35 + frontend_v2/src/components/SearchControls.vue | 147 + frontend_v2/src/components/SearchResult.vue | 113 + frontend_v2/src/components/SearchResults.vue | 130 + frontend_v2/src/directives/OneTap.ts | 58 + frontend_v2/src/layouts/README.md | 5 + frontend_v2/src/main.ts | 23 + frontend_v2/src/pages/README.md | 5 + frontend_v2/src/pages/about.vue | 5 + frontend_v2/src/pages/index.vue | 24 + frontend_v2/src/pages/privacy.vue | 491 ++ frontend_v2/src/pages/tos.vue | 381 + frontend_v2/src/plugins/README.md | 3 + frontend_v2/src/plugins/index.ts | 17 + frontend_v2/src/plugins/vuetify.ts | 19 + frontend_v2/src/router/index.ts | 16 + .../src/services/bellingcat.service.ts | 100 + frontend_v2/src/services/firebase.ts | 20 + frontend_v2/src/services/mapbox.service.ts | 14 + .../src/services/openstreetmap.service.ts | 26 + frontend_v2/src/stores/README.md | 5 + frontend_v2/src/stores/app.ts | 260 + frontend_v2/src/stores/index.ts | 4 + frontend_v2/src/styles/README.md | 3 + frontend_v2/src/styles/settings.scss | 10 + frontend_v2/src/typed-router.d.ts | 26 + frontend_v2/src/vite-env.d.ts | 7 + frontend_v2/tsconfig.json | 30 + frontend_v2/tsconfig.node.json | 9 + frontend_v2/vite.config.mts | 68 + frontend_v2/vue.config.ts | 14 + 53 files changed, 10201 insertions(+) create mode 100644 frontend_v2/.browserslistrc create mode 100644 frontend_v2/.editorconfig create mode 100644 frontend_v2/.eslintrc-auto-import.json create mode 100644 frontend_v2/.eslintrc.js create mode 100644 frontend_v2/.gitignore create mode 100644 frontend_v2/.prettierrc.json create mode 100644 frontend_v2/README.md create mode 100644 frontend_v2/index.html create mode 100644 frontend_v2/package-lock.json create mode 100644 frontend_v2/package.json create mode 100644 frontend_v2/public/favicon.ico create mode 100644 frontend_v2/src/App.vue create mode 100644 frontend_v2/src/assets/fonts/GoogleSans-Regular.ttf create mode 100644 frontend_v2/src/assets/queries.ts create mode 100644 frontend_v2/src/auto-imports.d.ts create mode 100644 frontend_v2/src/components.d.ts create mode 100644 frontend_v2/src/components/FeatureCustom.vue create mode 100644 frontend_v2/src/components/FeatureSelector.vue create mode 100644 frontend_v2/src/components/FeatureView.vue create mode 100644 frontend_v2/src/components/FirebaseLogin.vue create mode 100755 frontend_v2/src/components/GoogleLogin.vue create mode 100644 frontend_v2/src/components/HelpCard.vue create mode 100644 frontend_v2/src/components/README.md create mode 100644 frontend_v2/src/components/SearchControls.vue create mode 100644 frontend_v2/src/components/SearchResult.vue create mode 100644 frontend_v2/src/components/SearchResults.vue create mode 100644 frontend_v2/src/directives/OneTap.ts create mode 100644 frontend_v2/src/layouts/README.md create mode 100644 frontend_v2/src/main.ts create mode 100644 frontend_v2/src/pages/README.md create mode 100644 frontend_v2/src/pages/about.vue create mode 100644 frontend_v2/src/pages/index.vue create mode 100644 frontend_v2/src/pages/privacy.vue create mode 100644 frontend_v2/src/pages/tos.vue create mode 100644 frontend_v2/src/plugins/README.md create mode 100644 frontend_v2/src/plugins/index.ts create mode 100644 frontend_v2/src/plugins/vuetify.ts create mode 100644 frontend_v2/src/router/index.ts create mode 100644 frontend_v2/src/services/bellingcat.service.ts create mode 100644 frontend_v2/src/services/firebase.ts create mode 100644 frontend_v2/src/services/mapbox.service.ts create mode 100644 frontend_v2/src/services/openstreetmap.service.ts create mode 100644 frontend_v2/src/stores/README.md create mode 100644 frontend_v2/src/stores/app.ts create mode 100644 frontend_v2/src/stores/index.ts create mode 100644 frontend_v2/src/styles/README.md create mode 100644 frontend_v2/src/styles/settings.scss create mode 100644 frontend_v2/src/typed-router.d.ts create mode 100644 frontend_v2/src/vite-env.d.ts create mode 100644 frontend_v2/tsconfig.json create mode 100644 frontend_v2/tsconfig.node.json create mode 100644 frontend_v2/vite.config.mts create mode 100644 frontend_v2/vue.config.ts diff --git a/frontend_v2/.browserslistrc b/frontend_v2/.browserslistrc new file mode 100644 index 0000000..dc3bc09 --- /dev/null +++ b/frontend_v2/.browserslistrc @@ -0,0 +1,4 @@ +> 1% +last 2 versions +not dead +not ie 11 diff --git a/frontend_v2/.editorconfig b/frontend_v2/.editorconfig new file mode 100644 index 0000000..7053c49 --- /dev/null +++ b/frontend_v2/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/frontend_v2/.eslintrc-auto-import.json b/frontend_v2/.eslintrc-auto-import.json new file mode 100644 index 0000000..b08dacb --- /dev/null +++ b/frontend_v2/.eslintrc-auto-import.json @@ -0,0 +1,69 @@ +{ + "globals": { + "Component": true, + "ComponentPublicInstance": true, + "ComputedRef": true, + "EffectScope": true, + "ExtractDefaultPropTypes": true, + "ExtractPropTypes": true, + "ExtractPublicPropTypes": true, + "InjectionKey": true, + "PropType": true, + "Ref": true, + "VNode": true, + "WritableComputedRef": true, + "computed": true, + "createApp": true, + "customRef": true, + "defineAsyncComponent": true, + "defineComponent": true, + "effectScope": true, + "getCurrentInstance": true, + "getCurrentScope": true, + "h": true, + "inject": true, + "isProxy": true, + "isReactive": true, + "isReadonly": true, + "isRef": true, + "markRaw": true, + "nextTick": true, + "onActivated": true, + "onBeforeMount": true, + "onBeforeUnmount": true, + "onBeforeUpdate": true, + "onDeactivated": true, + "onErrorCaptured": true, + "onMounted": true, + "onRenderTracked": true, + "onRenderTriggered": true, + "onScopeDispose": true, + "onServerPrefetch": true, + "onUnmounted": true, + "onUpdated": true, + "provide": true, + "reactive": true, + "readonly": true, + "ref": true, + "resolveComponent": true, + "shallowReactive": true, + "shallowReadonly": true, + "shallowRef": true, + "toRaw": true, + "toRef": true, + "toRefs": true, + "toValue": true, + "triggerRef": true, + "unref": true, + "useAttrs": true, + "useCssModule": true, + "useCssVars": true, + "useRoute": true, + "useRouter": true, + "useSlots": true, + "watch": true, + "watchEffect": true, + "watchPostEffect": true, + "watchSyncEffect": true + } +} diff --git a/frontend_v2/.eslintrc.js b/frontend_v2/.eslintrc.js new file mode 100644 index 0000000..7dee003 --- /dev/null +++ b/frontend_v2/.eslintrc.js @@ -0,0 +1,21 @@ +/** + * .eslint.js + * + * ESLint configuration file. + */ + +module.exports = { + root: true, + env: { + node: true, + }, + extends: [ + "plugin:vue/vue3-essential", + "eslint:recommended", + "@vue/eslint-config-typescript", + "prettier", + ], + rules: { + "vue/multi-word-component-names": "off", + }, +}; diff --git a/frontend_v2/.gitignore b/frontend_v2/.gitignore new file mode 100644 index 0000000..11f5d71 --- /dev/null +++ b/frontend_v2/.gitignore @@ -0,0 +1,22 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend_v2/.prettierrc.json b/frontend_v2/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/frontend_v2/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/frontend_v2/README.md b/frontend_v2/README.md new file mode 100644 index 0000000..9fc0ac6 --- /dev/null +++ b/frontend_v2/README.md @@ -0,0 +1,82 @@ +# Vuetify (Default) + +This is the official scaffolding tool for Vuetify, designed to give you a head start in building your new Vuetify application. It sets up a base template with all the necessary configurations and standard directory structure, enabling you to begin development without the hassle of setting up the project from scratch. + +## ❗️ Important Links + +- 📄 [Docs](https://vuetifyjs.com/) +- 🚨 [Issues](https://issues.vuetifyjs.com/) +- 🏬 [Store](https://store.vuetifyjs.com/) +- 🎮 [Playground](https://play.vuetifyjs.com/) +- 💬 [Discord](https://community.vuetifyjs.com) + +## 💿 Install + +Set up your project using your preferred package manager. Use the corresponding command to install the dependencies: + +| Package Manager | Command | +| --------------------------------------------------------- | -------------- | +| [yarn](https://yarnpkg.com/getting-started) | `yarn install` | +| [npm](https://docs.npmjs.com/cli/v7/commands/npm-install) | `npm install` | +| [pnpm](https://pnpm.io/installation) | `pnpm install` | +| [bun](https://bun.sh/#getting-started) | `bun install` | + +After completing the installation, your environment is ready for Vuetify development. + +## ✨ Features + +- 🖼️ **Optimized Front-End Stack**: Leverage the latest Vue 3 and Vuetify 3 for a modern, reactive UI development experience. [Vue 3](https://v3.vuejs.org/) | [Vuetify 3](https://vuetifyjs.com/en/) +- 🗃️ **State Management**: Integrated with [Pinia](https://pinia.vuejs.org/), the intuitive, modular state management solution for Vue. +- 🚦 **Routing and Layouts**: Utilizes Vue Router for SPA navigation and vite-plugin-vue-layouts for organizing Vue file layouts. [Vue Router](https://router.vuejs.org/) | [vite-plugin-vue-layouts](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) +- 💻 **Enhanced Development Experience**: Benefit from TypeScript's static type checking and the ESLint plugin suite for Vue, ensuring code quality and consistency. [TypeScript](https://www.typescriptlang.org/) | [ESLint Plugin Vue](https://eslint.vuejs.org/) +- ⚡ **Next-Gen Tooling**: Powered by Vite, experience fast cold starts and instant HMR (Hot Module Replacement). [Vite](https://vitejs.dev/) +- 🧩 **Automated Component Importing**: Streamline your workflow with unplugin-vue-components, automatically importing components as you use them. [unplugin-vue-components](https://github.com/antfu/unplugin-vue-components) +- 🛠️ **Strongly-Typed Vue**: Use vue-tsc for type-checking your Vue components, and enjoy a robust development experience. [vue-tsc](https://github.com/johnsoncodehk/volar/tree/master/packages/vue-tsc) + +These features are curated to provide a seamless development experience from setup to deployment, ensuring that your Vuetify application is both powerful and maintainable. + +## 💡 Usage + +This section covers how to start the development server and build your project for production. + +### Starting the Development Server + +To start the development server with hot-reload, run the following command. The server will be accessible at [http://localhost:3000](http://localhost:3000): + +```bash +yarn dev +``` + +(Repeat for npm, pnpm, and bun with respective commands.) + +> Add NODE_OPTIONS='--no-warnings' to suppress the JSON import warnings that happen as part of the Vuetify import mapping. If you are on Node [v21.3.0](https://nodejs.org/en/blog/release/v21.3.0) or higher, you can change this to NODE_OPTIONS='--disable-warning=5401'. If you don't mind the warning, you can remove this from your package.json dev script. + +### Building for Production + +To build your project for production, use: + +```bash +yarn build +``` + +(Repeat for npm, pnpm, and bun with respective commands.) + +Once the build process is completed, your application will be ready for deployment in a production environment. + +## 💪 Support Vuetify Development + +This project is built with [Vuetify](https://vuetifyjs.com/en/), a UI Library with a comprehensive collection of Vue components. Vuetify is an MIT licensed Open Source project that has been made possible due to the generous contributions by our [sponsors and backers](https://vuetifyjs.com/introduction/sponsors-and-backers/). If you are interested in supporting this project, please consider: + +- [Requesting Enterprise Support](https://support.vuetifyjs.com/) +- [Sponsoring John on Github](https://github.com/users/johnleider/sponsorship) +- [Sponsoring Kael on Github](https://github.com/users/kaelwd/sponsorship) +- [Supporting the team on Open Collective](https://opencollective.com/vuetify) +- [Becoming a sponsor on Patreon](https://www.patreon.com/vuetify) +- [Becoming a subscriber on Tidelift](https://tidelift.com/subscription/npm/vuetify) +- [Making a one-time donation with Paypal](https://paypal.me/vuetify) + +## 📑 License + +[MIT](http://opensource.org/licenses/MIT) + +Copyright (c) 2016-present Vuetify, LLC diff --git a/frontend_v2/index.html b/frontend_v2/index.html new file mode 100644 index 0000000..f450a73 --- /dev/null +++ b/frontend_v2/index.html @@ -0,0 +1,14 @@ + + + + + + + Welcome to Vuetify 3 + + + +
+ + + diff --git a/frontend_v2/package-lock.json b/frontend_v2/package-lock.json new file mode 100644 index 0000000..5775c4a --- /dev/null +++ b/frontend_v2/package-lock.json @@ -0,0 +1,6431 @@ +{ + "name": "frontend_v2", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend_v2", + "version": "0.0.0", + "dependencies": { + "@mdi/font": "6.2.95", + "core-js": "^3.34.0", + "export-to-csv": "^1.3.0", + "file-saver": "^2.0.5", + "firebaseui": "^6.1.0", + "roboto-fontface": "*", + "tokml": "^0.4.0", + "vue": "^3.4.21", + "vuedraggable": "^4.1.0", + "vuetify": "^3.5.8" + }, + "devDependencies": { + "@babel/types": "^7.24.0", + "@types/node": "^20.11.25", + "@vitejs/plugin-vue": "^5.0.4", + "@vue-leaflet/vue-leaflet": "^0.10.1", + "@vue/eslint-config-typescript": "^13.0.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-vue": "^9.22.0", + "leaflet": "1.9.4", + "pinia": "^2.1.7", + "prettier": "3.2.5", + "sass": "^1.71.1", + "typescript": "^5.4.2", + "unplugin-auto-import": "^0.17.5", + "unplugin-fonts": "^1.1.1", + "unplugin-vue-components": "^0.26.0", + "unplugin-vue-router": "^0.8.4", + "vite": "^5.1.5", + "vite-plugin-vue-layouts": "^0.11.0", + "vite-plugin-vuetify": "^2.0.3", + "vue-router": "^4.3.0", + "vue-tsc": "^2.0.6" + } + }, + "node_modules/@antfu/utils": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.8.tgz", + "integrity": "sha512-rWQkqXRESdjXtc+7NRfK9lASQjpXJu1ayp7qi1d23zZorY+wBHVLHHoVcMsEnkqEBWTFqbztO7/QdJFzyEcLTg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "peer": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@firebase/analytics": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.2.tgz", + "integrity": "sha512-6Gv/Fndih+dOEEfsBJEeKlwxw9EvCO9D/y+yJMasblvCmj78wUVtn+T96zguSrbhfZ2yBhLS1vukYiPg6hI49w==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/installations": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/analytics-compat": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.8.tgz", + "integrity": "sha512-scvzDPIsP9HcLWM77YQD7F3yLQksGvPUzyfqUrPo9XxIx26txJvGMJAS8O8BHa6jIvsjUenaTZ5oXEtKqNZQ9Q==", + "peer": true, + "dependencies": { + "@firebase/analytics": "0.10.2", + "@firebase/analytics-types": "0.8.1", + "@firebase/component": "0.6.6", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/analytics-types": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.1.tgz", + "integrity": "sha512-niv/67/EOkTlGUxyiOYfIkysSMGYxkIUHJzT9pNkeIGt6zOz759oCUXOAwwjJzckh11dMBFjIYBmtWrdSgbmJw==", + "peer": true + }, + "node_modules/@firebase/app": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.2.tgz", + "integrity": "sha512-Sk0lQYG0IRIUXkj6Ovaxu0o1E1OdC+IR+UYEYLjXuddr6YjnpFuZ69rTxVja2Ef4TpidJky9o8OoVIaXNjDJ5A==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-check": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.8.3.tgz", + "integrity": "sha512-nvlsj5oZBtYDjFTygQJ6xpyiYj8Jao2bFFyNJkUUPdg/QB8uhqDeG74P+gUH6iY9qzd1g5ZokmmGsoIhv9tdSQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/app-check-compat": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.10.tgz", + "integrity": "sha512-v+jiLG3rQ1fhpIuNIm3WqrL4dkPUIkgOWoic7QABVsZKSAv2YhOFvAenp7IhSP/pz/aiPniJ8G7el/MWieECTg==", + "peer": true, + "dependencies": { + "@firebase/app-check": "0.8.3", + "@firebase/app-check-types": "0.5.1", + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/app-check-interop-types": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.1.tgz", + "integrity": "sha512-NILZbe6RH3X1pZmJnfOfY2gLIrlKmrkUMMrrK6VSXHcSE0eQv28xFEcw16D198i9JYZpy5Kwq394My62qCMaIw==", + "peer": true + }, + "node_modules/@firebase/app-check-types": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.1.tgz", + "integrity": "sha512-NqeIcuGzZjl+khpXV0qsyOoaTqLeiG/K0kIDrebol+gb7xpmfOvXXqPEls+1WFBgHcPGdu+XRLhBA7xLzrVdpA==", + "peer": true + }, + "node_modules/@firebase/app-compat": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.32.tgz", + "integrity": "sha512-xxfAQKwCmpzwwdBHXT1DTnmilwSeSy6Sa1vThL0q0mq5GPHi52onkm5wl1lrOaiP0uQwQutkZBf/Wy4tDW+5WQ==", + "peer": true, + "dependencies": { + "@firebase/app": "0.10.2", + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/app-types": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.1.tgz", + "integrity": "sha512-nFGqTYsnDFn1oXf1tCwPAc+hQPxyvBT/QB7qDjwK+IDYThOn63nGhzdUTXxVD9Ca8gUY/e5PQMngeo0ZW/E3uQ==", + "peer": true + }, + "node_modules/@firebase/auth": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.2.tgz", + "integrity": "sha512-I8rrmhjdSYRokfCdElqm4fjJZdi7hh9NDGhXTRmcxkgUNcWoo82nZ0Ncm66MFlTdeLhNHEPzHqd38Gv6b+zpBg==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0", + "undici": "5.28.4" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@firebase/auth-compat": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.7.tgz", + "integrity": "sha512-NcHgTsqrdZxSEElJ+TtUzPT+LELlABVgVpxHEZX1xKY6YG8OIq2PsH5bk/0nzBvYnnYy7bJsKHsiSfS46MbRZA==", + "peer": true, + "dependencies": { + "@firebase/auth": "1.7.2", + "@firebase/auth-types": "0.12.1", + "@firebase/component": "0.6.6", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0", + "undici": "5.28.4" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/auth-interop-types": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.2.tgz", + "integrity": "sha512-k3NA28Jfoo0+o391bFjoV9X5QLnUL1WbLhZZRbTQhZdmdGYJfX8ixtNNlHsYQ94bwG0QRbsmvkzDnzuhHrV11w==", + "peer": true + }, + "node_modules/@firebase/auth-types": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.12.1.tgz", + "integrity": "sha512-B3dhiWRWf/njWosx4zdhSEoD4WHJmr4zbnBw6t20mRG/IZ4u0rWUBlMP1vFjhMstKIow1XmoGhTwD65X5ZXLjw==", + "peer": true, + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/component": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.6.tgz", + "integrity": "sha512-pp7sWqHmAAlA3os6ERgoM3k5Cxff510M9RLXZ9Mc8KFKMBc2ct3RkZTWUF7ixJNvMiK/iNgRLPDrLR2gtRJ9iQ==", + "peer": true, + "dependencies": { + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.4.tgz", + "integrity": "sha512-k84cXh+dtpzvY6yOhfyr1B+I1vjvSMtmlqotE0lTNVylc8m5nmOohjzpTLEQDrBWvwACX/VP5fEyajAdmnOKqA==", + "peer": true, + "dependencies": { + "@firebase/app-check-interop-types": "0.3.1", + "@firebase/auth-interop-types": "0.2.2", + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-compat": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.4.tgz", + "integrity": "sha512-GEEDAvsSMAkqy0BIFSVtFzoOIIcKHFfDM4aXHtWL/JCaNn4OOjH7td73jDfN3ALvpIN4hQki0FcxQ89XjqaTjQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/database": "1.0.4", + "@firebase/database-types": "1.0.2", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/database-types": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.2.tgz", + "integrity": "sha512-JRigr5JNLEHqOkI99tAGHDZF47469/cJz1tRAgGs8Feh+3ZmQy/vVChSqwMp2DuVUGp9PlmGsNSlpINJ/hDuIA==", + "peer": true, + "dependencies": { + "@firebase/app-types": "0.9.1", + "@firebase/util": "1.9.5" + } + }, + "node_modules/@firebase/firestore": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.1.tgz", + "integrity": "sha512-MaBOBu+QcZOp6SJzCmigiJ4Dt0HNic91w8GghbTE9L//VW/zdO7ezXrcXRK4TjWWOcazBrJZJSHTIsFdwZyvtQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "@firebase/webchannel-wrapper": "0.10.6", + "@grpc/grpc-js": "~1.9.0", + "@grpc/proto-loader": "^0.7.8", + "tslib": "^2.1.0", + "undici": "5.28.4" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/firestore-compat": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.30.tgz", + "integrity": "sha512-fnNvNBBdPwziYK01tY1J9zrVYAtGUOsLhpNcU1rpfcklKEUPwXfmiJoFdtNqmgk2x5RjggGpurOPAv6aoEl/PQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/firestore": "4.6.1", + "@firebase/firestore-types": "3.0.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/firestore-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.1.tgz", + "integrity": "sha512-mVhPcHr5FICjF67m6JHgj+XRvAz/gZ62xifeGfcm00RFl6tNKfCzCfKeyB2BDIEc9dUnEstkmIXlmLIelOWoaA==", + "peer": true, + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/functions": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.11.4.tgz", + "integrity": "sha512-FeMpXtlZG8hnxUauI5J8BSmIbY/Gcv7UVlByxHuHmGxxeS8mJPuAdIxPLUBNtV/naf+MeimIPcpPMslYr6tN6w==", + "peer": true, + "dependencies": { + "@firebase/app-check-interop-types": "0.3.1", + "@firebase/auth-interop-types": "0.2.2", + "@firebase/component": "0.6.6", + "@firebase/messaging-interop-types": "0.2.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0", + "undici": "5.28.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/functions-compat": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.10.tgz", + "integrity": "sha512-2Yidp6Dgf2k8LqJDQUTqdYFdf4ySNmZ71yeDX4lThby1HRMww+Y3nN98YaM6hHarZX3PUfaMUiMBZMHCRRT2IA==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/functions": "0.11.4", + "@firebase/functions-types": "0.6.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/functions-types": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.1.tgz", + "integrity": "sha512-DirqgTXSBzyKsQwcKnx/YdGMaRdJhywnThrINP+Iog8QfQnrL7aprTXHDFHlpZEMwykS54YRk53xzz7j396QXQ==", + "peer": true + }, + "node_modules/@firebase/installations": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.6.tgz", + "integrity": "sha512-dNGRGoHmstgEJqh9Kzk22fR2ZrVBH1JWliaL6binQ6pIzlWscreHNczzJDgOKoVT0PjWTrAmh/azztiX/e2uTw==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/util": "1.9.5", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/installations-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.6.tgz", + "integrity": "sha512-uxBAt2WsuEMT5dalA/1O+Uyi9DS25zKHgIPdrQ7KO1ZUdBURiGScIyjdhIM/7NMSvHGYugK4PUVdK9NFIffeiw==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/installations": "0.6.6", + "@firebase/installations-types": "0.5.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/installations-types": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.1.tgz", + "integrity": "sha512-OyREnRTfe2wIWTrzCz65ajyo4lFm6VgbeVqMMP+3GJLfCtNvY9VXkmqs3WFEsyYezzdcRqOt39FynZoLlkO+cQ==", + "peer": true, + "peerDependencies": { + "@firebase/app-types": "0.x" + } + }, + "node_modules/@firebase/logger": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.1.tgz", + "integrity": "sha512-tTIixB5UJbG9ZHSGZSZdX7THr3KWOLrejZ9B7jYsm6fpwgRNngKznQKA2wgYVyvBc1ta7dGFh9NtJ8n7qfiYIw==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/messaging": { + "version": "0.12.8", + "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.8.tgz", + "integrity": "sha512-FbCTNhv5DUBo8It+Wj3XbKM1xf3PeoHsHk8PjMWBNm0yP+LL8Jhd3ejRsukEYdysTMvgxY4sU5Cs5YNTK44qTQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/installations": "0.6.6", + "@firebase/messaging-interop-types": "0.2.1", + "@firebase/util": "1.9.5", + "idb": "7.1.1", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/messaging-compat": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.8.tgz", + "integrity": "sha512-/2ibL9u64jn76g67qjAZutVnPTV6euu0z3BvCjcqlNbMMdtoyNjyHOBRe/D7eVcrRt0uB4rTPnjr3A6sVKdjuA==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/messaging": "0.12.8", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/messaging-interop-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.1.tgz", + "integrity": "sha512-jfGJ7Jc32BDHXvXHyXi34mVLzZY8X0t929DTMwz7Tj2Hc40Zuzx8VRCIPLRrRUyvBrJCd5EpIcQgCygXhtaN1A==", + "peer": true + }, + "node_modules/@firebase/performance": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.6.6.tgz", + "integrity": "sha512-UOUHhvj2GJcjyJewdX1ShnON0/eqTswHvYzzQPC4nrIuMFvHwMGk8NpCaqh7JZmpaxh9AMr6kM+M/p37DrKWXA==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/installations": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/performance-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.6.tgz", + "integrity": "sha512-JSGdNNHBAMRTocGpN+m+7tk+9rulBcwuG+Ejw/ooDj45FGcON1Eymxh/qbe5M6Dlj5P1ClbkHLj4yf7MiCHOag==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/performance": "0.6.6", + "@firebase/performance-types": "0.2.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/performance-types": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.1.tgz", + "integrity": "sha512-kQ8pEr4d6ArhPoYrngcFlEJMNWMdEZTpvMAttWH0C2vegBgj47cm6xXFy9+0j27OBhOIiPn48Z+2WE2XNu33CQ==", + "peer": true + }, + "node_modules/@firebase/remote-config": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.4.6.tgz", + "integrity": "sha512-qtanFS+AX5k/7e/+Azf27Hq4reX28QsUvRcYWyS5cOaRMS9jtll4MK4winWmzX8MdJY637nFzIx43PlMKVnaKw==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/installations": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/remote-config-compat": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.6.tgz", + "integrity": "sha512-cFdpmN/rzDhm4pbk0WpOzK9JQ9I1ZhXzhtYbKRBwUag3pG1odEfIORygMDCGQniPpcae/QGXho4srJHfoijKuw==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/logger": "0.4.1", + "@firebase/remote-config": "0.4.6", + "@firebase/remote-config-types": "0.3.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/remote-config-types": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.3.1.tgz", + "integrity": "sha512-PgmfUugcJAinPLsJlYcBbNZe7KE2omdQw1WCT/z46nKkNVGkuHdVFSq54s3wiFa9BoHmLZ01u4hGXIhm6MdLOw==", + "peer": true + }, + "node_modules/@firebase/storage": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.4.tgz", + "integrity": "sha512-HcmUcp2kSSr5cHkIqFrgUW+i20925EEjkXepQxgBcI2Vx0cyqshr8iETtGow2+cMBFeY8H2swsKKabOKAjIwlQ==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0", + "undici": "5.28.4" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "node_modules/@firebase/storage-compat": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.7.tgz", + "integrity": "sha512-pTlNAm8/QPN7vhYRyd5thr2ouCykP+wIFXHY1AV42WTrk98sTGdIlt/tusHzmrH4mJ34MPaICS0cn2lYikiq8w==", + "peer": true, + "dependencies": { + "@firebase/component": "0.6.6", + "@firebase/storage": "0.12.4", + "@firebase/storage-types": "0.8.1", + "@firebase/util": "1.9.5", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "node_modules/@firebase/storage-types": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.1.tgz", + "integrity": "sha512-yj0vypPT9UbbfYYwzpXPYchnjWqCADcTbGNawAIebww8rnQYPGbESYTKQdFRPXiLspYPB7xCHTXThmMJuvDcsQ==", + "peer": true, + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "node_modules/@firebase/util": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.9.5.tgz", + "integrity": "sha512-PP4pAFISDxsf70l3pEy34Mf3GkkUcVQ3MdKp6aSVb7tcpfUQxnsdV7twDd8EkfB6zZylH6wpUAoangQDmCUMqw==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/@firebase/webchannel-wrapper": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.6.tgz", + "integrity": "sha512-EnfRJvrnzkHwN3BPMCayCFT5lCqInzg3RdlRsDjDvB1EJli6Usj26T6lJ67BU2UcYXBS5xcp1Wj4+zRzj2NaZg==", + "peer": true + }, + "node_modules/@grpc/grpc-js": { + "version": "1.9.14", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz", + "integrity": "sha512-nOpuzZ2G3IuMFN+UPPpKrC6NsLmWsTqSsm66IRfnBt1D4pwTqE27lmbpcPM+l2Ua4gE7PfjRHI6uedAy7hoXUw==", + "peer": true, + "dependencies": { + "@grpc/proto-loader": "^0.7.8", + "@types/node": ">=12.12.47" + }, + "engines": { + "node": "^8.13.0 || >=10.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", + "peer": true, + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@mdi/font": { + "version": "6.2.95", + "resolved": "https://registry.npmjs.org/@mdi/font/-/font-6.2.95.tgz", + "integrity": "sha512-0RKkhabkFZP3ALwKqrjhdKdhydQpoydIjX6cvjIwLyjADCsE0pG68YkGY+S3qnfdErmhS4m8adwvgrAFXp2AYQ==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "peer": true + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "peer": true + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "peer": true + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "peer": true + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "peer": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "peer": true + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "peer": true + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "peer": true + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "peer": true + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "peer": true + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", + "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", + "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", + "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", + "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", + "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", + "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", + "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", + "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", + "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", + "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", + "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", + "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", + "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", + "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", + "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", + "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "devOptional": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", + "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", + "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", + "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", + "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", + "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", + "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", + "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", + "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.15", + "@types/semver": "^7.5.8", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "semver": "^7.6.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", + "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.8.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.4.tgz", + "integrity": "sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.2.2.tgz", + "integrity": "sha512-GuvEL4JdxbnLVhPLICncCGT+tVW4cIz9GxXNeDofNnJ4iNTKhr5suGVsA1GLOne9PbraSjn8PlLt+pvLxuRVeQ==", + "dev": true, + "dependencies": { + "@volar/source-map": "2.2.2" + } + }, + "node_modules/@volar/source-map": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.2.2.tgz", + "integrity": "sha512-vUwvZuSW6iN4JI9QRinh9EjFasx1TUtnaWMKwgWx08xz1PyYuNkLlWlrZXBZ5GGBhML0u230M/7X+AHY2h9yKg==", + "dev": true, + "dependencies": { + "muggle-string": "^0.4.0" + } + }, + "node_modules/@volar/typescript": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.2.2.tgz", + "integrity": "sha512-WcwOREz7+uOrpjUrKhOMaOKKmyPdtqF95HWX7SE0d9hhBB1KkfahxhaAex5U9Bn43LfINHlycLoYCNEtfeKm0g==", + "dev": true, + "dependencies": { + "@volar/language-core": "2.2.2", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue-leaflet/vue-leaflet": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@vue-leaflet/vue-leaflet/-/vue-leaflet-0.10.1.tgz", + "integrity": "sha512-RNEDk8TbnwrJl8ujdbKgZRFygLCxd0aBcWLQ05q/pGv4+d0jamE3KXQgQBqGAteE1mbQsk3xoNcqqUgaIGfWVg==", + "dev": true, + "dependencies": { + "vue": "^3.2.25" + }, + "peerDependencies": { + "@types/leaflet": "^1.5.7", + "leaflet": "^1.6.0" + }, + "peerDependenciesMeta": { + "@types/leaflet": { + "optional": true + } + } + }, + "node_modules/@vue-macros/common": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-1.10.3.tgz", + "integrity": "sha512-YSgzcbXrRo8a/TF/YIguqEmTld1KA60VETKJG8iFuaAfj7j+Tbdin3cj7/cYbcCHORSq1v9IThgq7r8keH7LXQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@rollup/pluginutils": "^5.1.0", + "@vue/compiler-sfc": "^3.4.25", + "ast-kit": "^0.12.1", + "local-pkg": "^0.5.0", + "magic-string-ast": "^0.5.0" + }, + "engines": { + "node": ">=16.14.0" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.27.tgz", + "integrity": "sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==", + "dependencies": { + "@babel/parser": "^7.24.4", + "@vue/shared": "3.4.27", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.27.tgz", + "integrity": "sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==", + "dependencies": { + "@vue/compiler-core": "3.4.27", + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.27.tgz", + "integrity": "sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==", + "dependencies": { + "@babel/parser": "^7.24.4", + "@vue/compiler-core": "3.4.27", + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.10", + "postcss": "^8.4.38", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.27.tgz", + "integrity": "sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==", + "dependencies": { + "@vue/compiler-dom": "3.4.27", + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.1.tgz", + "integrity": "sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA==", + "dev": true + }, + "node_modules/@vue/eslint-config-typescript": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@vue/eslint-config-typescript/-/eslint-config-typescript-13.0.0.tgz", + "integrity": "sha512-MHh9SncG/sfqjVqjcuFLOLD6Ed4dRAis4HNt0dXASeAuLqIAx4YMB1/m2o4pUKK1vCt8fUvYG8KKX2Ot3BVZTg==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^7.1.1", + "@typescript-eslint/parser": "^7.1.1", + "vue-eslint-parser": "^9.3.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "peerDependencies": { + "eslint": "^8.56.0", + "eslint-plugin-vue": "^9.0.0", + "typescript": ">=4.7.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.0.17.tgz", + "integrity": "sha512-tHw2J6G9yL4kn3jN5MftOHEq86Y6qnuohBQ1OHkJ73fAv3OYgwDI1cfX7ds0OEJEycOMG64BA3ql5bDgDa41zw==", + "dev": true, + "dependencies": { + "@volar/language-core": "~2.2.2", + "@vue/compiler-dom": "^3.4.0", + "@vue/shared": "^3.4.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.27.tgz", + "integrity": "sha512-kK0g4NknW6JX2yySLpsm2jlunZJl2/RJGZ0H9ddHdfBVHcNzxmQ0sS0b09ipmBoQpY8JM2KmUw+a6sO8Zo+zIA==", + "dependencies": { + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.27.tgz", + "integrity": "sha512-7aYA9GEbOOdviqVvcuweTLe5Za4qBZkUY7SvET6vE8kyypxVgaT1ixHLg4urtOlrApdgcdgHoTZCUuTGap/5WA==", + "dependencies": { + "@vue/reactivity": "3.4.27", + "@vue/shared": "3.4.27" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.27.tgz", + "integrity": "sha512-ScOmP70/3NPM+TW9hvVAz6VWWtZJqkbdf7w6ySsws+EsqtHvkhxaWLecrTorFxsawelM5Ys9FnDEMt6BPBDS0Q==", + "dependencies": { + "@vue/runtime-core": "3.4.27", + "@vue/shared": "3.4.27", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.27.tgz", + "integrity": "sha512-dlAMEuvmeA3rJsOMJ2J1kXU7o7pOxgsNHVr9K8hB3ImIkSuBrIdy0vF66h8gf8Tuinf1TK3mPAz2+2sqyf3KzA==", + "dependencies": { + "@vue/compiler-ssr": "3.4.27", + "@vue/shared": "3.4.27" + }, + "peerDependencies": { + "vue": "3.4.27" + } + }, + "node_modules/@vue/shared": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.27.tgz", + "integrity": "sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==" + }, + "node_modules/@vuetify/loader-shared": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@vuetify/loader-shared/-/loader-shared-2.0.3.tgz", + "integrity": "sha512-Ss3GC7eJYkp2SF6xVzsT7FAruEmdihmn4OCk2+UocREerlXKWgOKKzTN5PN3ZVN5q05jHHrsNhTuWbhN61Bpdg==", + "devOptional": true, + "dependencies": { + "upath": "^2.0.1" + }, + "peerDependencies": { + "vue": "^3.0.0", + "vuetify": "^3.0.0" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "devOptional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-kit": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-0.12.1.tgz", + "integrity": "sha512-O+33g7x6irsESUcd47KdfWUrS2F6aGp9KeVJFGj0YjIznfXpBxVGjA0w+y/1OKqX4mFOfmZ9Xpf1ixPT4n9xxw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.23.9", + "pathe": "^1.1.2" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.6.1.tgz", + "integrity": "sha512-0ZdQEsSfH3mX4BFbRCc3xOBjx5bDbm73+aAdQOHerPQNf8K0XFMAv79ucd2BpnSc4UMyvBDixiroT8yjm2Y6bw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.24.0", + "ast-kit": "^0.12.1" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "devOptional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "devOptional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.2.tgz", + "integrity": "sha512-4hr0gS7+NK47X6WbA/okVFrN5qGh3WLT7N3hMRv7+hlkXnbUIdU2u05n6r0RQv6cq6xke06nVl70r0NW0WM2OQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", + "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bunker": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/bunker/-/bunker-0.1.2.tgz", + "integrity": "sha512-YnahkcXBNT522S46k5LUA9P18lzvgkunbMl0qIJQ8oeRMQ+dAg3YI3k32q5TnO+AAUErFHO6R768To6jslgYmQ==", + "dependencies": { + "burrito": ">=0.2.5 <0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/burrito": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/burrito/-/burrito-0.2.12.tgz", + "integrity": "sha512-ZhhT5iVTAgzQ+s8rily7m45Swxe/cU3dVCHTzqmHVWD/cc0Ds3W4Q4MExbkevY+fm0Me3lEwpehIy6TH7p+ehw==", + "dependencies": { + "traverse": "~0.5.1", + "uglify-js": "~1.1.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/burrito/node_modules/traverse": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.5.2.tgz", + "integrity": "sha512-PUBVcfB3RqgLpzgTRGNiqK4duqrDbgGa1bobbUtzUwLiBNAjZ7vd5eCOdBxqZ/Fgezagr9o69IxP2fZp41RGFA==", + "engines": { + "node": "*" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charm": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", + "integrity": "sha512-syedaZ9cPe7r3hoQA9twWYKu5AIyCswN5+szkmPBe9ccdLrj4bYaCnLVPTLd2kgVRc7+zoX4tyPgRnFKCj5YjQ==" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "devOptional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "devOptional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true + }, + "node_modules/core-js": { + "version": "3.37.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz", + "integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "devOptional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-equal": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.0.0.tgz", + "integrity": "sha512-p1bI/kkDPT6auUI0U+WLuIIrzmDIDo80I406J8tT4y6I4ZGtBuMeTudrKDtBdMJFAcxqrQdx27gosqPVyY3IvQ==", + "engines": { + "node": "*" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dialog-polyfill": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/dialog-polyfill/-/dialog-polyfill-0.4.10.tgz", + "integrity": "sha512-j5yGMkP8T00UFgyO+78OxiN5vC5dzRQF3BEio+LhNvDbyfxWBsi3sfPArDm54VloaJwy2hm3erEiDWqHRC8rzw==" + }, + "node_modules/difflet": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/difflet/-/difflet-0.2.6.tgz", + "integrity": "sha512-ruldDDRmY1t678UOAJBng6sL77f62SqjHj0498YC0EJhxIe2yKkqJn2qEchwG3eU/dqJ/RxPZkAnYjePS4pDCw==", + "dependencies": { + "charm": "0.1.x", + "deep-is": "0.1.x", + "traverse": "0.6.x" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "peer": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "devOptional": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.0.tgz", + "integrity": "sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==", + "dev": true, + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "dependencies": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.6.0.tgz", + "integrity": "sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.6.0", + "eslint-compat-utils": "^0.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.5.0", + "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", + "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-n/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "dependencies": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "engines": { + "node": ">=8.10.0" + }, + "peerDependencies": { + "eslint": ">=5.16.0" + } + }, + "node_modules/eslint-plugin-node/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-node/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-node/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.26.0.tgz", + "integrity": "sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.0", + "vue-eslint-parser": "^9.4.2", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/export-to-csv": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/export-to-csv/-/export-to-csv-1.3.0.tgz", + "integrity": "sha512-msPjbfozZdYzDghAEKmCVH5veMeKHNacplE6noXvGiA8AeV1qa/SOxp6JXDjF9R8Kf6v3ypI6jskiY19dkhZeA==", + "engines": { + "node": "^v12.20.0 || >=v14.13.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "peer": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "devOptional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/firebase": { + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.11.1.tgz", + "integrity": "sha512-7T6FJJb4PBi6IYR1212/a0djjal6nGph9AQazobWaO75+4zeyEvBDlsofWLEawVAEN2PCp8qXvFe4pMdIB5U1w==", + "peer": true, + "dependencies": { + "@firebase/analytics": "0.10.2", + "@firebase/analytics-compat": "0.2.8", + "@firebase/app": "0.10.2", + "@firebase/app-check": "0.8.3", + "@firebase/app-check-compat": "0.3.10", + "@firebase/app-compat": "0.2.32", + "@firebase/app-types": "0.9.1", + "@firebase/auth": "1.7.2", + "@firebase/auth-compat": "0.5.7", + "@firebase/database": "1.0.4", + "@firebase/database-compat": "1.0.4", + "@firebase/firestore": "4.6.1", + "@firebase/firestore-compat": "0.3.30", + "@firebase/functions": "0.11.4", + "@firebase/functions-compat": "0.3.10", + "@firebase/installations": "0.6.6", + "@firebase/installations-compat": "0.2.6", + "@firebase/messaging": "0.12.8", + "@firebase/messaging-compat": "0.2.8", + "@firebase/performance": "0.6.6", + "@firebase/performance-compat": "0.2.6", + "@firebase/remote-config": "0.4.6", + "@firebase/remote-config-compat": "0.2.6", + "@firebase/storage": "0.12.4", + "@firebase/storage-compat": "0.3.7", + "@firebase/util": "1.9.5" + } + }, + "node_modules/firebaseui": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/firebaseui/-/firebaseui-6.1.0.tgz", + "integrity": "sha512-5WiVYVxPGMANuZKxg6KLyU1tyqIsbqf/59Zm4HrdFYwPtM5lxxB0THvgaIk4ix+hCgF0qmY89sKiktcifKzGIA==", + "dependencies": { + "dialog-polyfill": "^0.4.7", + "material-design-lite": "^1.2.0" + }, + "peerDependencies": { + "firebase": "^9.1.3 || ^10.0.0" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "peer": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "peer": true + }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", + "peer": true + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==", + "devOptional": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "devOptional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/json5/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/leaflet": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", + "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/local-pkg": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", + "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "dev": true, + "dependencies": { + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "peer": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "peer": true + }, + "node_modules/lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==" + }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/magic-string-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-0.5.0.tgz", + "integrity": "sha512-mxjxZ5zoR4+ybulZ7Z5qdZUTdAfiKJ1Il80kN/I4jWsHTTqNKZ9KsBa3Jepo+3U09I04qiyC2+7MZD8v4rJOoA==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.9" + }, + "engines": { + "node": ">=16.14.0" + } + }, + "node_modules/material-design-lite": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/material-design-lite/-/material-design-lite-1.3.0.tgz", + "integrity": "sha512-ao76b0bqSTKcEMt7Pui+J/S3eVF0b3GWfuKUwfe2lP5DKlLZOwBq37e0/bXEzxrw7/SuHAuYAdoCwY6mAYhrsg==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.1.0.tgz", + "integrity": "sha512-wR5Ipl99t0mTGwLjQJnBjrP/O7zBbLZqvA3aw32DmLx+nXHfWctUjzDjnDx09pX1Po86WFQazF9xUzfMea3Cnw==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mlly": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz", + "integrity": "sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.0", + "ufo": "^1.5.3" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "devOptional": true + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/nopt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", + "integrity": "sha512-gIOTA/uJuhPwFqp+spY7VQ1satbnGlD+iQVZxI18K6hs8Evq4sX81Ml7BB5byP/LsbR2yBVtmvdEmhi7evJ6Aw==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "devOptional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.7.tgz", + "integrity": "sha512-+C2AHFtcFqjPih0zpYuvof37SFxMQ7OEG2zV9jRI12i9BOy3YQVAHwdKtyyc8pDcDyIc33WCIsZaCFWU7WWxGQ==", + "dev": true, + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz", + "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/pkg-types": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", + "dev": true, + "dependencies": { + "confbox": "^0.1.7", + "mlly": "^1.7.0", + "pathe": "^1.1.2" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/protobufjs": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.3.0.tgz", + "integrity": "sha512-YWD03n3shzV9ImZRX3ccbjqLxj7NokGN0V/ESiBV5xWqrommYHYiihuIyavq03pWSGqlyvYUFmfoMKd+1rPA/g==", + "hasInstallScript": true, + "peer": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "devOptional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/roboto-fontface": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", + "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" + }, + "node_modules/rollup": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", + "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "devOptional": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.17.2", + "@rollup/rollup-android-arm64": "4.17.2", + "@rollup/rollup-darwin-arm64": "4.17.2", + "@rollup/rollup-darwin-x64": "4.17.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", + "@rollup/rollup-linux-arm-musleabihf": "4.17.2", + "@rollup/rollup-linux-arm64-gnu": "4.17.2", + "@rollup/rollup-linux-arm64-musl": "4.17.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", + "@rollup/rollup-linux-riscv64-gnu": "4.17.2", + "@rollup/rollup-linux-s390x-gnu": "4.17.2", + "@rollup/rollup-linux-x64-gnu": "4.17.2", + "@rollup/rollup-linux-x64-musl": "4.17.2", + "@rollup/rollup-win32-arm64-msvc": "4.17.2", + "@rollup/rollup-win32-ia32-msvc": "4.17.2", + "@rollup/rollup-win32-x64-msvc": "4.17.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/runforcover": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/runforcover/-/runforcover-0.0.2.tgz", + "integrity": "sha512-yarCIK2HcAOadqnKW419+FA38qpWDCKcOr5RZU+jnyLL/hn3No9BHZY+YJDEzvQ0k8Oyl7ffLjZv9ZUxvyKoLQ==", + "dependencies": { + "bunker": "0.1.X" + }, + "engines": { + "node": "*" + } + }, + "node_modules/rw": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/rw/-/rw-0.0.4.tgz", + "integrity": "sha512-JXKZaF+LLZNj4vwbrexrjafIACEUxe1BCzjZ7BTIsFGwhk6xY/nEx2jenGwJfRtFx13dFX+ophHr00vm14Thmw==" + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "peer": true + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sass": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.0.tgz", + "integrity": "sha512-eGj4HNfXqBWtSnvItNkn7B6icqH14i3CiCGbzMKs3BAPTq62pp9NBYsBgyN4cA+qssqo9r26lW4JSvlaUUWbgw==", + "devOptional": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha512-NwrtjCg+lZoqhFU8fOwl4ay2ei8PaqCBOUV3/ektPY9trO1yQ1oXEfmHAhKArUVUr/hOHvy5f6AdP17dCM0zMw==", + "engines": { + "node": "*" + } + }, + "node_modules/sortablejs": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz", + "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==" + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", + "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", + "dev": true, + "dependencies": { + "acorn": "^8.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strxml": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/strxml/-/strxml-0.0.0.tgz", + "integrity": "sha512-w3AyPYFyzSPGVJG/lYdn7MXrJX2uHuFoXhyNKuMkHBwqgQ5KdTr7WoEMey+z5HVFW4VlN7WAaZXjSKM33fhxig==", + "dependencies": { + "tap": "~0.4.8" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tap": { + "version": "0.4.13", + "resolved": "https://registry.npmjs.org/tap/-/tap-0.4.13.tgz", + "integrity": "sha512-DRPT9T2qqeUQ9nC8nwnZPQQnKA+bVhzaNrIDoFETFqWLXGOvil/JMhuWj5uO6XeNzIdvvPKLqPHQzIkJnjNnDQ==", + "dependencies": { + "buffer-equal": "~0.0.0", + "deep-equal": "~0.0.0", + "difflet": "~0.2.0", + "glob": "~3.2.1", + "inherits": "*", + "mkdirp": "~0.3 || 0.4 || 0.5", + "nopt": "~2", + "runforcover": "~0.0.2", + "slide": "*", + "yamlish": "*" + }, + "bin": { + "tap": "bin/tap.js" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tap/node_modules/glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", + "dependencies": { + "inherits": "2", + "minimatch": "0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tap/node_modules/minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "devOptional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tokml": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/tokml/-/tokml-0.4.0.tgz", + "integrity": "sha512-D7e2FyPOBAfozooh5LGL2TrCriHydVV0HH7mUt+mG1dA0Q5ueSMuSPlRz0FDnFEbhg4/o+kM/vjbx0wFr3uy9w==", + "dependencies": { + "minimist": "0.1.0", + "rw": "0.0.4", + "strxml": "0.0.0" + }, + "bin": { + "tokml": "tokml" + } + }, + "node_modules/traverse": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.9.tgz", + "integrity": "sha512-7bBrcF+/LQzSgFmT0X5YclVqQxtv7TDJ1f8Wj7ibBu/U6BMLeOpUxuZjV7rMc44UtKxlnMFigdhFAIszSX1DMg==", + "dependencies": { + "gopd": "^1.0.1", + "typedarray.prototype.slice": "^1.0.3", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "peer": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz", + "integrity": "sha512-8WbVAQAUlENo1q3c3zZYuy5k9VzBQvp8AX9WOtbvyWlLM1v5JaSRmjubLjzHF4JFtptjH/5c/i95yaElvcjC0A==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-offset": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "devOptional": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", + "dev": true + }, + "node_modules/uglify-js": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.1.1.tgz", + "integrity": "sha512-YYY9Dle1leC+btgrHnAR05eq0aRdcPJsXlYYD+SYw2lqc5HFuFNHg3wWEW4SNE0iXXEUl0fz43gTQ3r1YK76rg==", + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": "*" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici": { + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "peer": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unimport": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-3.7.1.tgz", + "integrity": "sha512-V9HpXYfsZye5bPPYUgs0Otn3ODS1mDUciaBlXljI4C2fTwfFpvFZRywmlOu943puN9sncxROMZhsZCjNXEpzEQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "acorn": "^8.11.2", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.5", + "mlly": "^1.4.2", + "pathe": "^1.1.1", + "pkg-types": "^1.0.3", + "scule": "^1.1.1", + "strip-literal": "^1.3.0", + "unplugin": "^1.5.1" + } + }, + "node_modules/unimport/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/unplugin": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.10.1.tgz", + "integrity": "sha512-d6Mhq8RJeGA8UfKCu54Um4lFA0eSaRa3XxdAJg8tIdxbu1ubW0hBCZUL7yI2uGyYCRndvbK8FLHzqy2XKfeMsg==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "chokidar": "^3.6.0", + "webpack-sources": "^3.2.3", + "webpack-virtual-modules": "^0.6.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.6.tgz", + "integrity": "sha512-dmX0Pex5DzMzVuALkexboOZvh51fL/BD6aoPO7qHoTYGlQp0GRKsREv2KMF1lzYI9SXKQiRxAjwzbQnrFFNydQ==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.8", + "@rollup/pluginutils": "^5.1.0", + "fast-glob": "^3.3.2", + "local-pkg": "^0.5.0", + "magic-string": "^0.30.10", + "minimatch": "^9.0.4", + "unimport": "^3.7.1", + "unplugin": "^1.10.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-fonts": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unplugin-fonts/-/unplugin-fonts-1.1.1.tgz", + "integrity": "sha512-/Aw/rL9D2aslGGM0vi+2R2aG508RSwawLnnBuo+JDSqYc4cHJO1R1phllhN6GysEhBp/6a4B6+vSFPVapWyAAw==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.12", + "unplugin": "^1.3.1" + }, + "peerDependencies": { + "@nuxt/kit": "^3.0.0", + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.26.0.tgz", + "integrity": "sha512-s7IdPDlnOvPamjunVxw8kNgKNK8A5KM1YpK5j/p97jEKTjlPNrA0nZBiSfAKKlK1gWZuyWXlKL5dk3EDw874LQ==", + "dev": true, + "dependencies": { + "@antfu/utils": "^0.7.6", + "@rollup/pluginutils": "^5.0.4", + "chokidar": "^3.5.3", + "debug": "^4.3.4", + "fast-glob": "^3.3.1", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.3", + "minimatch": "^9.0.3", + "resolve": "^1.22.4", + "unplugin": "^1.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/unplugin-vue-router": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.8.6.tgz", + "integrity": "sha512-yd7A4qIT2ZvCELchL32qVueFXx8BE9zD0UEzWJjHAlVy2Xb2luPkNJG6uCAeqdObCS1lSKTOFAFmQXAxdchqTw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.0", + "@rollup/pluginutils": "^5.1.0", + "@vue-macros/common": "^1.10.2", + "ast-walker-scope": "^0.6.1", + "chokidar": "^3.6.0", + "fast-glob": "^3.3.2", + "json5": "^2.2.3", + "local-pkg": "^0.5.0", + "mlly": "^1.6.1", + "pathe": "^1.1.2", + "scule": "^1.3.0", + "unplugin": "^1.10.1", + "yaml": "^2.4.1" + }, + "peerDependencies": { + "vue-router": "^4.3.0" + }, + "peerDependenciesMeta": { + "vue-router": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-router/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "devOptional": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vite": { + "version": "5.2.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", + "integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==", + "devOptional": true, + "dependencies": { + "esbuild": "^0.20.1", + "postcss": "^8.4.38", + "rollup": "^4.13.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-vue-layouts": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-layouts/-/vite-plugin-vue-layouts-0.11.0.tgz", + "integrity": "sha512-uh6NW7lt+aOXujK4eHfiNbeo55K9OTuB7fnv+5RVc4OBn/cZull6ThXdYH03JzKanUfgt6QZ37NbbtJ0og59qw==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "fast-glob": "^3.3.2" + }, + "peerDependencies": { + "vite": "^4.0.0 || ^5.0.0", + "vue": "^3.2.4", + "vue-router": "^4.0.11" + } + }, + "node_modules/vite-plugin-vuetify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vite-plugin-vuetify/-/vite-plugin-vuetify-2.0.3.tgz", + "integrity": "sha512-HbYajgGgb/noaVKNRhnnXIiQZrNXfNIeanUGAwXgOxL6h/KULS40Uf51Kyz8hNmdegF+DwjgXXI/8J1PNS83xw==", + "devOptional": true, + "dependencies": { + "@vuetify/loader-shared": "^2.0.3", + "debug": "^4.3.3", + "upath": "^2.0.1" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": ">=5", + "vue": "^3.0.0", + "vuetify": "^3.0.0" + } + }, + "node_modules/vue": { + "version": "3.4.27", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.27.tgz", + "integrity": "sha512-8s/56uK6r01r1icG/aEOHqyMVxd1bkYcSe9j8HcKtr/xTOFWvnzIVTehNW+5Yt89f+DLBe4A569pnZLS5HzAMA==", + "dependencies": { + "@vue/compiler-dom": "3.4.27", + "@vue/compiler-sfc": "3.4.27", + "@vue/runtime-dom": "3.4.27", + "@vue/server-renderer": "3.4.27", + "@vue/shared": "3.4.27" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.4.2.tgz", + "integrity": "sha512-Ry9oiGmCAK91HrKMtCrKFWmSFWvYkpGglCeFAIqDdr9zdXmMMpJOmUJS7WWsW7fX81h6mwHmUZCQQ1E0PkSwYQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.3.2.tgz", + "integrity": "sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q==", + "dev": true, + "dependencies": { + "@vue/devtools-api": "^6.5.1" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.0.17.tgz", + "integrity": "sha512-RRZsiCBD1hvATQb321xV+SkRDKsK5hgFQ4WXy5wuYsyyjz8xAK4DjxHkpH7PFoJKUbZTbeW8KzhejzXZS49Tzw==", + "dev": true, + "dependencies": { + "@volar/typescript": "~2.2.2", + "@vue/language-core": "2.0.17", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/vuedraggable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz", + "integrity": "sha512-FU5HCWBmsf20GpP3eudURW3WdWTKIbEIQxh9/8GE806hydR9qZqRRxRE3RjqX7PkuLuMQG/A7n3cfj9rCEchww==", + "dependencies": { + "sortablejs": "1.14.0" + }, + "peerDependencies": { + "vue": "^3.0.1" + } + }, + "node_modules/vuetify": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.6.4.tgz", + "integrity": "sha512-H0s+VQAuFDIaqJaxaYv3DuJoSlThMfIJX5l06sGkxk9YDMxiEjE4ABT58fTAZGdPMF/TzMXtTHbRNCHes0UaHQ==", + "engines": { + "node": "^12.20 || >=14.13" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/johnleider" + }, + "peerDependencies": { + "typescript": ">=4.7", + "vite-plugin-vuetify": ">=1.0.0", + "vue": "^3.3.0", + "vue-i18n": "^9.0.0", + "webpack-plugin-vuetify": ">=2.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vite-plugin-vuetify": { + "optional": true + }, + "vue-i18n": { + "optional": true + }, + "webpack-plugin-vuetify": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.1.tgz", + "integrity": "sha512-poXpCylU7ExuvZK8z+On3kX+S8o/2dQ/SVYueKA0D4WEMXROXgY8Ez50/bQEUmvoSMMrWcrJqCHuhAbsiwg7Dg==", + "dev": true + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "peer": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", + "dev": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yamlish": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/yamlish/-/yamlish-0.0.7.tgz", + "integrity": "sha512-MfSpIJj5Hmm0Yz788MEW1NWfdOhZR/O0WPrdiUeWBKTtCNm0jZwMJZhScqveQoE6CvUoXOQBs5/1I/nC6Sbj/w==" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "peer": true, + "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.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/frontend_v2/package.json b/frontend_v2/package.json new file mode 100644 index 0000000..70d9f12 --- /dev/null +++ b/frontend_v2/package.json @@ -0,0 +1,52 @@ +{ + "name": "frontend_v2", + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview", + "lint": "eslint . --fix --ignore-path .gitignore", + "format": "prettier . --write" + }, + "dependencies": { + "@mdi/font": "6.2.95", + "core-js": "^3.34.0", + "export-to-csv": "^1.3.0", + "file-saver": "^2.0.5", + "firebaseui": "^6.1.0", + "roboto-fontface": "*", + "tokml": "^0.4.0", + "vue": "^3.4.21", + "vuedraggable": "^4.1.0", + "vuetify": "^3.5.8" + }, + "devDependencies": { + "@babel/types": "^7.24.0", + "@types/node": "^20.11.25", + "@vitejs/plugin-vue": "^5.0.4", + "@vue-leaflet/vue-leaflet": "^0.10.1", + "@vue/eslint-config-typescript": "^13.0.0", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-config-standard": "^17.1.0", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "eslint-plugin-vue": "^9.22.0", + "leaflet": "1.9.4", + "pinia": "^2.1.7", + "prettier": "3.2.5", + "sass": "^1.71.1", + "typescript": "^5.4.2", + "unplugin-auto-import": "^0.17.5", + "unplugin-fonts": "^1.1.1", + "unplugin-vue-components": "^0.26.0", + "unplugin-vue-router": "^0.8.4", + "vite": "^5.1.5", + "vite-plugin-vue-layouts": "^0.11.0", + "vite-plugin-vuetify": "^2.0.3", + "vue-router": "^4.3.0", + "vue-tsc": "^2.0.6" + } +} diff --git a/frontend_v2/public/favicon.ico b/frontend_v2/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8fb9f91b3aab4eec0c76ffc5342528033c61e247 GIT binary patch literal 15406 zcmeHO3v5%@8NNVarCoU?zSqezmT6npu}xxXJJhY(x=s~hQ>SSYYSncU&|(|9Y?QVX z@}TB1G8mASM;tRKYgJkrAW)&g7${B%c>oE7;)O>NNO_bu4G-IdNB({PbTkJL{ZGDJe2DLL+vq#sL?l$jZPe_*I2y@|4sBRjso zUy`aUlJo$60})6B%aMKN&yMG1Qvjth%4dDy{HM^34) z&_TyGJg3UC{J|n2-wr)LDYwhNWBH4VL-JgYz;erTEKiMF20`|$Cf~GysBU40j@&)u zboK>@(yL25%R|RmS~6@99bG>PviV`j>&k~M@~J%cn{`uCzUOyY^23rlWt6DH=aut3 zlZo^g63xIXwP(4)hgT<|I>hSGqh7YbLP$jL+%p0>vM2Su?wmOV;-uyLFww=KN5Ox{j<% zmi}mZc22bZyxbmI!x+Ch3+qsk+#YbHJ{CdQjDh~;LRJB63Pq&~p

*N){PEn7FA;EAwj=|b_AUGw z{Eb1Zt8`N8chL?vjkw~yAvg~N+W_qV|N7U7a3HGfPY0GBqUxOaLJzPO2|Qz7H&yF{ z!Y@7SbxH$-YlpxgCaImE$Fk6T4dUMU!=a+u##*PZb&m9d@{VbA<&v z;n*Hvm#Nt5zF}Ud{=9#v%+3;8${f~WV?Q`CFATe5JXp$wT(q1TOU7#0jK6PDXZ)(1 zOSF4N3hStRA?+K$*ZctH(lRF!KFSL%W20hM6%Rz+k9We?_C36J>PVG2%Y`27X;nW+ z*x`6oe7S`dXABgw#vFYvuM;-c|L9ua=7z9?9B!cL=Fyiz34xz{6kpCd?PeyG2V7mkg!!m@d$btKgDK_Ib zt|Qt#$Am-fZ&{xA0GOAnn8Ue+QQBY3NiO*vfvd{5lsp3L_K5f@hhj{}^Nk#us4?p+ ztOM)g!1L3Ff(Tk8KQe4khoQS4_&0;4zo|FQr(iM%k4L+U*z zff0J2FQWxM*K?>u4d$6_8R>l`cK8U+!w`A!D@A2^2+L%A~GSv8* z(uV!wgkD)YqY(1-;X}j zv4?n}%=LOp! z;8GgCC~I2q%*#5{$kpuKJ6-ET*}o#)Z>p>vQsxF25{?c6CQ5()gsGtn{Ul`*ykb!bDMnnlGUdfYdn+9lsY%+pJ_Z_xHs+imH? z!L`+luUT1yv*4C1Z&<#Qlui*r2~lxBI`sAm+}oX{s=OcRf9A0%Q^56>8DC==kKtgy z>D-TeE@f3uu4&Y?ZVVlM3wLg~Z>Y}xfNE|1MIAijELQN`Y2<45F5=t5>wtYuk>yuH zXEJj-vN;uZD0|537U$Eq5Oek?f#JlNGq{dN(qiDuxO185eWG@Tuk1zKUsCs)MAVm# zZTvIN+Wl0&MDXYQF#3{qXA$(Ft>uw;>&qkE2f#n|`-?1D`gl8Gqj+=j77qvaV7#CH z-mDV$x0TsBRP5B|jZ%mFQ}FDv4Rn5l$yl(|`Q7Oe;~u+P58Qvv*6uy)7U=EIpPM-5 zPv}(pkwc!Zx3$@4;Y){)0d2tO5v#db4**wJ~;d2`ShTX zw|GaKwMoD4ydIzqSN(;l&j_8}$q^eYga7tU+}ZvgxyO*m1UDkuojePFZ zG`-$PpE1`DpyrLMO}R7wCfu3t6Y|B7d%f_n+{8^32;HSdS9&hVGwt*sUYr-!%%`a~|XP)!GJa zaPfvq9vz7{ms4}`U~qpQ+@r?~G$CeSuOWUWWPj8xrxoKsi%ALkMoN~Re@yeI<`b#& zQakqh?^Bfdlv*~90r${a#kP)=j;z5r;Qua|_8~6ciamnnhpFd84r{fjgNVx%{UgRa z5XnEKlf}cZ&elidYgP}Qi}Z0^o$C^y%G~k#_Qp8=1^BDy6=xQN&GlMeiCUK;x&F$^ zjA44c!M?-)Y1kOO--Oix|DE7=F!d?WE|oc-P;ICUYO&YsIA3qS68`^+SoxzLDfxQ- z)V%&7_{XQaWqV^?8s0=b5Yxwfs(L2+kBDu`F4FIF*gxGfML8AK#-01US-npCiqalZ z?M~DOWA<^ZR|~P;79^A!*A-C1sshAC6<~Z9P|a%vs7IcNOJh792S@Vc$sCItcXG)K z1Fn?E#hswKujQD~WT#qpf3`ix0(EL{#By^?PeQ2& + + + Bellingcat OpenStreetMap + search + + + {{ user.email }} + + Sign Out + + + + + + + Privacy Policy + Terms of Service + + + + + + + diff --git a/frontend_v2/src/assets/fonts/GoogleSans-Regular.ttf b/frontend_v2/src/assets/fonts/GoogleSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ab605f9e2e3c347708a810435ba3a7debc52e1df GIT binary patch literal 119984 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", + value: "5", + cast: "cast_to_float", + }, + { + parameter: "building:levels", + comparison: "<", + value: "10", + cast: "cast_to_float", + }, + ], + }, + { + name: "Building (10+ stories)", + type: "polygon", + method: "OR", + filters: [ + { + parameter: "building:levels", + comparison: ">=", + value: "10", + cast: "cast_to_float", + }, + ], + }, + { + name: "Beach", + type: "polygon", + method: "OR", + filters: [ + { + parameter: "natural", + comparison: "=", + value: "beach", + }, + ], + }, + { + name: "Church", + type: "any", + method: "OR", + filters: [ + { + parameter: "amenity", + comparison: "=", + value: "place_of_worship", + }, + ], + }, + { + name: "Hospital", + type: "any", + method: "OR", + filters: [ + { + parameter: "amenity", + comparison: "=", + value: "hospital", + }, + ], + }, + { + name: "Military use", + type: "any", + method: "OR", + filters: [ + { + parameter: "military", + comparison: "is not null", + }, + { + parameter: "landuse", + comparison: "=", + value: "military", + }, + ], + }, + { + name: "Restaurant", + type: "any", + method: "OR", + filters: [ + { + parameter: "amenity", + comparison: "=", + value: "restaurant", + }, + { + parameter: "amenity", + comparison: "=", + value: "cafe", + }, + { + parameter: "amenity", + comparison: "=", + value: "pub", + }, + { + parameter: "amenity", + comparison: "=", + value: "fast_food", + }, + ], + }, + { + name: "Convenience store", + type: "any", + method: "OR", + filters: [ + { + parameter: "shop", + comparison: "=", + value: "convenience", + }, + ], + }, + { + name: "Supermarket", + type: "any", + method: "OR", + filters: [ + { + parameter: "shop", + comparison: "=", + value: "supermarket", + }, + ], + }, + { + name: "Shop (any)", + type: "any", + method: "OR", + filters: [ + { + parameter: "shop", + comparison: "is not null", + }, + ], + }, + { + name: "Fountain", + type: "any", + method: "OR", + filters: [ + { + parameter: "amenity", + comparison: "=", + value: "fountain", + }, + ], + }, + { + name: "Water", + type: "any", + method: "OR", + filters: [ + { + parameter: "water", + comparison: "is not null", + }, + { + parameter: "waterway", + comparison: "is not null", + }, + ], + }, +]; diff --git a/frontend_v2/src/auto-imports.d.ts b/frontend_v2/src/auto-imports.d.ts new file mode 100644 index 0000000..f7b0c96 --- /dev/null +++ b/frontend_v2/src/auto-imports.d.ts @@ -0,0 +1,191 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// noinspection JSUnusedGlobalSymbols +// Generated by unplugin-auto-import +export {} +declare global { + const EffectScope: typeof import('vue')['EffectScope'] + const computed: typeof import('vue')['computed'] + const createApp: typeof import('vue')['createApp'] + const customRef: typeof import('vue')['customRef'] + const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'] + const defineComponent: typeof import('vue')['defineComponent'] + const effectScope: typeof import('vue')['effectScope'] + const getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + const isReadonly: typeof import('vue')['isReadonly'] + const isRef: typeof import('vue')['isRef'] + const markRaw: typeof import('vue')['markRaw'] + const nextTick: typeof import('vue')['nextTick'] + const onActivated: typeof import('vue')['onActivated'] + const onBeforeMount: typeof import('vue')['onBeforeMount'] + const onBeforeRouteLeave: (typeof import("vue-router"))["onBeforeRouteLeave"] + const onBeforeRouteUpdate: (typeof import("vue-router"))["onBeforeRouteUpdate"] + const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'] + const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'] + const onDeactivated: typeof import('vue')['onDeactivated'] + const onErrorCaptured: typeof import('vue')['onErrorCaptured'] + const onMounted: typeof import('vue')['onMounted'] + const onRenderTracked: typeof import('vue')['onRenderTracked'] + const onRenderTriggered: typeof import('vue')['onRenderTriggered'] + const onScopeDispose: typeof import('vue')['onScopeDispose'] + const onServerPrefetch: typeof import('vue')['onServerPrefetch'] + const onUnmounted: typeof import('vue')['onUnmounted'] + const onUpdated: typeof import('vue')['onUpdated'] + const provide: typeof import('vue')['provide'] + const reactive: typeof import('vue')['reactive'] + const readonly: typeof import('vue')['readonly'] + const ref: typeof import('vue')['ref'] + const resolveComponent: typeof import('vue')['resolveComponent'] + const shallowReactive: typeof import('vue')['shallowReactive'] + const shallowReadonly: typeof import('vue')['shallowReadonly'] + const shallowRef: typeof import('vue')['shallowRef'] + const toRaw: typeof import('vue')['toRaw'] + const toRef: typeof import('vue')['toRef'] + const toRefs: typeof import('vue')['toRefs'] + const toValue: typeof import('vue')['toValue'] + const triggerRef: typeof import('vue')['triggerRef'] + const unref: typeof import('vue')['unref'] + const useAttrs: typeof import('vue')['useAttrs'] + const useCssModule: typeof import('vue')['useCssModule'] + const useCssVars: typeof import('vue')['useCssVars'] + const useLink: (typeof import("vue-router"))["useLink"] + const useRoute: typeof import('vue-router/auto')['useRoute'] + const useRouter: typeof import('vue-router/auto')['useRouter'] + const useSlots: typeof import('vue')['useSlots'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} +// for type re-export +declare global { + // @ts-ignore + export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue' + import('vue') +} +// for vue template auto import +import { UnwrapRef } from 'vue' +declare module 'vue' { + interface GlobalComponents {} + interface ComponentCustomProperties { + readonly EffectScope: UnwrapRef + readonly computed: UnwrapRef + readonly createApp: UnwrapRef + readonly customRef: UnwrapRef + readonly defineAsyncComponent: UnwrapRef + readonly defineComponent: UnwrapRef + readonly effectScope: UnwrapRef + readonly getCurrentInstance: UnwrapRef + readonly getCurrentScope: UnwrapRef + readonly h: UnwrapRef + readonly inject: UnwrapRef + readonly isProxy: UnwrapRef + readonly isReactive: UnwrapRef + readonly isReadonly: UnwrapRef + readonly isRef: UnwrapRef + readonly markRaw: UnwrapRef + readonly nextTick: UnwrapRef + readonly onActivated: UnwrapRef + readonly onBeforeMount: UnwrapRef + readonly onBeforeUnmount: UnwrapRef + readonly onBeforeUpdate: UnwrapRef + readonly onDeactivated: UnwrapRef + readonly onErrorCaptured: UnwrapRef + readonly onMounted: UnwrapRef + readonly onRenderTracked: UnwrapRef + readonly onRenderTriggered: UnwrapRef + readonly onScopeDispose: UnwrapRef + readonly onServerPrefetch: UnwrapRef + readonly onUnmounted: UnwrapRef + readonly onUpdated: UnwrapRef + readonly provide: UnwrapRef + readonly reactive: UnwrapRef + readonly readonly: UnwrapRef + readonly ref: UnwrapRef + readonly resolveComponent: UnwrapRef + readonly shallowReactive: UnwrapRef + readonly shallowReadonly: UnwrapRef + readonly shallowRef: UnwrapRef + readonly toRaw: UnwrapRef + readonly toRef: UnwrapRef + readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef + readonly triggerRef: UnwrapRef + readonly unref: UnwrapRef + readonly useAttrs: UnwrapRef + readonly useCssModule: UnwrapRef + readonly useCssVars: UnwrapRef + readonly useRoute: UnwrapRef + readonly useRouter: UnwrapRef + readonly useSlots: UnwrapRef + readonly watch: UnwrapRef + readonly watchEffect: UnwrapRef + readonly watchPostEffect: UnwrapRef + readonly watchSyncEffect: UnwrapRef + } +} +declare module '@vue/runtime-core' { + interface GlobalComponents {} + interface ComponentCustomProperties { + readonly EffectScope: UnwrapRef + readonly computed: UnwrapRef + readonly createApp: UnwrapRef + readonly customRef: UnwrapRef + readonly defineAsyncComponent: UnwrapRef + readonly defineComponent: UnwrapRef + readonly effectScope: UnwrapRef + readonly getCurrentInstance: UnwrapRef + readonly getCurrentScope: UnwrapRef + readonly h: UnwrapRef + readonly inject: UnwrapRef + readonly isProxy: UnwrapRef + readonly isReactive: UnwrapRef + readonly isReadonly: UnwrapRef + readonly isRef: UnwrapRef + readonly markRaw: UnwrapRef + readonly nextTick: UnwrapRef + readonly onActivated: UnwrapRef + readonly onBeforeMount: UnwrapRef + readonly onBeforeUnmount: UnwrapRef + readonly onBeforeUpdate: UnwrapRef + readonly onDeactivated: UnwrapRef + readonly onErrorCaptured: UnwrapRef + readonly onMounted: UnwrapRef + readonly onRenderTracked: UnwrapRef + readonly onRenderTriggered: UnwrapRef + readonly onScopeDispose: UnwrapRef + readonly onServerPrefetch: UnwrapRef + readonly onUnmounted: UnwrapRef + readonly onUpdated: UnwrapRef + readonly provide: UnwrapRef + readonly reactive: UnwrapRef + readonly readonly: UnwrapRef + readonly ref: UnwrapRef + readonly resolveComponent: UnwrapRef + readonly shallowReactive: UnwrapRef + readonly shallowReadonly: UnwrapRef + readonly shallowRef: UnwrapRef + readonly toRaw: UnwrapRef + readonly toRef: UnwrapRef + readonly toRefs: UnwrapRef + readonly toValue: UnwrapRef + readonly triggerRef: UnwrapRef + readonly unref: UnwrapRef + readonly useAttrs: UnwrapRef + readonly useCssModule: UnwrapRef + readonly useCssVars: UnwrapRef + readonly useRoute: UnwrapRef + readonly useRouter: UnwrapRef + readonly useSlots: UnwrapRef + readonly watch: UnwrapRef + readonly watchEffect: UnwrapRef + readonly watchPostEffect: UnwrapRef + readonly watchSyncEffect: UnwrapRef + } +} diff --git a/frontend_v2/src/components.d.ts b/frontend_v2/src/components.d.ts new file mode 100644 index 0000000..0b6958a --- /dev/null +++ b/frontend_v2/src/components.d.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +export {} + +declare module 'vue' { + export interface GlobalComponents { + FeatureCustom: typeof import('./components/FeatureCustom.vue')['default'] + FeatureSelector: typeof import('./components/FeatureSelector.vue')['default'] + FeatureView: typeof import('./components/FeatureView.vue')['default'] + FirebaseLogin: typeof import('./components/FirebaseLogin.vue')['default'] + GoogleLogin: typeof import('./components/GoogleLogin.vue')['default'] + HelloWorld: (typeof import("./src/components/HelloWorld.vue"))["default"] + HelpCard: typeof import('./components/HelpCard.vue')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + SearchControls: typeof import('./components/SearchControls.vue')['default'] + SearchResult: typeof import('./components/SearchResult.vue')['default'] + SearchResults: typeof import('./components/SearchResults.vue')['default'] + } +} diff --git a/frontend_v2/src/components/FeatureCustom.vue b/frontend_v2/src/components/FeatureCustom.vue new file mode 100644 index 0000000..520574e --- /dev/null +++ b/frontend_v2/src/components/FeatureCustom.vue @@ -0,0 +1,100 @@ + + + diff --git a/frontend_v2/src/components/FeatureSelector.vue b/frontend_v2/src/components/FeatureSelector.vue new file mode 100644 index 0000000..f72e9ca --- /dev/null +++ b/frontend_v2/src/components/FeatureSelector.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/frontend_v2/src/components/FeatureView.vue b/frontend_v2/src/components/FeatureView.vue new file mode 100644 index 0000000..8e40d61 --- /dev/null +++ b/frontend_v2/src/components/FeatureView.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/frontend_v2/src/components/FirebaseLogin.vue b/frontend_v2/src/components/FirebaseLogin.vue new file mode 100644 index 0000000..d668139 --- /dev/null +++ b/frontend_v2/src/components/FirebaseLogin.vue @@ -0,0 +1,50 @@ + + + + + diff --git a/frontend_v2/src/components/GoogleLogin.vue b/frontend_v2/src/components/GoogleLogin.vue new file mode 100755 index 0000000..d0c325e --- /dev/null +++ b/frontend_v2/src/components/GoogleLogin.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/frontend_v2/src/components/HelpCard.vue b/frontend_v2/src/components/HelpCard.vue new file mode 100644 index 0000000..60c3f05 --- /dev/null +++ b/frontend_v2/src/components/HelpCard.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/frontend_v2/src/components/README.md b/frontend_v2/src/components/README.md new file mode 100644 index 0000000..50fa09e --- /dev/null +++ b/frontend_v2/src/components/README.md @@ -0,0 +1,35 @@ +# Components + +Vue template files in this folder are automatically imported. + +## 🚀 Usage + +Importing is handled by [unplugin-vue-components](https://github.com/unplugin/unplugin-vue-components). This plugin automatically imports `.vue` files created in the `src/components` directory, and registers them as global components. This means that you can use any component in your application without having to manually import it. + +The following example assumes a component located at `src/components/MyComponent.vue`: + +```vue + + + +``` + +When your template is rendered, the component's import will automatically be inlined, which renders to this: + +```vue + + + +``` diff --git a/frontend_v2/src/components/SearchControls.vue b/frontend_v2/src/components/SearchControls.vue new file mode 100644 index 0000000..9928674 --- /dev/null +++ b/frontend_v2/src/components/SearchControls.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/frontend_v2/src/components/SearchResult.vue b/frontend_v2/src/components/SearchResult.vue new file mode 100644 index 0000000..ee46555 --- /dev/null +++ b/frontend_v2/src/components/SearchResult.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/frontend_v2/src/components/SearchResults.vue b/frontend_v2/src/components/SearchResults.vue new file mode 100644 index 0000000..ff55877 --- /dev/null +++ b/frontend_v2/src/components/SearchResults.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/frontend_v2/src/directives/OneTap.ts b/frontend_v2/src/directives/OneTap.ts new file mode 100644 index 0000000..28bcea4 --- /dev/null +++ b/frontend_v2/src/directives/OneTap.ts @@ -0,0 +1,58 @@ +/* eslint-disable no-undef */ + +export default { + beforeMount: function (el, binding, vnode) { + checkComponentMethods(); + + const clientId = binding.value.clientId; + + const googleBtnConfigs = { + type: binding.value.type || "standard", + shape: binding.value.shape || "rectangular", + theme: binding.value.theme || "outline", + text: binding.value.text || "signin", + size: binding.value.size || "large", + logo_alignment: binding.value.logo_alignment || "center", + locale: binding.value.locale || "en-us", + }; + + const googleLoginButtonId = el.id; + + const googleSignInAPI = document.createElement("script"); + googleSignInAPI.setAttribute( + "src", + "https://accounts.google.com/gsi/client", + ); + document.head.appendChild(googleSignInAPI); + googleSignInAPI.onload = InitGoogleButton; + + function InitGoogleButton() { + // prettier-ignore + google.accounts.id.initialize({ + client_id: clientId, + callback: OnSuccess + }); + + // prettier-ignore + google.accounts.id.renderButton( + document.getElementById(googleLoginButtonId), googleBtnConfigs + ); + } + + function OnSuccess(resp) { + vnode.context.onGoogleAuthSuccess(resp.credential); + } + + function checkComponentMethods() { + if (!el.id) + throw new Error( + "The google sign in container requires an 'id' attribute", + ); + + if (!vnode.context.onGoogleAuthSuccess) + throw new Error( + "The method onGoogleAuthSuccess must be defined on the component", + ); + } + }, +}; diff --git a/frontend_v2/src/layouts/README.md b/frontend_v2/src/layouts/README.md new file mode 100644 index 0000000..4016af3 --- /dev/null +++ b/frontend_v2/src/layouts/README.md @@ -0,0 +1,5 @@ +# Layouts + +Layouts are reusable components that wrap around pages. They are used to provide a consistent look and feel across multiple pages. + +Full documentation for this feature can be found in the Official [vite-plugin-vue-layouts](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) repository. diff --git a/frontend_v2/src/main.ts b/frontend_v2/src/main.ts new file mode 100644 index 0000000..a149d00 --- /dev/null +++ b/frontend_v2/src/main.ts @@ -0,0 +1,23 @@ +/** + * main.ts + * + * Bootstraps Vuetify and other plugins then mounts the App` + */ + +// Plugins +import { registerPlugins } from "@/plugins"; +// https://github.com/vue-leaflet/vue-leaflet/issues/371 + +// Components +import App from "./App.vue"; +// Composables +import { createApp } from "vue"; + +//Styles +import "leaflet/dist/leaflet.css"; + +const app = createApp(App); + +registerPlugins(app); + +app.mount("#app"); diff --git a/frontend_v2/src/pages/README.md b/frontend_v2/src/pages/README.md new file mode 100644 index 0000000..341536c --- /dev/null +++ b/frontend_v2/src/pages/README.md @@ -0,0 +1,5 @@ +# Pages + +Vue components created in this folder will automatically be converted to navigatable routes. + +Full documentation for this feature can be found in the Official [unplugin-vue-router](https://github.com/posva/unplugin-vue-router) repository. diff --git a/frontend_v2/src/pages/about.vue b/frontend_v2/src/pages/about.vue new file mode 100644 index 0000000..3fa2807 --- /dev/null +++ b/frontend_v2/src/pages/about.vue @@ -0,0 +1,5 @@ + diff --git a/frontend_v2/src/pages/index.vue b/frontend_v2/src/pages/index.vue new file mode 100644 index 0000000..0211db6 --- /dev/null +++ b/frontend_v2/src/pages/index.vue @@ -0,0 +1,24 @@ + + + diff --git a/frontend_v2/src/pages/privacy.vue b/frontend_v2/src/pages/privacy.vue new file mode 100644 index 0000000..ecf07c9 --- /dev/null +++ b/frontend_v2/src/pages/privacy.vue @@ -0,0 +1,491 @@ + diff --git a/frontend_v2/src/pages/tos.vue b/frontend_v2/src/pages/tos.vue new file mode 100644 index 0000000..a721a22 --- /dev/null +++ b/frontend_v2/src/pages/tos.vue @@ -0,0 +1,381 @@ + diff --git a/frontend_v2/src/plugins/README.md b/frontend_v2/src/plugins/README.md new file mode 100644 index 0000000..62201c7 --- /dev/null +++ b/frontend_v2/src/plugins/README.md @@ -0,0 +1,3 @@ +# Plugins + +Plugins are a way to extend the functionality of your Vue application. Use this folder for registering plugins that you want to use globally. diff --git a/frontend_v2/src/plugins/index.ts b/frontend_v2/src/plugins/index.ts new file mode 100644 index 0000000..3c18184 --- /dev/null +++ b/frontend_v2/src/plugins/index.ts @@ -0,0 +1,17 @@ +/** + * plugins/index.ts + * + * Automatically included in `./src/main.ts` + */ + +// Plugins +import vuetify from "./vuetify"; +import pinia from "../stores"; +import router from "../router"; + +// Types +import type { App } from "vue"; + +export function registerPlugins(app: App) { + app.use(vuetify).use(router).use(pinia); +} diff --git a/frontend_v2/src/plugins/vuetify.ts b/frontend_v2/src/plugins/vuetify.ts new file mode 100644 index 0000000..0f1718d --- /dev/null +++ b/frontend_v2/src/plugins/vuetify.ts @@ -0,0 +1,19 @@ +/** + * plugins/vuetify.ts + * + * Framework documentation: https://vuetifyjs.com` + */ + +// Styles +import "@mdi/font/css/materialdesignicons.css"; +import "vuetify/styles"; + +// Composables +import { createVuetify } from "vuetify"; + +// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides +export default createVuetify({ + theme: { + defaultTheme: "dark", + }, +}); diff --git a/frontend_v2/src/router/index.ts b/frontend_v2/src/router/index.ts new file mode 100644 index 0000000..743a0c1 --- /dev/null +++ b/frontend_v2/src/router/index.ts @@ -0,0 +1,16 @@ +/** + * router/index.ts + * + * Automatic routes for `./src/pages/*.vue` + */ + +// Composables +import { createRouter, createWebHistory } from "vue-router/auto"; +import { setupLayouts } from "virtual:generated-layouts"; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + extendRoutes: setupLayouts, +}); + +export default router; diff --git a/frontend_v2/src/services/bellingcat.service.ts b/frontend_v2/src/services/bellingcat.service.ts new file mode 100644 index 0000000..3c192c0 --- /dev/null +++ b/frontend_v2/src/services/bellingcat.service.ts @@ -0,0 +1,100 @@ +const PAGE_SIZE = 100; +const OSM_SEARCH_API = "https://api.osm-search.bellingcat.com"; + +class BellingCatService { + token: string | null; + lastRequest: string | null; + cache: Map>; + + constructor() { + this.token = null; + this.lastRequest = null; + this.cache = new Map(); + } + + setToken(token) { + this.token = token; + } + + search({ bbox, range, filters, page = 0, prefetchNext = false }) { + // Check cache based on parameters and page + const requestKey = `${bbox[0][1]}_${bbox[0][0]}_${bbox[1][1]}_${bbox[1][0]}_${range}_${filters}`; + const cacheKey = `${requestKey}_${page}`; + + if (this.lastRequest && this.lastRequest != requestKey) { + this.cache.clear(); + } + this.lastRequest = requestKey; + + const cachedData = this.cache.get(cacheKey); + if (cachedData) { + if (prefetchNext) { + setTimeout(() => { + this.search({ bbox, range, filters, page: page + 1 }); + }, 1000); + } + return Promise.resolve(cachedData); + } + + const result = new Promise((resolve, reject) => { + const time1 = performance.now(); + + fetch( + `${OSM_SEARCH_API}/intersection?l=${bbox[0][1]}&b=${bbox[0][0]}&r=${bbox[1][1]}&t=${bbox[1][0]}&buffer=${range}&filters=${filters}&limit=${PAGE_SIZE}&page=${page}`, + { + headers: { + Authorization: "Bearer " + this.token, + }, + }, + ) + .then((d) => { + if (d.status != 200) { + return Promise.reject(Error(`${d.status}`)); + } + return d.json(); + }) + .then(({ data, has_more }) => { + const time2 = performance.now(); + const responseTime = time2 - time1; + const response = { responseTime, data, hasMore: has_more }; + if (has_more && prefetchNext) { + setTimeout(() => { + this.search({ bbox, range, filters, page: page + 1 }); + }, 1000); + } + + resolve(response); + }) + .catch((e) => { + switch (e.message) { + case "400": + reject( + "Your search area is too large, or your search timed out. Zoom in on a smaller area or change your search parameters.", + ); + break; + case "401": + reject("The data provided was invalid."); + break; + case "403": + reject("Your login has expired. Please log in again."); + break; + case "408": + reject("The request timed out."); + break; + case "500": + reject("The server encountered an error."); + break; + default: + reject( + "Search error. Check your custom features or email logan@bellingcat.com.", + ); + } + }); + }); + + this.cache.set(cacheKey, result); + return result; + } +} + +export const bellingCatService = new BellingCatService(); diff --git a/frontend_v2/src/services/firebase.ts b/frontend_v2/src/services/firebase.ts new file mode 100644 index 0000000..feb62ba --- /dev/null +++ b/frontend_v2/src/services/firebase.ts @@ -0,0 +1,20 @@ +import { initializeApp } from "firebase/app"; +import { getAuth } from "firebase/auth"; +import { getFirestore } from "firebase/firestore"; + +const firebaseConfig = { + apiKey: import.meta.env.VITE_VUE_APP_FIREBASE_API_KEY, + authDomain: import.meta.env.VITE_VUE_APP_FIREBASE_AUTH_DOMAIN, + projectId: import.meta.env.VITE_VUE_APP_FIREBASE_PROJECT_ID, + storageBucket: import.meta.env.VITE_VUE_APP_FIREBASE_STORAGE_BUCKET, + messagingSenderId: import.meta.env.VITE_VUE_APP_FIREBASE_MESSAGING_SENDER_ID, + appId: import.meta.env.VITE_VUE_APP_FIREBASE_APP_ID, +}; + +const firebaseApp = initializeApp(firebaseConfig); + +const firebaseAuth = getAuth(firebaseApp); + +const firebaseFirestore = getFirestore(firebaseApp); + +export { firebaseApp, firebaseAuth, firebaseFirestore, firebaseConfig }; diff --git a/frontend_v2/src/services/mapbox.service.ts b/frontend_v2/src/services/mapbox.service.ts new file mode 100644 index 0000000..4c49946 --- /dev/null +++ b/frontend_v2/src/services/mapbox.service.ts @@ -0,0 +1,14 @@ +class MapBoxService { + searchLocation(search_text) { + return fetch( + `https://api.mapbox.com/geocoding/v5/mapbox.places/${search_text}.json?access_token=${import.meta.env.VITE_VUE_APP_MAPBOX_TOKEN}`, + ).then((d) => { + if (d.status != 200) { + return Promise.reject(Error(`${d.status}`)); + } + return d.json(); + }); + } +} + +export const mapboxService = new MapBoxService(); diff --git a/frontend_v2/src/services/openstreetmap.service.ts b/frontend_v2/src/services/openstreetmap.service.ts new file mode 100644 index 0000000..be45e61 --- /dev/null +++ b/frontend_v2/src/services/openstreetmap.service.ts @@ -0,0 +1,26 @@ +class OsmService { + getKeys() { + return fetch( + "https://taginfo.openstreetmap.org/api/4/keys/all?page=1&rp=200&filter=in_wiki&sortname=count_all&sortorder=desc", + ).then((d) => { + if (d.status != 200) { + return Promise.reject(Error(`${d.status}`)); + } + return d.json(); + }); + } + + getValues(v) { + return fetch( + "https://taginfo.openstreetmap.org/api/4/key/values?rp=50&sortname=count_all&sortorder=desc&page=1&key=" + + v, + ).then((d) => { + if (d.status != 200) { + return Promise.reject(Error(`${d.status}`)); + } + return d.json(); + }); + } +} + +export const osmService = new OsmService(); diff --git a/frontend_v2/src/stores/README.md b/frontend_v2/src/stores/README.md new file mode 100644 index 0000000..54f8e03 --- /dev/null +++ b/frontend_v2/src/stores/README.md @@ -0,0 +1,5 @@ +# Store + +Pinia stores are used to store reactive state and expose actions to mutate it. + +Full documentation for this feature can be found in the Official [Pinia](https://pinia.esm.dev/) repository. diff --git a/frontend_v2/src/stores/app.ts b/frontend_v2/src/stores/app.ts new file mode 100644 index 0000000..304495b --- /dev/null +++ b/frontend_v2/src/stores/app.ts @@ -0,0 +1,260 @@ +// Utilities +import { defineStore } from "pinia"; +import firebase from "firebase/compat/app"; +import "firebase/compat/auth"; +import { firebaseFirestore } from "../services/firebase"; +import { + collection, + addDoc, + serverTimestamp, + query, + where, + getDocs, + deleteDoc, + doc, +} from "firebase/firestore"; +import queries from "@/assets/queries"; +import { bellingCatService } from "../services/bellingcat.service"; +import { osmService } from "../services/openstreetmap.service"; +import { mapboxService } from "../services/mapbox.service"; + +interface State { + selected: any[]; + searchResults: any[]; + bbox: number[]; + error: boolean | string; + range: number; + hovered: any | null; + selectedResult: any | null; + mode: string; + loading: boolean; + token: boolean; + mapCenter: number[]; + mapZoom: number; + responseTime: number | null; + osmKeys: any[]; + selectedKeyValues: any[]; + user: any | null; + presets: typeof queries; + customPresets: any[]; + page: number; + hasMore: boolean; +} + +export const useAppStore = defineStore("app", { + state: (): State => ({ + selected: [], + searchResults: [], + bbox: [], + error: false, + range: 100, + hovered: null, + selectedResult: null, + mode: "osm", + loading: false, + token: false, + mapCenter: [42.2, -71.7], + mapZoom: 8, + responseTime: null, + osmKeys: [], + selectedKeyValues: [], + user: null, + presets: queries, + customPresets: [], + page: 0, + hasMore: false, + }), + actions: { + setUser(user) { + this.user = user; + }, + setToken(token) { + this.token = token; + bellingCatService.setToken(token); + }, + updateSelected(value) { + this.selected = [...value]; + }, + removeSelected(index) { + const value = this.selected; + const newValue = [ + ...value.slice(0, index), + ...value.slice(index + 1, value.length), + ]; + this.selected = newValue; + }, + setSearchResults(data) { + this.searchResults = data; + }, + setBbox(bbox) { + this.bbox = bbox; + }, + setRange(range) { + this.range = range; + }, + setHoveredResult(index) { + this.hovered = index; + }, + setSelectedResult(index) { + this.selectedResult = index; + }, + setMode(mode) { + this.mode = mode; + }, + setLoading(loading) { + this.loading = loading; + }, + setError(error) { + this.error = error; + }, + setMapPosition({ center, zoom }) { + this.mapCenter = center; + this.mapZoom = zoom; + }, + setZoom(zoom) { + this.mapZoom = zoom; + }, + setCenter(center) { + this.mapCenter = center; + }, + setResponseTime(t) { + this.responseTime = t; + }, + setSelectedKeyValues(values) { + this.selectedKeyValues = values; + }, + setCustomPresets(presets) { + this.customPresets = presets; + }, + setPage(page) { + this.page = page; + }, + + async signout() { + try { + await firebase.auth().signOut(); + console.log("User is signed out from firebase."); + + // clean user from store + this.$reset; + } catch (error) { + console.error("signOutUser (firebase/auth.js): ", error); + } + }, + + nextPage() { + this.page++; + this.search(); + }, + + previousPage() { + this.page--; + this.search(); + }, + + async getKeys() { + osmService.getKeys().then((data) => { + this.osmKeys = data.data.map((d) => d.key); + }); + }, + + async getValues(v) { + this.selectedKeyValues = []; + if (v == "" || v == undefined || v == null) { + return; + } + + osmService.getValues(v).then((data) => { + this.selectedKeyValues = data.data + .filter((d) => d.fraction > 0.002) + .map((d) => d.value); + }); + }, + + async search() { + const bbox = this.bbox; + const range = this.range; + const filters = JSON.stringify(this.selected); + const page = this.page; + + this.loading = true; + try { + const { data, responseTime, hasMore } = await bellingCatService.search({ + bbox, + range, + filters, + page, + prefetchNext: true, + }); + this.responseTime = responseTime; + this.searchResults = data; + this.hasMore = hasMore; + this.loading = false; + this.error = false; + } catch (e) { + this.loading = false; + this.error = e; + } + }, + + async searchLocation(search_text) { + const locationData = await mapboxService.searchLocation(search_text); + let zoom = 14; + + if (locationData.features[0].bbox) { + const maxBounds = Math.max( + locationData.features[0].bbox[2] - locationData.features[0].bbox[0], + locationData.features[0].bbox[3] - locationData.features[0].bbox[1], + ); + + zoom = Math.round(9 - Math.log2(maxBounds)); + } + + this.mapPosiion = { + center: [ + locationData.features[0].center[1], + locationData.features[0].center[0], + ], + zoom, + }; + }, + + async savePreset({ index, name }) { + try { + const docRef = await addDoc(collection(firebaseFirestore, "presets"), { + filters: this.selected[index].filters, + method: this.selected[index].method, + type: this.selected[index].type, + name: name, + author_uid: this.user.uid, + timestamp: serverTimestamp(), + }); + + console.log("Document written with ID: ", docRef.id); + + await this.getCustomPresets(); + } catch (e) { + console.error("Error adding document: ", e); + } + }, + + async getCustomPresets() { + const q = query( + collection(firebaseFirestore, "presets"), + where("author_uid", "==", this.user.uid), + ); + const querySnapshot = await getDocs(q); + + const customPresets = querySnapshot.docs.map((d) => ({ + ...d.data(), + id: d.id, + })); + this.customPresets = customPresets; + }, + + async removePreset(id) { + await deleteDoc(doc(firebaseFirestore, "presets", id)); + await this.getCustomPresets(); + }, + }, +}); diff --git a/frontend_v2/src/stores/index.ts b/frontend_v2/src/stores/index.ts new file mode 100644 index 0000000..7b11dba --- /dev/null +++ b/frontend_v2/src/stores/index.ts @@ -0,0 +1,4 @@ +// Utilities +import { createPinia } from "pinia"; + +export default createPinia(); diff --git a/frontend_v2/src/styles/README.md b/frontend_v2/src/styles/README.md new file mode 100644 index 0000000..ea86179 --- /dev/null +++ b/frontend_v2/src/styles/README.md @@ -0,0 +1,3 @@ +# Styles + +This directory is for configuring the styles of the application. diff --git a/frontend_v2/src/styles/settings.scss b/frontend_v2/src/styles/settings.scss new file mode 100644 index 0000000..3e36a27 --- /dev/null +++ b/frontend_v2/src/styles/settings.scss @@ -0,0 +1,10 @@ +/** + * src/styles/settings.scss + * + * Configures SASS variables and Vuetify overwrites + */ + +// https://vuetifyjs.com/features/sass-variables/` +// @use 'vuetify/settings' with ( +// $color-pack: false +// ); diff --git a/frontend_v2/src/typed-router.d.ts b/frontend_v2/src/typed-router.d.ts new file mode 100644 index 0000000..ba8f4b9 --- /dev/null +++ b/frontend_v2/src/typed-router.d.ts @@ -0,0 +1,26 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️ +// It's recommended to commit this file. +// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry. + +declare module 'vue-router/auto-routes' { + import type { + RouteRecordInfo, + ParamValue, + ParamValueOneOrMore, + ParamValueZeroOrMore, + ParamValueZeroOrOne, + } from 'unplugin-vue-router/types' + + /** + * Route name map generated by unplugin-vue-router + */ + export interface RouteNamedMap { + '/': RouteRecordInfo<'/', '/', Record, Record>, + '/about': RouteRecordInfo<'/about', '/about', Record, Record>, + '/privacy': RouteRecordInfo<'/privacy', '/privacy', Record, Record>, + '/tos': RouteRecordInfo<'/tos', '/tos', Record, Record>, + } +} diff --git a/frontend_v2/src/vite-env.d.ts b/frontend_v2/src/vite-env.d.ts new file mode 100644 index 0000000..fc81239 --- /dev/null +++ b/frontend_v2/src/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/frontend_v2/tsconfig.json b/frontend_v2/tsconfig.json new file mode 100644 index 0000000..9392695 --- /dev/null +++ b/frontend_v2/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "target": "ESNext", + "jsx": "preserve", + "lib": ["DOM", "ESNext"], + "baseUrl": ".", + "module": "ESNext", + "moduleResolution": "bundler", + "paths": { + "@/*": ["src/*"] + }, + "resolveJsonModule": true, + "types": [ + "vite/client", + "vite-plugin-vue-layouts/client", + "unplugin-vue-router/client" + ], + "allowJs": true, + "strict": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "skipLibCheck": true + }, + "include": ["./src/typed-router.d.ts"], + "exclude": ["dist", "node_modules", "cypress"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/frontend_v2/tsconfig.node.json b/frontend_v2/tsconfig.node.json new file mode 100644 index 0000000..348f346 --- /dev/null +++ b/frontend_v2/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.mts"] +} diff --git a/frontend_v2/vite.config.mts b/frontend_v2/vite.config.mts new file mode 100644 index 0000000..d21dc4a --- /dev/null +++ b/frontend_v2/vite.config.mts @@ -0,0 +1,68 @@ +// Plugins +import AutoImport from "unplugin-auto-import/vite"; +import Components from "unplugin-vue-components/vite"; +import Fonts from "unplugin-fonts/vite"; +import Layouts from "vite-plugin-vue-layouts"; +import Vue from "@vitejs/plugin-vue"; +import VueRouter from "unplugin-vue-router/vite"; +import Vuetify, { transformAssetUrls } from "vite-plugin-vuetify"; + +// Utilities +import { defineConfig } from "vite"; +import { fileURLToPath, URL } from "node:url"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + VueRouter({ + dts: "src/typed-router.d.ts", + }), + Layouts(), + AutoImport({ + imports: [ + "vue", + { + "vue-router/auto": ["useRoute", "useRouter"], + }, + ], + dts: "src/auto-imports.d.ts", + eslintrc: { + enabled: true, + }, + vueTemplate: true, + }), + Components({ + dts: "src/components.d.ts", + }), + Vue({ + template: { transformAssetUrls }, + }), + // https://github.com/vuetifyjs/vuetify-loader/tree/master/packages/vite-plugin#readme + Vuetify({ + autoImport: true, + styles: { + configFile: "src/styles/settings.scss", + }, + }), + Fonts({ + google: { + families: [ + { + name: "Roboto", + styles: "wght@100;300;400;500;700;900", + }, + ], + }, + }), + ], + define: { "process.env": {} }, + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + extensions: [".js", ".json", ".jsx", ".mjs", ".ts", ".tsx", ".vue"], + }, + server: { + port: 3000, + }, +}); diff --git a/frontend_v2/vue.config.ts b/frontend_v2/vue.config.ts new file mode 100644 index 0000000..e1de0a1 --- /dev/null +++ b/frontend_v2/vue.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "vite"; +import vue from "@vitejs/plugin-vue"; + +export default defineConfig({ + plugins: [vue()], + optimizeDeps: { + include: ["vuetify", "leaflet"], + }, + define: { + "process.env": { + NODE_ENV: JSON.stringify(process.env.NODE_ENV), + }, + }, +}); From d37c7c4f8be48e24b550d544945a86dd84c6bbb1 Mon Sep 17 00:00:00 2001 From: zameji Date: Mon, 13 May 2024 23:12:49 +0200 Subject: [PATCH 19/30] refactor: result display --- frontend_v2/src/App.vue | 13 +- frontend_v2/src/auto-imports.d.ts | 424 +++++++++++------- frontend_v2/src/components.d.ts | 26 +- frontend_v2/src/components/FeatureCustom.vue | 81 +++- frontend_v2/src/components/HelpCard.vue | 47 +- frontend_v2/src/components/SearchControls.vue | 95 +++- frontend_v2/src/components/SearchResult.vue | 21 +- frontend_v2/src/components/SearchResults.vue | 2 +- frontend_v2/src/stores/app.ts | 4 + 9 files changed, 459 insertions(+), 254 deletions(-) diff --git a/frontend_v2/src/App.vue b/frontend_v2/src/App.vue index 92d00e7..e7c312d 100644 --- a/frontend_v2/src/App.vue +++ b/frontend_v2/src/App.vue @@ -1,8 +1,11 @@ - - - - diff --git a/frontend_v2/src/assets/fonts/GoogleSans-Regular.ttf b/frontend_v2/src/assets/fonts/GoogleSans-Regular.ttf deleted file mode 100644 index ab605f9e2e3c347708a810435ba3a7debc52e1df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 119984 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 - - Custom feature - - - - - - - - - - - - - - - - - - - - Add condition - Add custom feature - - - - - diff --git a/frontend_v2/src/components/FeatureSelector.vue b/frontend_v2/src/components/FeatureSelector.vue deleted file mode 100644 index f72e9ca..0000000 --- a/frontend_v2/src/components/FeatureSelector.vue +++ /dev/null @@ -1,156 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/FeatureView.vue b/frontend_v2/src/components/FeatureView.vue deleted file mode 100644 index 8e40d61..0000000 --- a/frontend_v2/src/components/FeatureView.vue +++ /dev/null @@ -1,111 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/FirebaseLogin.vue b/frontend_v2/src/components/FirebaseLogin.vue deleted file mode 100644 index d668139..0000000 --- a/frontend_v2/src/components/FirebaseLogin.vue +++ /dev/null @@ -1,50 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/GoogleLogin.vue b/frontend_v2/src/components/GoogleLogin.vue deleted file mode 100755 index d0c325e..0000000 --- a/frontend_v2/src/components/GoogleLogin.vue +++ /dev/null @@ -1,64 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/HelpCard.vue b/frontend_v2/src/components/HelpCard.vue deleted file mode 100644 index 37afe90..0000000 --- a/frontend_v2/src/components/HelpCard.vue +++ /dev/null @@ -1,74 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/SearchControls.vue b/frontend_v2/src/components/SearchControls.vue deleted file mode 100644 index 74d7d3d..0000000 --- a/frontend_v2/src/components/SearchControls.vue +++ /dev/null @@ -1,196 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/SearchResult.vue b/frontend_v2/src/components/SearchResult.vue deleted file mode 100644 index deb0a22..0000000 --- a/frontend_v2/src/components/SearchResult.vue +++ /dev/null @@ -1,128 +0,0 @@ - - - - - diff --git a/frontend_v2/src/components/SearchResults.vue b/frontend_v2/src/components/SearchResults.vue deleted file mode 100644 index fa0828e..0000000 --- a/frontend_v2/src/components/SearchResults.vue +++ /dev/null @@ -1,130 +0,0 @@ - - - - - diff --git a/frontend_v2/src/pages/index.vue b/frontend_v2/src/pages/index.vue deleted file mode 100644 index 0211db6..0000000 --- a/frontend_v2/src/pages/index.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - From 33169f4adb746e164fc7019ef28683578bf65234 Mon Sep 17 00:00:00 2001 From: zameji Date: Fri, 24 May 2024 00:53:19 +0200 Subject: [PATCH 21/30] refactor: further UI refactoring --- frontend/index.html | 4 +- frontend/package-lock.json | 18 +- frontend/package.json | 3 +- frontend/public/favicon.ico | Bin 15406 -> 0 bytes frontend/src/App.vue | 7 +- frontend/src/assets/bellingcat-bimi.svg | 45 ++ .../src/assets/fonts/GoogleSans-Regular.ttf | Bin 119984 -> 0 bytes frontend/src/auto-imports.d.ts | 424 +++++++----------- frontend/src/components.d.ts | 30 +- frontend/src/components/FeatureCustom.vue | 4 +- frontend/src/components/FeatureSelector.vue | 78 +--- frontend/src/components/FeatureView.vue | 47 +- frontend/src/components/FirebaseLogin.vue | 3 +- frontend/src/components/GoogleLogin.vue | 64 --- frontend/src/components/MainMap.vue | 70 +-- frontend/src/components/MapMarker.vue | 5 +- frontend/src/components/SearchControls.vue | 8 +- frontend/src/components/SearchResult.vue | 5 +- frontend/src/components/SearchResults.vue | 56 +-- frontend/src/{assets => constants}/queries.ts | 0 frontend/src/directives/OneTap.ts | 58 --- frontend/src/main.ts | 5 + frontend/src/plugins/vuetify.ts | 5 + frontend/src/stores/app.ts | 2 +- frontend/src/styles/firebaseui.override.css | 2 + frontend/src/styles/settings.scss | 6 + frontend/vite.config.mts | 4 +- 27 files changed, 362 insertions(+), 591 deletions(-) delete mode 100644 frontend/public/favicon.ico create mode 100644 frontend/src/assets/bellingcat-bimi.svg delete mode 100644 frontend/src/assets/fonts/GoogleSans-Regular.ttf delete mode 100755 frontend/src/components/GoogleLogin.vue rename frontend/src/{assets => constants}/queries.ts (100%) delete mode 100644 frontend/src/directives/OneTap.ts create mode 100644 frontend/src/styles/firebaseui.override.css diff --git a/frontend/index.html b/frontend/index.html index f450a73..bc3f6d0 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2,9 +2,9 @@ - + - Welcome to Vuetify 3 + Bellingcat OpenStreetMap search diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5775c4a..19e6bb6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,12 +8,13 @@ "name": "frontend_v2", "version": "0.0.0", "dependencies": { + "@fontsource/roboto": "^5.0.13", + "@fontsource/roboto-mono": "^5.0.18", "@mdi/font": "6.2.95", "core-js": "^3.34.0", "export-to-csv": "^1.3.0", "file-saver": "^2.0.5", "firebaseui": "^6.1.0", - "roboto-fontface": "*", "tokml": "^0.4.0", "vue": "^3.4.21", "vuedraggable": "^4.1.0", @@ -1060,6 +1061,16 @@ "integrity": "sha512-EnfRJvrnzkHwN3BPMCayCFT5lCqInzg3RdlRsDjDvB1EJli6Usj26T6lJ67BU2UcYXBS5xcp1Wj4+zRzj2NaZg==", "peer": true }, + "node_modules/@fontsource/roboto": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.0.13.tgz", + "integrity": "sha512-j61DHjsdUCKMXSdNLTOxcG701FWnF0jcqNNQi2iPCDxU8seN/sMxeh62dC++UiagCWq9ghTypX+Pcy7kX+QOeQ==" + }, + "node_modules/@fontsource/roboto-mono": { + "version": "5.0.18", + "resolved": "https://registry.npmjs.org/@fontsource/roboto-mono/-/roboto-mono-5.0.18.tgz", + "integrity": "sha512-hKuwk/cy3i6fWPzazT5xjgWq4YNqZWDHVbJh2Wwj3KYvWGi2v3ToBw/4LKQ+ggEkPLcIG6VU8GpCT3Xtf+mbbA==" + }, "node_modules/@grpc/grpc-js": { "version": "1.9.14", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.14.tgz", @@ -5069,11 +5080,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/roboto-fontface": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.10.0.tgz", - "integrity": "sha512-OlwfYEgA2RdboZohpldlvJ1xngOins5d7ejqnIBWr9KaMxsnBqotpptRXTyfNRLnFpqzX6sTDt+X+a+6udnU8g==" - }, "node_modules/rollup": { "version": "4.17.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 70d9f12..2840f67 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,12 +9,13 @@ "format": "prettier . --write" }, "dependencies": { + "@fontsource/roboto": "^5.0.13", + "@fontsource/roboto-mono": "^5.0.18", "@mdi/font": "6.2.95", "core-js": "^3.34.0", "export-to-csv": "^1.3.0", "file-saver": "^2.0.5", "firebaseui": "^6.1.0", - "roboto-fontface": "*", "tokml": "^0.4.0", "vue": "^3.4.21", "vuedraggable": "^4.1.0", diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index 8fb9f91b3aab4eec0c76ffc5342528033c61e247..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15406 zcmeHO3v5%@8NNVarCoU?zSqezmT6npu}xxXJJhY(x=s~hQ>SSYYSncU&|(|9Y?QVX z@}TB1G8mASM;tRKYgJkrAW)&g7${B%c>oE7;)O>NNO_bu4G-IdNB({PbTkJL{ZGDJe2DLL+vq#sL?l$jZPe_*I2y@|4sBRjso zUy`aUlJo$60})6B%aMKN&yMG1Qvjth%4dDy{HM^34) z&_TyGJg3UC{J|n2-wr)LDYwhNWBH4VL-JgYz;erTEKiMF20`|$Cf~GysBU40j@&)u zboK>@(yL25%R|RmS~6@99bG>PviV`j>&k~M@~J%cn{`uCzUOyY^23rlWt6DH=aut3 zlZo^g63xIXwP(4)hgT<|I>hSGqh7YbLP$jL+%p0>vM2Su?wmOV;-uyLFww=KN5Ox{j<% zmi}mZc22bZyxbmI!x+Ch3+qsk+#YbHJ{CdQjDh~;LRJB63Pq&~p

*N){PEn7FA;EAwj=|b_AUGw z{Eb1Zt8`N8chL?vjkw~yAvg~N+W_qV|N7U7a3HGfPY0GBqUxOaLJzPO2|Qz7H&yF{ z!Y@7SbxH$-YlpxgCaImE$Fk6T4dUMU!=a+u##*PZb&m9d@{VbA<&v z;n*Hvm#Nt5zF}Ud{=9#v%+3;8${f~WV?Q`CFATe5JXp$wT(q1TOU7#0jK6PDXZ)(1 zOSF4N3hStRA?+K$*ZctH(lRF!KFSL%W20hM6%Rz+k9We?_C36J>PVG2%Y`27X;nW+ z*x`6oe7S`dXABgw#vFYvuM;-c|L9ua=7z9?9B!cL=Fyiz34xz{6kpCd?PeyG2V7mkg!!m@d$btKgDK_Ib zt|Qt#$Am-fZ&{xA0GOAnn8Ue+QQBY3NiO*vfvd{5lsp3L_K5f@hhj{}^Nk#us4?p+ ztOM)g!1L3Ff(Tk8KQe4khoQS4_&0;4zo|FQr(iM%k4L+U*z zff0J2FQWxM*K?>u4d$6_8R>l`cK8U+!w`A!D@A2^2+L%A~GSv8* z(uV!wgkD)YqY(1-;X}j zv4?n}%=LOp! z;8GgCC~I2q%*#5{$kpuKJ6-ET*}o#)Z>p>vQsxF25{?c6CQ5()gsGtn{Ul`*ykb!bDMnnlGUdfYdn+9lsY%+pJ_Z_xHs+imH? z!L`+luUT1yv*4C1Z&<#Qlui*r2~lxBI`sAm+}oX{s=OcRf9A0%Q^56>8DC==kKtgy z>D-TeE@f3uu4&Y?ZVVlM3wLg~Z>Y}xfNE|1MIAijELQN`Y2<45F5=t5>wtYuk>yuH zXEJj-vN;uZD0|537U$Eq5Oek?f#JlNGq{dN(qiDuxO185eWG@Tuk1zKUsCs)MAVm# zZTvIN+Wl0&MDXYQF#3{qXA$(Ft>uw;>&qkE2f#n|`-?1D`gl8Gqj+=j77qvaV7#CH z-mDV$x0TsBRP5B|jZ%mFQ}FDv4Rn5l$yl(|`Q7Oe;~u+P58Qvv*6uy)7U=EIpPM-5 zPv}(pkwc!Zx3$@4;Y){)0d2tO5v#db4**wJ~;d2`ShTX zw|GaKwMoD4ydIzqSN(;l&j_8}$q^eYga7tU+}ZvgxyO*m1UDkuojePFZ zG`-$PpE1`DpyrLMO}R7wCfu3t6Y|B7d%f_n+{8^32;HSdS9&hVGwt*sUYr-!%%`a~|XP)!GJa zaPfvq9vz7{ms4}`U~qpQ+@r?~G$CeSuOWUWWPj8xrxoKsi%ALkMoN~Re@yeI<`b#& zQakqh?^Bfdlv*~90r${a#kP)=j;z5r;Qua|_8~6ciamnnhpFd84r{fjgNVx%{UgRa z5XnEKlf}cZ&elidYgP}Qi}Z0^o$C^y%G~k#_Qp8=1^BDy6=xQN&GlMeiCUK;x&F$^ zjA44c!M?-)Y1kOO--Oix|DE7=F!d?WE|oc-P;ICUYO&YsIA3qS68`^+SoxzLDfxQ- z)V%&7_{XQaWqV^?8s0=b5Yxwfs(L2+kBDu`F4FIF*gxGfML8AK#-01US-npCiqalZ z?M~DOWA<^ZR|~P;79^A!*A-C1sshAC6<~Z9P|a%vs7IcNOJh792S@Vc$sCItcXG)K z1Fn?E#hswKujQD~WT#qpf3`ix0(EL{#By^?PeQ2& diff --git a/frontend/src/components/MainMap.vue b/frontend/src/components/MainMap.vue index c706e8a..8849a01 100644 --- a/frontend/src/components/MainMap.vue +++ b/frontend/src/components/MainMap.vue @@ -5,79 +5,41 @@ Search area - + - + - + - - + + - + Your search area is too large. Zoom in to reduce the search area. - + Your search area is very large. You can still run it, but the search may fail or take a long time to execute. Zoom in to reduce the search area. - + {{ store.error }} diff --git a/frontend/src/assets/queries.ts b/frontend/src/constants/queries.ts similarity index 100% rename from frontend/src/assets/queries.ts rename to frontend/src/constants/queries.ts diff --git a/frontend/src/directives/OneTap.ts b/frontend/src/directives/OneTap.ts deleted file mode 100644 index 28bcea4..0000000 --- a/frontend/src/directives/OneTap.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable no-undef */ - -export default { - beforeMount: function (el, binding, vnode) { - checkComponentMethods(); - - const clientId = binding.value.clientId; - - const googleBtnConfigs = { - type: binding.value.type || "standard", - shape: binding.value.shape || "rectangular", - theme: binding.value.theme || "outline", - text: binding.value.text || "signin", - size: binding.value.size || "large", - logo_alignment: binding.value.logo_alignment || "center", - locale: binding.value.locale || "en-us", - }; - - const googleLoginButtonId = el.id; - - const googleSignInAPI = document.createElement("script"); - googleSignInAPI.setAttribute( - "src", - "https://accounts.google.com/gsi/client", - ); - document.head.appendChild(googleSignInAPI); - googleSignInAPI.onload = InitGoogleButton; - - function InitGoogleButton() { - // prettier-ignore - google.accounts.id.initialize({ - client_id: clientId, - callback: OnSuccess - }); - - // prettier-ignore - google.accounts.id.renderButton( - document.getElementById(googleLoginButtonId), googleBtnConfigs - ); - } - - function OnSuccess(resp) { - vnode.context.onGoogleAuthSuccess(resp.credential); - } - - function checkComponentMethods() { - if (!el.id) - throw new Error( - "The google sign in container requires an 'id' attribute", - ); - - if (!vnode.context.onGoogleAuthSuccess) - throw new Error( - "The method onGoogleAuthSuccess must be defined on the component", - ); - } - }, -}; diff --git a/frontend/src/main.ts b/frontend/src/main.ts index a149d00..f516770 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -13,9 +13,14 @@ import App from "./App.vue"; // Composables import { createApp } from "vue"; + //Styles import "leaflet/dist/leaflet.css"; +// Fonts +import "@fontsource/roboto"; // Defaults to weight 400 +import "@fontsource/roboto-mono"; // Defaults to weight 400 + const app = createApp(App); registerPlugins(app); diff --git a/frontend/src/plugins/vuetify.ts b/frontend/src/plugins/vuetify.ts index 0f1718d..3f48134 100644 --- a/frontend/src/plugins/vuetify.ts +++ b/frontend/src/plugins/vuetify.ts @@ -13,6 +13,11 @@ import { createVuetify } from "vuetify"; // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides export default createVuetify({ + defaults: { + font: { + default: false, + }, + }, theme: { defaultTheme: "dark", }, diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index b66068b..7d15390 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -13,7 +13,7 @@ import { deleteDoc, doc, } from "firebase/firestore"; -import queries from "@/assets/queries"; +import queries from "../constants/queries"; import { bellingCatService } from "../services/bellingcat.service"; import { osmService } from "../services/openstreetmap.service"; import { mapboxService } from "../services/mapbox.service"; diff --git a/frontend/src/styles/firebaseui.override.css b/frontend/src/styles/firebaseui.override.css new file mode 100644 index 0000000..5a6f929 --- /dev/null +++ b/frontend/src/styles/firebaseui.override.css @@ -0,0 +1,2 @@ +/*@import url(https://fonts.googleapis.com/css?family=Roboto:400,500,700&display=swap);*/ +.mdl-button{background:0 0;border:none;border-radius:2px;color:#000;position:relative;height:36px;margin:0;min-width:64px;padding:0 16px;display:inline-block;font-family:Roboto,Helvetica,Arial,sans-serif;font-size:14px;font-weight:500;text-transform:uppercase;line-height:1;letter-spacing:0;overflow:hidden;will-change:box-shadow;transition:box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1);outline:0;cursor:pointer;text-decoration:none;text-align:center;line-height:36px;vertical-align:middle}.mdl-button::-moz-focus-inner{border:0}.mdl-button:hover{background-color:rgba(158,158,158,.2)}.mdl-button:focus:not(:active){background-color:rgba(0,0,0,.12)}.mdl-button:active{background-color:rgba(158,158,158,.4)}.mdl-button.mdl-button--colored{color:#3f51b5}.mdl-button.mdl-button--colored:focus:not(:active){background-color:rgba(0,0,0,.12)}input.mdl-button[type=submit]{-webkit-appearance:none}.mdl-button--raised{background:rgba(158,158,158,.2);box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.mdl-button--raised:active{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);background-color:rgba(158,158,158,.4)}.mdl-button--raised:focus:not(:active){box-shadow:0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36);background-color:rgba(158,158,158,.4)}.mdl-button--raised.mdl-button--colored{background:#3f51b5;color:#fff}.mdl-button--raised.mdl-button--colored:hover{background-color:#3f51b5}.mdl-button--raised.mdl-button--colored:active{background-color:#3f51b5}.mdl-button--raised.mdl-button--colored:focus:not(:active){background-color:#3f51b5}.mdl-button--raised.mdl-button--colored .mdl-ripple{background:#fff}.mdl-button--fab{border-radius:50%;font-size:24px;height:56px;margin:auto;min-width:56px;width:56px;padding:0;overflow:hidden;background:rgba(158,158,158,.2);box-shadow:0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24);position:relative;line-height:normal}.mdl-button--fab .material-icons{position:absolute;top:50%;left:50%;transform:translate(-12px,-12px);line-height:24px;width:24px}.mdl-button--fab.mdl-button--mini-fab{height:40px;min-width:40px;width:40px}.mdl-button--fab .mdl-button__ripple-container{border-radius:50%;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-button--fab:active{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);background-color:rgba(158,158,158,.4)}.mdl-button--fab:focus:not(:active){box-shadow:0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36);background-color:rgba(158,158,158,.4)}.mdl-button--fab.mdl-button--colored{background:#ff4081;color:#fff}.mdl-button--fab.mdl-button--colored:hover{background-color:#ff4081}.mdl-button--fab.mdl-button--colored:focus:not(:active){background-color:#ff4081}.mdl-button--fab.mdl-button--colored:active{background-color:#ff4081}.mdl-button--fab.mdl-button--colored .mdl-ripple{background:#fff}.mdl-button--icon{border-radius:50%;font-size:24px;height:32px;margin-left:0;margin-right:0;min-width:32px;width:32px;padding:0;overflow:hidden;color:inherit;line-height:normal}.mdl-button--icon .material-icons{position:absolute;top:50%;left:50%;transform:translate(-12px,-12px);line-height:24px;width:24px}.mdl-button--icon.mdl-button--mini-icon{height:24px;min-width:24px;width:24px}.mdl-button--icon.mdl-button--mini-icon .material-icons{top:0;left:0}.mdl-button--icon .mdl-button__ripple-container{border-radius:50%;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-button__ripple-container{display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:0;overflow:hidden}.mdl-button.mdl-button--disabled .mdl-button__ripple-container .mdl-ripple,.mdl-button[disabled] .mdl-button__ripple-container .mdl-ripple{background-color:transparent}.mdl-button--primary.mdl-button--primary{color:#3f51b5}.mdl-button--primary.mdl-button--primary .mdl-ripple{background:#fff}.mdl-button--primary.mdl-button--primary.mdl-button--fab,.mdl-button--primary.mdl-button--primary.mdl-button--raised{color:#fff;background-color:#3f51b5}.mdl-button--accent.mdl-button--accent{color:#ff4081}.mdl-button--accent.mdl-button--accent .mdl-ripple{background:#fff}.mdl-button--accent.mdl-button--accent.mdl-button--fab,.mdl-button--accent.mdl-button--accent.mdl-button--raised{color:#fff;background-color:#ff4081}.mdl-button.mdl-button--disabled.mdl-button--disabled,.mdl-button[disabled][disabled]{color:rgba(0,0,0,.26);cursor:default;background-color:transparent}.mdl-button--fab.mdl-button--disabled.mdl-button--disabled,.mdl-button--fab[disabled][disabled]{background-color:rgba(0,0,0,.12);color:rgba(0,0,0,.26)}.mdl-button--raised.mdl-button--disabled.mdl-button--disabled,.mdl-button--raised[disabled][disabled]{background-color:rgba(0,0,0,.12);color:rgba(0,0,0,.26);box-shadow:none}.mdl-button--colored.mdl-button--disabled.mdl-button--disabled,.mdl-button--colored[disabled][disabled]{color:rgba(0,0,0,.26)}.mdl-button .material-icons{vertical-align:middle}.mdl-card{display:flex;flex-direction:column;font-size:16px;font-weight:400;min-height:200px;overflow:hidden;width:330px;z-index:1;position:relative;background:#fff;border-radius:2px;box-sizing:border-box}.mdl-card__media{background-color:#ff4081;background-repeat:repeat;background-position:50% 50%;background-size:cover;background-origin:padding-box;background-attachment:scroll;box-sizing:border-box}.mdl-card__title{align-items:center;color:#000;display:block;display:flex;justify-content:stretch;line-height:normal;padding:16px 16px;perspective-origin:165px 56px;transform-origin:165px 56px;box-sizing:border-box}.mdl-card__title.mdl-card--border{border-bottom:1px solid rgba(0,0,0,.1)}.mdl-card__title-text{align-self:flex-end;color:inherit;display:block;display:flex;font-size:24px;font-weight:300;line-height:normal;overflow:hidden;transform-origin:149px 48px;margin:0}.mdl-card__subtitle-text{font-size:14px;color:rgba(0,0,0,.54);margin:0}.mdl-card__supporting-text{color:rgba(0,0,0,.54);font-size:1rem;line-height:18px;overflow:hidden;padding:16px 16px;width:90%}.mdl-card__supporting-text.mdl-card--border{border-bottom:1px solid rgba(0,0,0,.1)}.mdl-card__actions{font-size:16px;line-height:normal;width:100%;background-color:rgba(0,0,0,0);padding:8px;box-sizing:border-box}.mdl-card__actions.mdl-card--border{border-top:1px solid rgba(0,0,0,.1)}.mdl-card--expand{flex-grow:1}.mdl-card__menu{position:absolute;right:16px;top:16px}.mdl-dialog{border:none;box-shadow:0 9px 46px 8px rgba(0,0,0,.14),0 11px 15px -7px rgba(0,0,0,.12),0 24px 38px 3px rgba(0,0,0,.2);width:280px}.mdl-dialog__title{padding:24px 24px 0;margin:0;font-size:2.5rem}.mdl-dialog__actions{padding:8px 8px 8px 24px;display:flex;flex-direction:row-reverse;flex-wrap:wrap}.mdl-dialog__actions>*{margin-right:8px;height:36px}.mdl-dialog__actions>:first-child{margin-right:0}.mdl-dialog__actions--full-width{padding:0 0 8px 0}.mdl-dialog__actions--full-width>*{height:48px;flex:0 0 100%;padding-right:16px;margin-right:0;text-align:right}.mdl-dialog__content{padding:20px 24px 24px 24px;color:rgba(0,0,0,.54)}.mdl-progress{display:block;position:relative;height:4px;width:500px;max-width:100%}.mdl-progress>.bar{display:block;position:absolute;top:0;bottom:0;width:0%;transition:width .2s cubic-bezier(.4,0,.2,1)}.mdl-progress>.progressbar{background-color:#3f51b5;z-index:1;left:0}.mdl-progress>.bufferbar{background-image:linear-gradient(to right,rgba(255,255,255,.7),rgba(255,255,255,.7)),linear-gradient(to right,#3f51b5,#3f51b5);z-index:0;left:0}.mdl-progress>.auxbar{right:0}@supports (-webkit-appearance:none){.mdl-progress:not(.mdl-progress--indeterminate):not(.mdl-progress--indeterminate)>.auxbar,.mdl-progress:not(.mdl-progress__indeterminate):not(.mdl-progress__indeterminate)>.auxbar{background-image:linear-gradient(to right,rgba(255,255,255,.7),rgba(255,255,255,.7)),linear-gradient(to right,#3f51b5,#3f51b5);mask:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgd2lkdGg9IjEyIiBoZWlnaHQ9IjQiIHZpZXdQb3J0PSIwIDAgMTIgNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxlbGxpcHNlIGN4PSIyIiBjeT0iMiIgcng9IjIiIHJ5PSIyIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImN4IiBmcm9tPSIyIiB0bz0iLTEwIiBkdXI9IjAuNnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiAvPgogIDwvZWxsaXBzZT4KICA8ZWxsaXBzZSBjeD0iMTQiIGN5PSIyIiByeD0iMiIgcnk9IjIiIGNsYXNzPSJsb2FkZXIiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3giIGZyb209IjE0IiB0bz0iMiIgZHVyPSIwLjZzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L2VsbGlwc2U+Cjwvc3ZnPgo=)}}.mdl-progress:not(.mdl-progress--indeterminate)>.auxbar,.mdl-progress:not(.mdl-progress__indeterminate)>.auxbar{background-image:linear-gradient(to right,rgba(255,255,255,.9),rgba(255,255,255,.9)),linear-gradient(to right,#3f51b5,#3f51b5)}.mdl-progress.mdl-progress--indeterminate>.bar1,.mdl-progress.mdl-progress__indeterminate>.bar1{background-color:#3f51b5;animation-name:indeterminate1;animation-duration:2s;animation-iteration-count:infinite;animation-timing-function:linear}.mdl-progress.mdl-progress--indeterminate>.bar3,.mdl-progress.mdl-progress__indeterminate>.bar3{background-image:none;background-color:#3f51b5;animation-name:indeterminate2;animation-duration:2s;animation-iteration-count:infinite;animation-timing-function:linear}@keyframes indeterminate1{0%{left:0;width:0%}50%{left:25%;width:75%}75%{left:100%;width:0%}}@keyframes indeterminate2{0%{left:0;width:0%}50%{left:0;width:0%}75%{left:0;width:25%}100%{left:100%;width:0%}}.mdl-shadow--2dp{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.mdl-shadow--3dp{box-shadow:0 3px 4px 0 rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.2),0 1px 8px 0 rgba(0,0,0,.12)}.mdl-shadow--4dp{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2)}.mdl-shadow--6dp{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.2)}.mdl-shadow--8dp{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.2)}.mdl-shadow--16dp{box-shadow:0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12),0 8px 10px -5px rgba(0,0,0,.2)}.mdl-shadow--24dp{box-shadow:0 9px 46px 8px rgba(0,0,0,.14),0 11px 15px -7px rgba(0,0,0,.12),0 24px 38px 3px rgba(0,0,0,.2)}.mdl-spinner{display:inline-block;position:relative;width:28px;height:28px}.mdl-spinner:not(.is-upgraded).is-active:after{content:"Loading..."}.mdl-spinner.is-upgraded.is-active{animation:mdl-spinner__container-rotate 1.568s linear infinite}@keyframes mdl-spinner__container-rotate{to{transform:rotate(360deg)}}.mdl-spinner__layer{position:absolute;width:100%;height:100%;opacity:0}.mdl-spinner__layer-1{border-color:#42a5f5}.mdl-spinner--single-color .mdl-spinner__layer-1{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-1{animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1) infinite both,mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(.4,0,.2,1) infinite both}.mdl-spinner__layer-2{border-color:#f44336}.mdl-spinner--single-color .mdl-spinner__layer-2{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-2{animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1) infinite both,mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(.4,0,.2,1) infinite both}.mdl-spinner__layer-3{border-color:#fdd835}.mdl-spinner--single-color .mdl-spinner__layer-3{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-3{animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1) infinite both,mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(.4,0,.2,1) infinite both}.mdl-spinner__layer-4{border-color:#4caf50}.mdl-spinner--single-color .mdl-spinner__layer-4{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-4{animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1) infinite both,mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(.4,0,.2,1) infinite both}@keyframes mdl-spinner__fill-unfill-rotate{12.5%{transform:rotate(135deg)}25%{transform:rotate(270deg)}37.5%{transform:rotate(405deg)}50%{transform:rotate(540deg)}62.5%{transform:rotate(675deg)}75%{transform:rotate(810deg)}87.5%{transform:rotate(945deg)}to{transform:rotate(1080deg)}}@keyframes mdl-spinner__layer-1-fade-in-out{from{opacity:.99}25%{opacity:.99}26%{opacity:0}89%{opacity:0}90%{opacity:.99}100%{opacity:.99}}@keyframes mdl-spinner__layer-2-fade-in-out{from{opacity:0}15%{opacity:0}25%{opacity:.99}50%{opacity:.99}51%{opacity:0}}@keyframes mdl-spinner__layer-3-fade-in-out{from{opacity:0}40%{opacity:0}50%{opacity:.99}75%{opacity:.99}76%{opacity:0}}@keyframes mdl-spinner__layer-4-fade-in-out{from{opacity:0}65%{opacity:0}75%{opacity:.99}90%{opacity:.99}100%{opacity:0}}.mdl-spinner__gap-patch{position:absolute;box-sizing:border-box;top:0;left:45%;width:10%;height:100%;overflow:hidden;border-color:inherit}.mdl-spinner__gap-patch .mdl-spinner__circle{width:1000%;left:-450%}.mdl-spinner__circle-clipper{display:inline-block;position:relative;width:50%;height:100%;overflow:hidden;border-color:inherit}.mdl-spinner__circle-clipper.mdl-spinner__left{float:left}.mdl-spinner__circle-clipper.mdl-spinner__right{float:right}.mdl-spinner__circle-clipper .mdl-spinner__circle{width:200%}.mdl-spinner__circle{box-sizing:border-box;height:100%;border-width:3px;border-style:solid;border-color:inherit;border-bottom-color:transparent!important;border-radius:50%;animation:none;position:absolute;top:0;right:0;bottom:0;left:0}.mdl-spinner__left .mdl-spinner__circle{border-right-color:transparent!important;transform:rotate(129deg)}.mdl-spinner.is-active .mdl-spinner__left .mdl-spinner__circle{animation:mdl-spinner__left-spin 1333ms cubic-bezier(.4,0,.2,1) infinite both}.mdl-spinner__right .mdl-spinner__circle{left:-100%;border-left-color:transparent!important;transform:rotate(-129deg)}.mdl-spinner.is-active .mdl-spinner__right .mdl-spinner__circle{animation:mdl-spinner__right-spin 1333ms cubic-bezier(.4,0,.2,1) infinite both}@keyframes mdl-spinner__left-spin{from{transform:rotate(130deg)}50%{transform:rotate(-5deg)}to{transform:rotate(130deg)}}@keyframes mdl-spinner__right-spin{from{transform:rotate(-130deg)}50%{transform:rotate(5deg)}to{transform:rotate(-130deg)}}.mdl-textfield{position:relative;font-size:16px;display:inline-block;box-sizing:border-box;width:300px;max-width:100%;margin:0;padding:20px 0}.mdl-textfield .mdl-button{position:absolute;bottom:20px}.mdl-textfield--align-right{text-align:right}.mdl-textfield--full-width{width:100%}.mdl-textfield--expandable{min-width:32px;width:auto;min-height:32px}.mdl-textfield--expandable .mdl-button--icon{top:16px}.mdl-textfield__input{border:none;border-bottom:1px solid rgba(0,0,0,.12);display:block;font-size:16px;font-family:Helvetica,Arial,sans-serif;margin:0;padding:4px 0;width:100%;background:0 0;text-align:left;color:inherit}.mdl-textfield__input[type=number]{-moz-appearance:textfield}.mdl-textfield__input[type=number]::-webkit-inner-spin-button,.mdl-textfield__input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.mdl-textfield.is-focused .mdl-textfield__input{outline:0}.mdl-textfield.is-invalid .mdl-textfield__input{border-color:#d50000;box-shadow:none}.mdl-textfield.is-disabled .mdl-textfield__input,fieldset[disabled] .mdl-textfield .mdl-textfield__input{background-color:transparent;border-bottom:1px dotted rgba(0,0,0,.12);color:rgba(0,0,0,.26)}.mdl-textfield textarea.mdl-textfield__input{display:block}.mdl-textfield__label{bottom:0;color:rgba(0,0,0,.26);font-size:16px;left:0;right:0;pointer-events:none;position:absolute;display:block;top:24px;width:100%;overflow:hidden;white-space:nowrap;text-align:left}.mdl-textfield.has-placeholder .mdl-textfield__label,.mdl-textfield.is-dirty .mdl-textfield__label{visibility:hidden}.mdl-textfield--floating-label .mdl-textfield__label{transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.mdl-textfield--floating-label.has-placeholder .mdl-textfield__label{transition:none}.mdl-textfield.is-disabled.is-disabled .mdl-textfield__label,fieldset[disabled] .mdl-textfield .mdl-textfield__label{color:rgba(0,0,0,.26)}.mdl-textfield--floating-label.has-placeholder .mdl-textfield__label,.mdl-textfield--floating-label.is-dirty .mdl-textfield__label,.mdl-textfield--floating-label.is-focused .mdl-textfield__label{color:#3f51b5;font-size:12px;top:4px;visibility:visible}.mdl-textfield--floating-label.has-placeholder .mdl-textfield__expandable-holder .mdl-textfield__label,.mdl-textfield--floating-label.is-dirty .mdl-textfield__expandable-holder .mdl-textfield__label,.mdl-textfield--floating-label.is-focused .mdl-textfield__expandable-holder .mdl-textfield__label{top:-16px}.mdl-textfield--floating-label.is-invalid .mdl-textfield__label{color:#d50000;font-size:12px}.mdl-textfield__label:after{background-color:#3f51b5;bottom:20px;content:"";height:2px;left:45%;position:absolute;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);visibility:hidden;width:10px}.mdl-textfield.is-focused .mdl-textfield__label:after{left:0;visibility:visible;width:100%}.mdl-textfield.is-invalid .mdl-textfield__label:after{background-color:#d50000}.mdl-textfield__error{color:#d50000;position:absolute;font-size:12px;margin-top:3px;visibility:hidden;display:block}.mdl-textfield.is-invalid .mdl-textfield__error{visibility:visible}.mdl-textfield__expandable-holder{display:inline-block;position:relative;margin-left:32px;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:inline-block;max-width:.1px}.mdl-textfield.is-dirty .mdl-textfield__expandable-holder,.mdl-textfield.is-focused .mdl-textfield__expandable-holder{max-width:600px}.mdl-textfield__expandable-holder .mdl-textfield__label:after{bottom:0}dialog{position:absolute;left:0;right:0;width:-moz-fit-content;width:-webkit-fit-content;width:fit-content;height:-moz-fit-content;height:-webkit-fit-content;height:fit-content;margin:auto;border:solid;padding:1em;background:#fff;color:#000;display:block}dialog:not([open]){display:none}dialog+.backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:rgba(0,0,0,.1)}._dialog_overlay{position:fixed;top:0;right:0;bottom:0;left:0}dialog.fixed{position:fixed;top:50%;transform:translate(0,-50%)}.firebaseui-container{background-color:#fff;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;color:rgba(0,0,0,.87);direction:ltr;font:16px Roboto,arial,sans-serif;margin:0 auto;max-width:360px;overflow:visible;position:relative;text-align:left;width:100%}.firebaseui-container.mdl-card{overflow:visible}.firebaseui-card-header{padding:24px 24px 0 24px}.firebaseui-card-content{padding:0 24px}.firebaseui-card-footer{padding:0 24px}.firebaseui-card-actions{box-sizing:border-box;display:table;font-size:14px;padding:8px 24px 24px 24px;text-align:left;width:100%}.firebaseui-form-links{display:table-cell;vertical-align:middle;width:100%}.firebaseui-form-actions{display:table-cell;text-align:right;white-space:nowrap;width:100%}.firebaseui-subtitle,.firebaseui-title{color:rgba(0,0,0,.87);direction:ltr;font-size:20px;font-weight:500;line-height:24px;margin:0;padding:0;text-align:left}.firebaseui-title{padding-bottom:16px}.firebaseui-subtitle{margin:16px 0}.firebaseui-text{color:rgba(0,0,0,.87);direction:ltr;font-size:16px;line-height:24px;text-align:left}.firebaseui-id-page-password-recovery-email-sent p.firebaseui-text{margin:16px 0}.firebaseui-text-emphasis{font-weight:700}.firebaseui-error{color:#dd2c00;direction:ltr;font-size:12px;line-height:16px;margin:0;text-align:left}.firebaseui-text-input-error{margin:-16px 0 16px}.firebaseui-error-wrapper{min-height:16px}.firebaseui-list-item{direction:ltr;margin:0;padding:0;text-align:left}.firebaseui-hidden{display:none}.firebaseui-relative-wrapper{position:relative}.firebaseui-label{color:rgba(0,0,0,.54);direction:ltr;font-size:16px;text-align:left}.mdl-textfield--floating-label.is-dirty .mdl-textfield__label,.mdl-textfield--floating-label.is-focused .mdl-textfield__label{color:#757575}.firebaseui-input,.firebaseui-input-invalid{border-radius:0;color:rgba(0,0,0,.87);direction:ltr;font-size:16px;width:100%}input.firebaseui-input,input.firebaseui-input-invalid{direction:ltr;text-align:left}.firebaseui-input-invalid{border-color:#dd2c00}.firebaseui-textfield{width:100%}.firebaseui-textfield.mdl-textfield .firebaseui-input{border-color:rgba(0,0,0,.12)}.firebaseui-textfield.mdl-textfield .firebaseui-label::after{background-color:#3f51b5}.firebaseui-textfield-invalid.mdl-textfield .firebaseui-input{border-color:#dd2c00}.firebaseui-textfield-invalid.mdl-textfield .firebaseui-label::after{background-color:#dd2c00}.firebaseui-button{display:inline-block;height:36px;margin-left:8px;min-width:88px}.firebaseui-link{color:#4285f4;font-variant:normal;font-weight:400;text-decoration:none}.firebaseui-link:hover{text-decoration:underline}.firebaseui-indent{margin-left:1em}.firebaseui-tos{color:#757575;direction:ltr;font-size:12px;line-height:16px;margin-bottom:24px;margin-top:0;text-align:left}.firebaseui-provider-sign-in-footer>.firebaseui-tos{text-align:center}.firebaseui-tos-list{list-style:none;text-align:right}.firebaseui-inline-list-item{display:inline-block;margin-left:5px;margin-right:5px}.firebaseui-page-provider-sign-in,.firebaseui-page-select-tenant{background:inherit}.firebaseui-idp-list,.firebaseui-tenant-list{list-style:none;margin:1em 0;padding:0}.firebaseui-idp-button,.firebaseui-tenant-button{direction:ltr;font-weight:500;height:auto;line-height:normal;max-width:220px;min-height:40px;padding:8px 16px;text-align:left;width:100%}.firebaseui-idp-list>.firebaseui-list-item,.firebaseui-tenant-list>.firebaseui-list-item{margin-bottom:15px;text-align:center}.firebaseui-idp-icon-wrapper{display:table-cell;vertical-align:middle}.firebaseui-idp-icon{border:none;display:inline-block;height:18px;vertical-align:middle;width:18px}.firebaseui-idp-favicon{border:none;display:inline-block;height:14px;margin-right:5px;vertical-align:middle;width:14px}.firebaseui-idp-text{color:#fff;display:table-cell;font-size:14px;padding-left:16px;text-transform:none;vertical-align:middle}.firebaseui-idp-text.firebaseui-idp-text-long{display:table-cell}.firebaseui-idp-text.firebaseui-idp-text-short{display:none}@media (max-width:268px){.firebaseui-idp-text.firebaseui-idp-text-long{display:none}.firebaseui-idp-text.firebaseui-idp-text-short{display:table-cell}}@media (max-width:320px){.firebaseui-recaptcha-container>div>div{transform:scale(.9);-webkit-transform:scale(.9);transform-origin:0 0;-webkit-transform-origin:0 0}}.firebaseui-idp-google>.firebaseui-idp-text{color:#757575}[data-provider-id="yahoo.com"]>.firebaseui-idp-icon-wrapper>.firebaseui-idp-icon{height:22px;width:22px}.firebaseui-info-bar{background-color:#f9edbe;border:1px solid #f0c36d;box-shadow:0 2px 4px rgba(0,0,0,.2);-webkit-box-shadow:0 2px 4px rgba(0,0,0,.2);-moz-box-shadow:0 2px 4px rgba(0,0,0,.2);left:10%;padding:8px 16px;position:absolute;right:10%;text-align:center;top:0}.firebaseui-info-bar-message{font-size:12px;margin:0}.firebaseui-dialog{box-sizing:border-box;color:rgba(0,0,0,.87);font:16px Roboto,arial,sans-serif;height:auto;max-height:fit-content;padding:24px;text-align:left}.firebaseui-dialog-icon-wrapper{display:table-cell;vertical-align:middle}.firebaseui-dialog-icon{float:left;height:40px;margin-right:24px;width:40px}.firebaseui-progress-dialog-message{display:table-cell;font-size:16px;font-weight:400;min-height:40px;vertical-align:middle}.firebaseui-progress-dialog-loading-icon{height:28px;margin:6px 30px 6px 6px;width:28px}.firebaseui-icon-done{background-image:url(https://www.gstatic.com/images/icons/material/system/2x/done_googgreen_36dp.png);background-position:center;background-repeat:no-repeat;background-size:36px 36px}.firebaseui-phone-number{display:flex}.firebaseui-country-selector{background-image:url(https://www.gstatic.com/images/icons/material/system/1x/arrow_drop_down_grey600_18dp.png);background-position:right center;background-repeat:no-repeat;background-size:18px auto;border-radius:0;border-bottom:1px solid rgba(0,0,0,.12);color:rgba(0,0,0,.87);flex-shrink:0;font-size:16px;font-weight:400;height:initial;line-height:normal;margin:20px 24px 20px 0;padding:4px 20px 4px 0;width:90px}.firebaseui-country-selector-flag{display:inline-block;margin-right:1ex}.firebaseui-flag{background-image:url(https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/flags_sprite_2x.png);background-size:100% auto;filter:drop-shadow(1px 1px 1px rgba(0, 0, 0, .54));height:14px;width:24px}.firebaseui-list-box-dialog{max-height:90%;overflow:auto;padding:8px 0 0 0}.firebaseui-list-box-actions{padding-bottom:8px}.firebaseui-list-box-icon-wrapper{display:table-cell;padding-right:24px;vertical-align:top}.firebaseui-list-box-label-wrapper{display:table-cell;vertical-align:top}.firebaseui-list-box-dialog-button{color:rgba(0,0,0,.87);direction:ltr;font-size:16px;font-weight:400;height:initial;line-height:normal;min-height:48px;padding:14px 24px;text-align:left;text-transform:none;width:100%}.firebaseui-phone-number-error{margin-left:114px}.mdl-progress.firebaseui-busy-indicator{height:2px;left:0;position:absolute;top:55px;width:100%}.mdl-spinner.firebaseui-busy-indicator{direction:initial;height:56px;left:0;margin:auto;position:absolute;right:0;top:30%;width:56px}.firebaseui-callback-indicator-container .firebaseui-busy-indicator{top:0}.firebaseui-callback-indicator-container{height:120px}.firebaseui-new-password-component{display:inline-block;position:relative;width:100%}.firebaseui-input-floating-button{background-position:center;background-repeat:no-repeat;display:block;height:24px;position:absolute;right:0;top:20px;width:24px}.firebaseui-input-toggle-on{background-image:url(https://www.gstatic.com/images/icons/material/system/1x/visibility_black_24dp.png)}.firebaseui-input-toggle-off{background-image:url(https://www.gstatic.com/images/icons/material/system/1x/visibility_off_black_24dp.png)}.firebaseui-input-toggle-focus{opacity:.87}.firebaseui-input-toggle-blur{opacity:.38}.firebaseui-recaptcha-wrapper{display:table;margin:0 auto;padding-bottom:8px}.firebaseui-recaptcha-container{display:table-cell}.firebaseui-recaptcha-error-wrapper{caption-side:bottom;display:table-caption}.firebaseui-change-phone-number-link{display:block}.firebaseui-resend-container{direction:ltr;margin:20px 0;text-align:center}.firebaseui-id-resend-countdown{color:rgba(0,0,0,.38)}.firebaseui-id-page-phone-sign-in-start .firebaseui-form-actions div{float:left}@media (max-width:480px){.firebaseui-container{box-shadow:none;max-width:none;width:100%}.firebaseui-card-header{border-bottom:1px solid #e0e0e0;margin-bottom:16px;padding:16px 24px 0 24px}.firebaseui-title{padding-bottom:16px}.firebaseui-card-actions{padding-right:24px}.firebaseui-busy-indicator{top:0}}.mdl-textfield__label{font-weight:400;margin-bottom:0}.firebaseui-id-page-blank{background:inherit;height:64px}.firebaseui-id-page-spinner{background:inherit;height:64px}.firebaseui-email-sent{background-image:url(https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/success_status.png);background-position:center;background-repeat:no-repeat;background-size:64px 64px;height:64px;margin-top:16px;text-align:center}.firebaseui-text-justify{text-align:justify}.firebaseui-flag-KY{background-position:0 0}.firebaseui-flag-AC{background-position:0 -14px}.firebaseui-flag-AE{background-position:0 -28px}.firebaseui-flag-AF{background-position:0 -42px}.firebaseui-flag-AG{background-position:0 -56px}.firebaseui-flag-AI{background-position:0 -70px}.firebaseui-flag-AL{background-position:0 -84px}.firebaseui-flag-AM{background-position:0 -98px}.firebaseui-flag-AO{background-position:0 -112px}.firebaseui-flag-AQ{background-position:0 -126px}.firebaseui-flag-AR{background-position:0 -140px}.firebaseui-flag-AS{background-position:0 -154px}.firebaseui-flag-AT{background-position:0 -168px}.firebaseui-flag-AU{background-position:0 -182px}.firebaseui-flag-AW{background-position:0 -196px}.firebaseui-flag-AX{background-position:0 -210px}.firebaseui-flag-AZ{background-position:0 -224px}.firebaseui-flag-BA{background-position:0 -238px}.firebaseui-flag-BB{background-position:0 -252px}.firebaseui-flag-BD{background-position:0 -266px}.firebaseui-flag-BE{background-position:0 -280px}.firebaseui-flag-BF{background-position:0 -294px}.firebaseui-flag-BG{background-position:0 -308px}.firebaseui-flag-BH{background-position:0 -322px}.firebaseui-flag-BI{background-position:0 -336px}.firebaseui-flag-BJ{background-position:0 -350px}.firebaseui-flag-BL{background-position:0 -364px}.firebaseui-flag-BM{background-position:0 -378px}.firebaseui-flag-BN{background-position:0 -392px}.firebaseui-flag-BO{background-position:0 -406px}.firebaseui-flag-BQ{background-position:0 -420px}.firebaseui-flag-BR{background-position:0 -434px}.firebaseui-flag-BS{background-position:0 -448px}.firebaseui-flag-BT{background-position:0 -462px}.firebaseui-flag-BV{background-position:0 -476px}.firebaseui-flag-BW{background-position:0 -490px}.firebaseui-flag-BY{background-position:0 -504px}.firebaseui-flag-BZ{background-position:0 -518px}.firebaseui-flag-CA{background-position:0 -532px}.firebaseui-flag-CC{background-position:0 -546px}.firebaseui-flag-CD{background-position:0 -560px}.firebaseui-flag-CF{background-position:0 -574px}.firebaseui-flag-CG{background-position:0 -588px}.firebaseui-flag-CH{background-position:0 -602px}.firebaseui-flag-CI{background-position:0 -616px}.firebaseui-flag-CK{background-position:0 -630px}.firebaseui-flag-CL{background-position:0 -644px}.firebaseui-flag-CM{background-position:0 -658px}.firebaseui-flag-CN{background-position:0 -672px}.firebaseui-flag-CO{background-position:0 -686px}.firebaseui-flag-CP{background-position:0 -700px}.firebaseui-flag-CR{background-position:0 -714px}.firebaseui-flag-CU{background-position:0 -728px}.firebaseui-flag-CV{background-position:0 -742px}.firebaseui-flag-CW{background-position:0 -756px}.firebaseui-flag-CX{background-position:0 -770px}.firebaseui-flag-CY{background-position:0 -784px}.firebaseui-flag-CZ{background-position:0 -798px}.firebaseui-flag-DE{background-position:0 -812px}.firebaseui-flag-DG{background-position:0 -826px}.firebaseui-flag-DJ{background-position:0 -840px}.firebaseui-flag-DK{background-position:0 -854px}.firebaseui-flag-DM{background-position:0 -868px}.firebaseui-flag-DO{background-position:0 -882px}.firebaseui-flag-DZ{background-position:0 -896px}.firebaseui-flag-EA{background-position:0 -910px}.firebaseui-flag-EC{background-position:0 -924px}.firebaseui-flag-EE{background-position:0 -938px}.firebaseui-flag-EG{background-position:0 -952px}.firebaseui-flag-EH{background-position:0 -966px}.firebaseui-flag-ER{background-position:0 -980px}.firebaseui-flag-ES{background-position:0 -994px}.firebaseui-flag-ET{background-position:0 -1008px}.firebaseui-flag-EU{background-position:0 -1022px}.firebaseui-flag-FI{background-position:0 -1036px}.firebaseui-flag-FJ{background-position:0 -1050px}.firebaseui-flag-FK{background-position:0 -1064px}.firebaseui-flag-FM{background-position:0 -1078px}.firebaseui-flag-FO{background-position:0 -1092px}.firebaseui-flag-FR{background-position:0 -1106px}.firebaseui-flag-GA{background-position:0 -1120px}.firebaseui-flag-GB{background-position:0 -1134px}.firebaseui-flag-GD{background-position:0 -1148px}.firebaseui-flag-GE{background-position:0 -1162px}.firebaseui-flag-GF{background-position:0 -1176px}.firebaseui-flag-GG{background-position:0 -1190px}.firebaseui-flag-GH{background-position:0 -1204px}.firebaseui-flag-GI{background-position:0 -1218px}.firebaseui-flag-GL{background-position:0 -1232px}.firebaseui-flag-GM{background-position:0 -1246px}.firebaseui-flag-GN{background-position:0 -1260px}.firebaseui-flag-GP{background-position:0 -1274px}.firebaseui-flag-GQ{background-position:0 -1288px}.firebaseui-flag-GR{background-position:0 -1302px}.firebaseui-flag-GS{background-position:0 -1316px}.firebaseui-flag-GT{background-position:0 -1330px}.firebaseui-flag-GU{background-position:0 -1344px}.firebaseui-flag-GW{background-position:0 -1358px}.firebaseui-flag-GY{background-position:0 -1372px}.firebaseui-flag-HK{background-position:0 -1386px}.firebaseui-flag-HM{background-position:0 -1400px}.firebaseui-flag-HN{background-position:0 -1414px}.firebaseui-flag-HR{background-position:0 -1428px}.firebaseui-flag-HT{background-position:0 -1442px}.firebaseui-flag-HU{background-position:0 -1456px}.firebaseui-flag-IC{background-position:0 -1470px}.firebaseui-flag-ID{background-position:0 -1484px}.firebaseui-flag-IE{background-position:0 -1498px}.firebaseui-flag-IL{background-position:0 -1512px}.firebaseui-flag-IM{background-position:0 -1526px}.firebaseui-flag-IN{background-position:0 -1540px}.firebaseui-flag-IO{background-position:0 -1554px}.firebaseui-flag-IQ{background-position:0 -1568px}.firebaseui-flag-IR{background-position:0 -1582px}.firebaseui-flag-IS{background-position:0 -1596px}.firebaseui-flag-IT{background-position:0 -1610px}.firebaseui-flag-JE{background-position:0 -1624px}.firebaseui-flag-JM{background-position:0 -1638px}.firebaseui-flag-JO{background-position:0 -1652px}.firebaseui-flag-JP{background-position:0 -1666px}.firebaseui-flag-KE{background-position:0 -1680px}.firebaseui-flag-KG{background-position:0 -1694px}.firebaseui-flag-KH{background-position:0 -1708px}.firebaseui-flag-KI{background-position:0 -1722px}.firebaseui-flag-KM{background-position:0 -1736px}.firebaseui-flag-KN{background-position:0 -1750px}.firebaseui-flag-KP{background-position:0 -1764px}.firebaseui-flag-KR{background-position:0 -1778px}.firebaseui-flag-KW{background-position:0 -1792px}.firebaseui-flag-AD{background-position:0 -1806px}.firebaseui-flag-KZ{background-position:0 -1820px}.firebaseui-flag-LA{background-position:0 -1834px}.firebaseui-flag-LB{background-position:0 -1848px}.firebaseui-flag-LC{background-position:0 -1862px}.firebaseui-flag-LI{background-position:0 -1876px}.firebaseui-flag-LK{background-position:0 -1890px}.firebaseui-flag-LR{background-position:0 -1904px}.firebaseui-flag-LS{background-position:0 -1918px}.firebaseui-flag-LT{background-position:0 -1932px}.firebaseui-flag-LU{background-position:0 -1946px}.firebaseui-flag-LV{background-position:0 -1960px}.firebaseui-flag-LY{background-position:0 -1974px}.firebaseui-flag-MA{background-position:0 -1988px}.firebaseui-flag-MC{background-position:0 -2002px}.firebaseui-flag-MD{background-position:0 -2016px}.firebaseui-flag-ME{background-position:0 -2030px}.firebaseui-flag-MF{background-position:0 -2044px}.firebaseui-flag-MG{background-position:0 -2058px}.firebaseui-flag-MH{background-position:0 -2072px}.firebaseui-flag-MK{background-position:0 -2086px}.firebaseui-flag-ML{background-position:0 -2100px}.firebaseui-flag-MM{background-position:0 -2114px}.firebaseui-flag-MN{background-position:0 -2128px}.firebaseui-flag-MO{background-position:0 -2142px}.firebaseui-flag-MP{background-position:0 -2156px}.firebaseui-flag-MQ{background-position:0 -2170px}.firebaseui-flag-MR{background-position:0 -2184px}.firebaseui-flag-MS{background-position:0 -2198px}.firebaseui-flag-MT{background-position:0 -2212px}.firebaseui-flag-MU{background-position:0 -2226px}.firebaseui-flag-MV{background-position:0 -2240px}.firebaseui-flag-MW{background-position:0 -2254px}.firebaseui-flag-MX{background-position:0 -2268px}.firebaseui-flag-MY{background-position:0 -2282px}.firebaseui-flag-MZ{background-position:0 -2296px}.firebaseui-flag-NA{background-position:0 -2310px}.firebaseui-flag-NC{background-position:0 -2324px}.firebaseui-flag-NE{background-position:0 -2338px}.firebaseui-flag-NF{background-position:0 -2352px}.firebaseui-flag-NG{background-position:0 -2366px}.firebaseui-flag-NI{background-position:0 -2380px}.firebaseui-flag-NL{background-position:0 -2394px}.firebaseui-flag-NO{background-position:0 -2408px}.firebaseui-flag-NP{background-position:0 -2422px}.firebaseui-flag-NR{background-position:0 -2436px}.firebaseui-flag-NU{background-position:0 -2450px}.firebaseui-flag-NZ{background-position:0 -2464px}.firebaseui-flag-OM{background-position:0 -2478px}.firebaseui-flag-PA{background-position:0 -2492px}.firebaseui-flag-PE{background-position:0 -2506px}.firebaseui-flag-PF{background-position:0 -2520px}.firebaseui-flag-PG{background-position:0 -2534px}.firebaseui-flag-PH{background-position:0 -2548px}.firebaseui-flag-PK{background-position:0 -2562px}.firebaseui-flag-PL{background-position:0 -2576px}.firebaseui-flag-PM{background-position:0 -2590px}.firebaseui-flag-PN{background-position:0 -2604px}.firebaseui-flag-PR{background-position:0 -2618px}.firebaseui-flag-PS{background-position:0 -2632px}.firebaseui-flag-PT{background-position:0 -2646px}.firebaseui-flag-PW{background-position:0 -2660px}.firebaseui-flag-PY{background-position:0 -2674px}.firebaseui-flag-QA{background-position:0 -2688px}.firebaseui-flag-RE{background-position:0 -2702px}.firebaseui-flag-RO{background-position:0 -2716px}.firebaseui-flag-RS{background-position:0 -2730px}.firebaseui-flag-RU{background-position:0 -2744px}.firebaseui-flag-RW{background-position:0 -2758px}.firebaseui-flag-SA{background-position:0 -2772px}.firebaseui-flag-SB{background-position:0 -2786px}.firebaseui-flag-SC{background-position:0 -2800px}.firebaseui-flag-SD{background-position:0 -2814px}.firebaseui-flag-SE{background-position:0 -2828px}.firebaseui-flag-SG{background-position:0 -2842px}.firebaseui-flag-SH{background-position:0 -2856px}.firebaseui-flag-SI{background-position:0 -2870px}.firebaseui-flag-SJ{background-position:0 -2884px}.firebaseui-flag-SK{background-position:0 -2898px}.firebaseui-flag-SL{background-position:0 -2912px}.firebaseui-flag-SM{background-position:0 -2926px}.firebaseui-flag-SN{background-position:0 -2940px}.firebaseui-flag-SO{background-position:0 -2954px}.firebaseui-flag-SR{background-position:0 -2968px}.firebaseui-flag-SS{background-position:0 -2982px}.firebaseui-flag-ST{background-position:0 -2996px}.firebaseui-flag-SV{background-position:0 -3010px}.firebaseui-flag-SX{background-position:0 -3024px}.firebaseui-flag-SY{background-position:0 -3038px}.firebaseui-flag-SZ{background-position:0 -3052px}.firebaseui-flag-TA{background-position:0 -3066px}.firebaseui-flag-TC{background-position:0 -3080px}.firebaseui-flag-TD{background-position:0 -3094px}.firebaseui-flag-TF{background-position:0 -3108px}.firebaseui-flag-TG{background-position:0 -3122px}.firebaseui-flag-TH{background-position:0 -3136px}.firebaseui-flag-TJ{background-position:0 -3150px}.firebaseui-flag-TK{background-position:0 -3164px}.firebaseui-flag-TL{background-position:0 -3178px}.firebaseui-flag-TM{background-position:0 -3192px}.firebaseui-flag-TN{background-position:0 -3206px}.firebaseui-flag-TO{background-position:0 -3220px}.firebaseui-flag-TR{background-position:0 -3234px}.firebaseui-flag-TT{background-position:0 -3248px}.firebaseui-flag-TV{background-position:0 -3262px}.firebaseui-flag-TW{background-position:0 -3276px}.firebaseui-flag-TZ{background-position:0 -3290px}.firebaseui-flag-UA{background-position:0 -3304px}.firebaseui-flag-UG{background-position:0 -3318px}.firebaseui-flag-UM{background-position:0 -3332px}.firebaseui-flag-UN{background-position:0 -3346px}.firebaseui-flag-US{background-position:0 -3360px}.firebaseui-flag-UY{background-position:0 -3374px}.firebaseui-flag-UZ{background-position:0 -3388px}.firebaseui-flag-VA{background-position:0 -3402px}.firebaseui-flag-VC{background-position:0 -3416px}.firebaseui-flag-VE{background-position:0 -3430px}.firebaseui-flag-VG{background-position:0 -3444px}.firebaseui-flag-VI{background-position:0 -3458px}.firebaseui-flag-VN{background-position:0 -3472px}.firebaseui-flag-VU{background-position:0 -3486px}.firebaseui-flag-WF{background-position:0 -3500px}.firebaseui-flag-WS{background-position:0 -3514px}.firebaseui-flag-XK{background-position:0 -3528px}.firebaseui-flag-YE{background-position:0 -3542px}.firebaseui-flag-YT{background-position:0 -3556px}.firebaseui-flag-ZA{background-position:0 -3570px}.firebaseui-flag-ZM{background-position:0 -3584px}.firebaseui-flag-ZW{background-position:0 -3598px} diff --git a/frontend/src/styles/settings.scss b/frontend/src/styles/settings.scss index 3e36a27..6fe56bc 100644 --- a/frontend/src/styles/settings.scss +++ b/frontend/src/styles/settings.scss @@ -8,3 +8,9 @@ // @use 'vuetify/settings' with ( // $color-pack: false // ); + +$custom-family: "Roboto", sans-serif; +@use "vuetify/settings" with ( + $body-font-family: $custom-family, + $heading-font-family: $custom-family +); diff --git a/frontend/vite.config.mts b/frontend/vite.config.mts index d21dc4a..daa011c 100644 --- a/frontend/vite.config.mts +++ b/frontend/vite.config.mts @@ -44,7 +44,7 @@ export default defineConfig({ configFile: "src/styles/settings.scss", }, }), - Fonts({ + /*Fonts({ google: { families: [ { @@ -53,7 +53,7 @@ export default defineConfig({ }, ], }, - }), + })*/, ], define: { "process.env": {} }, resolve: { From 4ef7849b51b53e1c5ec7b74c67554067736c1afa Mon Sep 17 00:00:00 2001 From: zameji Date: Sat, 25 May 2024 00:14:50 +0200 Subject: [PATCH 22/30] refactor: search control cleanup --- frontend/src/App.vue | 1 - frontend/src/components.d.ts | 2 +- frontend/src/components/FeatureCustom.vue | 97 +- frontend/src/components/FeatureSelector.vue | 97 +- frontend/src/components/FeatureView.vue | 98 +- frontend/src/components/MainMap.vue | 76 +- frontend/src/components/MapMarker.vue | 2 +- frontend/src/components/SearchControls.vue | 34 +- frontend/src/components/SearchResult.vue | 49 +- frontend/src/components/SearchResults.vue | 34 +- frontend/src/main.ts | 1 - frontend/src/pages/index.vue | 17 +- frontend/src/stores/app.ts | 17 +- frontend/src/styles/firebaseui.override.css | 2268 ++++++++++++++++++- frontend/src/styles/settings.scss | 4 +- frontend/vite.config.mts | 3 +- 16 files changed, 2564 insertions(+), 236 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index c8b64d7..1faf633 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -53,7 +53,6 @@ function toggleDarkMode() { diff --git a/frontend/src/components/MainMap.vue b/frontend/src/components/MainMap.vue index 8849a01..c65ce6d 100644 --- a/frontend/src/components/MainMap.vue +++ b/frontend/src/components/MainMap.vue @@ -1,43 +1,85 @@ @@ -143,14 +120,6 @@ function clicked() { padding: 8px; } -a.outlink { - /* color: black !important; */ -} - -.outlink:hover { - /* background-color: #ddd; */ -} - .result .v-btn__content { user-select: all; } diff --git a/frontend/src/components/SearchResults.vue b/frontend/src/components/SearchResults.vue index 6b0999a..7d4369b 100644 --- a/frontend/src/components/SearchResults.vue +++ b/frontend/src/components/SearchResults.vue @@ -1,6 +1,5 @@ diff --git a/frontend/src/components/MainMap.vue b/frontend/src/components/MainMap.vue index c65ce6d..4bc64b7 100644 --- a/frontend/src/components/MainMap.vue +++ b/frontend/src/components/MainMap.vue @@ -37,8 +37,8 @@ @update:bounds="updateBbox" > - @@ -117,6 +117,10 @@ const zoom = computed({ }, }); +const searchResults = computed(() => { + return store.searchResults; +}); + const url = computed(() => { if (mode.value == "google") { return "http://mt0.google.com/vt/lyrs=m&x={x}&y={y}&z={z}"; diff --git a/frontend/src/components/MapMarker.vue b/frontend/src/components/MainMapMarker.vue similarity index 50% rename from frontend/src/components/MapMarker.vue rename to frontend/src/components/MainMapMarker.vue index 3e9e26e..cf4bfaa 100644 --- a/frontend/src/components/MapMarker.vue +++ b/frontend/src/components/MainMapMarker.vue @@ -1,13 +1,9 @@ diff --git a/frontend/src/components/SearchResult.vue b/frontend/src/components/SearchResult.vue index 87cdc1b..5f69f07 100644 --- a/frontend/src/components/SearchResult.vue +++ b/frontend/src/components/SearchResult.vue @@ -10,9 +10,10 @@ - +

- + +
@@ -22,7 +23,7 @@ {{ name || " "}} + append-icon="mdi-open-in-new" target="_blank"> ({{ lat }}, {{ lng }}) @@ -36,12 +37,14 @@ import L from "leaflet"; globalThis.L = L; import { LMap, LTileLayer } from "@vue-leaflet/vue-leaflet"; -import { useAppStore } from "@/stores/app"; -import { computed } from "vue"; +import { useAppStore, SearchResult } from "@/stores/app"; +import { computed, ref } from "vue"; -const props = defineProps({ - result: Object, -}); +const zoom = ref(14) + +const props = defineProps<{ + result: SearchResult, +}>(); const store = useAppStore(); const url = computed(() => { @@ -84,6 +87,10 @@ const index = computed(() => { return props.result.index; }); +const geometries = computed(() => { + return props.result.geometry; +}); + function clicked() { store.setSelectedResult(index.value); store.setMapPosition({ @@ -102,7 +109,7 @@ function clicked() { } .result:hover { - background-color: #d1c4e9; + background-color: #118833; cursor: default; } diff --git a/frontend/src/services/bellingcat.service.ts b/frontend/src/services/bellingcat.service.ts index 6e1f8d5..e4c0d3f 100644 --- a/frontend/src/services/bellingcat.service.ts +++ b/frontend/src/services/bellingcat.service.ts @@ -1,6 +1,7 @@ const PAGE_SIZE = 100; const OSM_SEARCH_API = "http://localhost:5050"; //"https://api.osm-search.bellingcat.com"; + class BellingCatService { token: string | null; lastRequest: string | null; @@ -69,7 +70,6 @@ class BellingCatService { this.search({ bbox, range, filters, page: page + 1 }); }, 1000); } - resolve(response); }) .catch((e) => { diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index cf9c679..caac02b 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -18,9 +18,25 @@ import { bellingCatService } from "../services/bellingcat.service"; import { osmService } from "../services/openstreetmap.service"; import { mapboxService } from "../services/mapbox.service"; + +export interface SearchResult { + geometry: GeoJSON[] + lat: number + lng: number + name: string + index: number + hovered?: boolean + selected?: boolean +} + +export interface GeoJSON { + coordinates: number[][] + type: string +} + interface State { selected: any[]; - searchResults: any[]; + searchResults: SearchResult[]; bbox: number[]; error: boolean | string; range: number; From eba92b659df581f09d0c711c07b06fb5dc1f426f Mon Sep 17 00:00:00 2001 From: zameji Date: Mon, 27 May 2024 22:44:29 +0200 Subject: [PATCH 24/30] feat: allow multiple instances of same feature --- api/api.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/api/api.py b/api/api.py index 392f42b..929caa5 100644 --- a/api/api.py +++ b/api/api.py @@ -253,7 +253,8 @@ def build_cte_from_filter(f: Filter, id: sql.SQL) -> sql.Composed: assembled: sql.Composed = sql.SQL( """{id} AS (SELECT - way AS geom + way AS geom, + osm_id FROM {source_table}, envelope WHERE ({filter}) AND (way && envelope.geom))""" ).format(id=id, source_table=source_table, filter=filter_query) @@ -281,6 +282,7 @@ def build_query( initial_cte = sql.SQL( """initial_table AS ( SELECT + osm_id, tags->'name' AS name, ST_Transform(ST_Centroid(way), 4326) AS point_geom, way AS geom @@ -301,7 +303,8 @@ def build_query( [initial_cte, *[cte_sql for cte_id, cte_sql in additional_cte_list]] ), select_statement_initial=sql.SQL( - "SELECT point_geom, name, ST_Y(point_geom) AS lat, ST_X(point_geom) AS lng, ST_AsGeoJSON(ST_Transform(initial_table.geom, 4326)) AS main_geom," + "SELECT point_geom, name, ST_Y(point_geom) AS lat, ST_X(point_geom) AS lng, ST_AsGeoJSON(ST_Transform(initial_table.geom, 4326)) AS main_geom" + + ("" if len(additional_cte_list) == 0 else ",") ), select_statements_cte=sql.SQL(" ,").join( [ @@ -315,9 +318,26 @@ def build_query( join_staments=sql.SQL(" ").join( [ sql.SQL( - "JOIN {cte_id} ON ST_DWithin(initial_table.geom, {cte_id}.geom, {buffer})" - ).format(cte_id=cte_id, buffer=sql.Literal(buffer)) - for cte_id, cte_sql in additional_cte_list + "JOIN {cte_id} ON ST_DWithin(initial_table.geom, {cte_id}.geom, {buffer}) AND {self_join_exclusion_clause}" + ).format( + cte_id=cte_id, + buffer=sql.Literal(buffer), + self_join_exclusion_clause=sql.SQL(" AND ").join( + [ + sql.SQL("{cte_id}.osm_id != initial_table.osm_id").format( + cte_id=cte_id + ) + ] + + [ + sql.SQL("{cte_id}.osm_id != {cte_id2}.osm_id").format( + cte_id=cte_id, cte_id2=cte_id2 + ) + for cte_id2, _ in additional_cte_list[0:index] + if cte_id2 != cte_id + ] + ), + ) + for index, [cte_id, cte_sql] in enumerate(additional_cte_list) ] ), pagination=sql.SQL( From 1d2d55dfc3d38ca36fd33d988da80849bb39e0b4 Mon Sep 17 00:00:00 2001 From: zameji Date: Mon, 27 May 2024 22:44:47 +0200 Subject: [PATCH 25/30] feat: simplify return for no results --- frontend/src/components/SearchResults.vue | 101 ++++++++++++---------- frontend/src/pages/index.vue | 2 +- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/frontend/src/components/SearchResults.vue b/frontend/src/components/SearchResults.vue index 7d4369b..522b44a 100644 --- a/frontend/src/components/SearchResults.vue +++ b/frontend/src/components/SearchResults.vue @@ -1,52 +1,53 @@ + diff --git a/frontend/src/components/GeoJsonVisualizer.vue b/frontend/src/components/GeoJsonVisualizer.vue index c31788f..1f61406 100644 --- a/frontend/src/components/GeoJsonVisualizer.vue +++ b/frontend/src/components/GeoJsonVisualizer.vue @@ -1,48 +1,64 @@ diff --git a/frontend/src/components/MainMapMarker.vue b/frontend/src/components/MainMapMarker.vue index cf4bfaa..829a85d 100644 --- a/frontend/src/components/MainMapMarker.vue +++ b/frontend/src/components/MainMapMarker.vue @@ -1,9 +1,22 @@ diff --git a/frontend/src/components/SearchControls.vue b/frontend/src/components/SearchControls.vue index f4e6a56..375efe3 100644 --- a/frontend/src/components/SearchControls.vue +++ b/frontend/src/components/SearchControls.vue @@ -10,14 +10,27 @@ Longer distance will take longer to search.
- +
- Search + Search Select at least one feature to begin a search. diff --git a/frontend/src/components/SearchResult.vue b/frontend/src/components/SearchResult.vue index 5f69f07..f5e125f 100644 --- a/frontend/src/components/SearchResult.vue +++ b/frontend/src/components/SearchResult.vue @@ -1,10 +1,22 @@