From 3b27feb430089849b642da84c09e9f77a352becc Mon Sep 17 00:00:00 2001 From: Bogdan Date: Thu, 19 Dec 2024 15:23:01 +0300 Subject: [PATCH] Added many changes, main is added login and regestration backend, also modified frontend --- backend/.gitignore | 2 + backend/Cargo.lock | 1289 +++++++++++++++++++++++++++- backend/Cargo.toml | 12 +- backend/src/config.rs | 4 + backend/src/main.rs | 46 +- backend/src/models/counter.rs | 7 + backend/src/models/mod.rs | 11 + backend/src/routes/mod.rs | 8 + backend/src/routes/user_routes.rs | 148 ++++ backend/src/services/mod.rs | 1 + backend/src/utils/db.rs | 20 + backend/src/utils/mod.rs | 1 + frontend/src/app/favicon.ico | Bin 25931 -> 113847 bytes frontend/src/app/layout.tsx | 44 +- frontend/src/app/login/page.tsx | 44 +- frontend/src/app/register/page.tsx | 50 +- frontend/src/app/success/page.tsx | 18 + 17 files changed, 1624 insertions(+), 81 deletions(-) create mode 100644 backend/src/config.rs create mode 100644 backend/src/models/counter.rs create mode 100644 backend/src/models/mod.rs create mode 100644 backend/src/routes/mod.rs create mode 100644 backend/src/routes/user_routes.rs create mode 100644 backend/src/services/mod.rs create mode 100644 backend/src/utils/db.rs create mode 100644 backend/src/utils/mod.rs create mode 100644 frontend/src/app/success/page.tsx diff --git a/backend/.gitignore b/backend/.gitignore index ea8c4bf..711174a 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1 +1,3 @@ /target +.env +Cargo.lock \ No newline at end of file diff --git a/backend/Cargo.lock b/backend/Cargo.lock index f76655a..d40c6e5 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags", + "bitflags 2.6.0", "bytes", "futures-core", "futures-sink", @@ -19,6 +19,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "actix-cors" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e772b3bcafe335042b5db010ab7c09013dad6eac4915c91d8d50902769f331" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + [[package]] name = "actix-http" version = "3.9.0" @@ -30,8 +45,8 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64", - "bitflags", + "base64 0.22.1", + "bitflags 2.6.0", "brotli", "bytes", "bytestring", @@ -65,7 +80,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -182,7 +197,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -237,6 +252,81 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -247,7 +337,17 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" name = "backend" version = "0.1.0" dependencies = [ + "actix-cors", "actix-web", + "bcrypt", + "dotenv", + "env_logger", + "futures-util", + "jsonwebtoken", + "log", + "mongodb", + "serde", + "serde_json", ] [[package]] @@ -262,21 +362,64 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bcrypt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b1866ecef4f2d06a0bb77880015fdf2b89e25a1c2e5addacb87e459c86dc67e" +dependencies = [ + "base64 0.22.1", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -286,6 +429,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "brotli" version = "6.0.0" @@ -307,6 +460,33 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bson" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068208f2b6fcfa27a7f1ee37488d2bb8ba2640f68f5475d08e1d9130696aba59" +dependencies = [ + "ahash", + "base64 0.13.1", + "bitvec", + "hex", + "indexmap 2.7.0", + "js-sys", + "once_cell", + "rand", + "serde", + "serde_bytes", + "serde_json", + "time", + "uuid", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -345,6 +525,35 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "convert_case" version = "0.4.0" @@ -362,6 +571,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.16" @@ -390,6 +605,47 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.90", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "deranged" version = "0.3.11" @@ -397,6 +653,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", + "serde", +] + +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -409,7 +677,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.90", ] [[package]] @@ -420,6 +688,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -430,9 +699,15 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + [[package]] name = "encoding_rs" version = "0.8.35" @@ -442,6 +717,41 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -473,12 +783,55 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", +] + [[package]] name = "futures-core" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "futures-sink" version = "0.3.31" @@ -498,9 +851,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", + "futures-io", + "futures-macro", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -520,8 +877,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -542,19 +901,102 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hickory-proto" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -578,6 +1020,35 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -693,9 +1164,15 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.0.3" @@ -723,6 +1200,17 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0" +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.7.0" @@ -730,9 +1218,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", + "serde", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" version = "1.0.14" @@ -748,6 +1270,31 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -760,6 +1307,12 @@ version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "litemap" version = "0.7.4" @@ -799,6 +1352,31 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -829,7 +1407,76 @@ dependencies = [ "libc", "log", "wasi", - "windows-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "mongodb" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1f6edf7fe8828429647a2200f684681ca6d5a33b45edc3140c81390d852301" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bitflags 1.3.2", + "bson", + "chrono", + "derive-where", + "derive_more", + "futures-core", + "futures-executor", + "futures-io", + "futures-util", + "hex", + "hickory-proto", + "hickory-resolver", + "hmac", + "md-5", + "mongodb-internal-macros", + "once_cell", + "pbkdf2", + "percent-encoding", + "rand", + "rustc_version_runtime", + "rustls", + "rustls-pemfile", + "serde", + "serde_bytes", + "serde_with", + "sha-1", + "sha2", + "socket2", + "stringprep", + "strsim", + "take_mut", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "typed-builder", + "uuid", + "webpki-roots", +] + +[[package]] +name = "mongodb-internal-macros" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b07bfd601af78e39384707a8e80041946c98260e3e0190e294ee7435823e6bf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", ] [[package]] @@ -838,6 +1485,24 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.5" @@ -873,7 +1538,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -882,6 +1547,25 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -930,6 +1614,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.37" @@ -939,6 +1629,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -975,7 +1671,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags", + "bitflags 2.6.0", ] [[package]] @@ -1013,6 +1709,31 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1028,6 +1749,47 @@ dependencies = [ "semver", ] +[[package]] +name = "rustc_version_runtime" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd18cd2bae1820af0b6ad5e54f4a51d0f3fcc53b05f845675074efcc7af071d" +dependencies = [ + "rustc_version", + "semver", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.18" @@ -1040,6 +1802,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "semver" version = "1.0.23" @@ -1048,22 +1820,31 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] -name = "serde_derive" -version = "1.0.215" +name = "serde_bytes" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -1072,6 +1853,7 @@ version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ + "indexmap 2.7.0", "itoa", "memchr", "ryu", @@ -1090,6 +1872,47 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha1" version = "0.10.6" @@ -1101,6 +1924,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1116,6 +1950,18 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + [[package]] name = "slab" version = "0.4.9" @@ -1138,15 +1984,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.90" @@ -1166,7 +2052,39 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] @@ -1210,6 +2128,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.42.0" @@ -1224,7 +2157,29 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "socket2", - "windows-sys", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", ] [[package]] @@ -1235,6 +2190,7 @@ checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -1248,9 +2204,21 @@ checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "tracing-core" version = "0.1.33" @@ -1260,18 +2228,56 @@ dependencies = [ "once_cell", ] +[[package]] +name = "typed-builder" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.4" @@ -1295,6 +2301,22 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "version_check" version = "0.9.5" @@ -1307,13 +2329,143 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1322,28 +2474,46 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1356,30 +2526,64 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -1392,6 +2596,15 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "yoke" version = "0.7.5" @@ -1412,7 +2625,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", "synstructure", ] @@ -1434,7 +2647,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -1454,10 +2667,16 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zerovec" version = "0.10.4" @@ -1477,7 +2696,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 174f84b..a1ee186 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -7,4 +7,14 @@ edition = "2021" unused_imports = "allow" [dependencies] -actix-web = "4" \ No newline at end of file +actix-web = "4.0" +serde = { version = "1.0.216", features = ["derive"] } +serde_json = "1.0" +mongodb = "3.1.1" +bcrypt = "0.16.0" +jsonwebtoken = "9.3.0" +dotenv = "0.15" +env_logger = "0.11.5" +log = "0.4" +actix-cors = "0.7.0" +futures-util = "0.3.31" \ No newline at end of file diff --git a/backend/src/config.rs b/backend/src/config.rs new file mode 100644 index 0000000..85d799c --- /dev/null +++ b/backend/src/config.rs @@ -0,0 +1,4 @@ +pub fn init() { + // Initialize any configurations if needed + // Currently, this function is empty as we are not using logging +} \ No newline at end of file diff --git a/backend/src/main.rs b/backend/src/main.rs index d650da8..53c80af 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,19 +1,37 @@ -use actix_web::{get, web, App, HttpServer, Responder}; +mod config; +mod models; +mod routes; +mod services; +mod utils; -#[get("/")] -async fn index() -> impl Responder { - "Hello, World!" -} - -#[get("/{name}")] -async fn hello(name: web::Path) -> impl Responder { - format!("Hello {}!", &name) -} +use actix_cors::Cors; +use actix_web::{web, App, HttpServer}; +use dotenv::from_filename; +use std::env; +use env_logger::Env; +use log::info; #[actix_web::main] async fn main() -> std::io::Result<()> { - HttpServer::new(|| App::new().service(index).service(hello)) - .bind(("127.0.0.1", 8080))? - .run() - .await + from_filename("src/.env").ok(); // Load environment variables from src/.env file + env_logger::init_from_env(Env::default().default_filter_or("info")); // Initialize the logger + config::init(); // Initialize configurations + let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + info!("DATABASE_URL: {}", db_url); // Print the DATABASE_URL to verify + let db = utils::db::MongoRepo::init(&db_url).await; + + HttpServer::new(move || { + App::new() + .wrap( + Cors::default() + .allow_any_origin() + .allow_any_method() + .allow_any_header() + ) + .app_data(web::Data::new(db.clone())) + .configure(routes::init) + }) + .bind(("127.0.0.1", 8080))? + .run() + .await } \ No newline at end of file diff --git a/backend/src/models/counter.rs b/backend/src/models/counter.rs new file mode 100644 index 0000000..edb5bf2 --- /dev/null +++ b/backend/src/models/counter.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Counter { + pub id: String, + pub seq: i32, +} \ No newline at end of file diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs new file mode 100644 index 0000000..fa8285b --- /dev/null +++ b/backend/src/models/mod.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct User { + pub id: Option, + pub name: String, + pub email: String, + pub password: String, +} +pub mod counter; +pub use counter::Counter; // Add this line to re-export the Counter struct \ No newline at end of file diff --git a/backend/src/routes/mod.rs b/backend/src/routes/mod.rs new file mode 100644 index 0000000..653488a --- /dev/null +++ b/backend/src/routes/mod.rs @@ -0,0 +1,8 @@ +use actix_web::web; + +mod user_routes; + +pub fn init(cfg: &mut web::ServiceConfig) { + cfg.service(user_routes::register); + cfg.service(user_routes::login); +} \ No newline at end of file diff --git a/backend/src/routes/user_routes.rs b/backend/src/routes/user_routes.rs new file mode 100644 index 0000000..0e463b8 --- /dev/null +++ b/backend/src/routes/user_routes.rs @@ -0,0 +1,148 @@ +use actix_web::{post, web, HttpResponse}; +use bcrypt::{hash, verify}; +use futures_util::stream::TryStreamExt; // Import TryStreamExt +use mongodb::bson::doc; +use serde::{Deserialize, Serialize}; +use log::{info, error}; + +use crate::models::{User as ModelUser, Counter}; +use crate::utils::db::MongoRepo; + +#[derive(Debug, Serialize, Deserialize)] +pub struct User { + pub id: Option, + pub name: String, + pub email: String, + pub password: String, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct AuthRequest { + pub email: String, + pub password: String, +} + +async fn get_next_id(db: &MongoRepo) -> i32 { + let counter_collection = db.collection::("counters"); + let filter = doc! { "id": "user_id" }; + + // Check if counter exists + let counter = counter_collection + .find_one(filter.clone()) + .await + .expect("Failed to check counter"); + + match counter { + Some(_) => { + // Increment existing counter + let update = doc! { "$inc": { "seq": 1 } }; + let updated = counter_collection + .find_one_and_update(filter, update) + .await + .expect("Failed to update counter") + .unwrap(); + updated.seq + } + None => { + // Initialize counter with 100 + let initial_counter = Counter { + id: "user_id".to_string(), + seq: 100, + }; + counter_collection + .insert_one(initial_counter) + .await + .expect("Failed to initialize counter"); + 100 + } + } +} + +#[post("/api/users/register")] +async fn register( + db: web::Data, + user: web::Json, +) -> HttpResponse { + info!("Received registration request for email: {}", user.email); + + let hashed_name = match hash(&user.name, 4) { + Ok(hn) => hn, + Err(e) => { + error!("Error hashing name: {:?}", e); + return HttpResponse::InternalServerError().json("Error hashing name"); + } + }; + + let hashed_email = match hash(&user.email, 4) { + Ok(he) => he, + Err(e) => { + error!("Error hashing email: {:?}", e); + return HttpResponse::InternalServerError().json("Error hashing email"); + } + }; + + let hashed_password = match hash(&user.password, 4) { + Ok(hp) => hp, + Err(e) => { + error!("Error hashing password: {:?}", e); + return HttpResponse::InternalServerError().json("Error hashing password"); + } + }; + + let user_id = get_next_id(&db).await; + + let new_user = ModelUser { + id: Some(user_id.to_string()), // Convert user_id to String + name: hashed_name, + email: hashed_email, + password: hashed_password, + }; + + let user_collection = db.collection::("users"); + let result = user_collection + .insert_one(new_user) + .await; + + match result { + Ok(_) => { + info!("User registered successfully"); + HttpResponse::Ok().json("User registered successfully") + }, + Err(e) => { + error!("Error inserting user: {:?}", e); + HttpResponse::InternalServerError().json("Error registering user") + } + } +} + +#[post("/api/users/login")] +async fn login( + db: web::Data, + auth: web::Json, +) -> HttpResponse { + info!("Received login request for email: {}", auth.email); + + let user_collection = db.collection::("users"); + let users = user_collection + .find(doc! {}) // Pass an empty document to find all users + .await + .unwrap() + .try_collect::>() + .await + .unwrap(); + + for user in users { + if verify(&auth.email, &user.email).unwrap() { + if verify(&auth.password, &user.password).unwrap() { + info!("Login successful for email: {}", auth.email); + return HttpResponse::Ok().json("Login successful"); + } else { + info!("Invalid credentials for email: {}", auth.email); + return HttpResponse::Unauthorized().json("Invalid credentials"); + } + } + } + + info!("Invalid credentials for email: {}", auth.email); + HttpResponse::Unauthorized().json("Invalid credentials") +} \ No newline at end of file diff --git a/backend/src/services/mod.rs b/backend/src/services/mod.rs new file mode 100644 index 0000000..4737792 --- /dev/null +++ b/backend/src/services/mod.rs @@ -0,0 +1 @@ +// This file can be used to define additional services if needed \ No newline at end of file diff --git a/backend/src/utils/db.rs b/backend/src/utils/db.rs new file mode 100644 index 0000000..e086ade --- /dev/null +++ b/backend/src/utils/db.rs @@ -0,0 +1,20 @@ +use mongodb::{options::ClientOptions, Client, Database}; +use std::sync::Arc; + +#[derive(Clone)] +pub struct MongoRepo { + pub db: Arc, +} + +impl MongoRepo { + pub async fn init(db_url: &str) -> Self { + let client_options = ClientOptions::parse(db_url).await.unwrap(); + let client = Client::with_options(client_options).unwrap(); + let db = client.database("socialnetwork"); + MongoRepo { db: Arc::new(db) } + } + + pub fn collection(&self, name: &str) -> mongodb::Collection { + self.db.collection(name) + } +} \ No newline at end of file diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs new file mode 100644 index 0000000..8c5eabd --- /dev/null +++ b/backend/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod db; \ No newline at end of file diff --git a/frontend/src/app/favicon.ico b/frontend/src/app/favicon.ico index 718d6fea4835ec2d246af9800eddb7ffb276240c..d908f5b42fb9b1ff7255fd23a55f7f79c23e6408 100644 GIT binary patch literal 113847 zcmeEv2Rzl^|NkX~5`{uhD!Y=c5E^z885w0|WR^0rB}Iy;tn86wBzqTGWoJ`13E6wx z|2el$zyIgkr@mdH^!YlE$93I%-|zE2=lOb_b6)4Q4g!IJz(K%*f!Ku*Wm@r)T;$cTcn5 zY=9=Mr?`ix3klb~>H}}?>&QHhc^);uD)lMq=+$je6gm=FB~1uE=Ia9mtiogM`&(O`|ZJ5+gvgYW9}Us&if{}gZHjHJiENpdE6Mr+!x8{5SxSvI!UMLuM0KlXb5_>Rfz#CG_FWKt~0 zgQ;I1Gi)I0B1k)-5Wux>KiR`>4ig!t8)s*=FVzwqIA+t}e*QWC(;=$So|daaZ_RAS zSREwzG`C|lT$?q~cp8*_x}up{$B>jgNtD7Dd;Fxs3@t9WqIQ8xP^fjsytk;{2DyM=O22-x?LT5?oB=#4QiVzp)Rw*VesUJCT5!;sVjp zXIh@BEx~sCGpw(1ihbOEqQ)k>#*Wx-ODL(t``V4?}ux+=?+oT9iN|1wiub(4Z~ zt~^`5(yjLL03!|Tfc2%6rZ=Bma1%yu3cSm)rTj#=m%B`RNd>Q zw@sXyJp>EQM3^JX zGj6@qtFkOsqHH$DSU977{GWNg|B#_QRdb}5zmJ?$1NW#Ri_XB7E0dzN`tJJ8pW+Q) zgr?O{5?AHo3FLN~I6Z0dZK~tYkmuMVPs+t#wNFAXY#-JzmQ<+cf|)e#-p0K&$24vS z8Tl2?V7R?6^+=lcxSQmm?{8@=+K#mg!!_RQ6I+KxOg_La?hA= zR}u-EKCaFZ9I3zvEal+?ProuI@_al*%S;m7+KO?ok@myBGIGOnryucdVKbKov>f8K zEV# zpCbmY7_uUI?-QFkrUx(7r`J7>&*vMO&BuFTeUL|&`|95Isi)K$$9yG1jqBuTgz||F zP}Giz2V7&wvpVJK1vUkjY+k_2a~a6J)K)L0!R9{nmu(wc-;y zHrCr#JdSx|O?{q(4iR`WzUIo~mb={JTCe=KJKZ3^BxF;had|xGM9(tx;82C9>aEd#z}lgPgS?Vvd7l)wnK-wF{Vh)Y$Q%$ zmzOM5zQ(Wh;n8ko)+zEfx%-R)Cy1(FK72>jv~!%izVB_4WFw`0hX%L-YeRxlyq@m{ zy4__t#B7H`@IE%n$|R|=A3t?^s4M7Cv^`5oXMPg zbIZ@GMr_z6^jhU>D#Dp$F)CY@*0w@x#lw56@D8_PA)e(Q7B_K{Utlb}(ZMoJ!!!IY zD(CRQMykH&1VckIM{*{a`*c1LNn#me3V3rVX9Z31FEm}~i%JlqwTa)$eP+W zGAb&k?ATe@N2*C`xy5S4Co;EYAZI3JT>pLVz2e%5dqG;*FLcOq!VgVcEOHJM(vh*Q zv^H@|dn~8bb&j`*9uU5^Jnp4j!-bDADd$zPNDuX%^*oi@cPvP~h%^%`?}Ad2_j!jo zk8$!6=J(cjLU>MB21hE=;|G%ry&A;k9hG+aboF`Ekz*d!VTf1MR##}d0VC8g(_g-A zx=a4DV@vu+5@l8lCe@Is+bwS2rl~(A+6?NEZ@RxxTAttFp~t{QN@?TlLBL zOS406O-@f!RfWCvWV2+qu^0uf=eH6jADTOjE zub*9Ya|>jc+|ILuy|R1fV@m{DvKFo(e69(WbGm)H>X0lcD*ia^ ziAqIukLoAi_78WJgz3V@nJM|Zx!#pGP3Rn_O~6r!%9x^PbV5l zro7$M@^|S6*N*H4lThc@qY*}Wru@X!&HDvU4j>F$Djr!gwfDz+^Kh|yzozicFQ5!q zfAx;TLrK9|3Q@hsLE*c38(S>Y0)^ z`@V7|ua5TkU}^e-6JRX&PrH-{Xs@d^j0_UI$I7t>5n4x*Gk^6}FPBDlghc+C0n+PN zrH^X(1wA=Y(YU|&!{#x4k1@lE5B*6>vlrDby{8CuRgrO3c`I?}EQ@y_%f2%22j$9m zn99+t`n^QFBbntI=LtUy#O-<@c2AZWq4;u)vQ!UwsJtPR<&rW6lT=&ueyl0-NFx&V zWD(B62V;X{y-mAy2i%`_OGK$FiEyxnkssd1c10|K`*HF9hAD?9?ucl)*4bx0LFH|O z+PdcxW~}k#lMp)CY{b6u3mO4zM#nWjzIjxs9W5A3q^cgNw?*HoUIR%TXwPR;`iQ?r zJK8O`He4=lw7%=N zjl*Z=a?YMxmxJ!Bb>vaGQEjRp4@=68y%6z9rz~gt=z`wnyq%1^r--T_%&G{cZtOD? z$)5DO8r||y_SI<`0=aNRBpJAF_-PJanu$siy{(TNY3M*w=(ZONc^K;hMtd7HnW~ka zMrXuSjEFn&>~ZllD#)B1#U*X%INd;duFX28VXsA-8(aT1*2to!ko6a8@C0^{OJ;Ar z)K9nB%xV1f!;ESY;wuzN*gOG47M*7Ull=4#G8Y{__U4qjYtoG3Bd%t0&PRu~4z~?^ zPwUDg`>oSxI`CX8w6oU>bJGrdIgiJ38=i_G+KYyo>UP`AKD|}>v=OIKEYm@U;1bp0 zYuHT_v-xajqe%1biEo?>*t>J(AtQBCAH6s z#AsflD2BSU>Jh`6$#)HO(|O4ByV)3VALDSJDk5Aa=a7@g)RGURclODi$&%vT<5)`7 zWXs)Ju~V}sHCdJhNO|w4Zo13F371HEKNt)l;o>W(7oy2hqCvK|RLffj2*_@D(HYrI zhm;RU5LRcsdcQyF)Ctp?h6V4!+qS;pMkb_gc8pq`QSDx~{ykMj5BQuOMB!Hocwgr$ zpSGGUe|}{`Zt!f-MQqhE-}Vn~M1W;iD7)_G@VXEF1=YZ4+N zmgAN)rQS0_f_W*dvhwApWig3v8h=uF)sO;appzeKF6S!_mz{gbmgA*Xo=|%*#P|A< zrw=6Lo|%RQ1=H;EypdwFgVls?UJ0`|uQ{;|OppmFTWYoEA!k|f+u@B_ASk5l(prFSxi$H44- zRPp9Wj}$!OP~Q%I!nCWh7`=uAi4OW(Is1pqySp})XZO?Ea!~V`Pk{e3AF1VSa+9dF zd8|u~rK+kaa%oPRx+7(59kR@W@9E_nd*-9wT$$ryMKuX7bJFQbheKm%aqpDM4)Y_eX@eI&wDh(WX9%aW6Kxq0Hy(J@UjLL@E&H%~AE_-?1x4&RsoHd< z$40H>2go<=*fjOgj7{IFX#Z?Y*~I*j@jDLs)xy}DF|?_2uz$mYO> zw@-@Nj(`n9oAa&hUa}X7rS*!c1(A|&aW-5XWpk4+#p-rhr?f>H7+yBZCuTAzI%2c+ z08XKctkq;Pqd0N-^)jkr`5Zqmrepo(J4bsv@yw67Dpy*W?~VvRR+aE%q(A{ksv{w4 zLlPx7%rtoDrOmY>+&dE%sNLe`*tQKId0kF$sl9)esUtTxm-mQTIl1(NtW{mBOukbH zR#C1QeYiqz4!tT(q*6c42khi^AiOAT>=qrQ=r1cNu*9TZ(ZysVZ zqqB@S=l&#t_(&6?bigAWM^NVJe1d7H=DV$K1rId~^8nM`PDmymDI&G5liwxCyOUO! z9X$VR6LUj)Q(Po%A}PmA2kwDPVzw)io5M6?gEjQ((*~zs&`ew5r?(n#^8}|I3QL_6 zEU7VZY2ZobF}_5@+;|C3ceE{G!3&w~sue!Z?fqcSjmp~62Kr;ESeAjK(*=PSboE7T z9-FpK+l5=?Raq5vMv8V7kyqn6l`*8(=8qZ0MIU%YN`s(tbKDppdpzw*31#AQrjmr5 zz_wm5#t%x7M6ULubi3~^XuP^ZI54TIWYhG3r*}k~n%{_pM5HC`J$IHjmIT&j=<&2U!l*1o_U!OH+6hdgxvTNThkZ=u?|DeIXV4^H#c^EPOtmTqq`O2S*BCGXF;w zn>RhL%0oK+Z#eQPzDrXxN8a)7$x$Nbsc>-*ZV=6D2;IDa?eKJ@Ew#fto?Q)KHt#ts zUruN|AJSgb(sO8rkXpXHX%ny0*hzLq(q6&3!^L19m9=gQ=_M|6AEKj;svmv!Y)k zz)It`<0X~0uH3dI5s~RQ;X5D4o_>Z@eKAqU+f=~Uc14Yv`feK#`)`}{hVQXG{hASR zT4(lEOIn0Ht)6sqUlX!DP)l5!TqXF`X4j1u&rP?CZaja6h9M?aE)#KX?(M!9m1Ji< z4<7rFNLK<~obrO>Y8Gyo7l;uW{U2?|gsFWBI>l-4BvV>W?A-LBslR57@v*w!x%m|2 z8&;Xn8N;jL9Wt9SXE-hUXB7pG-4?m9&0Uvd$NXuvZBjx6^i2ngn74xs@J4^JBQ41H z=d5oo1hIz1bZPddx8Fqev6{u|&P6wk*q+`rFX(htN#9k+h#Q#AZeS?QpHwf)BJHS4C3?^7 zmuxvUIHCKA=tGzp2FAvKGp;J~ohDtI?Vsbms5U6A+2AtgA!@}#(WCZuliRyf)0%o# z6}Dsc?fptDr@dqMPh6x`qN^WwEH4o90`ZWYQK(DQvm z*YT=+L9yXzpnVn<-+U5Zd!ZA@PHR<5`mlF=x=BEe1bg4gN~SGbM8mwPR;=BoZM4zV z_pKi8DCH4q(rsfW`MLuwqP@e7+8|Zkpbd{}h$BTTredp;!ZKgUp~#-UWvwrP!|hadO5z5n6`1yE3mRKR7}dN_}@DPz<$jiWX9c9!uEe znUsHSlFd2k`Q*@k$_K+;_!vNt5hh%pIkR(w>|RB}R@M7S+8H*YF$XXXQaF_{Ztd|X zog>Di@WtW@9Mj8Alw}}0yfcoyfu80>-{7tderB^{1R^uZ*RD*6Q7A=srHp;DB~6)V zdq9oIp9EWlK&}N&O$(N^>vlvy>qf>KT92#=+Dqz3Cy(2#ZhpqBP#b*6>XacHO&v|4P zs^qgg^WBU@V5*$9)t91EydQF(&&04{K+g8rp{*uw!?WmaUv>iPTfcd3o;Y_*hA)s{ z-&XII!h82_gPNI~#&zGW{IP*tX;K7flUAT2-7EtyAyCg`k=7fg?KmE+cKOU6zSACv zph~Hhef7!Zp(zFPTW6C+6f0hsCa$||J}@llSXJeoNIi*UF)4G0?K>IHJo>bCR}D3>u<>~2 z^L1=bKIA~X$*G*^$OBKij+5>#3>WL?q`;XlPmFsq(8+}0U&rUSH%0|d(Ft#RXSQjq ziy5MzUbWx@X;zikVZ21vL^JVgvw8a8I@sIt#z7&g4Rec#OgBP2_Ua-P(1ATbdD*A-SN;C>$1Qb zwa-jF_ZB^z^_1Uqr_@wJYs=l6$ES05h{anb`N5^p+ZYE90q zO3r!;VHzUDx=T9s&r0|BU777?e5`jpOglk41E0=u469?0FTEO9yIYo!Vh(pnUZ>9U zBqSr}l{n%nu~#vrUXg9rm%Y@>h~TMB9YE6cDl_$-quX+)QJhfdCVLtQ&-!pnEHd%h z8S%o3_xp8wjWLax3#2HR4`H0!rK7Xe`BT5#y8VgqOzVB{e?C*5Md8Ys{b)@ZinU28N zAY*zUpMeG|d=G+pU)lDi8Kz+Q3jD@8dF&ulAT!vDj7KfuPGXeoi$W8sOG?LO!pMW#T0mv8%-&r!n zQFK->^!Pfv*A=w}Cb5)v#lm9GRWveGFg7>_<)1y~E#AZTcrSwUda-yaZluPYCJb&y zFQBXhY@>79y$5fr7J-`BK%Pt!#=a6-rANENk`N{s0>a^2H1*|FLkjnb3L>g3%Ae#T zwrYE3VU}<<4&)4GP}+sE4qNjGCE!uX+?ISPOSOpVM~BVQ2XaCw z+yf||il(t`(6!uCK>dXK2;BjMV$*<&|pjOS*rOney)J(fWAbD=#FUUJ-MUxrGrnCd4O?J*A7=Tq;6C zeH_0`BIID4G&knn_exCr!=t(dV@V}k!!;U+y9n5b!wv8cbHtuiBnsC(rUR{G^@@Cg zt*;8BM2ya*bzjrf(C>MlvLNoQV>z~4j5Hn7OJvs_`wo7B7#amU5`hy#z(&GXK0~8t zB`v=90HR8~@X_-#ce$K%jCQ5ym`~Q|gde*cVvcuFkANViqT<})!jAR%-XzH% zBS1guF=!T;!sX3FMLEStYA4d!Z%PX1tLpD8>YiZ4N09T#c^>fyPg*CUjNmQr?x#Cx zn0CCj?yid<(+346-M-j>yqsD#K?!PcGo@ie@;POx@rT*&HI6 z-#Z~@c4kw7U10pD!#-P7F3}DLbQHNOi6n2~Y}z%H(7QJ;d^f^IXm2B*oR~sD3e`H@ zGsh1x5{3rHmtGT;DOmnBA3{yC})KBM7GN&s9=BxB(2Qv_%n8N`YIaca)r@ z>vOu1Y{DSpRc0wEioiMYhrdY+CjG? z{4r-G559eU+Jejg`^Bke0ecM|b`zM$_;SCb4JfETbf)Eg08xaTcCR+pz`NoJF|Q*M zZhGAj%A6G!g_v~uJg|H&=Xf%g&ADo6N$(*}tY@JBnjsrnK5B`Rh>st!vy?PLuz3TR z$#O1uXAWSga)hcMn>>7$g9Cx^OyTHAkqBYg5Ca7Eumkyi?$ubkijJBEO0b)hZ)mM0 z&G+wRvy&O_nB;qLj1#?r~9#XP6Dm zhHs0-87>m$#!%;18~8WR=fq=Hq?9IkHZXXfHt3%M|IT@V$=;QvRjH>)*_WpD2 zT25jw`@^)V-{Ax$QQv(tf8e55WuI?@sK0riAp^FxQf9Ro;t9STQF6RSx!v(=#a%;| zR3+tPIOVDL2I-lvYpZu_OQ;9TM^xZMYYRxXcxP{y7M&<};~gZ{^kmw&rK($n(7(2% zJhe|i*uvYtYGZ)(J_$N+WSqg!+`S%gll6*QFg~=jbrfsHx#^ET&>D(v!sdRRS7DJ~ zW%XRLM(8@-z#|51n$30rcRac`*^hbh;E3S85qBbdZ;aVWPx$!#t>XPO+vd3nYBSi) zaIbMbq)k=vkbh!CGRD_=+AE0P&V2%3Ysx|WvILJCLb&)K4v@To;i&y!+TMMk!LcvP z9?TR}H9x<99O3A=-x5fY9{UM73mR_(+HyUAcb)R?mLPR*q~ZNk9@$C^bJaNc=X)bP zR6>lbibBIf-QPWEWf7P$9vS!UI#I__bni(1iJs0r&cWUB^jYy6E{NY$eLGQgAr)-U z4%dkRJGkXWk&7Ytvo|){Mgkh&+QJSzXO7&VHzLc3AX|`Xxb)}@p@2pTQpMV1VoUNd z<_0EF!de3JL{sPEGV0i^77m`m>hjbdMEq|Y%CpS5JCv#UlseI&_Q1<@jJPmP9h%b6 zcb8r~)($=1hea1<7qm%off4A~2TU>UR^J+N;>q)66IORPyd|c;s<9&B^z#k@UA-W2 zM#O%9hff4lCkKiZZ(w{NlguGyWBG{n;@&3WP^Y&>`Ofm^C~C7OIHR}T9e?`F1ZvYXRY?DnYTW~z-vwYNKS593#JvqrbjHl(W1Hp#SZ zkQ$Lre_u+~$7$(22%yeCo7Y9CZb+E1n_BpJGgU26wrO3WZHVH(y?^d(O4``MR+?>g z5nBa~a>6XHAE&c2W9B2{jY%~cp>cSzcg> zKahsN#nYRmA*3AgWDXuvok>>v@JPMi7ciBF+L*7_hiLT~)5|KhF7&{{W*Ob!ZPV5A z`1Dq;JHRcYG($gKqpFz4W~&o31F#)tsMvMb7w?Cf#WWkyHoE>^b=Q-gEtzka{NhiZ zJ;$L$_o1Pa#rTCdZwMm|*e}Kg+)h)Js5R#Pv`#~H=u!K}2JaiaSo?GEBXMyynS;%K zQAG8^>?plopqx@l>kAX0)tK8jZbgaV!MO&aG1=cZs%ipK)=wK z{zf}ajuQj8Bh?y>*FP^8&vX|S(Tg&lP4E8TmUr3uxbTC~nU)*C7+m|BueXNZY5y!Q zxUwjse!2%d3xSJqXTQVsmSUmW9{3=i#kh=zQA{70sbIU`R99_k8OE+^h&h4 z>$ng6=o9#yG(uETN+xoquVFXX|2}RU@3}1{he1^J2^08eAUbVb_-GGQOhWQ&KFhEr}YMS45f)s4x^NLM_MFEftM9lcTERD^v9mUzjA?L=y|ex)jsD}lNS(V`6u{a{ed#zO z*l1}|V6C&{rJ5GI@M!+_nfr(-jDD*|?Kg&Q^x>-hWBO4;J}s{@Cw+baNG5RvQL@j631REQvzm-A)73R6%Lwvk<4!!Xt#cNL zxxDc1*5vuysU~?3!z1pwhpK<*_tfWUt;{$}OQm2X1?(KpYECQd9BvrDPe?o6jG$*H zb#AQD%$z$6F)rI8b`MIz2KuuUZ&O^sG-e5a|CtQZVXItb0IwH}huf zRS*ADI2+Gb0Zp;9(n0$eijAYj*n;l zmW9LWACtvN6z@cm(F$|W*^plDyh(laWN&yIg~oZK9+@LNo6OlCy!_aATRI*S0k+K+ z)65?ara#*tGW_vK)2^xUmQIVF8h7W@+H}c{-efg9kQPOL{Lei3IX*cnWzB87nt0{R z7|Bz845BR*ide{xEwy{FolQw**q;+P?BU-y-Fv=ES=E^IQkO)@DI{azy`4^)GMirM zVh1?d&hyvEACE8ZIUP*rnIVGbXLgNu*b?LMIX8uKduv9|BnujM-9MU74Gc}ObWHv2 zwZq}iYR?mQTsb31I&hBBX-24iGRf{vlUQBbq+p~u2BJt4yFB}mnyE6IxzOgWsxizf-F&#m$jGZ5({9bN0zV=F_x*8}w>w5z3c4q9#yf7k zH98^TS|4N><(X4KlWKGu`ubF;1k2k53e|uy@q#K4i0t9mc^}**Y50R~-A~rd8|d@Z z;K!?E>7S1}Wog!RuDALyqf_st(gwivqZf;E6Yo$werG6tq9WtONRc4mxVfnMnQc#^ zg8Q{q>)v8)U~|g%xpkvqY$PSvxa8nLE;WOEFprec8Qko+OmXP&0t0}p{%YwB;?2Sf zWwa(Dq93269CmtW`Z7S<%9M{XES)}FP!Mbe;4{~T5r|js7<228 zIquF%zJ-MA^_$hU`=#y?v|zz`xNT#e7YSgYOWh)lft#Nk*vJ$Y^K!KHUXS$z@Aisj zIqU1eAF&Xs131ONTSvi{>ybIf?k4Yr>s|r#CNrhC{B|;A&y=%5GjBwhvq0Lxf@_n= ziMq{3Ia^o{g}h}MouYJn1N{li`;A{T638YF=G=@TLD;>wam#Bd_fT^B?As7l#VEt< zou)B0Y+Gb9G2k7CyySF~>PcgvLJf53l1H8@8Xv`PJDpx^w5#Oh`(qe4a{|K?QV!Gc zpNU5x665Y=&h?xHPEkT}I$?qDOJ8J}A5ra>Z6ieX?BEF;wrC5~*44k7VV}rSkZh0a zYU!RHQYdN9jPLm*U23gSKHq0nA7581o8`GP3Rn-;8>n~;&R?M9pE5f{E1bCh<-U9~ z=?^?WL&t5x-aWxl3Va*tvs)f#V+ngGYFbnp_g?qz;CD{ti#BLVA!)X>-IhP{p2M%- zTd&W9#+f5bRCWVGVY5O`O~(!XvY~FmJ%)r#R~qeKV&>bYWU8hv1ne06r_wkb3Tvb4J+lc@0{Y(cRscV;%Eqx1BX5 zzs6uFbJpY3>3i+nq=A%fmHNuo1L$e`5pr$+|*eyoAPtY z)0VR|z~{%fRq9#PmX~ss!WjHSyr$eQ2(b!nFg5C`PLeOMJ30nYT^2W9P$+5b^^RF@ zHNm&NBIRUN{qCY_=jw#FQ3Nr-tiDxiV+sz()=2Yj!vxgKdH5J6=#&gH~Yw;}7D_*@q0C{74b8P%ObChS_}f`RMGr}fQ?LgVuz zNb1swbPQz7xAg#P4awlb?)EB6e0!CFd3~Sv3e=4`TAqBPgV!!!jhQnaQ z0oCrpLQ7Ao#c5B5JbcU>l!E^A({oBJ+V5}a4BqRveBbk;4zqS#-hylzBkk(R;g^1! zp&|HPmAU=1LzEY2OB$YL1IBt6g*RnQ@l+b|LNYTO!_9Ws=%Ym!fA^tLq2m$RnK%SC zIGF;#5yN~|7<$yiYlUh~vK`3?*!ba-Qg~=Tv8$WTf$W`^(v7VtZcNO+X1~wxmaF5} zmNF^z>~eXIA{~FUI)+__1!l`a!oI8Hrc6|il__Q{NY~`pU?5b3&V1 zaRDXOJP$8$zV=D4x%9q-xhd%Vkg!YJZI`xDUu9tQXOB#+cuD^HlTVz6Ula0`IA@*_ zNAsvH74UC*AvsZYuK4AkCeYkIvS9<;)>iCrf=xDCPJh@Otl`&?d{9Hdn+t3qxSMEt z6_|S8@9ORKidJC;dZpM4Iv?+Lmz^vH(VuOShl|`Km@5-HW7}eb^2o_&&8j>0NSid-r1w&rshdr-4h5mTB%m zHbd_~PRF#2r0H|mY0=~axJu*I?@-a8~CXbckBI+4)os2H%TqJ&Ugo2GVtcW?h zk7eot(U!T~`rAkIsw36fX>};~?7b4>75%QYGFu3!a&-*7fFFIwp7gNY#9EnD4$H#J^cxVW#^n#hqw_s}Q# z1D9~GYiry^@^*eadtuO*@3jriJa6K2VVsza1qy|owT8~yUQFGoQt%PS%gAX@NL0nX z*qy9p@scEY6!UERzO30?JL%dNCZkktkF$N$RNc;B)uIxW^2C(VR6jFX%S1hxMG=f& zXn$EaIA>!wa1oZ4Os7B3oggSzpN^VO9V?N#wF@m}Byf%Ut)T{Pb^$2HZWp?32b^`Y0p`IWB?XJ=8)%Bnpb zNA^=bR`rHTx;6VBdJPugP59|)p6m|xDhcF%LEm+gq> z>uL9P5uuBfbt!*8ssFGu;5x=E;f(BHwUXE)MDzLtPbV4S-FI^+SUJOr+40Skq}0!B zYzt94nbY~ii**M#NkwDt!&&Cr#CGdd!2&ek&|b%11bkuJw2wDD-3X!*qO!Qz^&5IF z4e@Z^NcrL_zfLu=bg%NGgyb4Jw^zW#zmJ)MxBObeA*vme+lVc&<}+wc+3ZoBmvbxF zD(HSmK9SIY*beJpf$zBz*X^I0&j8nB=(RrQl&oF-f}jfJ{*Oa+CC*E~X)xa6aiK4P z$6cx>|Av7?svUF)JfJiO8aItPc2wX&OyGQOVzv?$lW}G5DRq2<6cQZ+9sSK?2BW|o zq%tF4V}Mq$P*K$MLF!&vd`X0KNPXU?TG{*|n$jtP{Q75FHm{#$s#e_Klu5FBppco% zR&eAd@Ho=*3epZ82z{oOQJ9Y5)-9KEU2Fp#f<{2k+mBtD7dV~Bve?M5@#rc%;^=(1 zG2L56YMuHs*50H$_o_K?fm`f;N(Uh6Usd8W-7%!wdnNyH_zOG%=SuvDLXJ9S2Apzw zp#x2^Tv6`1iu>fT#Tutr_q$?zB3G-rzKdySFHq&oP>qn)_r>dG2rGGAse3|GfG0rC zLU9?pu-UEb6>!S#uBEwCi__*D#oj#C*~8ZO$!`2zGy}$C5xF( z62a)&bt13Gy}dx#rElj&p;-E@5gVszW;v$q6*k{c-x&Oeqp;l5m zR!}Yj{!tQ&kW4<-SHWr)7!P|0#5XvFTa-56A8$VIo%Ax_xS^Z2(`)1DP3?18>xWy0 z)hDN1X3h#qY15e}11GVY1#*Jcp+RZKDw-K}E_$+aZusa2LW)eyJc=8Uv_+|S=Lxtm zBBc`@xH(_lE9EOxIXER*xNQ5UcCEah;b~GsS zVVK)d->Twnub;I`X}wQ+ZcfMT*JhZeR*XQ8%fi%Ts^O{UnrvFn+0adlxeG*Hl~a+2 zkuaqY8Iqm{!4fd~%M7FAr{lcPj3ApsI_~8>;m@Ld0))sRL{CT_k3FjDKo9=6gI|F7 zIT&E~xxiq$|18M0vWCDK0&57YA+UzP8UkwwtRb+5z#0N;2&^HnhQJyEYY40%u!g`I z0&58Ti3rTiBNry8kqd(($oZar!q6ykw)!1%I_?E>^4?SAxTP<0%)kvfs(J%CDrbWn zku*n+h+ajGh<){f-+|xYHSpRo{kzEVYrd#Drej|qXDb>3AB`fB)3Zner9|n*!S*6H{8^Op?1v})3^tI2lKJ}BdMu%76Gayd@UVzVrZJ5a{ zLA43FHZ80eD=th-q1Nb0&uHYB`YjaxsJR>+nyutDa6N(Z0%+6Zy(r||+jq!?@yQj# z;eV}SD8J1XRU;>C9)WRg`FZ_bNqYWF-H;c+`ZI3jhn#`y18DnNSt0^JmYaE5jvO<& z57u7OpIgI!hNers7qofok_U1orwk>RE)j+Qz1!v&kh5=Uk>ghY-68hBVohHvjem6C zUu_=;JUm-m0|b{f0pYt04fa&??Y+oJ_bB9uob~d^?mwc>ulgOzi=a;vZckA9g|+?T zS6l$+`iwWou?x`ZA>5QC7Em~U>{$hcJk#XdNWAL9n&o7pbz)$_`7ad-R+mN)L$A{lL0bppB#I zH&Gb;udN3QQ`5-l*q6vrCHv*WRniPODr=1#)4q+Iun$B|C*~vPYFm-BCG|^s#-#6a zlul=^rUf~j@CsGun3fCb8Ox@306YaTfLK6G{uj!^)C_XcEAF%Y=D&?$bbf{)u2LH2}NK@PEKK*V?lr`cH+V{6{_T!~DQ7YP?SQCm-@*fMK7;*PvK|lER>rOUP_o=od@+6*{r|=XQ0|0nhIXMP%>|GL zz&!A$uLV$^L9O>oSsS5jtYC|rj?Y6PXXn14yXf~{PX8}01Z|#vmWv#fw_TF_3Fi-# zJOD8K6ARqWpyYh$JAsZY|MzRa8ai(K2sz)~|I=OnZS?=E?-isK^Z$Imt+=;OR93t01K(qAu*_HfPz;~qtOaQ{k_)kuH1 zmZNw8`mQc!EdX=sOvdX~>3=@o{sCp%Ud)<5s^qXDbN=7?XjRhxuLi>P4q~tv%%G11 z^pjat1^6{V-!6GX<92>US@rY>AV4e@ zB{u^MA?B+=7Myuej{f@fm%KOM`{`GZ9`%erf&Q?e5EE1^(<0KQBK0`QyuUFDCYKL872HUh9iYYqT=hMBCAUk34nBe3y-as9)#L0u2f3;(XM z4*~g8=?^hO>D1BDtHHe$$V2ig3e0(f(o>)__sdv;yh%;JqFLX4#ve<6&?AW52*B`% z;|$OO(&Sg=`F_TMZgVB#_vWga!Q2jf$iHge zKR!c!Fvx$mk~Sfj{}AoD|Kc5B*IFJQ-oNt@w3VUy4&@?rUq8a`d%vSwKfDgicQDRr zxeN698@q_+8UXAos2r8c-H5;HgLySkc@V#c*O%`B9uv32SELpHNB=L+S|#r==j2NH zFhVTRTEjq&N=T!XDln%iT6#%fmzc>eU6E$2R{BF+R?4;s_x5Pn*F zixwXOS#++cb48l5YUvN=JQ$a}5_(u@H$!XP1#N&dT1uSckB9|xVZ(gL|BySrG5?Nf z0UyP_!5>w*q~BL9{Q(XW*MSaZ1^lz;KMsQ2SRkh28(4q+9gMYI37-I%Lmlqtzkc4g zK98F|T(Q{I)l7esKgJ5=ghs_sn|YyyJ){w&)p8e@6CdV9{}#Q!{%*nr$bNH6kJ7jtH$8=22azFn6>RZ+H2YbNT!j0K&z@Z_5P!h7SE#%Koz``!BFnLYw7kC`+b)aLQ_EKB^5U`>!UN_FrJ5 zN1a=}+^vWHAMk80boSD~4{fe_W&A%D+pYPfp8o*O|5zy-)?)hru|%D5i-zpAQvM&X z&Css%yZyfwiyh2MhL-QlSJ+P6270`o$UD8*cK)~Pp)Va;y1$k5{{jt!XP~3y{|V!f zTmgQopuil`=*H0eeSL-bbykZE1F=MF-d$n;&qe!xFH;WZpJAhgPa~gm?tV4C|4!>~ z{XZ%X?C8HRPto`KxG4W`;CH!_{@=(|5dZN#oWA!x)XR^e={xryd;sRsnY7~XRr|}n zUsU`D$Oi;zv|1>)R%n=IyC?K8ZZY;g{S|%eE^U@(e=6gCGnqt{;2sB<}Lmjt8aaV z@!yrdH~t%rHF$m_TE1)F>cbgp zuKA8$^n9njMgPCPgX3^2A{{xKSBX0J5Bm9i^HtV}T$o;lGkXALXzN?xe(M+Ie}I_6 zv%1mVQ~&1tFDM=Wa?2=)NkMB5^*tVdc{!o|6Zkiw{GfoJ&9~l1Rc|g!9O!D!|FY=( zPjC(W&2zxiV-QD=j_&e%^hfi17&rdYalim8D0iT{X8r2?Ptd<EXlX(|HpS=?*G;K-yr^r%l`;`0)mo%?;HSa z=497da4la(n*Y77pQS&<=ugQ13SmXtClzA-MMho5v)%qiTD1Q~ z?WxestG5Im`6>DXY@i&E_8j#a^FKqtmz4kgck5KaIso@=qhQ`#iFx2>=syjxK|7~1 z%=hz~^S?tLn8_(ae=Y@WhUXo@dHA;$AivJMDElm9E%TmWsq}}Kpw5C?#M<<`&woJC z5T5^Hav%M@6~KGKDP+a+11yHG=IYy!6Cjt^$Z0qiERS5c6#7HmB5K}8w+-OB)pGs| z#2cPLfL3hym-Q6L0&qXRD*S7Jj(xV^EfVIeK*iTV9nY6`F5!LA^oRQrbZtCe+OwL@ ze}W7E^c9Of{|)4=pH3@+cdw2DWG|>An2ygy`Pz;dx+6!G!P$JkrjF9{fw)Rk{PUN0 zs0W1O708mK%J!)IEaPB3p1kv9QRlQm4A9l_qxcf==kLy`{4IjP_<%7@pkw{Qqd$6w zvH-w$wz%e7)&1V@z?uf_Tu{$B-_nhoYiLKsRL@nt`}_{p4HyqI_pS?d79+e4>T98| z21@r2#xyzw_8rAzi&*m^#w(HE0iE{#*K0tZmvsKCq66y8lU1=6{MQaHnjCuOE z6xbJ({Tb|e7Pa1^aJhz@j(xd0_R5PO$imb#a`Is;dhsG(=>O#%+6sV<=(p<$7t!DE zT?+dE`+~Mk{|g529qjcWh7ij?vA}%z6V4!RbtyJixaI*}G1Q6wj&lQl8gHOafNlS* z(_MmY5sm?X-AbG(@Y8);L`>Sw7Ly+VbF$) z(&sMK#svBeeb)aiYv6p}5EAAkUJ?($c@T^RXcLEi5vX${f3q*yH~9dx3Ht3oUt#F$ zu%tN;_7z2YUywh0`OlL0X1jmUmna^9^T1Npf-h?#$Sni&8%%|#eLhogHShsw1I zWmc5W)=%{h*mVF#t0i`Rxmg3wXDE5#Cv7Y!9s+uI=pT(bU+#Cr=|Z~^@Xts2XhVOJ zpP~C-vL0%^{}=6hzQsRKo|*IlXNW<&%9nAy)OR2w!u{fB-~0?DjFp2r_?0T~JR_I~ zZR$zZ=eQhrHXm%mQrrLKK7a+pd*Hn=_X3Q+hjqepm`2Znv$)_`Uy3~Yh2CG@;T{KI z0CgpQ>K+eWn*ZZEfb;B|I+R{>S;o*8O#k8qRGbEozu~zVL(zk|QQYhbP==nsH8a|6ooUu?a9f5y-L4`~l{x+uLKI(+#L0RJ6dK%Mqd zY(`6(bKzVKbEv~S+7iHi59tbD@PGIn{B1er^B?gBc*cZ7&>y4EUvW+YcEg#B*I>K> z|AC*C4S$6F@BAI~4chN#Qi0#gO2+B0IKfun0bmY5e7cAt&aME0-S0%J_z*qH!lEu&&1epb)2l6(W(2KEau zE)K>Oq3#97y25y8l>TTn@B(ZD(BF)z-vnoGMgbkvyH%4n?qA6p zKs^KfZD%sypz@HwyeBALfcv&zAuGUVz-K|4gJ+Ll4@Bj|K%Kd_CfEIPmV@U(!JJeu z_tn^CkI!oa$b*R5M?yON?0gUFfO}F{C!qP5@jcYDW|cFK83j? zQTz6_alV>4;s3V{Yx5ccYY40%@W&tk za|wWWxY_bXdchMd(p@Vmk87g{twSlnNG+@U4uI7bv5Kb_!)q~S!pnaf6^x& zIi~CS*@qJyzdd*jc)@!ny`O!~1F#(DuKi437I8169n2Ylih284AH~1!9|f^xsN8A5 z-)XfL7@rS$cvK$5Q7==!zpe+?Jr$U|y8JVN&mfFvLHk^%Wx!@s)#-Em$#3>ogfyRU z2}hsa&_@&I%KHumDBgkBeCPMCzn^dpU(vh}|81;6e?pj(;OjR1<1>s81o>U3lL}Bd zr6)b2zk3hNAqrz9;kBsPX>jj9>iY^C*alSW;eTuFGXFML*ZSYjG6KHzV_GiA>A2i~ zoLi2{5%N_ZzVs25^W|@Cg=;3P12vcamlyz;Lu#(J^>25s+`p*4!~7QC=>saa-Lt&! z#t1E@|6h6meO;&H^FHUC``&Xwn^qbF$Y6JfNK(3IbqOjG(1!2n|%i~SWMsHF9qL@>CBzUc zcmI)~4XB)y-`7LjTh87%qGNL6c!yQ2DpN!T`1%wU_?S zZlV1N?z#R!d&u{R1!&jt^@S_ZfA|cjSNPUAm+9j?x%b`Z zJ{FbZ>`Q%L-eF%BlcNOgyS|mD2c83jZh?J4%|~$G_V?F!`u?S@|8ebK_d%XPx1i1{ z`hV@6-Hseb6~}LQ03IP1JOGctD7MTDIv-Va z`kYgzs$v)_2bxNg_5IjassA;5og4iz9!vh;{K8YEsM|Wq3w0;lp{X>ber&Ab_A6TrTx0rcbiv8FOAGIh zPd;7BKFhaK`sEX3z0T4Et}*@4RGJuK)~a+e^s?}nod5m;ZjLK!W`=pgYwVoTG?e~TwErBg>(qZ7 zX1e`f_Q$g{9G&lazNHjKk`rOb2;9Au91JM`2HOh{r3Hnyl}exTw}MehQgu_ z@j#XSlchglS2&K-SBLKzijKC3d!7D+&tRbp$?O{aH%EWhcX1hiS_~(x|9-w)f1tpe z{iA(rhNkW3f4R^$z5ZEGk?+QkgpKCq`MK8q0e;s0)mrgGQqHenxXMn!=T!5p3vpo` zdu(*4+t1bZuL{lKS))gXxcN2fp`*__ZmBbC^iYrEGv98H>C1ogBC==mfhBaSW&9ub zjFSE@Y-#BCvYhUOgiFL6<`ueWB=x2}W)VS_5{xSeMS$ ztye6JWF>W*8*|vc{9=-Ja9+ju7XK_6EDz6ClBBoa8gFU;C#~uAum5VFEbZ^% zd#}re!2=ld zyIdUETH+rX#5&_&8ktC&U00&)oUB9Mtuy|`X(GnR_V*FIl*~0*rEl?29m(O@S-Q>6 zk6%fC;~WQYT6g@D<77OLOm^4{XX)|iV(6no#>>#>k^83CF&5In^V>zc^MJmPl?MTy z*dyaJ7tMBNk4O9yN!f(_*E8&QY*_Y8OW86p55QqvF<(w=?o8cg!bS?DFl)Vtw z+p_;hAAa!Y#lMG4fDdb#|8PcogZ|9cdyT*y-M{i5;6s@_IbiT$FA zM;|$<{ik){8_>P+!xt@&`E&~79@j}S^X`aSNR5Z~*|O}5%DedVZ+Bv^4;#nN_{sZl zpL?z{CbGwDub6cc!j?DJU$gyc=5Sbr@8s@>RQB&>sIQ3#^+Dsg_EbvYKKkfMn=`)i zlUMgQKlj8!p2=5#Xue*2TjWiZ!G28^(=aerB<29)PvcYHOv1#^xO44>jZyh~JI@#(n8|;=m%$N|Jby!X1Cq_7AQn=j`<1?|2c1xqaojd|Qk2(SbQM zW{0+DZ6<2p=G%QMKlh;&f2U(lWu;;ytS!lpxoo08*ATO3l$g`1TLRcPrFPS&D4E|07FhZE@&9#hdjoS@l277P6Q^bm8@uzTL#N!jz zj*1}9GVxuFW1*PmUz&#C4-8~gSO?(JH-A6GEskZ}_~c_%zRIEaTa1=qhBSavQIcMT zZW6xBeCnDs7=Hn?IoyHV0H>0Dh0zT|+=-(hwyq|v0)Jq}F+3$>kv4BTpnLqtcRNwP zrFalxWWpnc3qR0N!#rH~>7J8Eo}1%kNgQrG$Dl7Zn6b~WzG|+gzkRclH*w4_xOFDt zdu3;|IB0$t^A)?&5d8aO8nDB7YjEqd(Ys^Rk8ORe~Z)8KFD2(y$gwPusK4^6CzgZLy0(A_PK1H`+5AuXS#~EeT~C$OZLAt zdph&hGWgq=KelXer1Vwv%rK8#_vrcTAzgz%b+g!h>ep6Vh5UrYwe5$#QQLo0RkWzxY6hs9lR^_szf0z2BB48a6-k zW!oos^Tbp8lSieSWc-T2Y~MrwDAeEJ!Giv*{fw)|`uFzsH$VH8Irt$ievQq$ue=M1 zISzv9`8XHr&ngVPYQcWd{GOV`yxy#zr>WZ<{tI)7D(x5W#HSb1Z}y{N+iDW~3#aBB zdbuh5EtWKzt5a(~f@9Ktzwgny`Cb&HxZ2%6y`?>|Uy?88N7@Vhik-Kf{i)d~Vay&e z>l=dM^l`?Au#Ei<=%oKd?Yel*JB1V`%3SC(=0A~7blH^iUx`Pnj7_wd%ZTsreyIP- z$j)kf)ORdOlj;X)U1KBjZ9=}sGSb^UxUbBA>pW9E zm`^L`KbM_9mc5G3g58Afi2iGbu5H~J;%B83#NSoNdtLr>CjnVOpT?)x!fa&u+<(?s zk?lsiu(rWm4(_G$HusP-wzk~>e{G9r&js?#>f%ltKZ@vT$L}J4R~MiC*+@Fp)-#7Q zeixBpc4680>9a>_{B(g1zkyDv{*FCu_O`BbdZxc}d_LyDVQ?S{2Rij$7)?GS2 zpreh`dawRO=`h;HoemS<@$Tz?+n@gGbvwB3^Cu6b8Gkf$t65LezqNB`=8)+bdC0q} z1YMKIzo+%1)A1Q|IJh3Byu4#^`2!GPF2kJPRps*^|5dnu!p5i1&GgsM$KT|&`4CIs zu=9)8=6v+TWZ0Tod~=mH?>`t*hgM5^MxHraS2}9#SUWhk^Ho16AIpUoWn#SKI#5*3&|1vl}+%)3kFNn`Z1GlS<*6-%;z6SU*wOU41iLJ7N0rA2N_{`E{T=P?Nrl-L+lgal=J`M`=3-x7bGlNXy0etrL@;m?GAvvAqnMXQA)U;XqRt{1X0qS)6Oy zKl%IkU()_4#}jb^PLKJd{6Xg2$~AqbQ|*t}`ubm3bhvI6W5cOBZ}ZDn+t>fdJ1>8_ z*H2=8z0+@J#rh#LId=c@j}|l+ti|McyX4QD{G}gv$Y1<&!18j#^IZSh**(bDBY(lQ zttZKfzV%?JN9HA(-wZz#hkQTy96W_Q&B-;-%b79{zP~53>$rsP&@X2`J;jCwJYy{Y zk29Qof6KhGd=|6&cROo5zpbB!$y}W)jzyAlNZRfMrKpj_DvM6*`#N*weZ^n z?3_H!meV`{=e8~yJm^P!OOPj&%fU5u>wU~|=G|JlW1Osw9g_YX;zHk~ExU|z8r!qk zA7@S9>e6w-GMBxEC-m`o`>U*NFAMYC`d;J?xb1)OQ{a}kOGoRcc#r->X&wA$e2jIM z(O)>Y-g~=$Ece!EygxoWivb+ndwRC!7Gn}zOHPc>erKONslC|=Hvnya6XhXqn4lN@roVY3ynO&axI4Y^hUE>%BW;ap zmFxN)-#OOjC6%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index a36cde0..2157a5f 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -1,35 +1,35 @@ -import type { Metadata } from "next"; -import localFont from "next/font/local"; -import "./globals.css"; +import type { Metadata } from 'next'; +import localFont from 'next/font/local'; +import './globals.css'; const geistSans = localFont({ - src: "./fonts/GeistVF.woff", - variable: "--font-geist-sans", - weight: "100 900", + src: './fonts/GeistVF.woff', + variable: '--font-geist-sans', + weight: '100 900', }); const geistMono = localFont({ - src: "./fonts/GeistMonoVF.woff", - variable: "--font-geist-mono", - weight: "100 900", + src: './fonts/GeistMonoVF.woff', + variable: '--font-geist-mono', + weight: '100 900', }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: 'The social network', + description: 'social network by deusbog', }; export default function RootLayout({ - children, + children, }: Readonly<{ - children: React.ReactNode; + children: React.ReactNode; }>) { - return ( - - - {children} - - - ); + return ( + + + {children} + + + ); } diff --git a/frontend/src/app/login/page.tsx b/frontend/src/app/login/page.tsx index 1dc9d6f..2c0be29 100644 --- a/frontend/src/app/login/page.tsx +++ b/frontend/src/app/login/page.tsx @@ -1,21 +1,54 @@ -import React from 'react'; +'use client'; + +import React, { useState } from 'react'; import Link from 'next/link'; +import { useRouter } from 'next/navigation'; export default function Login() { + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [message, setMessage] = useState(''); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + try { + const res = await fetch('http://localhost:8080/api/users/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ email, password }), + }); + + if (res.ok) { + localStorage.setItem('email', email); + router.push('/success'); // Redirect to the success page + } else { + setMessage('Error logging in'); + } + } catch (error) { + console.error('Error:', error); + setMessage('Failed to connect to the server'); + } + }; + return (

Login

-
+
setEmail(e.target.value)} required />
@@ -24,10 +57,12 @@ export default function Login() { Password setPassword(e.target.value)} required />
@@ -38,6 +73,7 @@ export default function Login() { Login + {message &&

{message}

}

Don't have an account?{' '} diff --git a/frontend/src/app/register/page.tsx b/frontend/src/app/register/page.tsx index 59210d7..a74034c 100644 --- a/frontend/src/app/register/page.tsx +++ b/frontend/src/app/register/page.tsx @@ -1,21 +1,56 @@ -import React from 'react'; +'use client'; + +import React, { useState } from 'react'; import Link from 'next/link'; +import { useRouter } from 'next/navigation'; export default function Register() { + const [name, setName] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [message, setMessage] = useState(''); + const router = useRouter(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + try { + const res = await fetch('http://localhost:8080/api/users/register', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ name, email, password }), + }); + + if (res.ok) { + localStorage.setItem('name', name); + localStorage.setItem('email', email); + router.push('/login'); + } else { + setMessage('Error registering user'); + } + } catch (error) { + console.error('Error:', error); + setMessage('Failed to connect to the server'); + } + }; + return (

Register

-
+
setName(e.target.value)} required />
@@ -24,10 +59,12 @@ export default function Register() { Email setEmail(e.target.value)} required />
@@ -36,10 +73,12 @@ export default function Register() { Password setPassword(e.target.value)} required />
@@ -50,6 +89,7 @@ export default function Register() { Register + {message &&

{message}

}

Already have an account?{' '} diff --git a/frontend/src/app/success/page.tsx b/frontend/src/app/success/page.tsx new file mode 100644 index 0000000..68fefe3 --- /dev/null +++ b/frontend/src/app/success/page.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import Link from 'next/link'; + +export default function Success() { + return ( +

+
+

+ Login Successful +

+

You have successfully logged in!

+ + Go to Home + +
+
+ ); +}