From 1058048a12a5746a50f6d62b999fab8bc91ed3bc Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 31 Jul 2025 22:00:48 +0200 Subject: [PATCH 01/98] fix memory leak --- macros/src/protos.rs | 7 +------ src/nex/matchmake.rs | 4 +++- src/nex/user.rs | 6 ++++++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/macros/src/protos.rs b/macros/src/protos.rs index 14ec2f6..fdf8b62 100644 --- a/macros/src/protos.rs +++ b/macros/src/protos.rs @@ -325,10 +325,5 @@ impl ToTokens for RmcProtocolData{ self.generate_raw_trait(tokens); self.generate_raw_info(tokens); self.generate_raw_remote_trait(tokens); - - - - } -} - +} \ No newline at end of file diff --git a/src/nex/matchmake.rs b/src/nex/matchmake.rs index bba55f5..c01c9a7 100644 --- a/src/nex/matchmake.rs +++ b/src/nex/matchmake.rs @@ -50,7 +50,7 @@ impl MatchmakeManager{ async fn garbage_collect(&self){ info!("running rnex garbage collector over all sessions and users"); - let idx = 0; + let mut idx = 0; let mut to_be_deleted_gids = Vec::new(); @@ -69,6 +69,8 @@ impl MatchmakeManager{ if !session.is_reachable(){ to_be_deleted_gids.push(gid); } + + idx += 1; } let mut sessions = self.sessions.write().await; diff --git a/src/nex/user.rs b/src/nex/user.rs index e166a80..d77c289 100644 --- a/src/nex/user.rs +++ b/src/nex/user.rs @@ -269,6 +269,12 @@ impl MatchmakeExtension for User { let session = self.matchmake_manager.get_session(join_session_param.gid).await?; let mut session = session.lock().await; + + if session.session.user_password_enabled{ + if join_session_param.user_password != session.session.user_password{ + return Err(ErrorCode::RendezVous_InvalidPassword) + } + } session.connected_players.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid)); -- 2.47.3 From a4ccc96ed01688e2f4cecbc2d6b423385b763776 Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 31 Jul 2025 23:39:26 +0200 Subject: [PATCH 02/98] update readme --- README.md | 2 +- macros/Cargo.lock | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4900bd8..f0526a0 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ - Pretendo team for the rest of the Servers and Reverse engineering efforts - Kinnay for his huge work on reversing nex servers and documentation(https://github.com/Kinnay/NintendoClients/) - Splatfestival testing team for helping us test our messes of code -- The SPFN team(Andrea and DJMrTV) \ No newline at end of file +- The SPFN team(Bloxer, Ceantix and Maple(aka TV)) \ No newline at end of file diff --git a/macros/Cargo.lock b/macros/Cargo.lock index a82b7df..acad79d 100644 --- a/macros/Cargo.lock +++ b/macros/Cargo.lock @@ -2,15 +2,55 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + [[package]] name = "macros" version = "0.0.0" dependencies = [ "proc-macro2", "quote", + "rand", "syn", ] +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro2" version = "1.0.93" @@ -29,6 +69,41 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + [[package]] name = "syn" version = "2.0.98" @@ -45,3 +120,41 @@ name = "unicode-ident" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] -- 2.47.3 From aab441490410122526da8df684ae9a3c77b67a0e Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 21 Sep 2025 15:59:27 +0200 Subject: [PATCH 03/98] refactor --- Cargo.lock | 3712 ----------------- Cargo.toml | 98 +- bu | 12 + macros/src/lib.rs | 30 +- macros/src/protos.rs | 30 +- prudpv1/src/executables/common.rs | 18 + {src => prudpv1/src}/executables/mod.rs | 0 .../src}/executables/proxy_insecure.rs | 40 +- .../src}/executables/proxy_secure.rs | 46 +- {src => prudpv1/src}/prudp/auth_module.rs | 0 {src => prudpv1/src}/prudp/mod.rs | 2 - {src => prudpv1/src}/prudp/packet.rs | 54 +- {src => prudpv1/src}/prudp/router.rs | 3 +- {src => prudpv1/src}/prudp/secure.rs | 8 +- {src => prudpv1/src}/prudp/socket.rs | 5 +- {src => prudpv1/src}/prudp/unsecure.rs | 0 {src => rnex-core/src}/common.rs | 0 .../executables/backend_server_insecure.rs | 38 +- .../src}/executables/backend_server_secure.rs | 24 +- {src => rnex-core/src}/executables/common.rs | 18 +- .../executables/edge_node_holder_server.rs | 14 +- rnex-core/src/executables/mod.rs | 1 + {src => rnex-core/src}/grpc/account.rs | 0 {src => rnex-core/src}/grpc/mod.rs | 1 - {src => rnex-core/src}/kerberos/mod.rs | 2 +- {src => rnex-core/src}/lib.rs | 4 +- {src => rnex-core/src}/main.rs | 6 - {src => rnex-core/src}/nex/account.rs | 0 {src => rnex-core/src}/nex/auth_handler.rs | 28 +- {src => rnex-core/src}/nex/matchmake.rs | 14 +- {src => rnex-core/src}/nex/mod.rs | 0 {src => rnex-core/src}/nex/remote_console.rs | 0 {src => rnex-core/src}/nex/user.rs | 24 +- rnex-core/src/prudp/mod.rs | 3 + .../src/prudp/socket_addr.rs | 7 +- {src => rnex-core/src}/prudp/station_url.rs | 2 +- rnex-core/src/prudp/virtual_port.rs | 49 + {src => rnex-core/src}/reggie.rs | 4 +- {src => rnex-core/src}/result.rs | 0 {src => rnex-core/src}/rmc/message.rs | 2 +- {src => rnex-core/src}/rmc/mod.rs | 0 {src => rnex-core/src}/rmc/protocols/auth.rs | 6 +- .../src}/rmc/protocols/matchmake.rs | 4 +- .../src}/rmc/protocols/matchmake_ext.rs | 2 +- .../src}/rmc/protocols/matchmake_extension.rs | 4 +- {src => rnex-core/src}/rmc/protocols/mod.rs | 12 +- .../src}/rmc/protocols/nat_traversal.rs | 2 +- .../src}/rmc/protocols/notifications.rs | 0 .../src}/rmc/protocols/ranking.rs | 0 .../src}/rmc/protocols/secure.rs | 6 +- {src => rnex-core/src}/rmc/response.rs | 4 +- {src => rnex-core/src}/rmc/structures/any.rs | 2 +- .../src}/rmc/structures/buffer.rs | 0 .../src}/rmc/structures/connection_data.rs | 3 +- {src => rnex-core/src}/rmc/structures/list.rs | 2 +- .../src}/rmc/structures/matchmake.rs | 4 +- {src => rnex-core/src}/rmc/structures/mod.rs | 0 .../src}/rmc/structures/networking.rs | 2 +- .../src}/rmc/structures/primitives.rs | 2 +- .../src}/rmc/structures/qbuffer.rs | 2 +- .../src}/rmc/structures/qresult.rs | 4 +- .../src}/rmc/structures/ranking.rs | 4 +- .../src}/rmc/structures/rmc_struct.rs | 2 +- .../src}/rmc/structures/string.rs | 2 +- .../src}/rmc/structures/variant.rs | 0 {src => rnex-core/src}/rnex_proxy_common.rs | 2 +- {src => rnex-core/src}/util.rs | 2 +- {src => rnex-core/src}/versions.rs | 0 {src => rnex-core/src}/web/mod.rs | 0 src/endianness.rs | 230 - src/grpc/protobufs.rs | 5 - 71 files changed, 292 insertions(+), 4315 deletions(-) delete mode 100644 Cargo.lock create mode 100644 bu create mode 100644 prudpv1/src/executables/common.rs rename {src => prudpv1/src}/executables/mod.rs (100%) rename {src => prudpv1/src}/executables/proxy_insecure.rs (70%) rename {src => prudpv1/src}/executables/proxy_secure.rs (71%) rename {src => prudpv1/src}/prudp/auth_module.rs (100%) rename {src => prudpv1/src}/prudp/mod.rs (71%) rename {src => prudpv1/src}/prudp/packet.rs (91%) rename {src => prudpv1/src}/prudp/router.rs (98%) rename {src => prudpv1/src}/prudp/secure.rs (96%) rename {src => prudpv1/src}/prudp/socket.rs (99%) rename {src => prudpv1/src}/prudp/unsecure.rs (100%) rename {src => rnex-core/src}/common.rs (100%) rename {src => rnex-core/src}/executables/backend_server_insecure.rs (70%) rename {src => rnex-core/src}/executables/backend_server_secure.rs (74%) rename {src => rnex-core/src}/executables/common.rs (69%) rename {src => rnex-core/src}/executables/edge_node_holder_server.rs (85%) create mode 100644 rnex-core/src/executables/mod.rs rename {src => rnex-core/src}/grpc/account.rs (100%) rename {src => rnex-core/src}/grpc/mod.rs (95%) rename {src => rnex-core/src}/kerberos/mod.rs (98%) rename {src => rnex-core/src}/lib.rs (90%) rename {src => rnex-core/src}/main.rs (98%) rename {src => rnex-core/src}/nex/account.rs (100%) rename {src => rnex-core/src}/nex/auth_handler.rs (89%) rename {src => rnex-core/src}/nex/matchmake.rs (95%) rename {src => rnex-core/src}/nex/mod.rs (100%) rename {src => rnex-core/src}/nex/remote_console.rs (100%) rename {src => rnex-core/src}/nex/user.rs (95%) create mode 100644 rnex-core/src/prudp/mod.rs rename src/prudp/sockaddr.rs => rnex-core/src/prudp/socket_addr.rs (85%) rename {src => rnex-core/src}/prudp/station_url.rs (99%) create mode 100644 rnex-core/src/prudp/virtual_port.rs rename {src => rnex-core/src}/reggie.rs (97%) rename {src => rnex-core/src}/result.rs (100%) rename {src => rnex-core/src}/rmc/message.rs (97%) rename {src => rnex-core/src}/rmc/mod.rs (100%) rename {src => rnex-core/src}/rmc/protocols/auth.rs (93%) rename {src => rnex-core/src}/rmc/protocols/matchmake.rs (86%) rename {src => rnex-core/src}/rmc/protocols/matchmake_ext.rs (82%) rename {src => rnex-core/src}/rmc/protocols/matchmake_extension.rs (87%) rename {src => rnex-core/src}/rmc/protocols/mod.rs (94%) rename {src => rnex-core/src}/rmc/protocols/nat_traversal.rs (94%) rename {src => rnex-core/src}/rmc/protocols/notifications.rs (100%) rename {src => rnex-core/src}/rmc/protocols/ranking.rs (100%) rename {src => rnex-core/src}/rmc/protocols/secure.rs (69%) rename {src => rnex-core/src}/rmc/response.rs (99%) rename {src => rnex-core/src}/rmc/structures/any.rs (94%) rename {src => rnex-core/src}/rmc/structures/buffer.rs (100%) rename {src => rnex-core/src}/rmc/structures/connection_data.rs (75%) rename {src => rnex-core/src}/rmc/structures/list.rs (96%) rename {src => rnex-core/src}/rmc/structures/matchmake.rs (97%) rename {src => rnex-core/src}/rmc/structures/mod.rs (100%) rename {src => rnex-core/src}/rmc/structures/networking.rs (94%) rename {src => rnex-core/src}/rmc/structures/primitives.rs (99%) rename {src => rnex-core/src}/rmc/structures/qbuffer.rs (91%) rename {src => rnex-core/src}/rmc/structures/qresult.rs (90%) rename {src => rnex-core/src}/rmc/structures/ranking.rs (96%) rename {src => rnex-core/src}/rmc/structures/rmc_struct.rs (95%) rename {src => rnex-core/src}/rmc/structures/string.rs (94%) rename {src => rnex-core/src}/rmc/structures/variant.rs (100%) rename {src => rnex-core/src}/rnex_proxy_common.rs (78%) rename {src => rnex-core/src}/util.rs (98%) rename {src => rnex-core/src}/versions.rs (100%) rename {src => rnex-core/src}/web/mod.rs (100%) delete mode 100644 src/endianness.rs delete mode 100644 src/grpc/protobufs.rs diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index fcc53fc..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,3712 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[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 = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] -name = "atomic" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "aws-lc-rs" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" -dependencies = [ - "bindgen", - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" - -[[package]] -name = "binascii" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" - -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.102", - "which", -] - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" - -[[package]] -name = "bytemuck" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cc" -version = "1.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "chrono" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-link", -] - -[[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 = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[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.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "ctrlc" -version = "3.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" -dependencies = [ - "nix", - "windows-sys 0.59.0", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "devise" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" -dependencies = [ - "devise_codegen", - "devise_core", -] - -[[package]] -name = "devise_codegen" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" -dependencies = [ - "devise_core", - "quote", -] - -[[package]] -name = "devise_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" -dependencies = [ - "bitflags", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "figment" -version = "0.10.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" -dependencies = [ - "atomic 0.6.0", - "pear", - "serde", - "toml", - "uncased", - "version_check", -] - -[[package]] -name = "fixedbitset" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[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.102", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.9.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.3.1", - "indexmap 2.9.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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.3.1", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.10", - "http 1.3.1", - "http-body 1.0.1", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http 1.3.1", - "hyper 1.6.0", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper 1.6.0", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.6.0", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.6.0", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "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 = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[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", -] - -[[package]] -name = "indexmap" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" -dependencies = [ - "equivalent", - "hashbrown 0.15.4", - "serde", -] - -[[package]] -name = "inlinable_string" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "json" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets 0.53.1", -] - -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "macros" -version = "0.0.0" -dependencies = [ - "proc-macro2", - "quote", - "rand 0.9.1", - "syn 2.0.102", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.3.1", - "httparse", - "memchr", - "mime", - "spin", - "tokio", - "tokio-util", - "version_check", -] - -[[package]] -name = "multimap" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-conv" -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-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pear" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "petgraph" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" -dependencies = [ - "fixedbitset", - "indexmap 2.9.0", -] - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" -dependencies = [ - "proc-macro2", - "syn 2.0.102", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", - "version_check", - "yansi", -] - -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" -dependencies = [ - "heck", - "itertools 0.14.0", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.102", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "prost-types" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] - -[[package]] -name = "rc4" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1256e23efe6097f27aa82d6ca6889361c001586ae0f6917cbad072f05eb275" -dependencies = [ - "cipher", -] - -[[package]] -name = "redox_syscall" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" -dependencies = [ - "bitflags", -] - -[[package]] -name = "ref-cast" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "reqwest" -version = "0.12.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "h2 0.4.10", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.6.0", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower 0.5.2", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rocket" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" -dependencies = [ - "async-stream", - "async-trait", - "atomic 0.5.3", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap 2.9.0", - "log", - "memchr", - "multer", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand 0.8.5", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "serde_json", - "state", - "tempfile", - "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" -dependencies = [ - "devise", - "glob", - "indexmap 2.9.0", - "proc-macro2", - "quote", - "rocket_http", - "syn 2.0.102", - "unicode-xid", - "version_check", -] - -[[package]] -name = "rocket_http" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" -dependencies = [ - "cookie", - "either", - "futures", - "http 0.2.12", - "hyper 0.14.32", - "indexmap 2.9.0", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", - "smallvec", - "stable-pattern", - "state", - "time", - "tokio", - "uncased", -] - -[[package]] -name = "rsa" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rust-nex" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-trait", - "bytemuck", - "chacha20", - "chrono", - "ctrlc", - "dotenv", - "futures", - "hex", - "hmac", - "json", - "log", - "macros", - "md-5", - "once_cell", - "paste", - "prost", - "rand 0.8.5", - "rc4", - "reqwest", - "rocket", - "rsa", - "rustls", - "rustls-pki-types", - "rustls-webpki", - "serde", - "sha2", - "simplelog", - "thiserror", - "tokio", - "tokio-rustls", - "tokio-stream", - "tokio-tungstenite", - "tonic", - "tonic-build", - "tungstenite", - "typenum", - "v_byte_macros", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" -dependencies = [ - "aws-lc-rs", - "log", - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - -[[package]] -name = "simplelog" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" -dependencies = [ - "log", - "termcolor", - "time", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "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 = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - -[[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.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6397daf94fa90f058bd0fd88429dd9e5738999cca8d701813c80723add80462" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix 1.0.7", - "windows-sys 0.59.0", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "libc", - "num-conv", - "num_threads", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.45.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.9.0", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow", -] - -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - -[[package]] -name = "tonic" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64", - "bytes", - "h2 0.4.10", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.6.0", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "socket2", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "prost-types", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "iri-string", - "pin-project-lite", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "tungstenite" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" -dependencies = [ - "bytes", - "data-encoding", - "http 1.3.1", - "httparse", - "log", - "rand 0.9.1", - "sha1", - "thiserror", - "utf-8", -] - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "ubyte" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" -dependencies = [ - "serde", -] - -[[package]] -name = "uncased" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" -dependencies = [ - "serde", - "version_check", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "v_byte_macros" -version = "0.0.3" -source = "git+https://github.com/DJMrTV/VByteMacros#1f2d596271933155a405ecdd362f750350960d44" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.102", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - -[[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-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[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" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "windows-link" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3bfe459f85da17560875b8bf1423d6f113b7a87a5d942e7da0ac71be7c61f8b" - -[[package]] -name = "windows-registry" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bab093bdd303a1240bb99b8aba8ea8a69ee19d34c9e2ef9594e708a4878820" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "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]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "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-targets" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30357ec391cde730f8fbfcdc29adc47518b06504528df977ab5af02ef23fdee9" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[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_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[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_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[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_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[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_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[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_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[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 = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.102", -] diff --git a/Cargo.toml b/Cargo.toml index dd12b89..9c63a93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,91 +1,7 @@ -[package] -name = "rust-nex" -version = "0.1.0" -edition = "2021" - -[profile.prod] -inherits = "release" -overflow-checks = false -strip = true -debug = false -debug-assertions = false -lto = true -incremental = false - - - -[dependencies] -bytemuck = { version = "1.21.0", features = ["derive"] } -dotenv = "0.15.0" -once_cell = "1.20.2" -rc4 = "0.1.0" -thiserror = "2.0.11" -v_byte_macros = { git = "https://github.com/DJMrTV/VByteMacros" } -simplelog = "0.12.2" -chrono = "0.4.39" -log = "0.4.25" -anyhow = "1.0.95" -rand = "0.8.5" - -hmac = "0.12.1" -md-5 = "^0.10.6" -tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } -tokio-stream = { version = "0.1.17", features = ["io-util"] } -tonic = "0.12.3" -prost = "0.13.4" -hex = "0.4.3" - -macros = { path = "macros" } -rocket = { version = "0.5.1", features = ["json", "serde_json"] } -serde = { version = "1.0.217", features = ["derive"] } -async-trait = "0.1.86" -paste = "1.0.15" -typenum = "1.18.0" -futures = "0.3.31" -reqwest = "0.12.18" -json = "0.12.4" -ctrlc = "3.4.7" -rsa = "0.9.8" -sha2 = "0.10.9" -chacha20 = "0.9.1" - -rustls = "0.23.27" - -rustls-pki-types = "1.12.0" -rustls-webpki = "0.103.3" -tokio-rustls = "0.26.2" -tokio-tungstenite = "0.27.0" -tungstenite = "0.27.0" - - - - -[build-dependencies] -tonic-build = "0.12.3" - -[features] -default = ["secure", "auth"] -secure = [] -auth = [] -no_tls = [] - -[[bin]] -name = "proxy_insecure" -path = "src/executables/proxy_insecure.rs" - -[[bin]] -name = "proxy_secure" -path = "src/executables/proxy_secure.rs" - -[[bin]] -name = "backend_server_insecure" -path = "src/executables/backend_server_insecure.rs" - - -[[bin]] -name = "backend_server_secure" -path = "src/executables/backend_server_secure.rs" - -[[bin]] -name = "edge_node_holder_server" -path = "src/executables/edge_node_holder_server.rs" \ No newline at end of file +[workspace] +resolver = "3" +members = [ + "macros", + "rnex-core", + "prudpv1" +] \ No newline at end of file diff --git a/bu b/bu new file mode 100644 index 0000000..da34886 --- /dev/null +++ b/bu @@ -0,0 +1,12 @@ + + +[build-dependencies] +tonic-build = "0.12.3" + +[features] +default = ["secure", "auth"] +secure = [] +auth = [] +no_tls = [] + + diff --git a/macros/src/lib.rs b/macros/src/lib.rs index ad77595..39639b3 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -65,7 +65,7 @@ fn gen_serialize_data_struct( let ident = f.ident.as_ref().unwrap(); serialize_content.append_all(quote! { - self.#ident.serialize(writer)?; + rnex_core::rmc::structures::RmcSerialize::serialize(&self.#ident, writer)?; }) } @@ -143,7 +143,7 @@ fn gen_serialize_data_struct( quote! { #pre_inner - rust_nex::rmc::structures::rmc_struct::write_struct(writer, #version, |mut writer|{ + rnex_core::rmc::structures::rmc_struct::write_struct(writer, #version, |mut writer|{ #serialize_base_content })?; @@ -176,7 +176,7 @@ fn gen_serialize_data_struct( quote! { #pre_inner - Ok(rust_nex::rmc::structures::rmc_struct::read_struct(reader, #version, move |mut reader|{ + Ok(rnex_core::rmc::structures::rmc_struct::read_struct(reader, #version, move |mut reader|{ #deserialize_base_content })?) } @@ -235,7 +235,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let name = &field.ident; base.append_all(quote!{ - #name: <#ty as rust_nex::rmc::structures::RmcSerialize>::deserialize(reader)?, + #name: <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?, }); } @@ -248,7 +248,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let ty = &field.ty; base.append_all(quote!{ - <#ty as rust_nex::rmc::structures::RmcSerialize>::deserialize(reader)?, + <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?, }); } @@ -260,7 +260,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { }; let mut se_with_fields = quote! { - <#ty as rust_nex::rmc::structures::RmcSerialize>::serialize(&#val, writer)?; + <#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(&#val, writer)?; }; match &variant.fields { @@ -270,7 +270,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let name = &field.ident; se_with_fields.append_all(quote!{ - <#ty as rust_nex::rmc::structures::RmcSerialize>::serialize(#name ,writer)?; + <#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#name ,writer)?; }); } } @@ -281,7 +281,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let ident = Ident::new(&format!("val_{}", i), Span::call_site()); se_with_fields.append_all(quote!{ - <#ty as rust_nex::rmc::structures::RmcSerialize>::serialize(#ident, writer)?; + <#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#ident, writer)?; }); } } @@ -344,9 +344,9 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { }; let deserialize_base_content = quote! { - let val: Self = match <#ty as rust_nex::rmc::structures::RmcSerialize>::deserialize(reader)?{ + let val: Self = match <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?{ #inner_match_de - v => return Err(rust_nex::rmc::structures::Error::UnexpectedValue(v as _)) + v => return Err(rnex_core::rmc::structures::Error::UnexpectedValue(v as _)) }; Ok(val) @@ -364,14 +364,14 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let ident = derive_input.ident; let tokens = quote! { - impl rust_nex::rmc::structures::RmcSerialize for #ident{ - fn serialize(&self, writer: &mut dyn ::std::io::Write) -> rust_nex::rmc::structures::Result<()>{ + impl rnex_core::rmc::structures::RmcSerialize for #ident{ + fn serialize(&self, writer: &mut dyn ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{ #serialize_base_content } - fn deserialize(reader: &mut dyn ::std::io::Read) -> rust_nex::rmc::structures::Result{ + fn deserialize(reader: &mut dyn ::std::io::Read) -> rnex_core::rmc::structures::Result{ #deserialize_base_content } } @@ -511,8 +511,8 @@ pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream { } - impl rust_nex::rmc::protocols::RmcCallable for #struct_name{ - async fn rmc_call(&self, remote_response_connection: &rust_nex::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ + impl rnex_core::rmc::protocols::RmcCallable for #struct_name{ + async fn rmc_call(&self, remote_response_connection: &rnex_core::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ ::rmc_call(self, remote_response_connection, protocol_id, method_id, call_id, rest).await; } } diff --git a/macros/src/protos.rs b/macros/src/protos.rs index fdf8b62..711e931 100644 --- a/macros/src/protos.rs +++ b/macros/src/protos.rs @@ -73,7 +73,7 @@ impl RmcProtocolData{ for (param_name, param_type) in parameters{ quote!{ let Ok(#param_name) = - <#param_type as rust_nex::rmc::structures::RmcSerialize>::deserialize( + <#param_type as rnex_core::rmc::structures::RmcSerialize>::deserialize( &mut cursor ) else }.to_tokens(tokens); @@ -84,7 +84,7 @@ impl RmcProtocolData{ quote! { { log::error!(#error_msg); - return Err(rust_nex::rmc::response::ErrorCode::Core_InvalidArgument); + return Err(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument); }; }.to_tokens(tokens) } else { @@ -116,7 +116,7 @@ impl RmcProtocolData{ quote!{ let retval = retval?; let mut vec = Vec::new(); - rust_nex::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok(); + rnex_core::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok(); Ok(vec) }.to_tokens(tokens); } @@ -126,7 +126,7 @@ impl RmcProtocolData{ quote!{ async fn rmc_call_proto( &self, - remote_response_connection: &rust_nex::util::SendingBufferConnection, + remote_response_connection: &rnex_core::util::SendingBufferConnection, method_id: u32, call_id: u32, data: Vec, @@ -165,7 +165,7 @@ impl RmcProtocolData{ }.to_tokens(tokens); if self.has_returns { quote! { - Err(rust_nex::rmc::response::ErrorCode::Core_NotImplemented) + Err(rnex_core::rmc::response::ErrorCode::Core_NotImplemented) }.to_tokens(tokens); } }); @@ -176,7 +176,7 @@ impl RmcProtocolData{ if *has_returns{ quote!{ - rust_nex::rmc::response::send_result( + rnex_core::rmc::response::send_result( remote_response_connection, ret, #id, @@ -209,7 +209,7 @@ impl RmcProtocolData{ // boilerplate tokens which all raw traits need quote!{ #[doc(hidden)] - pub trait #remote_name: rust_nex::rmc::protocols::HasRmcConnection + pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection }.to_tokens(tokens); // generate the body of the raw protocol trait @@ -247,12 +247,12 @@ impl RmcProtocolData{ for (param_name, param_type) in parameters{ quote!{ - rust_nex::result::ResultExtension::display_err_or_some( - <#param_type as rust_nex::rmc::structures::RmcSerialize>::serialize( + rnex_core::result::ResultExtension::display_err_or_some( + <#param_type as rnex_core::rmc::structures::RmcSerialize>::serialize( &#param_name, &mut cursor ) - ).ok_or(rust_nex::rmc::response::ErrorCode::Core_InvalidArgument) + ).ok_or(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument) }.to_tokens(tokens); if self.has_returns { quote! { @@ -268,25 +268,25 @@ impl RmcProtocolData{ quote!{ let call_id = rand::random(); - let message = rust_nex::rmc::message::RMCMessage{ + let message = rnex_core::rmc::message::RMCMessage{ call_id, method_id: #method_id, protocol_id: #proto_id, rest_of_data: send_data }; - let rmc_conn = ::get_connection(self); + let rmc_conn = ::get_connection(self); }.to_tokens(tokens); if *has_returns{ quote!{ - rust_nex::result::ResultExtension::display_err_or_some( + rnex_core::result::ResultExtension::display_err_or_some( rmc_conn.make_raw_call(&message).await - ).ok_or(rust_nex::rmc::response::ErrorCode::Core_Exception) + ).ok_or(rnex_core::rmc::response::ErrorCode::Core_Exception) }.to_tokens(tokens); } else { quote!{ - rust_nex::result::ResultExtension::display_err_or_some( + rnex_core::result::ResultExtension::display_err_or_some( rmc_conn.make_raw_call_no_response(&message).await ); }.to_tokens(tokens); diff --git a/prudpv1/src/executables/common.rs b/prudpv1/src/executables/common.rs new file mode 100644 index 0000000..e8162a1 --- /dev/null +++ b/prudpv1/src/executables/common.rs @@ -0,0 +1,18 @@ +use std::env; +use std::net::SocketAddrV4; +use once_cell::sync::Lazy; + +pub static EDGE_NODE_HOLDER: Lazy = Lazy::new(||{ + env::var("EDGE_NODE_HOLDER") + .ok() + .and_then(|s| s.parse().ok()) + .expect("EDGE_NODE_HOLDER not set") +}); + +pub static FORWARD_DESTINATION: Lazy = + Lazy::new(|| + env::var("FORWARD_DESTINATION") + .ok() + .and_then(|s| s.parse().ok()) + .expect("FORWARD_DESTINATION not set") + ); diff --git a/src/executables/mod.rs b/prudpv1/src/executables/mod.rs similarity index 100% rename from src/executables/mod.rs rename to prudpv1/src/executables/mod.rs diff --git a/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs similarity index 70% rename from src/executables/proxy_insecure.rs rename to prudpv1/src/executables/proxy_insecure.rs index 1232dc3..3ffe039 100644 --- a/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -1,5 +1,7 @@ -use rust_nex::reggie::RemoteEdgeNodeHolder; +use rnex_core::reggie::UnitPacketRead; +use rnex_core::reggie::UnitPacketWrite; +use rnex_core::rmc::structures::RmcSerialize; use std::env; use std::ffi::CStr; use std::io::{Read, Write}; @@ -7,35 +9,23 @@ use std::net::{Ipv4Addr, SocketAddrV4}; use std::sync::{Arc, OnceLock}; use std::time::Duration; use bytemuck::{Pod, Zeroable}; -use chacha20::{ChaCha20, Key}; -use chacha20::cipher::{Iv, KeyIvInit, StreamCipher}; use log::{error, warn}; -use macros::rmc_struct; use once_cell::sync::Lazy; -use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, Document}; -use rsa::{BigUint, Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey}; -use rsa::pkcs1::EncodeRsaPublicKey; -use rsa::pss::BlindedSigningKey; -use rsa::signature::{RandomizedSigner, SignatureEncoding}; -use sha2::Sha256; use tokio::net::{TcpSocket, TcpStream}; use tokio::sync::RwLock; use tokio::task; use tokio::time::sleep; -use rust_nex::common::setup; -use rust_nex::executables::common::{FORWARD_DESTINATION, OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_EDGE_NODE_HOLDER, SERVER_PORT}; -use rust_nex::prudp::packet::VirtualPort; -use rust_nex::prudp::router::Router; -use rust_nex::prudp::station_url::StationUrl; -use rust_nex::prudp::unsecure::Unsecure; -use rust_nex::reggie::{UnitPacketRead, UnitPacketWrite}; -use rust_nex::reggie::EdgeNodeHolderConnectOption::{DontRegister, Register}; -use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; -use rust_nex::rmc::response::ErrorCode; -use rust_nex::rmc::structures::RmcSerialize; -use rust_nex::rnex_proxy_common::ConnectionInitData; -use rust_nex::util::SplittableBufferConnection; - +use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER}; +use prudpv1::prudp::router::Router; +use prudpv1::prudp::unsecure::Unsecure; +use rnex_core::common::setup; +use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; +use rnex_core::prudp::virtual_port::VirtualPort; +use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; +use rnex_core::reggie::RemoteEdgeNodeHolder; +use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::rnex_proxy_common::ConnectionInitData; +use rnex_core::util::SplittableBufferConnection; @@ -43,7 +33,7 @@ use rust_nex::util::SplittableBufferConnection; async fn main() { setup(); - let conn = tokio::net::TcpStream::connect(&*SECURE_EDGE_NODE_HOLDER).await.unwrap(); + let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap(); let conn: SplittableBufferConnection = conn.into(); diff --git a/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs similarity index 71% rename from src/executables/proxy_secure.rs rename to prudpv1/src/executables/proxy_secure.rs index 1d554f9..b66fbc2 100644 --- a/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -1,35 +1,37 @@ -use std::net::SocketAddrV4; -use std::sync::Arc; +use rnex_core::reggie::UnitPacketRead; +use rnex_core::reggie::UnitPacketWrite; +use rnex_core::rmc::structures::RmcSerialize; +use std::env; +use std::ffi::CStr; +use std::io::{Read, Write}; +use std::net::{Ipv4Addr, SocketAddrV4}; +use std::sync::{Arc, OnceLock}; use std::time::Duration; -use futures::future::Remote; +use bytemuck::{Pod, Zeroable}; use log::{error, warn}; -use macros::rmc_struct; -use tokio::net::TcpStream; +use once_cell::sync::Lazy; +use tokio::net::{TcpSocket, TcpStream}; use tokio::sync::RwLock; use tokio::task; use tokio::time::sleep; -use tokio_rustls::client::TlsStream; -use tokio_tungstenite::MaybeTlsStream; -use rust_nex::common::setup; -use rust_nex::executables::common::{AUTH_SERVER_ACCOUNT, FORWARD_DESTINATION, OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_EDGE_NODE_HOLDER, SECURE_SERVER_ACCOUNT, SERVER_PORT}; -use rust_nex::prudp::packet::VirtualPort; -use rust_nex::prudp::router::Router; -use rust_nex::prudp::secure::Secure; -use rust_nex::prudp::unsecure::Unsecure; -use rust_nex::reggie::EdgeNodeHolderConnectOption::{DontRegister, Register}; -use rust_nex::rmc::response::ErrorCode; -use rust_nex::rnex_proxy_common::ConnectionInitData; -use rust_nex::reggie::{RemoteEdgeNodeHolder, UnitPacketWrite}; -use rust_nex::rmc::structures::RmcSerialize; -use rust_nex::reggie::UnitPacketRead; -use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote, RemoteInstantiatable}; -use rust_nex::util::SplittableBufferConnection; +use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER}; +use prudpv1::prudp::router::Router; +use prudpv1::prudp::secure::Secure; +use prudpv1::prudp::unsecure::Unsecure; +use rnex_core::common::setup; +use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT}; +use rnex_core::prudp::virtual_port::VirtualPort; +use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; +use rnex_core::reggie::RemoteEdgeNodeHolder; +use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::rnex_proxy_common::ConnectionInitData; +use rnex_core::util::SplittableBufferConnection; #[tokio::main] async fn main() { setup(); - let conn = tokio::net::TcpStream::connect(&*SECURE_EDGE_NODE_HOLDER).await.unwrap(); + let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap(); let conn: SplittableBufferConnection = conn.into(); diff --git a/src/prudp/auth_module.rs b/prudpv1/src/prudp/auth_module.rs similarity index 100% rename from src/prudp/auth_module.rs rename to prudpv1/src/prudp/auth_module.rs diff --git a/src/prudp/mod.rs b/prudpv1/src/prudp/mod.rs similarity index 71% rename from src/prudp/mod.rs rename to prudpv1/src/prudp/mod.rs index 966523e..7f237c6 100644 --- a/src/prudp/mod.rs +++ b/prudpv1/src/prudp/mod.rs @@ -2,7 +2,5 @@ pub mod packet; pub mod router; pub mod socket; mod auth_module; -pub mod sockaddr; -pub mod station_url; pub mod secure; pub mod unsecure; \ No newline at end of file diff --git a/src/prudp/packet.rs b/prudpv1/src/prudp/packet.rs similarity index 91% rename from src/prudp/packet.rs rename to prudpv1/src/prudp/packet.rs index b66167c..da376bd 100644 --- a/src/prudp/packet.rs +++ b/prudpv1/src/prudp/packet.rs @@ -12,11 +12,12 @@ use hmac::{Hmac, Mac}; use log::{error, warn}; use md5::{Md5, Digest}; use thiserror::Error; -use v_byte_macros::{SwapEndian}; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{SwapEndian}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::prudp::packet::flags::ACK; use crate::prudp::packet::PacketOption::{ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions}; -use crate::prudp::sockaddr::PRUDPSockAddr; +use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::prudp::virtual_port::VirtualPort; type Md5Hmac = Hmac; @@ -96,51 +97,7 @@ impl Debug for TypesFlags { } } -#[repr(transparent)] -#[derive(PartialEq, Eq, Ord, PartialOrd, Copy, Clone, Pod, Zeroable, SwapEndian, Hash)] -pub struct VirtualPort(pub(crate) u8); -impl VirtualPort { - - #[inline] - pub const fn get_stream_type(self) -> u8 { - (self.0 & 0xF0) >> 4 - } - - #[inline] - pub const fn get_port_number(self) -> u8 { - self.0 & 0x0F - } - - #[inline] - pub fn stream_type(self, val: u8) -> Self { - let masked_val = val & 0x0F; - assert_eq!(masked_val, val); - - Self((self.0 & 0x0F) | (masked_val << 4)) - } - - #[inline] - pub fn port_number(self, val: u8) -> Self { - let masked_val = val & 0x0F; - assert_eq!(masked_val, val); - - Self((self.0 & 0xF0) | masked_val) - } - - #[inline] - pub fn new(port: u8, stream_type: u8) -> Self { - Self(0).stream_type(stream_type).port_number(port) - } -} - -impl Debug for VirtualPort { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let stream_type = self.get_stream_type(); - let port_number = self.get_port_number(); - write!(f, "VirtualPort{{ stream_type: {}, port_number: {} }}", stream_type, port_number) - } -} #[repr(C)] #[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)] @@ -481,7 +438,8 @@ impl PRUDPV1Packet { mod test { use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; use crate::prudp::packet::types::DATA; - use super::{OptionId, PacketOption, PRUDPV1Header, TypesFlags, VirtualPort}; + use super::{OptionId, PacketOption, PRUDPV1Header, TypesFlags}; + use rnex_core::prudp::virtual_port::VirtualPort; #[test] fn size_test() { assert_eq!(size_of::(), 14); diff --git a/src/prudp/router.rs b/prudpv1/src/prudp/router.rs similarity index 98% rename from src/prudp/router.rs rename to prudpv1/src/prudp/router.rs index 3aa8bdd..3212155 100644 --- a/src/prudp/router.rs +++ b/prudpv1/src/prudp/router.rs @@ -15,7 +15,8 @@ use tokio::select; use tokio::sync::RwLock; use tokio::time::sleep; use crate::prudp::socket::{new_socket_pair, AnyInternalSocket, CryptoHandler, ExternalSocket}; -use crate::prudp::packet::{PRUDPV1Packet, VirtualPort}; +use crate::prudp::packet::{PRUDPV1Packet}; +use rnex_core::prudp::virtual_port::VirtualPort; use crate::prudp::router::Error::VirtualPortTaken; static SERVER_DATAGRAMS: Lazy = Lazy::new(||{ diff --git a/src/prudp/secure.rs b/prudpv1/src/prudp/secure.rs similarity index 96% rename from src/prudp/secure.rs rename to prudpv1/src/prudp/secure.rs index e0438d7..acf8bfb 100644 --- a/src/prudp/secure.rs +++ b/prudpv1/src/prudp/secure.rs @@ -5,12 +5,12 @@ use rc4::cipher::StreamCipherCoreWrapper; use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher}; use rc4::consts::U16; use typenum::U5; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::kerberos::{derive_key, TicketInternalData}; -use crate::nex::account::Account; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use rnex_core::kerberos::{derive_key, TicketInternalData}; +use rnex_core::nex::account::Account; use crate::prudp::packet::PRUDPV1Packet; use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair}; -use crate::rmc::structures::RmcSerialize; +use rnex_core::rmc::structures::RmcSerialize; pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)>{ let mut cursor = Cursor::new(data); diff --git a/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs similarity index 99% rename from src/prudp/socket.rs rename to prudpv1/src/prudp/socket.rs index 0455bd7..dde9b4d 100644 --- a/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -3,8 +3,9 @@ use crate::prudp::packet::types::{CONNECT, DATA, DISCONNECT, PING, SYN}; use crate::prudp::packet::PacketOption::{ ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions, }; -use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags, VirtualPort}; -use crate::prudp::sockaddr::PRUDPSockAddr; +use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags}; +use rnex_core::prudp::virtual_port::VirtualPort; +use rnex_core::prudp::socket_addr::PRUDPSockAddr; use async_trait::async_trait; use log::info; use log::error; diff --git a/src/prudp/unsecure.rs b/prudpv1/src/prudp/unsecure.rs similarity index 100% rename from src/prudp/unsecure.rs rename to prudpv1/src/prudp/unsecure.rs diff --git a/src/common.rs b/rnex-core/src/common.rs similarity index 100% rename from src/common.rs rename to rnex-core/src/common.rs diff --git a/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs similarity index 70% rename from src/executables/backend_server_insecure.rs rename to rnex-core/src/executables/backend_server_insecure.rs index 4cb8634..005936b 100644 --- a/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,4 +1,4 @@ -use rust_nex::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; +use rnex_core::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; use log::{error, info}; use once_cell::sync::Lazy; use rustls::client::danger::HandshakeSignatureValid; @@ -10,7 +10,7 @@ use rustls::{ SignatureScheme, }; use rustls_pki_types::PrivateKeyDer; -use rust_nex::common::setup; +use rnex_core::common::setup; use std::borrow::ToOwned; use std::{env, fs}; use std::io::Cursor; @@ -21,28 +21,22 @@ use tokio::io::AsyncReadExt; use tokio::net::{TcpListener, TcpSocket, TcpStream}; use tokio::task; use tokio_rustls::TlsAcceptor; -use rust_nex::define_rmc_proto; -use rust_nex::executables::common::{OWN_IP_PRIVATE, SECURE_EDGE_NODE_HOLDER, SECURE_SERVER_ACCOUNT, SERVER_PORT}; -use rust_nex::nex::auth_handler::AuthHandler; -use rust_nex::reggie::EdgeNodeHolderConnectOption::DontRegister; -use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; -use rust_nex::rmc::response::ErrorCode; -use rust_nex::rmc::structures::RmcSerialize; -use rust_nex::rnex_proxy_common::ConnectionInitData; -use rust_nex::util::SplittableBufferConnection; +use rnex_core::define_rmc_proto; +use rnex_core::executables::common::{OWN_IP_PRIVATE, SECURE_SERVER_ACCOUNT, SERVER_PORT}; +use rnex_core::nex::auth_handler::AuthHandler; +use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; +use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::rnex_proxy_common::ConnectionInitData; +use rnex_core::util::SplittableBufferConnection; -pub static SECURE_PROXY_ADDR: Lazy = Lazy::new(|| { - env::var("SECURE_PROXY_ADDR") + +pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(||{ + env::var("FORWARD_EDGE_NODE_HOLDER") .ok() .and_then(|s| s.parse().ok()) - .expect("no secure proxy ip specified") -}); - -pub static SECURE_PROXY_PORT: Lazy = Lazy::new(|| { - env::var("SECURE_PROXY_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(10000) + .expect("SECURE_EDGE_NODE_HOLDER not set") }); @@ -51,7 +45,7 @@ pub static SECURE_PROXY_PORT: Lazy = Lazy::new(|| { async fn main() { setup(); - let conn = TcpStream::connect(&*SECURE_EDGE_NODE_HOLDER).await.unwrap(); + let conn = TcpStream::connect(&*FORWARD_EDGE_NODE_HOLDER).await.unwrap(); let conn: SplittableBufferConnection = conn.into(); diff --git a/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs similarity index 74% rename from src/executables/backend_server_secure.rs rename to rnex-core/src/executables/backend_server_secure.rs index 6ada7b8..f758679 100644 --- a/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -1,22 +1,22 @@ use std::io::Cursor; -use rust_nex::rmc::structures::RmcSerialize; -use rust_nex::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; use std::net::SocketAddrV4; use std::sync::Arc; use std::sync::atomic::AtomicU32; use log::{error, info}; use tokio::net::{TcpListener, TcpStream}; use tokio::task; -use rust_nex::common::setup; -use rust_nex::executables::common::{OWN_IP_PRIVATE, SECURE_EDGE_NODE_HOLDER, SERVER_PORT}; -use rust_nex::nex::matchmake::MatchmakeManager; -use rust_nex::nex::remote_console::RemoteConsole; -use rust_nex::nex::user::User; -use rust_nex::reggie::EdgeNodeHolderConnectOption::DontRegister; -use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; -use rust_nex::rnex_proxy_common::ConnectionInitData; -use rust_nex::rmc::protocols::RemoteInstantiatable; -use rust_nex::util::SplittableBufferConnection; +use rnex_core::common::setup; +use rnex_core::executables::common::{OWN_IP_PRIVATE, SERVER_PORT}; +use rnex_core::nex::matchmake::MatchmakeManager; +use rnex_core::nex::remote_console::RemoteConsole; +use rnex_core::nex::user::User; +use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; +use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::rnex_proxy_common::ConnectionInitData; +use rnex_core::rmc::protocols::RemoteInstantiatable; +use rnex_core::util::SplittableBufferConnection; #[tokio::main] async fn main() { diff --git a/src/executables/common.rs b/rnex-core/src/executables/common.rs similarity index 69% rename from src/executables/common.rs rename to rnex-core/src/executables/common.rs index 3114436..77bccf7 100644 --- a/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -3,8 +3,8 @@ use std::net::{Ipv4Addr, SocketAddrV4}; use macros::{method_id, rmc_proto, RmcSerialize}; use once_cell::sync::Lazy; use tonic::transport::Server; -use rust_nex::define_rmc_proto; -use rust_nex::prudp::station_url::StationUrl; +use crate::define_rmc_proto; +use crate::prudp::station_url::StationUrl; use crate::nex::account::Account; use crate::rmc::response::ErrorCode; @@ -40,17 +40,5 @@ pub static AUTH_SERVER_ACCOUNT: Lazy = pub static SECURE_SERVER_ACCOUNT: Lazy = Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); -pub static SECURE_EDGE_NODE_HOLDER: Lazy = Lazy::new(||{ - env::var("SECURE_EDGE_NODE_HOLDER") - .ok() - .and_then(|s| s.parse().ok()) - .expect("SECURE_EDGE_NODE_HOLDER not set") -}); -pub static FORWARD_DESTINATION: Lazy = - Lazy::new(|| - env::var("FORWARD_DESTINATION") - .ok() - .and_then(|s| s.parse().ok()) - .expect("FORWARD_DESTINATION not set") - ); + diff --git a/src/executables/edge_node_holder_server.rs b/rnex-core/src/executables/edge_node_holder_server.rs similarity index 85% rename from src/executables/edge_node_holder_server.rs rename to rnex-core/src/executables/edge_node_holder_server.rs index 021dbb1..5146a86 100644 --- a/src/executables/edge_node_holder_server.rs +++ b/rnex-core/src/executables/edge_node_holder_server.rs @@ -5,13 +5,13 @@ use log::error; use macros::rmc_struct; use tokio::net::TcpListener; use tokio::sync::RwLock; -use rust_nex::common::setup; -use rust_nex::executables::common::{OWN_IP_PRIVATE, SERVER_PORT}; -use rust_nex::reggie::{EdgeNodeHolderConnectOption, EdgeNodeManagement, LocalEdgeNodeHolder}; -use rust_nex::rmc::protocols::new_rmc_gateway_connection; -use rust_nex::rmc::response::ErrorCode; -use rust_nex::util::SplittableBufferConnection; -use rust_nex::rmc::structures::RmcSerialize; +use rnex_core::common::setup; +use rnex_core::executables::common::{OWN_IP_PRIVATE, SERVER_PORT}; +use rnex_core::reggie::{EdgeNodeHolderConnectOption, EdgeNodeManagement, LocalEdgeNodeHolder}; +use rnex_core::rmc::protocols::new_rmc_gateway_connection; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::util::SplittableBufferConnection; +use rnex_core::rmc::structures::RmcSerialize; #[rmc_struct(EdgeNodeHolder)] struct EdgeNode{ diff --git a/rnex-core/src/executables/mod.rs b/rnex-core/src/executables/mod.rs new file mode 100644 index 0000000..ffac467 --- /dev/null +++ b/rnex-core/src/executables/mod.rs @@ -0,0 +1 @@ +pub mod common; \ No newline at end of file diff --git a/src/grpc/account.rs b/rnex-core/src/grpc/account.rs similarity index 100% rename from src/grpc/account.rs rename to rnex-core/src/grpc/account.rs diff --git a/src/grpc/mod.rs b/rnex-core/src/grpc/mod.rs similarity index 95% rename from src/grpc/mod.rs rename to rnex-core/src/grpc/mod.rs index 2ca742e..16cb73b 100644 --- a/src/grpc/mod.rs +++ b/rnex-core/src/grpc/mod.rs @@ -5,5 +5,4 @@ use tonic::{Request, Status}; type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result, Status> + Send)>; -mod protobufs; pub mod account; \ No newline at end of file diff --git a/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs similarity index 98% rename from src/kerberos/mod.rs rename to rnex-core/src/kerberos/mod.rs index a40b816..09dc46c 100644 --- a/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -135,7 +135,7 @@ pub struct Ticket{ } impl Ticket{ - pub(crate) fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]>{ + pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]>{ let mut data = bytes_of(self).to_vec(); internal_data.serialize(&mut data).expect("unable to write to vec"); diff --git a/src/lib.rs b/rnex-core/src/lib.rs similarity index 90% rename from src/lib.rs rename to rnex-core/src/lib.rs index 53553c2..21b354a 100644 --- a/src/lib.rs +++ b/rnex-core/src/lib.rs @@ -6,9 +6,8 @@ -extern crate self as rust_nex; +extern crate self as rnex_core; -pub mod endianness; pub mod prudp; pub mod rmc; //mod protocols; @@ -24,3 +23,4 @@ pub mod reggie; pub mod rnex_proxy_common; pub mod util; pub mod executables; +pub use macros::*; diff --git a/src/main.rs b/rnex-core/src/main.rs similarity index 98% rename from src/main.rs rename to rnex-core/src/main.rs index 338b9d3..b3b226b 100644 --- a/src/main.rs +++ b/rnex-core/src/main.rs @@ -14,11 +14,6 @@ use crate::nex::account::Account; use crate::nex::auth_handler::{AuthHandler, RemoteAuthClientProtocol}; use crate::nex::remote_console::RemoteConsole; use crate::nex::user::{RemoteUserProtocol, User}; -use crate::prudp::packet::VirtualPort; -use crate::prudp::router::Router; -use crate::prudp::secure::Secure; -use crate::prudp::sockaddr::PRUDPSockAddr; -use crate::prudp::unsecure::Unsecure; use crate::rmc::protocols::auth::Auth; use crate::rmc::protocols::auth::RawAuth; use crate::rmc::protocols::auth::RawAuthInfo; @@ -51,7 +46,6 @@ use crate::kerberos::KerberosDateTime; use crate::nex::matchmake::MatchmakeManager; use crate::rmc::protocols::secure::RemoteSecure; -mod endianness; mod prudp; pub mod rmc; //mod protocols; diff --git a/src/nex/account.rs b/rnex-core/src/nex/account.rs similarity index 100% rename from src/nex/account.rs rename to rnex-core/src/nex/account.rs diff --git a/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs similarity index 89% rename from src/nex/auth_handler.rs rename to rnex-core/src/nex/auth_handler.rs index ca7f970..134c1bc 100644 --- a/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -2,18 +2,18 @@ use std::hash::{DefaultHasher, Hasher}; use std::net::SocketAddrV4; use std::sync::Arc; use crate::grpc::account; -use crate::kerberos::{derive_key, KerberosDateTime, Ticket}; -use crate::nex::account::Account; -use crate::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth}; -use crate::rmc::response::ErrorCode; -use crate::rmc::response::ErrorCode::Core_Unknown; -use crate::rmc::structures::any::Any; -use crate::rmc::structures::connection_data::ConnectionData; -use crate::rmc::structures::qresult::QResult; +use rnex_core::kerberos::{derive_key, KerberosDateTime, Ticket}; +use rnex_core::nex::account::Account; +use rnex_core::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth}; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::response::ErrorCode::Core_Unknown; +use rnex_core::rmc::structures::any::Any; +use rnex_core::rmc::structures::connection_data::ConnectionData; +use rnex_core::rmc::structures::qresult::QResult; use crate::{define_rmc_proto, kerberos}; use macros::rmc_struct; use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; -use crate::rmc::protocols::OnlyRemote; +use rnex_core::rmc::protocols::OnlyRemote; define_rmc_proto!( proto AuthClientProtocol{ @@ -157,10 +157,10 @@ impl Auth for AuthHandler { #[cfg(test)] mod test { - use crate::rmc::structures::connection_data::ConnectionData; - use crate::rmc::structures::qresult::QResult; - use crate::rmc::structures::RmcSerialize; - use crate::rmc::response::RMCResponse; + use rnex_core::rmc::structures::connection_data::ConnectionData; + use rnex_core::rmc::structures::qresult::QResult; + use rnex_core::rmc::structures::RmcSerialize; + use rnex_core::rmc::response::RMCResponse; use std::io::Cursor; #[test] @@ -169,7 +169,7 @@ mod test { let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap(); - let crate::rmc::response::RMCResponseResult::Success { call_id, method_id, data: stuff} = stuff.response_result else { + let rnex_core::rmc::response::RMCResponseResult::Success { call_id, method_id, data: stuff} = stuff.response_result else { panic!() }; diff --git a/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs similarity index 95% rename from src/nex/matchmake.rs rename to rnex-core/src/nex/matchmake.rs index c01c9a7..1f4f61a 100644 --- a/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -8,15 +8,15 @@ use log::info; use rand::random; use tokio::sync::{Mutex, RwLock}; use tokio::time::sleep; -use crate::kerberos::KerberosDateTime; +use rnex_core::kerberos::KerberosDateTime; use crate::nex::user::User; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use crate::rmc::protocols::notifications::notification_types::{HOST_CHANGED, OWNERSHIP_CHANGED}; -use crate::rmc::response::ErrorCode; -use crate::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid}; -use crate::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; -use crate::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING; -use crate::rmc::structures::variant::Variant; +use rnex_core::rmc::protocols::notifications::notification_types::{HOST_CHANGED, OWNERSHIP_CHANGED}; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid}; +use rnex_core::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; +use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING; +use rnex_core::rmc::structures::variant::Variant; pub struct MatchmakeManager{ pub gid_counter: AtomicU32, diff --git a/src/nex/mod.rs b/rnex-core/src/nex/mod.rs similarity index 100% rename from src/nex/mod.rs rename to rnex-core/src/nex/mod.rs diff --git a/src/nex/remote_console.rs b/rnex-core/src/nex/remote_console.rs similarity index 100% rename from src/nex/remote_console.rs rename to rnex-core/src/nex/remote_console.rs diff --git a/src/nex/user.rs b/rnex-core/src/nex/user.rs similarity index 95% rename from src/nex/user.rs rename to rnex-core/src/nex/user.rs index d77c289..dd30cb4 100644 --- a/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -1,33 +1,33 @@ use crate::define_rmc_proto; use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}; use crate::nex::remote_console::RemoteConsole; -use crate::prudp::sockaddr::PRUDPSockAddr; -use crate::prudp::station_url::UrlOptions::{ +use rnex_core::prudp::station_url::StationUrl; +use rnex_core::prudp::station_url::UrlOptions::{ Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID, }; -use crate::prudp::station_url::{StationUrl}; use crate::rmc::protocols::matchmake::{ Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake, }; -use crate::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; -use crate::rmc::protocols::matchmake_extension::{ +use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; +use rnex_core::rmc::protocols::matchmake_extension::{ MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension, }; use crate::rmc::protocols::nat_traversal::{NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole}; -use crate::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; -use crate::rmc::protocols::matchmake_ext::{MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt}; -use crate::rmc::response::ErrorCode; -use crate::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession}; +use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; +use rnex_core::rmc::protocols::matchmake_ext::{MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt}; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession}; -use crate::rmc::structures::qresult::QResult; +use rnex_core::rmc::structures::qresult::QResult; use macros::rmc_struct; use std::sync::{Arc, Weak}; use log::info; use tokio::sync::{Mutex, RwLock}; -use crate::prudp::station_url::nat_types::PUBLIC; +use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::prudp::station_url::nat_types::PUBLIC; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use crate::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired}; +use rnex_core::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired}; define_rmc_proto!( proto UserProtocol{ diff --git a/rnex-core/src/prudp/mod.rs b/rnex-core/src/prudp/mod.rs new file mode 100644 index 0000000..093723d --- /dev/null +++ b/rnex-core/src/prudp/mod.rs @@ -0,0 +1,3 @@ +pub mod virtual_port; +pub mod station_url; +pub mod socket_addr; \ No newline at end of file diff --git a/src/prudp/sockaddr.rs b/rnex-core/src/prudp/socket_addr.rs similarity index 85% rename from src/prudp/sockaddr.rs rename to rnex-core/src/prudp/socket_addr.rs index 4e42fcc..f3ea10c 100644 --- a/src/prudp/sockaddr.rs +++ b/rnex-core/src/prudp/socket_addr.rs @@ -1,8 +1,9 @@ use std::io::Write; use std::net::SocketAddrV4; -use hmac::{Hmac, Mac}; +use hmac::{Hmac}; +use md5::digest::Mac; use macros::RmcSerialize; -use crate::prudp::packet::VirtualPort; +use rnex_core::prudp::virtual_port::VirtualPort; type Md5Hmac = Hmac; @@ -24,7 +25,7 @@ impl PRUDPSockAddr{ } } - pub(super) fn calculate_connection_signature(&self) -> [u8; 16] { + pub fn calculate_connection_signature(&self) -> [u8; 16] { let mut hmac = Md5Hmac::new_from_slice(&[0; 16]).expect("fuck"); let mut data = self.regular_socket_addr.ip().octets().to_vec(); diff --git a/src/prudp/station_url.rs b/rnex-core/src/prudp/station_url.rs similarity index 99% rename from src/prudp/station_url.rs rename to rnex-core/src/prudp/station_url.rs index 441c1b3..b2f70bb 100644 --- a/src/prudp/station_url.rs +++ b/rnex-core/src/prudp/station_url.rs @@ -111,7 +111,7 @@ impl StationUrl{ impl TryFrom<&str> for StationUrl{ type Error = (); - + fn try_from(value: &str) -> Result { let (url_type, options) = value.split_at(value.find(":/").ok_or(())?); diff --git a/rnex-core/src/prudp/virtual_port.rs b/rnex-core/src/prudp/virtual_port.rs new file mode 100644 index 0000000..54d2eeb --- /dev/null +++ b/rnex-core/src/prudp/virtual_port.rs @@ -0,0 +1,49 @@ +use std::fmt::{Debug, Formatter}; +use bytemuck::{Pod, Zeroable}; +use v_byte_helpers::SwapEndian; + +#[repr(transparent)] +#[derive(PartialEq, Eq, Ord, PartialOrd, Copy, Clone, Pod, Zeroable, SwapEndian, Hash, Default)] +pub struct VirtualPort(pub u8); + +impl VirtualPort { + + #[inline] + pub const fn get_stream_type(self) -> u8 { + (self.0 & 0xF0) >> 4 + } + + #[inline] + pub const fn get_port_number(self) -> u8 { + self.0 & 0x0F + } + + #[inline] + pub fn stream_type(self, val: u8) -> Self { + let masked_val = val & 0x0F; + assert_eq!(masked_val, val); + + Self((self.0 & 0x0F) | (masked_val << 4)) + } + + #[inline] + pub fn port_number(self, val: u8) -> Self { + let masked_val = val & 0x0F; + assert_eq!(masked_val, val); + + Self((self.0 & 0xF0) | masked_val) + } + + #[inline] + pub fn new(port: u8, stream_type: u8) -> Self { + Self(0).stream_type(stream_type).port_number(port) + } +} + +impl Debug for VirtualPort { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let stream_type = self.get_stream_type(); + let port_number = self.get_port_number(); + write!(f, "VirtualPort{{ stream_type: {}, port_number: {} }}", stream_type, port_number) + } +} \ No newline at end of file diff --git a/src/reggie.rs b/rnex-core/src/reggie.rs similarity index 97% rename from src/reggie.rs rename to rnex-core/src/reggie.rs index f57ebb0..b3d73c9 100644 --- a/src/reggie.rs +++ b/rnex-core/src/reggie.rs @@ -20,11 +20,11 @@ use tokio_rustls::client::TlsStream; use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; use tokio_tungstenite::tungstenite::Message; use webpki::anchor_from_trusted_cert; -use rust_nex::common::setup; +use crate::common::setup; use crate::define_rmc_proto; use crate::nex::account::Account; use crate::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote, RmcCallable, RmcConnection}; -use crate::rmc::response::ErrorCode; +use rnex_core::rmc::response::ErrorCode; use crate::rmc::structures::RmcSerialize; pub trait UnitPacketRead: AsyncRead + Unpin{ diff --git a/src/result.rs b/rnex-core/src/result.rs similarity index 100% rename from src/result.rs rename to rnex-core/src/result.rs diff --git a/src/rmc/message.rs b/rnex-core/src/rmc/message.rs similarity index 97% rename from src/rmc/message.rs rename to rnex-core/src/rmc/message.rs index f45b585..cf951bf 100644 --- a/src/rmc/message.rs +++ b/rnex-core/src/rmc/message.rs @@ -2,7 +2,7 @@ use std::io; use std::io::{Read, Seek, Write}; use bytemuck::bytes_of; use log::error; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::response::{ErrorCode, RMCResponseResult}; #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/rmc/mod.rs b/rnex-core/src/rmc/mod.rs similarity index 100% rename from src/rmc/mod.rs rename to rnex-core/src/rmc/mod.rs diff --git a/src/rmc/protocols/auth.rs b/rnex-core/src/rmc/protocols/auth.rs similarity index 93% rename from src/rmc/protocols/auth.rs rename to rnex-core/src/rmc/protocols/auth.rs index ed8d1cd..49feb2b 100644 --- a/src/rmc/protocols/auth.rs +++ b/rnex-core/src/rmc/protocols/auth.rs @@ -1,7 +1,7 @@ -use crate::rmc::response::ErrorCode; -use crate::rmc::structures::any::Any; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::any::Any; use crate::rmc::structures::connection_data::ConnectionData; -use crate::rmc::structures::qresult::QResult; +use rnex_core::rmc::structures::qresult::QResult; use macros::{method_id, rmc_proto}; diff --git a/src/rmc/protocols/matchmake.rs b/rnex-core/src/rmc/protocols/matchmake.rs similarity index 86% rename from src/rmc/protocols/matchmake.rs rename to rnex-core/src/rmc/protocols/matchmake.rs index 1c2d5e5..24942c0 100644 --- a/src/rmc/protocols/matchmake.rs +++ b/rnex-core/src/rmc/protocols/matchmake.rs @@ -1,6 +1,6 @@ use macros::{method_id, rmc_proto}; -use crate::prudp::station_url::StationUrl; -use crate::rmc::response::ErrorCode; +use rnex_core::prudp::station_url::StationUrl; +use rnex_core::rmc::response::ErrorCode; #[rmc_proto(21)] pub trait Matchmake{ diff --git a/src/rmc/protocols/matchmake_ext.rs b/rnex-core/src/rmc/protocols/matchmake_ext.rs similarity index 82% rename from src/rmc/protocols/matchmake_ext.rs rename to rnex-core/src/rmc/protocols/matchmake_ext.rs index b795d3d..46c1c09 100644 --- a/src/rmc/protocols/matchmake_ext.rs +++ b/rnex-core/src/rmc/protocols/matchmake_ext.rs @@ -1,5 +1,5 @@ use macros::{method_id, rmc_proto}; -use crate::rmc::response::ErrorCode; +use rnex_core::rmc::response::ErrorCode; #[rmc_proto(50)] pub trait MatchmakeExt{ diff --git a/src/rmc/protocols/matchmake_extension.rs b/rnex-core/src/rmc/protocols/matchmake_extension.rs similarity index 87% rename from src/rmc/protocols/matchmake_extension.rs rename to rnex-core/src/rmc/protocols/matchmake_extension.rs index cd3f281..fff5252 100644 --- a/src/rmc/protocols/matchmake_extension.rs +++ b/rnex-core/src/rmc/protocols/matchmake_extension.rs @@ -1,6 +1,6 @@ use macros::{method_id, rmc_proto}; -use crate::rmc::response::ErrorCode; -use crate::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession}; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession}; #[rmc_proto(109)] pub trait MatchmakeExtension{ diff --git a/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs similarity index 94% rename from src/rmc/protocols/mod.rs rename to rnex-core/src/rmc/protocols/mod.rs index b206b44..7ad8e8c 100644 --- a/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -154,7 +154,7 @@ macro_rules! define_rmc_proto { }) => { paste::paste!{ pub trait []: std::any::Any $( + [] + $protocol)* { - async fn rmc_call(&self, remote_response_connection: &rust_nex::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ + async fn rmc_call(&self, remote_response_connection: &rnex_core::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ match protocol_id{ $( []::PROTOCOL_ID => ]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await, @@ -164,10 +164,10 @@ macro_rules! define_rmc_proto { } } - pub struct [](rust_nex::rmc::protocols::RmcConnection); + pub struct [](rnex_core::rmc::protocols::RmcConnection); - impl rust_nex::rmc::protocols::RemoteInstantiatable for []{ - fn new(conn: rust_nex::rmc::protocols::RmcConnection) -> Self{ + impl rnex_core::rmc::protocols::RemoteInstantiatable for []{ + fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{ Self(conn) } async fn disconnect(&self){ @@ -175,8 +175,8 @@ macro_rules! define_rmc_proto { } } - impl rust_nex::rmc::protocols::HasRmcConnection for []{ - fn get_connection(&self) -> &rust_nex::rmc::protocols::RmcConnection{ + impl rnex_core::rmc::protocols::HasRmcConnection for []{ + fn get_connection(&self) -> &rnex_core::rmc::protocols::RmcConnection{ &self.0 } } diff --git a/src/rmc/protocols/nat_traversal.rs b/rnex-core/src/rmc/protocols/nat_traversal.rs similarity index 94% rename from src/rmc/protocols/nat_traversal.rs rename to rnex-core/src/rmc/protocols/nat_traversal.rs index 222e62c..c0862a8 100644 --- a/src/rmc/protocols/nat_traversal.rs +++ b/rnex-core/src/rmc/protocols/nat_traversal.rs @@ -1,5 +1,5 @@ use macros::{method_id, rmc_proto}; -use crate::rmc::response::ErrorCode; +use rnex_core::rmc::response::ErrorCode; #[rmc_proto(3)] pub trait NatTraversal{ diff --git a/src/rmc/protocols/notifications.rs b/rnex-core/src/rmc/protocols/notifications.rs similarity index 100% rename from src/rmc/protocols/notifications.rs rename to rnex-core/src/rmc/protocols/notifications.rs diff --git a/src/rmc/protocols/ranking.rs b/rnex-core/src/rmc/protocols/ranking.rs similarity index 100% rename from src/rmc/protocols/ranking.rs rename to rnex-core/src/rmc/protocols/ranking.rs diff --git a/src/rmc/protocols/secure.rs b/rnex-core/src/rmc/protocols/secure.rs similarity index 69% rename from src/rmc/protocols/secure.rs rename to rnex-core/src/rmc/protocols/secure.rs index 3071c3a..50afb5b 100644 --- a/src/rmc/protocols/secure.rs +++ b/rnex-core/src/rmc/protocols/secure.rs @@ -1,7 +1,7 @@ use macros::{method_id, rmc_proto}; -use crate::prudp::station_url::StationUrl; -use crate::rmc::response::ErrorCode; -use crate::rmc::structures::qresult::QResult; +use rnex_core::prudp::station_url::StationUrl; +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::qresult::QResult; #[rmc_proto(11)] pub trait Secure { diff --git a/src/rmc/response.rs b/rnex-core/src/rmc/response.rs similarity index 99% rename from src/rmc/response.rs rename to rnex-core/src/rmc/response.rs index dcdebc6..a732853 100644 --- a/src/rmc/response.rs +++ b/rnex-core/src/rmc/response.rs @@ -7,8 +7,8 @@ use std::io::{Read, Seek, Write}; use std::mem::transmute; use bytemuck::bytes_of; use log::error; -use v_byte_macros::EnumTryInto; -use crate::endianness::{ReadExtensions, IS_BIG_ENDIAN}; +use v_byte_helpers::EnumTryInto; +use v_byte_helpers::{ReadExtensions, IS_BIG_ENDIAN}; use crate::rmc::response::ErrorCode::Core_Exception; use crate::rmc::structures::qresult::ERROR_MASK; use crate::util::SendingBufferConnection; diff --git a/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs similarity index 94% rename from src/rmc/structures/any.rs rename to rnex-core/src/rmc/structures/any.rs index d402f3e..c1e68a4 100644 --- a/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -1,5 +1,5 @@ use std::io::{Read, Write}; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use super::{Result, RmcSerialize}; #[derive(Debug, Default)] diff --git a/src/rmc/structures/buffer.rs b/rnex-core/src/rmc/structures/buffer.rs similarity index 100% rename from src/rmc/structures/buffer.rs rename to rnex-core/src/rmc/structures/buffer.rs diff --git a/src/rmc/structures/connection_data.rs b/rnex-core/src/rmc/structures/connection_data.rs similarity index 75% rename from src/rmc/structures/connection_data.rs rename to rnex-core/src/rmc/structures/connection_data.rs index a949d91..da6a17b 100644 --- a/src/rmc/structures/connection_data.rs +++ b/rnex-core/src/rmc/structures/connection_data.rs @@ -1,7 +1,6 @@ use macros::RmcSerialize; -use crate::kerberos::KerberosDateTime; -use crate::rmc::structures::RmcSerialize; +use rnex_core::kerberos::KerberosDateTime; #[derive(Debug, RmcSerialize)] #[rmc_struct(1)] diff --git a/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs similarity index 96% rename from src/rmc/structures/list.rs rename to rnex-core/src/rmc/structures/list.rs index 870be65..1ebb60b 100644 --- a/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -3,7 +3,7 @@ use std::io::{Read, Write}; use std::mem::MaybeUninit; use bytemuck::bytes_of; use serde::Serialize; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; diff --git a/src/rmc/structures/matchmake.rs b/rnex-core/src/rmc/structures/matchmake.rs similarity index 97% rename from src/rmc/structures/matchmake.rs rename to rnex-core/src/rmc/structures/matchmake.rs index 28e851b..9194b97 100644 --- a/src/rmc/structures/matchmake.rs +++ b/rnex-core/src/rmc/structures/matchmake.rs @@ -1,5 +1,5 @@ -use crate::kerberos::KerberosDateTime; -use crate::rmc::structures::variant::Variant; +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures::variant::Variant; use macros::RmcSerialize; // rmc structure diff --git a/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs similarity index 100% rename from src/rmc/structures/mod.rs rename to rnex-core/src/rmc/structures/mod.rs diff --git a/src/rmc/structures/networking.rs b/rnex-core/src/rmc/structures/networking.rs similarity index 94% rename from src/rmc/structures/networking.rs rename to rnex-core/src/rmc/structures/networking.rs index 9a11c5a..824a442 100644 --- a/src/rmc/structures/networking.rs +++ b/rnex-core/src/rmc/structures/networking.rs @@ -1,6 +1,6 @@ use std::io::{Read, Write}; use std::net::{Ipv4Addr, SocketAddrV4}; -use crate::prudp::packet::VirtualPort; +use rnex_core::prudp::virtual_port::VirtualPort; use crate::rmc::structures::RmcSerialize; impl RmcSerialize for SocketAddrV4{ diff --git a/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs similarity index 99% rename from src/rmc/structures/primitives.rs rename to rnex-core/src/rmc/structures/primitives.rs index a834d9a..73985ed 100644 --- a/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -1,6 +1,6 @@ use std::io::{Read, Write}; use bytemuck::bytes_of; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; impl RmcSerialize for u8{ diff --git a/src/rmc/structures/qbuffer.rs b/rnex-core/src/rmc/structures/qbuffer.rs similarity index 91% rename from src/rmc/structures/qbuffer.rs rename to rnex-core/src/rmc/structures/qbuffer.rs index bb6c235..8fbfd5e 100644 --- a/src/rmc/structures/qbuffer.rs +++ b/rnex-core/src/rmc/structures/qbuffer.rs @@ -1,6 +1,6 @@ use std::io::{Read, Write}; use bytemuck::bytes_of; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::{Result, RmcSerialize}; diff --git a/src/rmc/structures/qresult.rs b/rnex-core/src/rmc/structures/qresult.rs similarity index 90% rename from src/rmc/structures/qresult.rs rename to rnex-core/src/rmc/structures/qresult.rs index 41a5263..77ad70e 100644 --- a/src/rmc/structures/qresult.rs +++ b/rnex-core/src/rmc/structures/qresult.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use bytemuck::{bytes_of, Pod, Zeroable}; -use v_byte_macros::SwapEndian; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::SwapEndian; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::response::ErrorCode; use crate::rmc::structures::{RmcSerialize, Result}; diff --git a/src/rmc/structures/ranking.rs b/rnex-core/src/rmc/structures/ranking.rs similarity index 96% rename from src/rmc/structures/ranking.rs rename to rnex-core/src/rmc/structures/ranking.rs index c912d3f..afb0698 100644 --- a/src/rmc/structures/ranking.rs +++ b/rnex-core/src/rmc/structures/ranking.rs @@ -1,6 +1,6 @@ use bytemuck::{Pod, Zeroable}; use macros::RmcSerialize; -use crate::rmc::structures::qbuffer::QBuffer; +use rnex_core::rmc::structures::qbuffer::QBuffer; #[derive(RmcSerialize, Debug)] #[rmc_struct(0)] @@ -27,7 +27,7 @@ mod test{ use bytemuck::from_bytes; use tokio::io::AsyncReadExt; use crate::rmc::structures::ranking::{UploadCompetitionData, UserData}; - use crate::rmc::structures::RmcSerialize; + use rnex_core::rmc::structures::RmcSerialize; #[test] fn test() { diff --git a/src/rmc/structures/rmc_struct.rs b/rnex-core/src/rmc/structures/rmc_struct.rs similarity index 95% rename from src/rmc/structures/rmc_struct.rs rename to rnex-core/src/rmc/structures/rmc_struct.rs index 8f51a5a..071cfdb 100644 --- a/src/rmc/structures/rmc_struct.rs +++ b/rnex-core/src/rmc/structures/rmc_struct.rs @@ -1,6 +1,6 @@ use std::io::{Cursor, Read, Write}; use bytemuck::bytes_of; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::Error::VersionMismatch; use crate::rmc::structures::Result; diff --git a/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs similarity index 94% rename from src/rmc/structures/string.rs rename to rnex-core/src/rmc/structures/string.rs index 690e6a1..d25bc81 100644 --- a/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -1,7 +1,7 @@ use std::io::{Read, Write}; use bytemuck::bytes_of; use log::error; -use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use super::{Result, RmcSerialize}; impl RmcSerialize for String{ diff --git a/src/rmc/structures/variant.rs b/rnex-core/src/rmc/structures/variant.rs similarity index 100% rename from src/rmc/structures/variant.rs rename to rnex-core/src/rmc/structures/variant.rs diff --git a/src/rnex_proxy_common.rs b/rnex-core/src/rnex_proxy_common.rs similarity index 78% rename from src/rnex_proxy_common.rs rename to rnex-core/src/rnex_proxy_common.rs index c300aa0..29cb161 100644 --- a/src/rnex_proxy_common.rs +++ b/rnex-core/src/rnex_proxy_common.rs @@ -1,5 +1,5 @@ use macros::RmcSerialize; -use crate::prudp::sockaddr::PRUDPSockAddr; +use crate::prudp::socket_addr::PRUDPSockAddr; #[derive(Debug, RmcSerialize)] #[rmc_struct(0)] diff --git a/src/util.rs b/rnex-core/src/util.rs similarity index 98% rename from src/util.rs rename to rnex-core/src/util.rs index 04c8400..b052fe2 100644 --- a/src/util.rs +++ b/rnex-core/src/util.rs @@ -5,7 +5,7 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::Notify; use tokio::task; -use rust_nex::reggie::{UnitPacketRead, UnitPacketWrite}; +use crate::reggie::{UnitPacketRead, UnitPacketWrite}; #[derive(Clone)] pub struct SendingBufferConnection(Sender>, Arc); diff --git a/src/versions.rs b/rnex-core/src/versions.rs similarity index 100% rename from src/versions.rs rename to rnex-core/src/versions.rs diff --git a/src/web/mod.rs b/rnex-core/src/web/mod.rs similarity index 100% rename from src/web/mod.rs rename to rnex-core/src/web/mod.rs diff --git a/src/endianness.rs b/src/endianness.rs deleted file mode 100644 index 160b1a1..0000000 --- a/src/endianness.rs +++ /dev/null @@ -1,230 +0,0 @@ -use std::{io, mem}; -use std::io::Read; -use std::marker::PhantomData; -use bytemuck::Pod; - -#[cfg(target_endian = "little")] -pub const IS_LITTLE_ENDIAN: bool = true; - -#[cfg(target_endian = "big")] -pub const IS_LITTLE_ENDIAN: bool = false; - -pub const IS_BIG_ENDIAN: bool = !IS_LITTLE_ENDIAN; - -pub mod little_endian{ - use std::io; - use std::io::Read; - - #[inline] - pub fn read_u16(reader: &mut (impl Read + ?Sized)) -> io::Result{ - let mut data = [0u8; 2]; - - reader.read_exact(&mut data)?; - - Ok(((data[0] as u16) << 8) | (data[1] as u16)) - } - - #[inline] - pub fn read_u32(reader: &mut (impl Read + ?Sized)) -> io::Result{ - let mut data = [0u8; 4]; - - reader.read_exact(&mut data)?; - - Ok( - ((data[0] as u32) << 24) | - ((data[1] as u32) << 16) | - ((data[2] as u32) << 8) | - (data[3] as u32) - ) - } -} - -pub struct StructMultiReadIter<'a, T: Pod + SwapEndian>{ - reader: &'a mut dyn Read, - left_to_read: usize, - swap_endian: bool, - _phantom_data: PhantomData<&'static T> -} - -impl<'a, T: Pod + SwapEndian> Iterator for StructMultiReadIter<'a, T>{ - type Item = io::Result; - - #[inline] - fn next(&mut self) -> Option { - if self.left_to_read == 0{ - None - } else { - Some(self.reader.read_struct(self.swap_endian)) - } - } -} - -impl<'a, T: Pod + SwapEndian> Drop for StructMultiReadIter<'a, T>{ - #[inline] - fn drop(&mut self) { - - // read all the structs we would be reading and discard them to make the result after using - // this always be the same - while let Some(_) = self.next() { } - } -} - - - - -pub trait ReadExtensions: Read{ - #[inline] - fn read_le_u16(&mut self) -> io::Result{ - little_endian::read_u16(self) - } - - #[inline] - fn read_le_u32(&mut self) -> io::Result{ - little_endian::read_u32(self) - } - - #[inline] - fn read_le_struct(&mut self) -> io::Result{ - let mut data = T::zeroed(); - let bytes = bytemuck::bytes_of_mut(&mut data); - - self.read_exact(bytes)?; - - if cfg!(not(target_endian = "little")){ - data = data.swap_endian(); - } - - Ok(data) - } - - #[inline] - fn read_struct(&mut self, swap_endian: bool) -> io::Result{ - let mut data = T::zeroed(); - let bytes = bytemuck::bytes_of_mut(&mut data); - - self.read_exact(bytes)?; - - if swap_endian{ - data = data.swap_endian(); - } - - Ok(data) - } - - - fn read_struct_multi(&mut self, swap_endian: bool, count: usize) -> io::Result>; -} - -impl ReadExtensions for T{ - // i was forced to put this here because it requires info about self - #[inline] - fn read_struct_multi(&mut self, swap_endian: bool, count: usize) -> io::Result>{ - Ok(StructMultiReadIter{ - reader: self, - swap_endian, - left_to_read: count, - _phantom_data: Default::default() - }) - } -} - - - - -pub trait SwapEndian: Clone + Copy{ - fn swap_endian(self) -> Self; -} - -impl SwapEndian for u8{ - #[inline] - fn swap_endian(self) -> Self { - self - } -} - -impl SwapEndian for u16{ - #[inline] - fn swap_endian(self) -> Self { - self.swap_bytes() - } -} -impl SwapEndian for u32{ - #[inline] - fn swap_endian(self) -> Self { - self.swap_bytes() - } -} - -impl SwapEndian for u64{ - #[inline] - fn swap_endian(self) -> Self { - self.swap_bytes() - } -} - -impl SwapEndian for f64{ - #[inline] - fn swap_endian(self) -> Self { - //trust me this is safe - unsafe{ mem::transmute::<_, f64>(mem::transmute::<_, u64>(self).swap_bytes()) } - } -} - -impl SwapEndian for i8{ - #[inline] - fn swap_endian(self) -> Self { - self - } -} - -impl SwapEndian for i16{ - #[inline] - fn swap_endian(self) -> Self { - self.swap_bytes() - } -} -impl SwapEndian for i32{ - #[inline] - fn swap_endian(self) -> Self { - self.swap_bytes() - } -} - -impl SwapEndian for i64{ - #[inline] - fn swap_endian(self) -> Self { - self.swap_bytes() - } -} - -impl SwapEndian for (T, U){ - #[inline] - fn swap_endian(self) -> Self { - (self.0.swap_endian(), self.1.swap_endian()) - } -} - -impl SwapEndian for (T, U, V){ - #[inline] - fn swap_endian(self) -> Self { - (self.0.swap_endian(), self.1.swap_endian(), self.2.swap_endian()) - } -} - -impl SwapEndian for (T, U, V, W){ - #[inline] - fn swap_endian(self) -> Self { - (self.0.swap_endian(), self.1.swap_endian(), self.2.swap_endian(), self.3.swap_endian()) - } -} - -impl SwapEndian for [T; SIZE]{ - #[inline] - fn swap_endian(mut self) -> Self { - for elem in &mut self{ - *elem = elem.swap_endian(); - } - - self - } -} \ No newline at end of file diff --git a/src/grpc/protobufs.rs b/src/grpc/protobufs.rs deleted file mode 100644 index bae7331..0000000 --- a/src/grpc/protobufs.rs +++ /dev/null @@ -1,5 +0,0 @@ - -pub mod account { - tonic::include_proto!("account"); -} - -- 2.47.3 From 4e830686621355a5632fc398a9dd81066f475559 Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 21 Sep 2025 16:21:58 +0200 Subject: [PATCH 04/98] remove temporary file and add missing ones --- Cargo.lock | 3697 ++++++++++++++++++++++++++++++++++++++++++ bu | 12 - prudpv1/Cargo.toml | 26 + prudpv1/src/lib.rs | 2 + rnex-core/Cargo.toml | 61 + 5 files changed, 3786 insertions(+), 12 deletions(-) create mode 100644 Cargo.lock delete mode 100644 bu create mode 100644 prudpv1/Cargo.toml create mode 100644 prudpv1/src/lib.rs create mode 100644 rnex-core/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d7d6490 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3697 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[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 = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "async-trait" +version = "0.1.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + +[[package]] +name = "atomic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-lc-rs" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "binascii" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" + +[[package]] +name = "bindgen" +version = "0.69.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.104", + "which", +] + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[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 = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctrlc" +version = "3.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + +[[package]] +name = "data-encoding" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "devise" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" +dependencies = [ + "devise_codegen", + "devise_core", +] + +[[package]] +name = "devise_codegen" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" +dependencies = [ + "devise_core", + "quote", +] + +[[package]] +name = "devise_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" +dependencies = [ + "bitflags", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic 0.6.1", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[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.104", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.10.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap 2.10.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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper 1.6.0", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.6.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.0", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "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 = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[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", +] + +[[package]] +name = "indexmap" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +dependencies = [ + "equivalent", + "hashbrown 0.15.4", + "serde", +] + +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "io-uring" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "libloading" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" +dependencies = [ + "cfg-if", + "windows-targets 0.53.3", +] + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "serde", + "serde_json", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "rand 0.9.2", + "syn 2.0.104", +] + +[[package]] +name = "macros" +version = "0.1.1" +source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "multer" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.3.1", + "httparse", + "memchr", + "mime", + "spin", + "tokio", + "tokio-util", + "version_check", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +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-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pear" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" +dependencies = [ + "proc-macro2", + "syn 2.0.104", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "version_check", + "yansi", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "prudpv1" +version = "0.1.0" +dependencies = [ + "async-trait", + "bytemuck", + "hmac", + "log", + "md-5", + "once_cell", + "rc4", + "rnex-core", + "thiserror", + "tokio", + "typenum", + "v-byte-helpers", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "rc4" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1256e23efe6097f27aa82d6ca6889361c001586ae0f6917cbad072f05eb275" +dependencies = [ + "cipher", +] + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower 0.5.2", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rnex-core" +version = "0.1.1" +dependencies = [ + "anyhow", + "async-trait", + "bytemuck", + "chacha20", + "chrono", + "ctrlc", + "dotenv", + "futures", + "hex", + "hmac", + "json", + "log", + "macros 0.0.0", + "md-5", + "once_cell", + "paste", + "prost", + "rand 0.8.5", + "rc4", + "reqwest", + "rocket", + "rsa", + "rustls", + "rustls-pki-types", + "rustls-webpki", + "serde", + "sha2", + "simplelog", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-tungstenite", + "tonic", + "tungstenite", + "typenum", + "v-byte-helpers", +] + +[[package]] +name = "rocket" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" +dependencies = [ + "async-stream", + "async-trait", + "atomic 0.5.3", + "binascii", + "bytes", + "either", + "figment", + "futures", + "indexmap 2.10.0", + "log", + "memchr", + "multer", + "num_cpus", + "parking_lot", + "pin-project-lite", + "rand 0.8.5", + "ref-cast", + "rocket_codegen", + "rocket_http", + "serde", + "serde_json", + "state", + "tempfile", + "time", + "tokio", + "tokio-stream", + "tokio-util", + "ubyte", + "version_check", + "yansi", +] + +[[package]] +name = "rocket_codegen" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" +dependencies = [ + "devise", + "glob", + "indexmap 2.10.0", + "proc-macro2", + "quote", + "rocket_http", + "syn 2.0.104", + "unicode-xid", + "version_check", +] + +[[package]] +name = "rocket_http" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" +dependencies = [ + "cookie", + "either", + "futures", + "http 0.2.12", + "hyper 0.14.32", + "indexmap 2.10.0", + "log", + "memchr", + "pear", + "percent-encoding", + "pin-project-lite", + "ref-cast", + "serde", + "smallvec", + "stable-pattern", + "state", + "time", + "tokio", + "uncased", +] + +[[package]] +name = "rsa" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.9.4", + "windows-sys 0.60.2", +] + +[[package]] +name = "rustls" +version = "0.23.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "serde_json" +version = "1.0.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simplelog" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0" +dependencies = [ + "log", + "termcolor", + "time", +] + +[[package]] +name = "slab" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable-pattern" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" +dependencies = [ + "memchr", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "state" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" +dependencies = [ + "loom", +] + +[[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.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.0.8", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.10.0", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64", + "bytes", + "h2 0.4.11", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.6.0", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "socket2 0.5.10", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" +dependencies = [ + "bytes", + "data-encoding", + "http 1.3.1", + "httparse", + "log", + "rand 0.9.2", + "sha1", + "thiserror", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "ubyte" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" +dependencies = [ + "serde", +] + +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "serde", + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "v-byte-helpers" +version = "0.1.1" +source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" +dependencies = [ + "bytemuck", + "macros 0.1.1", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.104", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.44", +] + +[[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-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[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" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "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-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + +[[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]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "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-targets" +version = "0.53.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[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_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[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_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[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_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[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_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[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 = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] diff --git a/bu b/bu deleted file mode 100644 index da34886..0000000 --- a/bu +++ /dev/null @@ -1,12 +0,0 @@ - - -[build-dependencies] -tonic-build = "0.12.3" - -[features] -default = ["secure", "auth"] -secure = [] -auth = [] -no_tls = [] - - diff --git a/prudpv1/Cargo.toml b/prudpv1/Cargo.toml new file mode 100644 index 0000000..bdf340e --- /dev/null +++ b/prudpv1/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "prudpv1" +version = "0.1.0" +edition = "2024" + +[dependencies] +bytemuck = { version = "1.23.1", features = ["derive"] } +tokio = { version = "1.47.0", features = ["full"] } +hmac = "0.12.1" +md-5 = "^0.10.6" +rc4 = "0.1.0" +v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1.1" } +thiserror = "2.0.12" +log = "0.4.27" +async-trait = "0.1.88" +typenum = "1.18.0" +once_cell = "1.21.3" +rnex-core = { path = "../rnex-core", version = "0.1.1" } + +[[bin]] +name = "proxy_insecure" +path = "src/executables/proxy_insecure.rs" + +[[bin]] +name = "proxy_secure" +path = "src/executables/proxy_secure.rs" \ No newline at end of file diff --git a/prudpv1/src/lib.rs b/prudpv1/src/lib.rs new file mode 100644 index 0000000..ed53644 --- /dev/null +++ b/prudpv1/src/lib.rs @@ -0,0 +1,2 @@ +pub mod prudp; +pub mod executables; \ No newline at end of file diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml new file mode 100644 index 0000000..8a5c9bd --- /dev/null +++ b/rnex-core/Cargo.toml @@ -0,0 +1,61 @@ +[package] +name = "rnex-core" +version = "0.1.1" +edition = "2024" + +[dependencies] +bytemuck = { version = "1.21.0", features = ["derive"] } +dotenv = "0.15.0" +once_cell = "1.20.2" +rc4 = "0.1.0" +thiserror = "2.0.11" +v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1.1" } +simplelog = "0.12.2" +chrono = "0.4.39" +log = "0.4.25" +anyhow = "1.0.95" +rand = "0.8.5" + +hmac = "0.12.1" +md-5 = "^0.10.6" +tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } +tokio-stream = { version = "0.1.17", features = ["io-util"] } +tonic = "0.12.3" +prost = "0.13.4" +hex = "0.4.3" + +macros = { path = "../macros" } +rocket = { version = "0.5.1", features = ["json", "serde_json"] } +serde = { version = "1.0.217", features = ["derive"] } +async-trait = "0.1.86" +paste = "1.0.15" +typenum = "1.18.0" +futures = "0.3.31" +reqwest = "0.12.18" +json = "0.12.4" +ctrlc = "3.4.7" +rsa = "0.9.8" +sha2 = "0.10.9" +chacha20 = "0.9.1" + +rustls = "0.23.27" + +rustls-pki-types = "1.12.0" +rustls-webpki = "0.103.3" +tokio-rustls = "0.26.2" +tokio-tungstenite = "0.27.0" +tungstenite = "0.27.0" + + +[[bin]] +name = "backend_server_insecure" +path = "src/executables/backend_server_insecure.rs" + + +[[bin]] +name = "backend_server_secure" +path = "src/executables/backend_server_secure.rs" + +[[bin]] +name = "edge_node_holder_server" +path = "src/executables/edge_node_holder_server.rs" \ No newline at end of file -- 2.47.3 From c698e0b3dd749d9d02c015231f76f87f06ce9328 Mon Sep 17 00:00:00 2001 From: Maple Date: Tue, 7 Oct 2025 20:39:52 +0200 Subject: [PATCH 05/98] chore: anti pretendo people note and cleanup --- Cargo.lock | 542 +----------------- README.md | 15 +- macros/Cargo.toml | 1 - macros/src/protos.rs | 2 + prudpv1/src/executables/proxy_insecure.rs | 15 +- prudpv1/src/executables/proxy_secure.rs | 17 +- prudpv1/src/prudp/auth_module.rs | 4 +- prudpv1/src/prudp/router.rs | 13 +- prudpv1/src/prudp/socket.rs | 2 +- prudpv1/src/prudp/unsecure.rs | 2 +- rnex-core/Cargo.toml | 14 - .../executables/backend_server_insecure.rs | 25 +- .../src/executables/backend_server_secure.rs | 10 +- rnex-core/src/executables/common.rs | 7 +- .../executables/edge_node_holder_server.rs | 3 +- rnex-core/src/main.rs | 29 +- rnex-core/src/nex/matchmake.rs | 4 +- rnex-core/src/prudp/socket_addr.rs | 2 +- rnex-core/src/reggie.rs | 29 +- rnex-core/src/rmc/protocols/matchmake.rs | 2 - rnex-core/src/rmc/protocols/mod.rs | 1 + rnex-core/src/rmc/structures/list.rs | 2 - rnex-core/src/rmc/structures/mod.rs | 4 +- rnex-core/src/util.rs | 4 +- rnex-core/src/web/mod.rs | 2 +- 25 files changed, 69 insertions(+), 682 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7d6490..fb9c740 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,12 +41,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - [[package]] name = "async-stream" version = "0.3.6" @@ -107,29 +101,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "aws-lc-rs" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" -dependencies = [ - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" -dependencies = [ - "bindgen", - "cc", - "cmake", - "dunce", - "fs_extra", -] - [[package]] name = "axum" version = "0.7.9" @@ -198,41 +169,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64ct" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" - [[package]] name = "binascii" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.104", - "which", -] - [[package]] name = "bitflags" version = "2.9.1" @@ -274,12 +216,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.10.1" @@ -292,20 +228,9 @@ version = "1.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" dependencies = [ - "jobserver", - "libc", "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.1" @@ -318,17 +243,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" -[[package]] -name = "chacha20" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "chrono" version = "0.4.41" @@ -353,32 +267,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - [[package]] name = "cookie" version = "0.18.1" @@ -406,15 +294,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -435,23 +314,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - [[package]] name = "deranged" version = "0.4.0" @@ -501,7 +363,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", - "const-oid", "crypto-common", "subtle", ] @@ -523,12 +384,6 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - [[package]] name = "either" version = "1.15.0" @@ -610,12 +465,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "futures" version = "0.3.31" @@ -624,7 +473,6 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -647,34 +495,12 @@ 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.104", -] - [[package]] name = "futures-sink" version = "0.3.31" @@ -696,7 +522,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-io", - "futures-macro", "futures-sink", "futures-task", "memchr", @@ -834,15 +659,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "http" version = "0.2.12" @@ -1232,40 +1048,12 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - [[package]] name = "js-sys" version = "0.3.77" @@ -1287,15 +1075,6 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" @@ -1303,28 +1082,6 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets 0.53.3", -] - -[[package]] -name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1374,7 +1131,6 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "rand 0.9.2", "syn 2.0.104", ] @@ -1425,12 +1181,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1499,16 +1249,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1519,49 +1259,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand 0.8.5", - "smallvec", - "zeroize", -] - [[package]] name = "num-conv" 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-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -1569,7 +1272,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -1708,15 +1410,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -1755,27 +1448,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - [[package]] name = "pkg-config" version = "0.3.32" @@ -1806,16 +1478,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" -dependencies = [ - "proc-macro2", - "syn 2.0.104", -] - [[package]] name = "proc-macro2" version = "1.0.95" @@ -1845,20 +1507,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" dependencies = [ "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.104", ] [[package]] @@ -1901,18 +1549,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_chacha", + "rand_core", ] [[package]] @@ -1922,17 +1560,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", + "rand_core", ] [[package]] @@ -1944,15 +1572,6 @@ dependencies = [ "getrandom 0.2.16", ] -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.3", -] - [[package]] name = "rc4" version = "0.1.0" @@ -2093,14 +1712,11 @@ dependencies = [ name = "rnex-core" version = "0.1.1" dependencies = [ - "anyhow", "async-trait", "bytemuck", - "chacha20", "chrono", "ctrlc", "dotenv", - "futures", "hex", "hmac", "json", @@ -2109,25 +1725,14 @@ dependencies = [ "md-5", "once_cell", "paste", - "prost", - "rand 0.8.5", + "rand", "rc4", "reqwest", "rocket", - "rsa", - "rustls", - "rustls-pki-types", - "rustls-webpki", - "serde", - "sha2", "simplelog", "thiserror", "tokio", - "tokio-rustls", - "tokio-stream", - "tokio-tungstenite", "tonic", - "tungstenite", "typenum", "v-byte-helpers", ] @@ -2153,7 +1758,7 @@ dependencies = [ "num_cpus", "parking_lot", "pin-project-lite", - "rand 0.8.5", + "rand", "ref-cast", "rocket_codegen", "rocket_http", @@ -2214,51 +1819,12 @@ dependencies = [ "uncased", ] -[[package]] -name = "rsa" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core 0.6.4", - "signature", - "spki", - "subtle", - "zeroize", -] - [[package]] name = "rustc-demangle" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.0.8" @@ -2268,7 +1834,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.9.4", + "linux-raw-sys", "windows-sys 0.60.2", ] @@ -2278,8 +1844,6 @@ version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ - "aws-lc-rs", - "log", "once_cell", "rustls-pki-types", "rustls-webpki", @@ -2302,7 +1866,6 @@ version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ - "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -2417,28 +1980,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sharded-slab" version = "0.1.7" @@ -2463,16 +2004,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core 0.6.4", -] - [[package]] name = "simplelog" version = "0.12.2" @@ -2522,16 +2053,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - [[package]] name = "stable-pattern" version = "0.1.0" @@ -2634,7 +2155,7 @@ dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.8", + "rustix", "windows-sys 0.59.0", ] @@ -2781,18 +2302,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-tungstenite" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite", -] - [[package]] name = "tokio-util" version = "0.7.15" @@ -2888,7 +2397,7 @@ dependencies = [ "indexmap 1.9.3", "pin-project", "pin-project-lite", - "rand 0.8.5", + "rand", "slab", "tokio", "tokio-util", @@ -3009,23 +2518,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d" -dependencies = [ - "bytes", - "data-encoding", - "http 1.3.1", - "httparse", - "log", - "rand 0.9.2", - "sha1", - "thiserror", - "utf-8", -] - [[package]] name = "typenum" version = "1.18.0" @@ -3080,12 +2572,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -3224,18 +2710,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "winapi" version = "0.3.9" diff --git a/README.md b/README.md index f0526a0..c5f1ada 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,17 @@ - Pretendo team for the rest of the Servers and Reverse engineering efforts - Kinnay for his huge work on reversing nex servers and documentation(https://github.com/Kinnay/NintendoClients/) - Splatfestival testing team for helping us test our messes of code -- The SPFN team(Bloxer, Ceantix and Maple(aka TV)) \ No newline at end of file +- The SPFN team(Bloxer, Ceantix and RusticMaple) + +This nex implementation was not created and is not intended to compete with pretendo, +we wholeheartedly support pretendo. +This project would never have been possible without their reverse engineering efforts. +As such if you want to respect the Authors wishes(Maple(Me) is pretty much the sole author of Rust-Nex), do not +use it if you mean any harm to pretendo. If you do show intent to harm them you will be blocked from ever contributing +and will be refused support, as such please also refrain from asking for support if you have been blocked by pretendo. + + +I felt like this needed to be said as there are far too many pretendo copycats who blatantly copy their code and use +their reversal efforts with no credits in sight in an attempt to harm them for some grudge or stupid reason. +I feel that by working together and not against each other we can reach a better and healthier future for the community, +health of developers and numerous more reasons. diff --git a/macros/Cargo.toml b/macros/Cargo.toml index e301949..d0bb83b 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -13,5 +13,4 @@ proc-macro = true quote = "1.0.38" proc-macro2 = "1.0.93" syn = { version = "2.0.98", features = ["full"] } -rand = "0.9.0" diff --git a/macros/src/protos.rs b/macros/src/protos.rs index 711e931..a19f01e 100644 --- a/macros/src/protos.rs +++ b/macros/src/protos.rs @@ -39,6 +39,7 @@ impl RmcProtocolData{ // boilerplate tokens which all raw traits need quote!{ #[doc(hidden)] + #[allow(unused_must_use)] pub trait #raw_name: #name }.to_tokens(tokens); @@ -209,6 +210,7 @@ impl RmcProtocolData{ // boilerplate tokens which all raw traits need quote!{ #[doc(hidden)] + #[allow(unused_must_use)] pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection }.to_tokens(tokens); diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 3ffe039..b33e069 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -2,17 +2,11 @@ use rnex_core::reggie::UnitPacketRead; use rnex_core::reggie::UnitPacketWrite; use rnex_core::rmc::structures::RmcSerialize; -use std::env; -use std::ffi::CStr; -use std::io::{Read, Write}; -use std::net::{Ipv4Addr, SocketAddrV4}; -use std::sync::{Arc, OnceLock}; +use std::net::SocketAddrV4; +use std::sync::Arc; use std::time::Duration; -use bytemuck::{Pod, Zeroable}; -use log::{error, warn}; -use once_cell::sync::Lazy; -use tokio::net::{TcpSocket, TcpStream}; -use tokio::sync::RwLock; +use log::error; +use tokio::net::TcpStream; use tokio::task; use tokio::time::sleep; use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER}; @@ -110,4 +104,5 @@ async fn main() { } }); } + drop(conn); } \ No newline at end of file diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index b66fbc2..91a66fa 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -1,23 +1,16 @@ use rnex_core::reggie::UnitPacketRead; use rnex_core::reggie::UnitPacketWrite; use rnex_core::rmc::structures::RmcSerialize; -use std::env; -use std::ffi::CStr; -use std::io::{Read, Write}; -use std::net::{Ipv4Addr, SocketAddrV4}; -use std::sync::{Arc, OnceLock}; +use std::net::SocketAddrV4; +use std::sync::Arc; use std::time::Duration; -use bytemuck::{Pod, Zeroable}; -use log::{error, warn}; -use once_cell::sync::Lazy; -use tokio::net::{TcpSocket, TcpStream}; -use tokio::sync::RwLock; +use log::error; +use tokio::net::TcpStream; use tokio::task; use tokio::time::sleep; use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER}; use prudpv1::prudp::router::Router; use prudpv1::prudp::secure::Secure; -use prudpv1::prudp::unsecure::Unsecure; use rnex_core::common::setup; use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT}; use rnex_core::prudp::virtual_port::VirtualPort; @@ -113,4 +106,6 @@ async fn main() { } }); } + + drop(conn); } \ No newline at end of file diff --git a/prudpv1/src/prudp/auth_module.rs b/prudpv1/src/prudp/auth_module.rs index d7e93b0..28659d6 100644 --- a/prudpv1/src/prudp/auth_module.rs +++ b/prudpv1/src/prudp/auth_module.rs @@ -1,8 +1,8 @@ +/* use std::net::Ipv4Addr; - pub trait AuthModule{ fn get_auth_key(addr: Ipv4Addr) -> [u8; 32]; -} +}*/ /* struct AuthServerAuthModule; diff --git a/prudpv1/src/prudp/router.rs b/prudpv1/src/prudp/router.rs index 3212155..ca28dd6 100644 --- a/prudpv1/src/prudp/router.rs +++ b/prudpv1/src/prudp/router.rs @@ -1,14 +1,12 @@ -use std::{env, io}; +use std::io; use std::io::Cursor; use std::marker::PhantomData; use tokio::net::UdpSocket; use std::net::{SocketAddr, SocketAddrV4}; use std::net::SocketAddr::V4; use std::sync::{Arc, Weak}; -use std::sync::atomic::{AtomicBool}; use std::time::Duration; use tokio::task::JoinHandle; -use once_cell::sync::Lazy; use log::{error, info}; use thiserror::Error; use tokio::select; @@ -19,16 +17,11 @@ use crate::prudp::packet::{PRUDPV1Packet}; use rnex_core::prudp::virtual_port::VirtualPort; use crate::prudp::router::Error::VirtualPortTaken; -static SERVER_DATAGRAMS: Lazy = Lazy::new(||{ - env::var("SERVER_DATAGRAM_COUNT").ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(1) -}); pub struct Router { endpoints: RwLock<[Option>; 16]>, - running: AtomicBool, + //running: AtomicBool, socket: Arc, _no_outside_construction: PhantomData<()> } @@ -114,7 +107,7 @@ impl Router { let own_impl = Router { endpoints: Default::default(), - running: AtomicBool::new(true), + // running: AtomicBool::new(true), socket: socket.clone(), _no_outside_construction: Default::default() }; diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index dde9b4d..4aca993 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -679,7 +679,7 @@ impl AnyInternalSocket for InternalSocket { self.send_packet_unbuffered(address, packet).await; - let Some(connect_ack_packet) = recv.recv().await else { + let Some(_connect_ack_packet) = recv.recv().await else { error!("what"); return None; }; diff --git a/prudpv1/src/prudp/unsecure.rs b/prudpv1/src/prudp/unsecure.rs index 6d7d9ff..6c45824 100644 --- a/prudpv1/src/prudp/unsecure.rs +++ b/prudpv1/src/prudp/unsecure.rs @@ -78,7 +78,7 @@ impl CryptoHandlerConnectionInstance for UnsecureInstance { packet.calculate_and_assign_signature(self.key, None, Some(self.self_signature)); } - fn verify_packet(&self, packet: &PRUDPV1Packet) -> bool { + fn verify_packet(&self, _packet: &PRUDPV1Packet) -> bool { true } } \ No newline at end of file diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 8a5c9bd..b41bc8d 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -13,38 +13,24 @@ v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1 simplelog = "0.12.2" chrono = "0.4.39" log = "0.4.25" -anyhow = "1.0.95" rand = "0.8.5" hmac = "0.12.1" md-5 = "^0.10.6" tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } -tokio-stream = { version = "0.1.17", features = ["io-util"] } tonic = "0.12.3" -prost = "0.13.4" hex = "0.4.3" macros = { path = "../macros" } rocket = { version = "0.5.1", features = ["json", "serde_json"] } -serde = { version = "1.0.217", features = ["derive"] } async-trait = "0.1.86" paste = "1.0.15" typenum = "1.18.0" -futures = "0.3.31" reqwest = "0.12.18" json = "0.12.4" ctrlc = "3.4.7" -rsa = "0.9.8" -sha2 = "0.10.9" -chacha20 = "0.9.1" -rustls = "0.23.27" -rustls-pki-types = "1.12.0" -rustls-webpki = "0.103.3" -tokio-rustls = "0.26.2" -tokio-tungstenite = "0.27.0" -tungstenite = "0.27.0" [[bin]] diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 005936b..7a9f88a 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,32 +1,17 @@ use rnex_core::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; use log::{error, info}; use once_cell::sync::Lazy; -use rustls::client::danger::HandshakeSignatureValid; -use rustls::pki_types::{CertificateDer, TrustAnchor, UnixTime}; -use rustls::server::danger::{ClientCertVerified, ClientCertVerifier}; -use rustls::server::{ClientCertVerifierBuilder, WebPkiClientVerifier}; -use rustls::{ - DigitallySignedStruct, DistinguishedName, Error, RootCertStore, ServerConfig, ServerConnection, - SignatureScheme, -}; -use rustls_pki_types::PrivateKeyDer; use rnex_core::common::setup; -use std::borrow::ToOwned; -use std::{env, fs}; +use std::{env}; use std::io::Cursor; -use std::net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}; +use std::net::SocketAddrV4; use std::sync::Arc; -use macros::{method_id, rmc_proto, rmc_struct}; -use tokio::io::AsyncReadExt; -use tokio::net::{TcpListener, TcpSocket, TcpStream}; +use tokio::net::{TcpListener, TcpStream}; use tokio::task; -use tokio_rustls::TlsAcceptor; -use rnex_core::define_rmc_proto; use rnex_core::executables::common::{OWN_IP_PRIVATE, SECURE_SERVER_ACCOUNT, SERVER_PORT}; use rnex_core::nex::auth_handler::AuthHandler; use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; -use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::util::SplittableBufferConnection; @@ -57,7 +42,7 @@ async fn main() { - while let Ok((mut stream, addr)) = listen.accept().await { + while let Ok((mut stream, _addr)) = listen.accept().await { let buffer = match stream.read_buffer().await{ Ok(v) => v, Err(e) => { @@ -68,7 +53,7 @@ async fn main() { let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer)); - let user_connection_data = match user_connection_data{ + let _user_connection_data = match user_connection_data{ Ok(v) => v, Err(e) => { error!("an error ocurred whilest reading connection data: {:?}", e); diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs index f758679..82d1a39 100644 --- a/rnex-core/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -1,22 +1,20 @@ use std::io::Cursor; use rnex_core::rmc::structures::RmcSerialize; -use rnex_core::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; +use rnex_core::reggie::UnitPacketRead; use std::net::SocketAddrV4; use std::sync::Arc; use std::sync::atomic::AtomicU32; use log::{error, info}; -use tokio::net::{TcpListener, TcpStream}; +use tokio::net::TcpListener; use tokio::task; use rnex_core::common::setup; use rnex_core::executables::common::{OWN_IP_PRIVATE, SERVER_PORT}; use rnex_core::nex::matchmake::MatchmakeManager; use rnex_core::nex::remote_console::RemoteConsole; use rnex_core::nex::user::User; -use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; -use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::rmc::protocols::new_rmc_gateway_connection; use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::rmc::protocols::RemoteInstantiatable; -use rnex_core::util::SplittableBufferConnection; #[tokio::main] async fn main() { @@ -35,7 +33,7 @@ async fn main() { MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - while let Ok((mut stream, addr)) = listen.accept().await { + while let Ok((mut stream, _addr)) = listen.accept().await { let buffer = match stream.read_buffer().await{ Ok(v) => v, Err(e) => { diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index 77bccf7..f12a84c 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -1,12 +1,7 @@ use std::env; -use std::net::{Ipv4Addr, SocketAddrV4}; -use macros::{method_id, rmc_proto, RmcSerialize}; +use std::net::Ipv4Addr; use once_cell::sync::Lazy; -use tonic::transport::Server; -use crate::define_rmc_proto; -use crate::prudp::station_url::StationUrl; use crate::nex::account::Account; -use crate::rmc::response::ErrorCode; pub static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { env::var("SERVER_IP") diff --git a/rnex-core/src/executables/edge_node_holder_server.rs b/rnex-core/src/executables/edge_node_holder_server.rs index 5146a86..ea798c5 100644 --- a/rnex-core/src/executables/edge_node_holder_server.rs +++ b/rnex-core/src/executables/edge_node_holder_server.rs @@ -1,7 +1,6 @@ use std::io::Cursor; use std::net::SocketAddrV4; use std::sync::{Arc, Weak}; -use log::error; use macros::rmc_struct; use tokio::net::TcpListener; use tokio::sync::RwLock; @@ -56,7 +55,7 @@ async fn main() { let holder: Arc = Default::default(); - while let Ok((mut stream, addr)) = listen.accept().await { + while let Ok((stream, _addr)) = listen.accept().await { let mut conn: SplittableBufferConnection = stream.into(); let Some(data) = conn.recv().await else { diff --git a/rnex-core/src/main.rs b/rnex-core/src/main.rs index b3b226b..0af4975 100644 --- a/rnex-core/src/main.rs +++ b/rnex-core/src/main.rs @@ -11,40 +11,15 @@ extern crate self as rust_nex; use crate::nex::account::Account; -use crate::nex::auth_handler::{AuthHandler, RemoteAuthClientProtocol}; -use crate::nex::remote_console::RemoteConsole; -use crate::nex::user::{RemoteUserProtocol, User}; -use crate::rmc::protocols::auth::Auth; -use crate::rmc::protocols::auth::RawAuth; -use crate::rmc::protocols::auth::RawAuthInfo; -use crate::rmc::protocols::auth::RemoteAuth; -use crate::rmc::protocols::matchmake_extension::RemoteMatchmakeExtension; -use crate::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote, RemoteInstantiatable}; -use crate::rmc::response::ErrorCode; -use crate::rmc::structures::any::Any; -use crate::rmc::structures::connection_data::ConnectionData; -use crate::rmc::structures::matchmake::{CreateMatchmakeSessionParam, Gathering, MatchmakeParam, MatchmakeSession}; -use crate::rmc::structures::qresult::QResult; use chrono::{Local, SecondsFormat}; -use log::{error, info}; -use macros::rmc_struct; use once_cell::sync::Lazy; use simplelog::{ ColorChoice, CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode, WriteLogger, }; use std::fs::File; -use std::marker::PhantomData; -use std::net::{Ipv4Addr, SocketAddrV4}; -use std::ops::{BitAnd, BitOr}; -use std::str::FromStr; -use std::sync::{Arc, Once, Weak}; -use std::time::Duration; +use std::net::{Ipv4Addr}; +use std::sync::Once; use std::{env, fs}; -use std::sync::atomic::AtomicU32; -use tokio::task::JoinHandle; -use crate::kerberos::KerberosDateTime; -use crate::nex::matchmake::MatchmakeManager; -use crate::rmc::protocols::secure::RemoteSecure; mod prudp; pub mod rmc; diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 1f4f61a..93e8ced 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -203,7 +203,7 @@ impl ExtendedMatchmakeSession{ }; - let other_pid = other_conn.pid; + // let other_pid = other_conn.pid; /*if other_pid == self.session.gathering.owner_pid && joining_pid == self.session.gathering.owner_pid{ continue; @@ -341,7 +341,7 @@ impl ExtendedMatchmakeSession{ } pub async fn migrate_host(&mut self, initiator_pid: u32) -> Result<(), ErrorCode>{ - let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect(); + // let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect(); self.session.gathering.host_pid = self.session.gathering.owner_pid; diff --git a/rnex-core/src/prudp/socket_addr.rs b/rnex-core/src/prudp/socket_addr.rs index f3ea10c..5c55e88 100644 --- a/rnex-core/src/prudp/socket_addr.rs +++ b/rnex-core/src/prudp/socket_addr.rs @@ -28,7 +28,7 @@ impl PRUDPSockAddr{ pub fn calculate_connection_signature(&self) -> [u8; 16] { let mut hmac = Md5Hmac::new_from_slice(&[0; 16]).expect("fuck"); - let mut data = self.regular_socket_addr.ip().octets().to_vec(); + let data = self.regular_socket_addr.ip().octets().to_vec(); //data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes()); hmac.write_all(&data).expect("figuring this out was complete ass"); diff --git a/rnex-core/src/reggie.rs b/rnex-core/src/reggie.rs index b3d73c9..47bf2d2 100644 --- a/rnex-core/src/reggie.rs +++ b/rnex-core/src/reggie.rs @@ -1,29 +1,8 @@ -use std::{env, fs, io}; -use std::hash::Hash; -use std::io::{Error, ErrorKind}; -use std::net::{SocketAddrV4, ToSocketAddrs}; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll}; -use futures::{SinkExt, StreamExt}; -use macros::{method_id, rmc_proto, rmc_struct, RmcSerialize}; -use once_cell::sync::Lazy; -use rustls::{ClientConfig, RootCertStore, ServerConfig}; -use rustls::client::WebPkiServerVerifier; -use rustls::server::WebPkiClientVerifier; -use rustls_pki_types::{CertificateDer, PrivateKeyDer, ServerName, TrustAnchor}; -use thiserror::Error; -use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf}; -use tokio::net::{TcpListener, TcpStream}; -use tokio_rustls::{TlsAcceptor, TlsConnector}; -use tokio_rustls::client::TlsStream; -use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream}; -use tokio_tungstenite::tungstenite::Message; -use webpki::anchor_from_trusted_cert; -use crate::common::setup; +use std::io; +use std::net::SocketAddrV4; +use macros::{method_id, rmc_proto, RmcSerialize}; +use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use crate::define_rmc_proto; -use crate::nex::account::Account; -use crate::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote, RmcCallable, RmcConnection}; use rnex_core::rmc::response::ErrorCode; use crate::rmc::structures::RmcSerialize; diff --git a/rnex-core/src/rmc/protocols/matchmake.rs b/rnex-core/src/rmc/protocols/matchmake.rs index 24942c0..595127a 100644 --- a/rnex-core/src/rmc/protocols/matchmake.rs +++ b/rnex-core/src/rmc/protocols/matchmake.rs @@ -8,10 +8,8 @@ pub trait Matchmake{ async fn unregister_gathering(&self, gid: u32) -> Result; #[method_id(41)] async fn get_session_urls(&self, gid: u32) -> Result, ErrorCode>; - #[method_id(42)] async fn update_session_host(&self, gid: u32, change_owner: bool) -> Result<(), ErrorCode>; - #[method_id(44)] async fn migrate_gathering_ownership(&self, gid: u32, candidates: Vec, participants_only: bool) -> Result<(), ErrorCode>; } \ No newline at end of file diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index 7ad8e8c..0b6fc65 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -153,6 +153,7 @@ macro_rules! define_rmc_proto { $($protocol:path),* }) => { paste::paste!{ + #[allow(unused_variables)] pub trait []: std::any::Any $( + [] + $protocol)* { async fn rmc_call(&self, remote_response_connection: &rnex_core::util::SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ match protocol_id{ diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs index 1ebb60b..f4843c1 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -1,8 +1,6 @@ -use std::array::from_fn; use std::io::{Read, Write}; use std::mem::MaybeUninit; use bytemuck::bytes_of; -use serde::Serialize; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index fd6d61d..9d127f7 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -49,10 +49,10 @@ pub trait RmcSerialize{ } impl RmcSerialize for (){ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, _writer: &mut dyn Write) -> Result<()> { Ok(()) } - fn deserialize(reader: &mut dyn Read) -> Result { + fn deserialize(_reader: &mut dyn Read) -> Result { Ok(()) } diff --git a/rnex-core/src/util.rs b/rnex-core/src/util.rs index b052fe2..ff0150c 100644 --- a/rnex-core/src/util.rs +++ b/rnex-core/src/util.rs @@ -81,7 +81,9 @@ impl SplittableBufferConnection { } } } - stream.shutdown().await; + if let Err(e) = stream.shutdown().await{ + error!("failed to shut down stream: {}", e); + } }); } diff --git a/rnex-core/src/web/mod.rs b/rnex-core/src/web/mod.rs index cd2bcf2..9412967 100644 --- a/rnex-core/src/web/mod.rs +++ b/rnex-core/src/web/mod.rs @@ -13,7 +13,7 @@ struct RnexApiAuth; impl<'r> FromRequest<'r> for RnexApiAuth{ type Error = (); - async fn from_request<'a>(request: &'r Request<'a>) -> Outcome { + async fn from_request<'a>(_request: &'r Request<'a>) -> Outcome { Outcome::Success(RnexApiAuth) } } -- 2.47.3 From d7f1ee404080ff169a9ff620fdbf8908688d8139 Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 5 Nov 2025 21:54:47 +0100 Subject: [PATCH 06/98] update ci --- .gitlab-ci.yml | 33 +++++++++++++++++++++------------ Dockerfile | 26 ++++++++++++++++++++------ 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 56c6940..02de8a8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,28 @@ -image: docker:latest +default: + image: quay.io/podman/stable variables: - IMAGE_NAME: "ci.perditum.com/perditum/rnex-splatoon" + DOCKER_TLS_CERTDIR: "/certs" IMAGE_TAG: "${CI_COMMIT_REF_SLUG}" -before_script: - - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" ci.perditum.com - stages: - - build-and-push + - test + - build-and-push-image + - push-retagged-branch + - push-retagged-latest -build-and-push: - stage: build-and-push +build-and-push-image: + stage: build-and-push-image script: - - docker build -t "$IMAGE_NAME:$IMAGE_TAG" . - - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$IMAGE_NAME:latest" - - docker push "$IMAGE_NAME:$IMAGE_TAG" - - docker push "$IMAGE_NAME:latest" + - git submodule update --init + - podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - podman build -t "$CI_REGISTRY_IMAGE/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . + - podman build -t "$CI_REGISTRY_IMAGE/proxy-secure-v1:$CI_COMMIT_SHORT_SHA" --target=proxy-secure-v1 . + - podman build -t "$CI_REGISTRY_IMAGE/proxy-insecure-v1:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure-v1 . + - podman build -t "$CI_REGISTRY_IMAGE/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth . + - podman build -t "$CI_REGISTRY_IMAGE/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure . + - podman push "$CI_REGISTRY_IMAGE/node-holder:$CI_COMMIT_SHORT_SHA" + - podman push "$CI_REGISTRY_IMAGE/proxy-secure-v1:$CI_COMMIT_SHORT_SHA" + - podman push "$CI_REGISTRY_IMAGE/proxy-insecure-v1:$CI_COMMIT_SHORT_SHA" + - podman push "$CI_REGISTRY_IMAGE/backend-auth:$CI_COMMIT_SHORT_SHA" + - podman push "$CI_REGISTRY_IMAGE/backend-secure:$CI_COMMIT_SHORT_SHA" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 74f7efd..5d32b23 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,12 +9,26 @@ RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-st RUN git submodule update --init --recursive RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --target x86_64-unknown-linux-musl -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --profile prod --target x86_64-unknown-linux-musl +RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --profile prod --target x86_64-unknown-linux-musl # -FROM scratch AS final +FROM scratch AS node-holder +COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/edge_node_holder_server /edge_node_holder_server +ENTRYPOINT ["/edge_node_holder_server"] -# Copy the compiled binary from the builder stage -COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/splatoon-server-rust /splatoon-server-rust -# Command to run the application -ENTRYPOINT ["/splatoon-server-rust"] +FROM scratch AS proxy-insecure-v1 +COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/proxy_insecure /proxy_insecure +ENTRYPOINT ["/proxy_insecure"] + +FROM scratch AS proxy-secure-v1 +COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/proxy_secure /proxy_secure +ENTRYPOINT ["/proxy_secure"] + + +FROM scratch AS backend-auth +COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/backend_server_insecure /backend_server_insecure +ENTRYPOINT ["/backend_server_secure"] + +FROM scratch AS backend-secure +COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/backend_server_secure /backend_server_secure +ENTRYPOINT ["/backend_server_secure"] -- 2.47.3 From 58eecef9058e464e9a718ce60032bab0326eff2a Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 5 Nov 2025 21:57:57 +0100 Subject: [PATCH 07/98] fix ci --- rnex-core/src/grpc/account.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/rnex-core/src/grpc/account.rs b/rnex-core/src/grpc/account.rs index d369501..5f49cbd 100644 --- a/rnex-core/src/grpc/account.rs +++ b/rnex-core/src/grpc/account.rs @@ -136,21 +136,4 @@ impl Client{ Ok(response) } } -*/ -#[cfg(test)] -mod test{ - use crate::grpc::account::Client; - - #[tokio::test] - async fn test(){ - dotenv::dotenv().ok(); - - let mut client = Client::new().await.unwrap(); - - let cli = client.get_nex_password(1699562916).await.unwrap(); - - println!("{:?}", cli); - } - - -} \ No newline at end of file +*/ \ No newline at end of file -- 2.47.3 From b8e24686db474bfa30b108652016b2f31937a7db Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 5 Nov 2025 22:03:03 +0100 Subject: [PATCH 08/98] disable doctests for macros --- macros/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/macros/Cargo.toml b/macros/Cargo.toml index d0bb83b..dca135c 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [lib] proc-macro = true +doctest = false [dependencies] quote = "1.0.38" -- 2.47.3 From c978ee8e8482e15a319977e30f28655abd287413 Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 5 Nov 2025 22:09:43 +0100 Subject: [PATCH 09/98] remove prod profile from dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 5d32b23..f482893 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-st RUN git submodule update --init --recursive RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --target x86_64-unknown-linux-musl -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --profile prod --target x86_64-unknown-linux-musl # +RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --target x86_64-unknown-linux-musl # FROM scratch AS node-holder COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/edge_node_holder_server /edge_node_holder_server -- 2.47.3 From d008859ad433776fb2fc8254dc7bd51bcdfc8c8a Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 5 Nov 2025 22:13:56 +0100 Subject: [PATCH 10/98] fix dockerfile --- Dockerfile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index f482893..422eacb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,23 +12,23 @@ RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_ST RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --target x86_64-unknown-linux-musl # FROM scratch AS node-holder -COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/edge_node_holder_server /edge_node_holder_server +COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /edge_node_holder_server ENTRYPOINT ["/edge_node_holder_server"] FROM scratch AS proxy-insecure-v1 -COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/proxy_insecure /proxy_insecure +COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /proxy_insecure ENTRYPOINT ["/proxy_insecure"] FROM scratch AS proxy-secure-v1 -COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/proxy_secure /proxy_secure +COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure ENTRYPOINT ["/proxy_secure"] FROM scratch AS backend-auth -COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/backend_server_insecure /backend_server_insecure +COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /backend_server_insecure ENTRYPOINT ["/backend_server_secure"] FROM scratch AS backend-secure -COPY --from=builder /app/target/x86_64-unknown-linux-musl/prod/backend_server_secure /backend_server_secure +COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /backend_server_secure ENTRYPOINT ["/backend_server_secure"] -- 2.47.3 From 41955a7e21a3bf22a350529fef9230c8a428ed65 Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 5 Nov 2025 22:21:17 +0100 Subject: [PATCH 11/98] build for release --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 422eacb..c65fcff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-st RUN git submodule update --init --recursive RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --target x86_64-unknown-linux-musl -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --target x86_64-unknown-linux-musl # +RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --target x86_64-unknown-linux-musl # FROM scratch AS node-holder COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /edge_node_holder_server -- 2.47.3 From d352e7537cdd9140be343868ed916a62315806f7 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Wed, 5 Nov 2025 22:47:06 +0100 Subject: [PATCH 12/98] add dev container and default ip --- Dockerfile | 11 ++++++++--- devcontainer.json | 3 +++ rnex-core/src/executables/common.rs | 4 ++-- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 devcontainer.json diff --git a/Dockerfile b/Dockerfile index c65fcff..30cd59f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,13 @@ -FROM rust:alpine AS builder +FROM rust:alpine AS dev-container + +RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static + +FROM dev-container as builder WORKDIR /app COPY . . -RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static - RUN git submodule update --init --recursive RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --target x86_64-unknown-linux-musl @@ -32,3 +34,6 @@ ENTRYPOINT ["/backend_server_secure"] FROM scratch AS backend-secure COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /backend_server_secure ENTRYPOINT ["/backend_server_secure"] + +# make sure the final output container is the dev container so that we can use it from the devcontainer.json +FROM final as dev-container diff --git a/devcontainer.json b/devcontainer.json new file mode 100644 index 0000000..a1447f1 --- /dev/null +++ b/devcontainer.json @@ -0,0 +1,3 @@ +{ + "build": { "dockerfile": "Dockerfile" } +} diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index f12a84c..5697d7c 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -6,8 +6,8 @@ use crate::nex::account::Account; pub static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { env::var("SERVER_IP") .ok() - .and_then(|s| s.parse().ok()) - .expect("SERVER_IP not specified") + .map(|s| s.parse().expect("invalid ip address")) + .unwrap_or(Ipv4Addr::UNSPECIFIED) }); pub static OWN_IP_PUBLIC: Lazy = Lazy::new(|| { -- 2.47.3 From d8e53407bcedcbb1308d6ae2ad34d375fe542388 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Wed, 5 Nov 2025 22:50:51 +0100 Subject: [PATCH 13/98] fix devcontainer --- devcontainer.json => .devcontainer.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename devcontainer.json => .devcontainer.json (100%) diff --git a/devcontainer.json b/.devcontainer.json similarity index 100% rename from devcontainer.json rename to .devcontainer.json -- 2.47.3 From 3672e0194406136a6f69be9b12866760c657af0e Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Wed, 5 Nov 2025 22:53:32 +0100 Subject: [PATCH 14/98] fix dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 30cd59f..4463896 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM rust:alpine AS dev-container RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static -FROM dev-container as builder +FROM dev-container AS builder WORKDIR /app @@ -36,4 +36,4 @@ COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server ENTRYPOINT ["/backend_server_secure"] # make sure the final output container is the dev container so that we can use it from the devcontainer.json -FROM final as dev-container +FROM dev-container AS final -- 2.47.3 From 66d323fe731422642949a15e67cfff8667c2b7b1 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Thu, 6 Nov 2025 22:22:37 +0100 Subject: [PATCH 15/98] add devcontainer build to ci --- .devcontainer.json | 2 +- .gitlab-ci.yml | 6 +++--- Dockerfile | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.devcontainer.json b/.devcontainer.json index a1447f1..ac711b7 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -1,3 +1,3 @@ { - "build": { "dockerfile": "Dockerfile" } + "image": "ci.virintox.com/spfn/rust-nex/dev-container:latest" } diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 02de8a8..24011c9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,14 +8,14 @@ variables: stages: - test - build-and-push-image - - push-retagged-branch - - push-retagged-latest build-and-push-image: stage: build-and-push-image script: - git submodule update --init - podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - podman build -t "$CI_REGISTRY_IMAGE/dev-container:latest" --target=dev-container . + - podman push "$CI_REGISTRY_IMAGE/dev-container:latest" - podman build -t "$CI_REGISTRY_IMAGE/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . - podman build -t "$CI_REGISTRY_IMAGE/proxy-secure-v1:$CI_COMMIT_SHORT_SHA" --target=proxy-secure-v1 . - podman build -t "$CI_REGISTRY_IMAGE/proxy-insecure-v1:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure-v1 . @@ -25,4 +25,4 @@ build-and-push-image: - podman push "$CI_REGISTRY_IMAGE/proxy-secure-v1:$CI_COMMIT_SHORT_SHA" - podman push "$CI_REGISTRY_IMAGE/proxy-insecure-v1:$CI_COMMIT_SHORT_SHA" - podman push "$CI_REGISTRY_IMAGE/backend-auth:$CI_COMMIT_SHORT_SHA" - - podman push "$CI_REGISTRY_IMAGE/backend-secure:$CI_COMMIT_SHORT_SHA" \ No newline at end of file + - podman push "$CI_REGISTRY_IMAGE/backend-secure:$CI_COMMIT_SHORT_SHA" diff --git a/Dockerfile b/Dockerfile index 4463896..c3b8a2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM rust:alpine AS dev-container RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static -FROM dev-container AS builder +FROM build-container AS builder WORKDIR /app @@ -36,4 +36,5 @@ COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server ENTRYPOINT ["/backend_server_secure"] # make sure the final output container is the dev container so that we can use it from the devcontainer.json -FROM dev-container AS final +FROM build-container AS dev-container +RUN apk add openjdk21-jdk gcompat -- 2.47.3 From 79835a1e199a0caed5ffbefcfd4ff761c27998bb Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Thu, 6 Nov 2025 22:25:17 +0100 Subject: [PATCH 16/98] fix dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c3b8a2c..0438d5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:alpine AS dev-container +FROM rust:alpine AS build-container RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static -- 2.47.3 From e2b564cc48cfecacb3b0a68ae01de705536871af Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Thu, 6 Nov 2025 22:55:41 +0000 Subject: [PATCH 17/98] add public ip inferrence --- Cargo.lock | 2 ++ rnex-core/Cargo.toml | 2 +- rnex-core/src/executables/common.rs | 16 ++++++++++++++-- rnex-core/src/prudp/socket_addr.rs | 1 - 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb9c740..82797de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1663,7 +1663,9 @@ dependencies = [ "base64", "bytes", "encoding_rs", + "futures-channel", "futures-core", + "futures-util", "h2 0.4.11", "http 1.3.1", "http-body 1.0.1", diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index b41bc8d..90ce871 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -26,7 +26,7 @@ rocket = { version = "0.5.1", features = ["json", "serde_json"] } async-trait = "0.1.86" paste = "1.0.15" typenum = "1.18.0" -reqwest = "0.12.18" +reqwest = { version= "0.12.18", features = ["blocking"]} json = "0.12.4" ctrlc = "3.4.7" diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index 5697d7c..0c553b4 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -2,6 +2,16 @@ use std::env; use std::net::Ipv4Addr; use once_cell::sync::Lazy; use crate::nex::account::Account; +use std::error::Error; + +const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip"; + + + +fn try_get_ip() -> Result> { + let req = reqwest::blocking::get(IP_REQ_SERVICE_URL)?; + Ok(req.text()?.parse()?) +} pub static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { env::var("SERVER_IP") @@ -13,8 +23,10 @@ pub static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { pub static OWN_IP_PUBLIC: Lazy = Lazy::new(|| { env::var("SERVER_IP_PUBLIC") .ok() - .and_then(|s| s.parse().ok()) - .expect("SERVER_IP_PUBLIC not specified") + .map(|s| s.parse().expect("invalid ip address")) + .unwrap_or_else(||{ + try_get_ip().unwrap() + }) }); pub static SERVER_PORT: Lazy = Lazy::new(|| { diff --git a/rnex-core/src/prudp/socket_addr.rs b/rnex-core/src/prudp/socket_addr.rs index 5c55e88..f5eb179 100644 --- a/rnex-core/src/prudp/socket_addr.rs +++ b/rnex-core/src/prudp/socket_addr.rs @@ -17,7 +17,6 @@ pub struct PRUDPSockAddr{ impl PRUDPSockAddr{ - pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self{ Self{ regular_socket_addr, -- 2.47.3 From a64699442ee7ad6c65bbc4d9ac0674dc5507ad44 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Fri, 7 Nov 2025 18:06:22 +0000 Subject: [PATCH 18/98] fix auth backend in dockerfile --- Dockerfile | 6 +++--- rnex-core/src/grpc/mod.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0438d5e..70d1b46 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,11 +25,11 @@ ENTRYPOINT ["/proxy_insecure"] FROM scratch AS proxy-secure-v1 COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure ENTRYPOINT ["/proxy_secure"] - - + + FROM scratch AS backend-auth COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /backend_server_insecure -ENTRYPOINT ["/backend_server_secure"] +ENTRYPOINT ["/backend_server_insecure"] FROM scratch AS backend-secure COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /backend_server_secure diff --git a/rnex-core/src/grpc/mod.rs b/rnex-core/src/grpc/mod.rs index 16cb73b..31831f8 100644 --- a/rnex-core/src/grpc/mod.rs +++ b/rnex-core/src/grpc/mod.rs @@ -4,5 +4,5 @@ //! This WILL be deprecated as soon as account rs is in a stable state. use tonic::{Request, Status}; -type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result, Status> + Send)>; +type InterceptorFunc = Box) -> Result, Status> + Send>; pub mod account; \ No newline at end of file -- 2.47.3 From d5b1be28fcf003218de9b18046ca6f88c6a90e8e Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Fri, 7 Nov 2025 18:37:28 +0000 Subject: [PATCH 19/98] fix ssl --- Dockerfile | 2 +- rnex-core/src/executables/backend_server_insecure.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 70d1b46..5b89318 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM rust:alpine AS build-container -RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static +RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static ca-certificates FROM build-container AS builder diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 7a9f88a..2997864 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -21,7 +21,7 @@ pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(||{ env::var("FORWARD_EDGE_NODE_HOLDER") .ok() .and_then(|s| s.parse().ok()) - .expect("SECURE_EDGE_NODE_HOLDER not set") + .expect("FORWARD_EDGE_NODE_HOLDER not set") }); -- 2.47.3 From e840d5c6198cd33f672bbf79c5c1f71c52daaf6e Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Fri, 7 Nov 2025 18:42:15 +0000 Subject: [PATCH 20/98] actually fix ca issues --- Dockerfile | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5b89318..f1ea22f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM rust:alpine AS build-container -RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static ca-certificates +RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static FROM build-container AS builder @@ -18,12 +18,16 @@ COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_hold ENTRYPOINT ["/edge_node_holder_server"] -FROM scratch AS proxy-insecure-v1 +FROM alpine:latest AS proxy-insecure-v1 COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /proxy_insecure +RUN apk add --no-cache ca-certificates +RUN update-ca-certificates ENTRYPOINT ["/proxy_insecure"] -FROM scratch AS proxy-secure-v1 +FROM alpine:latest AS proxy-secure-v1 COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure +RUN apk add --no-cache ca-certificates +RUN update-ca-certificates ENTRYPOINT ["/proxy_secure"] -- 2.47.3 From f5b30496d757aedf5f7995d30c11563de74bf06e Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 12:04:39 +0000 Subject: [PATCH 21/98] make sending data actually reliable --- prudpv1/src/prudp/socket.rs | 185 +++++++++++++++++++------ rnex-core/src/rmc/protocols/ranking.rs | 30 ++++ 2 files changed, 169 insertions(+), 46 deletions(-) diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index 4aca993..d44c97b 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -10,7 +10,11 @@ use async_trait::async_trait; use log::info; use log::error; use rc4::StreamCipher; +use rnex_core::rmc::structures::qbuffer::QBuffer; +use v_byte_helpers::ReadExtensions; +use v_byte_helpers::little_endian::{read_u16, read_u32}; use std::collections::{BTreeMap, HashMap}; +use std::io::Cursor; use std::marker::PhantomData; use std::ops::Deref; use std::sync::{Arc, Weak}; @@ -51,12 +55,14 @@ struct InternalConnection { connections: Weak>>>>>, reliable_server_counter: u16, reliable_client_counter: u16, + supported_function_version: u32, // maybe add connection id(need to see if its even needed) crypto_handler_instance: E, data_sender: Sender>, socket: Arc, packet_queue: HashMap, last_packet_time: Instant, + unacknowleged_packets: Vec<(Instant, PRUDPV1Packet)> } impl Deref for InternalConnection { @@ -67,6 +73,7 @@ impl Deref for InternalConnection { } impl InternalConnection { + /// gives back the next server packet sequence id which the client expects to send, incrementing it in the process fn next_server_count(&mut self) -> u16 { let prev_val = self.reliable_server_counter; let (val, _) = self.reliable_server_counter.overflowing_add(1); @@ -75,20 +82,15 @@ impl InternalConnection { prev_val } + /// Sends a raw packet to a given client on the connection + /// + /// a raw packet is one which does not get processed any further(other than to send it + /// off without buffering or anything), + /// as such you need to make sure that + /// the sizes are set correctly and so on #[inline] - async fn send_raw_packet(&self, mut prudp_packet: PRUDPV1Packet) { - prudp_packet.set_sizes(); - - let mut vec = Vec::new(); - - prudp_packet - .write_to(&mut vec) - .expect("somehow failed to convert backet to bytes"); - - self.socket - .send_to(&vec, self.socket_addr.regular_socket_addr) - .await - .expect("failed to send data back"); + async fn send_raw_packet(&self, prudp_packet: &PRUDPV1Packet) { + send_raw_prudp_to_sockaddr(&self.socket, self.socket_addr, prudp_packet).await; } } @@ -196,7 +198,9 @@ impl AnyInternalConnection for InternalConne self.crypto_handler_instance.sign_packet(&mut packet); - self.send_raw_packet(packet).await; + self.send_raw_packet(&packet).await; + + self.unacknowleged_packets.push((Instant::now(), packet)); } async fn close_connection(&mut self) { @@ -223,7 +227,7 @@ impl AnyInternalConnection for InternalConne self.crypto_handler_instance.sign_packet(&mut packet); - self.send_raw_packet(packet).await; + self.send_raw_packet(&packet).await; let Some(conns) = self.connections.upgrade() else { // this is fine as it implies the server has already quit, thus meaning that we dont @@ -240,6 +244,19 @@ impl AnyInternalConnection for InternalConne } } +async fn send_raw_prudp_to_sockaddr(udp_socket: &UdpSocket, dest: PRUDPSockAddr, packet: &PRUDPV1Packet){ + let mut vec = Vec::new(); + + packet + .write_to(&mut vec) + .expect("somehow failed to convert backet to bytes"); + + udp_socket + .send_to(&vec, dest.regular_socket_addr) + .await + .expect("failed to send data back"); +} + impl InternalSocket { async fn get_connection( &self, @@ -257,19 +274,12 @@ impl InternalSocket { Some(conn) } - async fn send_packet_unbuffered(&self, dest: PRUDPSockAddr, mut packet: PRUDPV1Packet) { - packet.set_sizes(); - - let mut vec = Vec::new(); - - packet - .write_to(&mut vec) - .expect("somehow failed to convert backet to bytes"); - - self.socket - .send_to(&vec, dest.regular_socket_addr) - .await - .expect("failed to send data back"); + /// sends a raw packet to a specific prudp socket address + /// + /// a raw packet is a packet is a packet which wont get processed any further, + /// sizes signatures etc need to be set before using this function + async fn send_packet_unbuffered(&self, dest: PRUDPSockAddr, packet: &PRUDPV1Packet) { + send_raw_prudp_to_sockaddr(&self.socket, dest, packet).await } async fn handle_syn(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) { @@ -304,7 +314,7 @@ impl InternalSocket { //println!("got syn: {:?}", response); - self.send_packet_unbuffered(address, response).await; + self.send_packet_unbuffered(address, &response).await; } async fn connection_thread( @@ -316,7 +326,7 @@ impl InternalSocket { let mut conn = conn.lock().await; if conn.last_packet_time < (Instant::now() - Duration::from_secs(5)) { - conn.send_raw_packet(PRUDPV1Packet { + conn.send_raw_packet(&PRUDPV1Packet { header: PRUDPV1Header { sequence_id: 0, substream_id: 0, @@ -336,9 +346,17 @@ impl InternalSocket { if conn.last_packet_time < (Instant::now() - Duration::from_secs(30)) { conn.close_connection().await; } + + for (send_time, packet) in &conn.unacknowleged_packets{ + if *send_time < (Instant::now() - Duration::from_millis(500)){ + info!("unacknowledged packet sat arround for more than 500 ms, resending"); + conn.send_raw_packet(packet).await; + } + } + drop(conn); - sleep(Duration::from_secs(5)).await; + sleep(Duration::from_millis(500)).await; } } @@ -348,6 +366,7 @@ impl InternalSocket { socket_addr: PRUDPSockAddr, session_id: u8, is_instantiator: bool, + supported_function_version: u32, ) { let common = Arc::new(CommonConnection { user_id: crypto_handler_instance.get_user_id(), @@ -368,6 +387,8 @@ impl InternalSocket { socket: self.socket.clone(), packet_queue: Default::default(), last_packet_time: Instant::now(), + unacknowleged_packets: Vec::new(), + supported_function_version }; let internal = Arc::new(Mutex::new(internal)); @@ -445,12 +466,17 @@ impl InternalSocket { .options .push(ConnectionSignature(Default::default())); + let mut functions: u32 = 0; + for option in &packet.options { match option { MaximumSubstreamId(max_substream) => { response.options.push(MaximumSubstreamId(*max_substream)) } - SupportedFunctions(funcs) => response.options.push(SupportedFunctions(*funcs & 0xFF)), + SupportedFunctions(funcs) => { + functions = *funcs & 0xFF; + response.options.push(SupportedFunctions(*funcs & 0xFF)); + }, _ => { /* ? */ } } } @@ -461,10 +487,10 @@ impl InternalSocket { //println!("connect out: {:?}", response); - self.create_connection(crypto, address, session_id, false) + self.create_connection(crypto, address, session_id, false, functions) .await; - self.send_packet_unbuffered(address, response).await; + self.send_packet_unbuffered(address, &response).await; } async fn handle_data(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) { @@ -503,7 +529,7 @@ impl InternalSocket { conn.crypto_handler_instance.sign_packet(&mut response); - self.send_packet_unbuffered(address, response).await; + self.send_packet_unbuffered(address, &response).await; conn.data_sender.send(packet.payload).await.ok(); @@ -529,7 +555,7 @@ impl InternalSocket { conn.crypto_handler_instance.sign_packet(&mut response); - self.send_packet_unbuffered(address, response).await; + self.send_packet_unbuffered(address, &response).await; } async fn handle_disconnect(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) { @@ -549,9 +575,9 @@ impl InternalSocket { conn.crypto_handler_instance.sign_packet(&mut response); - self.send_packet_unbuffered(address, response.clone()).await; - self.send_packet_unbuffered(address, response.clone()).await; - self.send_packet_unbuffered(address, response).await; + self.send_packet_unbuffered(address, &response).await; + self.send_packet_unbuffered(address, &response).await; + self.send_packet_unbuffered(address, &response).await; //self.internal_connections.lock().await; } @@ -572,7 +598,7 @@ impl AnyInternalSocket for InternalSocket { if (packet.header.types_and_flags.get_flags() & ACK) != 0 { info!("got ack"); - + if packet.header.types_and_flags.get_types() == SYN || packet.header.types_and_flags.get_types() == CONNECT { @@ -597,13 +623,76 @@ impl AnyInternalSocket for InternalSocket { } else { error!("got connection response without the active reciever being present"); } + return; + } + + if let Some(conn) = self.get_connection(address).await { + let mut conn = conn.lock().await; + + // remove the packet whose sequence id matches the ack packet + // or in other words keep all of those which dont match the sequence id + conn.unacknowleged_packets.retain_mut(|v| { + packet.header.sequence_id != v.1.header.sequence_id + }); + } else { + error!("non connection acknowledgement packet on nonexistent connection...") } return; } if (packet.header.types_and_flags.get_flags() & MULTI_ACK) != 0 { - info!("got multi ack"); + if let Some(conn) = self.get_connection(address).await { + let mut conn = conn.lock().await; + + if conn.supported_function_version == 1{ + let mut collected_ids: Vec = Vec::new(); + let mut cursor = Cursor::new(&packet.payload); + + while let Ok(v) = read_u16(&mut cursor){ + collected_ids.push(v); + } + + conn.unacknowleged_packets.retain_mut(|(_, up)| { + !( + collected_ids.iter().any(|id| up.header.sequence_id == *id) || + up.header.sequence_id < packet.header.sequence_id + ) + }); + + } else { + let mut collected_ids: Vec = Vec::new(); + let mut cursor = Cursor::new(&packet.payload); + + let Ok(_substream_id): Result = cursor.read_le_struct() else{ + error!("invalid data whilest reading new version agregate acknowledgement"); + return; + }; + let Ok(additional_sequence_ids): Result = cursor.read_le_struct() else { + error!("invalid data whilest reading new version agregate acknowledgement"); + return; + }; + let Ok(sequence_id): Result = cursor.read_le_struct() else { + error!("invalid data whilest reading new version agregate acknowledgement"); + return; + }; + for _ in 0..additional_sequence_ids{ + let Ok(additional_sequence_id): Result = cursor.read_le_struct() else { + error!("invalid data whilest reading new version agregate acknowledgement"); + return; + }; + collected_ids.push(additional_sequence_id); + conn.unacknowleged_packets.retain_mut(|(_, up)| { + !( + collected_ids.iter().any(|id| up.header.sequence_id == *id) || + up.header.sequence_id < sequence_id + ) + }); + } + } + } else { + error!("non connection acknowledgement packet on nonexistent connection...") + } return; } @@ -631,7 +720,7 @@ impl AnyInternalSocket for InternalSocket { let remote_signature = address.calculate_connection_signature(); - let packet = PRUDPV1Packet { + let mut packet = PRUDPV1Packet { header: PRUDPV1Header { source_port: self.virtual_port, destination_port: address.virtual_port, @@ -646,7 +735,9 @@ impl AnyInternalSocket for InternalSocket { ..Default::default() }; - self.send_packet_unbuffered(address, packet).await; + packet.set_sizes(); + + self.send_packet_unbuffered(address, &packet).await; let Some(syn_ack_packet) = recv.recv().await else { error!("what"); @@ -662,7 +753,7 @@ impl AnyInternalSocket for InternalSocket { return None; }; - let packet = PRUDPV1Packet { + let mut packet = PRUDPV1Packet { header: PRUDPV1Header { source_port: self.virtual_port, destination_port: address.virtual_port, @@ -677,7 +768,9 @@ impl AnyInternalSocket for InternalSocket { ..Default::default() }; - self.send_packet_unbuffered(address, packet).await; + packet.set_sizes(); + + self.send_packet_unbuffered(address, &packet).await; let Some(_connect_ack_packet) = recv.recv().await else { error!("what"); @@ -689,7 +782,7 @@ impl AnyInternalSocket for InternalSocket { .instantiate(remote_signature, *own_signature, &[], 1)?; //todo: make this work for secure servers as well - self.create_connection(crypt, address, 0, true).await; + self.create_connection(crypt, address, 0, true, 4).await; Some(()) } diff --git a/rnex-core/src/rmc/protocols/ranking.rs b/rnex-core/src/rmc/protocols/ranking.rs index 298922f..d5746e9 100644 --- a/rnex-core/src/rmc/protocols/ranking.rs +++ b/rnex-core/src/rmc/protocols/ranking.rs @@ -1,5 +1,35 @@ use macros::rmc_proto; +use crate::rmc::response::ErrorCode; +use macros::{method_id, rmc_struct, RmcSerialize}; + +#[derive(RmcSerialize, Debug, Default, Clone)] +struct ResultsRange{ + offset: u32, + size: u32 +} + +#[derive(RmcSerialize, Debug, Default, Clone)] +#[rmc_struct(1)] +struct CompetitionRankingGetParam{ + unk: u32, + range: ResultsRange, + festival_ids: Vec, +} + +#[derive(RmcSerialize, Debug, Default, Clone)] +#[rmc_struct(0)] +struct CompetitionRankingScoreInfo{ + fest_id: u32, + score_data: Vec, + unk: u32, + team_wins: Vec, + team_votes: Vec +} + + #[rmc_proto(112)] pub trait Ranking{ + //#[method_id(16)] + //async fn competition_ranking_get_param(&self, param: CompetitionRankingGetParam) -> Result,ErrorCode>; } \ No newline at end of file -- 2.47.3 From f264f34a18faef214c104a40661ab4157892b82d Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 12:17:21 +0000 Subject: [PATCH 22/98] add debugging to packet acknowledgements --- prudpv1/src/prudp/socket.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index d44c97b..f5fb448 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -4,6 +4,7 @@ use crate::prudp::packet::PacketOption::{ ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions, }; use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags}; +use md5::digest::generic_array::sequence; use rnex_core::prudp::virtual_port::VirtualPort; use rnex_core::prudp::socket_addr::PRUDPSockAddr; use async_trait::async_trait; @@ -626,6 +627,8 @@ impl AnyInternalSocket for InternalSocket { return; } + info!("got ack"); + if let Some(conn) = self.get_connection(address).await { let mut conn = conn.lock().await; @@ -682,13 +685,18 @@ impl AnyInternalSocket for InternalSocket { return; }; collected_ids.push(additional_sequence_id); - conn.unacknowleged_packets.retain_mut(|(_, up)| { - !( - collected_ids.iter().any(|id| up.header.sequence_id == *id) || - up.header.sequence_id < sequence_id - ) - }); } + + println!("multiack new summary: \n\tup_till_id {}\n\tadditionals {:?}", sequence_id, collected_ids); + println!("pre size: {}", conn.unacknowleged_packets.len()); + + conn.unacknowleged_packets.retain_mut(|(_, up)| { + !( + collected_ids.iter().any(|id| up.header.sequence_id == *id) || + up.header.sequence_id < sequence_id + ) + }); + println!("post size: {}", conn.unacknowleged_packets.len()); } } else { error!("non connection acknowledgement packet on nonexistent connection...") -- 2.47.3 From adae697154539e4f05176bad81a651dc74d7b972 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 12:27:17 +0000 Subject: [PATCH 23/98] fix resending issues and remove debugging again --- prudpv1/src/prudp/socket.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index f5fb448..3e88a70 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -659,7 +659,7 @@ impl AnyInternalSocket for InternalSocket { conn.unacknowleged_packets.retain_mut(|(_, up)| { !( collected_ids.iter().any(|id| up.header.sequence_id == *id) || - up.header.sequence_id < packet.header.sequence_id + up.header.sequence_id <= packet.header.sequence_id ) }); @@ -687,16 +687,12 @@ impl AnyInternalSocket for InternalSocket { collected_ids.push(additional_sequence_id); } - println!("multiack new summary: \n\tup_till_id {}\n\tadditionals {:?}", sequence_id, collected_ids); - println!("pre size: {}", conn.unacknowleged_packets.len()); - conn.unacknowleged_packets.retain_mut(|(_, up)| { !( collected_ids.iter().any(|id| up.header.sequence_id == *id) || - up.header.sequence_id < sequence_id + up.header.sequence_id <= sequence_id ) }); - println!("post size: {}", conn.unacknowleged_packets.len()); } } else { error!("non connection acknowledgement packet on nonexistent connection...") -- 2.47.3 From 6ea1518a9dcaf72d3621912483fc5de07a57e9b6 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 13:00:23 +0000 Subject: [PATCH 24/98] clean up a bit --- prudpv1/src/prudp/socket.rs | 4 +- .../executables/backend_server_insecure.rs | 55 ++++-------------- .../src/executables/backend_server_secure.rs | 57 ++++--------------- rnex-core/src/executables/common.rs | 42 +++++++++++++- rnex-core/src/rmc/protocols/ranking.rs | 4 +- 5 files changed, 65 insertions(+), 97 deletions(-) diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index 3e88a70..d85948c 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -4,16 +4,14 @@ use crate::prudp::packet::PacketOption::{ ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions, }; use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags}; -use md5::digest::generic_array::sequence; use rnex_core::prudp::virtual_port::VirtualPort; use rnex_core::prudp::socket_addr::PRUDPSockAddr; use async_trait::async_trait; use log::info; use log::error; use rc4::StreamCipher; -use rnex_core::rmc::structures::qbuffer::QBuffer; use v_byte_helpers::ReadExtensions; -use v_byte_helpers::little_endian::{read_u16, read_u32}; +use v_byte_helpers::little_endian::read_u16; use std::collections::{BTreeMap, HashMap}; use std::io::Cursor; use std::marker::PhantomData; diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 2997864..6b2625c 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,19 +1,15 @@ -use rnex_core::reggie::{RemoteEdgeNodeHolder, UnitPacketRead}; -use log::{error, info}; +use rnex_core::reggie::RemoteEdgeNodeHolder; use once_cell::sync::Lazy; use rnex_core::common::setup; -use std::{env}; -use std::io::Cursor; +use rnex_core::rmc::structures::RmcSerialize; +use std::env; use std::net::SocketAddrV4; use std::sync::Arc; -use tokio::net::{TcpListener, TcpStream}; -use tokio::task; -use rnex_core::executables::common::{OWN_IP_PRIVATE, SECURE_SERVER_ACCOUNT, SERVER_PORT}; +use tokio::net::TcpStream; +use rnex_core::executables::common::{SECURE_SERVER_ACCOUNT, new_simple_backend}; use rnex_core::nex::auth_handler::AuthHandler; use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; -use rnex_core::rmc::structures::RmcSerialize; -use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::util::SplittableBufferConnection; @@ -38,39 +34,12 @@ async fn main() { let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); - let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap(); - - - - while let Ok((mut stream, _addr)) = listen.accept().await { - let buffer = match stream.read_buffer().await{ - Ok(v) => v, - Err(e) => { - error!("an error ocurred whilest reading connection data buffer: {:?}", e); - continue; - } - }; - - let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer)); - - let _user_connection_data = match user_connection_data{ - Ok(v) => v, - Err(e) => { - error!("an error ocurred whilest reading connection data: {:?}", e); - continue; - } - }; + new_simple_backend(move |_, _|{ let controller = conn.clone(); - task::spawn(async move { - info!("connection to secure backend established"); - new_rmc_gateway_connection(stream.into(), |_| { - Arc::new(AuthHandler { - destination_server_acct: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - control_server: controller - }) - }); - }); - - } + Arc::new(AuthHandler { + destination_server_acct: &SECURE_SERVER_ACCOUNT, + build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", + control_server: controller + }) + }).await; } diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs index 82d1a39..1488369 100644 --- a/rnex-core/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -1,26 +1,16 @@ -use std::io::Cursor; -use rnex_core::rmc::structures::RmcSerialize; -use rnex_core::reggie::UnitPacketRead; -use std::net::SocketAddrV4; use std::sync::Arc; use std::sync::atomic::AtomicU32; -use log::{error, info}; -use tokio::net::TcpListener; -use tokio::task; use rnex_core::common::setup; -use rnex_core::executables::common::{OWN_IP_PRIVATE, SERVER_PORT}; +use rnex_core::executables::common::{new_simple_backend}; use rnex_core::nex::matchmake::MatchmakeManager; use rnex_core::nex::remote_console::RemoteConsole; use rnex_core::nex::user::User; -use rnex_core::rmc::protocols::new_rmc_gateway_connection; -use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::rmc::protocols::RemoteInstantiatable; #[tokio::main] async fn main() { setup(); - let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap(); let mmm = Arc::new(MatchmakeManager{ gid_counter: AtomicU32::new(1), @@ -33,40 +23,15 @@ async fn main() { MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - while let Ok((mut stream, _addr)) = listen.accept().await { - let buffer = match stream.read_buffer().await{ - Ok(v) => v, - Err(e) => { - error!("an error ocurred whilest reading connection data buffer: {:?}", e); - continue; - } - }; - - let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer)); - - let user_connection_data = match user_connection_data{ - Ok(v) => v, - Err(e) => { - error!("an error ocurred whilest reading connection data: {:?}", e); - continue; - } - }; - - + new_simple_backend(move |c, r|{ let mmm = mmm.clone(); - task::spawn(async move { - info!("connection to secure backend established"); - new_rmc_gateway_connection(stream.into(), |r| { - Arc::new_cyclic(|this| User{ - this: this.clone(), - ip: user_connection_data.prudpsock_addr, - pid: user_connection_data.pid, - remote: RemoteConsole::new(r), - matchmake_manager: mmm, - station_url: Default::default() - }) - }); - }); - - } + Arc::new_cyclic(move |this| User{ + this: this.clone(), + ip: c.prudpsock_addr, + pid:c.pid, + remote: RemoteConsole::new(r), + matchmake_manager: mmm, + station_url: Default::default() + }) + }).await; } \ No newline at end of file diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index 0c553b4..73571d7 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -1,8 +1,18 @@ use std::env; -use std::net::Ipv4Addr; +use std::io::Cursor; +use std::net::{Ipv4Addr, SocketAddrV4}; +use std::sync::Arc; use once_cell::sync::Lazy; -use crate::nex::account::Account; +use rnex_core::nex::account::Account; +use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection}; +use rnex_core::rnex_proxy_common::ConnectionInitData; +use rnex_core::rmc::structures::RmcSerialize; +use tokio::net::TcpListener; + use std::error::Error; +use log::error; + +use crate::reggie::UnitPacketRead; const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip"; @@ -48,4 +58,32 @@ pub static SECURE_SERVER_ACCOUNT: Lazy = Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); +pub async fn new_simple_backend(mut creation_function: F) +where + F: FnMut(ConnectionInitData, RmcConnection) -> Arc, +{ + let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap(); + while let Ok((mut stream, _addr)) = listen.accept().await { + let buffer = match stream.read_buffer().await{ + Ok(v) => v, + Err(e) => { + error!("an error ocurred whilest reading connection data buffer: {:?}", e); + continue; + } + }; + let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer)); + + let user_connection_data = match user_connection_data{ + Ok(v) => v, + Err(e) => { + error!("an error ocurred whilest reading connection data: {:?}", e); + continue; + } + }; + let fun_ref = &mut creation_function; + new_rmc_gateway_connection(stream.into(), move |r|{ + fun_ref(user_connection_data, r) + }); + } +} \ No newline at end of file diff --git a/rnex-core/src/rmc/protocols/ranking.rs b/rnex-core/src/rmc/protocols/ranking.rs index d5746e9..93dcb87 100644 --- a/rnex-core/src/rmc/protocols/ranking.rs +++ b/rnex-core/src/rmc/protocols/ranking.rs @@ -1,6 +1,4 @@ -use macros::rmc_proto; -use crate::rmc::response::ErrorCode; -use macros::{method_id, rmc_struct, RmcSerialize}; +use macros::{rmc_struct, rmc_proto, RmcSerialize}; #[derive(RmcSerialize, Debug, Default, Clone)] struct ResultsRange{ -- 2.47.3 From 449ce0c0ba5afb6b1f5f384aa7e46afad3914ead Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 13:41:41 +0000 Subject: [PATCH 25/98] add closing a connection if it becomes unreliable/doesnt ack a packet 5 times --- prudpv1/src/prudp/socket.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index d85948c..9307007 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -7,7 +7,7 @@ use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags}; use rnex_core::prudp::virtual_port::VirtualPort; use rnex_core::prudp::socket_addr::PRUDPSockAddr; use async_trait::async_trait; -use log::info; +use log::{info, warn}; use log::error; use rc4::StreamCipher; use v_byte_helpers::ReadExtensions; @@ -347,6 +347,11 @@ impl InternalSocket { } for (send_time, packet) in &conn.unacknowleged_packets{ + if *send_time < (Instant::now() - Duration::from_millis(3000)){ + warn!("failed to resend packet 5 times and never got response, destroying connection"); + conn.close_connection().await; + break; + } if *send_time < (Instant::now() - Duration::from_millis(500)){ info!("unacknowledged packet sat arround for more than 500 ms, resending"); conn.send_raw_packet(packet).await; -- 2.47.3 From 949c347569c254ca6f8c2640a339448bf4c80aa9 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 17:04:32 +0000 Subject: [PATCH 26/98] fix proxy not disconnecting propperly --- prudpv1/src/executables/proxy_insecure.rs | 6 ++--- prudpv1/src/executables/proxy_secure.rs | 6 ++--- prudpv1/src/prudp/socket.rs | 32 ++++++++++++++--------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index b33e069..cbfacec 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -76,12 +76,12 @@ async fn main() { tokio::select! { data = conn.recv() => { let Some(data) = data else { - break; + return; }; if let Err(e) = stream.send_buffer(&data[..]).await{ error!("error sending data to backend: {}", e); - break; + return; } }, data = stream.read_buffer() => { @@ -89,7 +89,7 @@ async fn main() { Ok(d) => d, Err(e) => { error!("error reveiving data from backend: {}", e); - break; + return; } }; diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index 91a66fa..b25a03a 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -78,12 +78,12 @@ async fn main() { tokio::select! { data = conn.recv() => { let Some(data) = data else { - break; + return; }; if let Err(e) = stream.send_buffer(&data[..]).await{ error!("error sending data to backend: {}", e); - break; + return; } }, data = stream.read_buffer() => { @@ -91,7 +91,7 @@ async fn main() { Ok(d) => d, Err(e) => { error!("error reveiving data from backend: {}", e); - break; + return; } }; diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index 9307007..6467d8f 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -91,6 +91,21 @@ impl InternalConnection { async fn send_raw_packet(&self, prudp_packet: &PRUDPV1Packet) { send_raw_prudp_to_sockaddr(&self.socket, self.socket_addr, prudp_packet).await; } + + async fn delete_connection(&self){ + let Some(conns) = self.connections.upgrade() else { + // this is fine as it implies the server has already quit, thus meaning that we dont + // have to remove ourselves from the server + return; + }; + + let mut conns = conns.lock().await; + + conns.remove(&self.socket_addr); + + // the connection will now drop as soon as we leave this due to no longer having a permanent + // reference + } } pub struct ExternalConnection { @@ -172,6 +187,8 @@ pub(super) trait AnyInternalConnection: async fn close_connection(&mut self); } + + #[async_trait] impl AnyInternalConnection for InternalConnection { async fn send_data_packet(&mut self, data: Vec) { @@ -202,6 +219,7 @@ impl AnyInternalConnection for InternalConne self.unacknowleged_packets.push((Instant::now(), packet)); } + async fn close_connection(&mut self) { // jon confirmed that this should be a safe way to dc a client @@ -228,18 +246,7 @@ impl AnyInternalConnection for InternalConne self.send_raw_packet(&packet).await; - let Some(conns) = self.connections.upgrade() else { - // this is fine as it implies the server has already quit, thus meaning that we dont - // have to remove ourselves from the server - return; - }; - - let mut conns = conns.lock().await; - - conns.remove(&self.socket_addr); - - // the connection will now drop as soon as we leave this due to no longer having a permanent - // reference + self.delete_connection().await; } } @@ -583,6 +590,7 @@ impl InternalSocket { self.send_packet_unbuffered(address, &response).await; self.send_packet_unbuffered(address, &response).await; + conn.delete_connection().await; //self.internal_connections.lock().await; } } -- 2.47.3 From 4de04a46275ef0cb213f847068f9b6e0e6949621 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 17:19:28 +0000 Subject: [PATCH 27/98] fix checking if a session has active players --- rnex-core/src/nex/matchmake.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 93e8ced..f74be5d 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -240,17 +240,21 @@ impl ExtendedMatchmakeSession{ }).await; } } + pub fn has_active_players(&self) -> bool{ + self.connected_players.iter().filter(|v| v.upgrade().is_some()).count() != 0 + } + #[inline] pub fn is_reachable(&self) -> bool{ (if self.session.gathering.flags & PERSISTENT_GATHERING != 0{ - if !self.connected_players.is_empty(){ + if self.has_active_players(){ true } else { self.session.open_participation } } else { - !self.connected_players.is_empty() - }) & !self.connected_players.is_empty() + !self.has_active_players() + }) & !self.has_active_players() } #[inline] pub fn is_joinable(&self) -> bool{ -- 2.47.3 From 6625dab9c1c4f756e41c7cf257a0910d62b3c250 Mon Sep 17 00:00:00 2001 From: Maple Nebel Date: Sat, 8 Nov 2025 20:27:36 +0000 Subject: [PATCH 28/98] fix is_reachable --- rnex-core/src/nex/matchmake.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index f74be5d..a2f8c20 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -253,8 +253,8 @@ impl ExtendedMatchmakeSession{ self.session.open_participation } } else { - !self.has_active_players() - }) & !self.has_active_players() + self.has_active_players() + }) & self.has_active_players() } #[inline] pub fn is_joinable(&self) -> bool{ -- 2.47.3 From 5782951e6893981b03cffe95698933b6276c61b9 Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 12 Nov 2025 22:41:34 +0100 Subject: [PATCH 29/98] optimize --- Cargo.lock | 245 ++++++++++ macros/src/lib.rs | 64 ++- macros/src/protos.rs | 2 + prudpv1/src/executables/proxy_insecure.rs | 4 +- prudpv1/src/executables/proxy_secure.rs | 4 +- rnex-core/Cargo.toml | 8 +- rnex-core/benches/rmc_serialization.rs | 99 ++++ .../executables/backend_server_insecure.rs | 2 +- rnex-core/src/kerberos/mod.rs | 4 +- rnex-core/src/lib.rs | 4 + rnex-core/src/main.rs | 447 ++++-------------- rnex-core/src/nex/auth_handler.rs | 2 + rnex-core/src/prudp/station_url.rs | 70 +-- rnex-core/src/rmc/structures/any.rs | 4 +- rnex-core/src/rmc/structures/buffer.rs | 16 +- rnex-core/src/rmc/structures/helpers.rs | 48 ++ rnex-core/src/rmc/structures/list.rs | 30 +- rnex-core/src/rmc/structures/mod.rs | 41 +- rnex-core/src/rmc/structures/networking.rs | 14 +- rnex-core/src/rmc/structures/primitives.rs | 213 +++++++-- rnex-core/src/rmc/structures/qbuffer.rs | 4 +- rnex-core/src/rmc/structures/qresult.rs | 4 +- rnex-core/src/rmc/structures/rmc_struct.rs | 104 +++- rnex-core/src/rmc/structures/string.rs | 32 +- rnex-core/src/rmc/structures/variant.rs | 4 +- 25 files changed, 962 insertions(+), 507 deletions(-) create mode 100644 rnex-core/benches/rmc_serialization.rs create mode 100644 rnex-core/src/rmc/structures/helpers.rs diff --git a/Cargo.lock b/Cargo.lock index 82797de..7965148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,24 @@ dependencies = [ "libc", ] +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + [[package]] name = "async-stream" version = "0.3.6" @@ -222,6 +240,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cc" version = "1.2.31" @@ -257,6 +281,33 @@ dependencies = [ "windows-link", ] +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "cipher" version = "0.4.4" @@ -267,6 +318,31 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + [[package]] name = "cookie" version = "0.18.1" @@ -294,6 +370,70 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "criterion" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -626,6 +766,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1048,6 +1199,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -1308,6 +1468,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + [[package]] name = "openssl" version = "0.10.73" @@ -1454,6 +1620,34 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "potential_utf" version = "0.1.2" @@ -1572,6 +1766,26 @@ dependencies = [ "getrandom 0.2.16", ] +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "rc4" version = "0.1.0" @@ -1714,9 +1928,11 @@ dependencies = [ name = "rnex-core" version = "0.1.1" dependencies = [ + "anyhow", "async-trait", "bytemuck", "chrono", + "criterion", "ctrlc", "dotenv", "hex", @@ -1885,6 +2101,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.27" @@ -2242,6 +2467,16 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tokio" version = "1.47.1" @@ -2607,6 +2842,16 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 39639b3..67486ef 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -48,7 +48,7 @@ impl Parse for ProtoInputParams { fn gen_serialize_data_struct( s: DataStruct, struct_attr: Option<&Attribute>, -) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { +) -> (proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream) { let serialize_base_content = { let mut serialize_content = quote! {}; @@ -119,6 +119,29 @@ fn gen_serialize_data_struct( } }; + let write_size = { + let mut size_content = quote! { 0 }; + + for f in &s.fields { + + + let ident = f.ident.as_ref().unwrap(); + let ty = &f.ty; + + size_content.append_all(quote! { + + rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)? + }) + } + + size_content + }; + let write_size = if let Some(_) = struct_attr { + quote!{ #write_size + if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 } } + } else { + write_size + }; + + // generate base with extends stuff let serialize_base_content = if let Some(attr) = struct_attr { @@ -143,9 +166,18 @@ fn gen_serialize_data_struct( quote! { #pre_inner - rnex_core::rmc::structures::rmc_struct::write_struct(writer, #version, |mut writer|{ - #serialize_base_content - })?; + rnex_core::rmc::structures::rmc_struct::write_struct( + writer, + #version, + rnex_core::rmc::structures::helpers::len_of_write( + |writer|{ + #serialize_base_content + } + ), + |writer|{ + #serialize_base_content + } + )?; Ok(()) } @@ -184,7 +216,13 @@ fn gen_serialize_data_struct( deserialize_base_content }; - (serialize_base_content, deserialize_base_content) + let write_size = quote!{ + fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result{ + Ok(#write_size) + } + }; + + (serialize_base_content, deserialize_base_content, write_size) } #[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))] @@ -210,7 +248,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { panic!("rmc struct type MUST be a struct"); };*/ - let (serialize_base_content, deserialize_base_content) = match derive_input.data { + let (serialize_base_content, deserialize_base_content, write_size) = match derive_input.data { Data::Struct(s) => gen_serialize_data_struct(s, struct_attr), Data::Enum(e) => { let Some(repr_attr) = repr_attr else { @@ -221,6 +259,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let mut inner_match_de = quote! {}; let mut inner_match_se = quote! {}; + let mut inner_match_len = quote!{}; for variant in e.variants { let Some((_, val)) = variant.discriminant else { @@ -352,7 +391,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { Ok(val) }; - (serialize_base_content, deserialize_base_content) + (serialize_base_content, deserialize_base_content, quote!{}) } Data::Union(_) => { unimplemented!() @@ -365,15 +404,16 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let tokens = quote! { impl rnex_core::rmc::structures::RmcSerialize for #ident{ - fn serialize(&self, writer: &mut dyn ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{ + #[inline(always)] + fn serialize(&self, writer: &mut impl ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{ #serialize_base_content - - } - - fn deserialize(reader: &mut dyn ::std::io::Read) -> rnex_core::rmc::structures::Result{ + #[inline(always)] + fn deserialize(reader: &mut impl ::std::io::Read) -> rnex_core::rmc::structures::Result{ #deserialize_base_content } + + #write_size } }; diff --git a/macros/src/protos.rs b/macros/src/protos.rs index a19f01e..7dd7bf1 100644 --- a/macros/src/protos.rs +++ b/macros/src/protos.rs @@ -55,6 +55,7 @@ impl RmcProtocolData{ let raw_name = Ident::new(&format!("raw_{}", name), name.span()); quote!{ + #[inline(always)] async fn #raw_name }.to_tokens(tokens); @@ -125,6 +126,7 @@ impl RmcProtocolData{ } quote!{ + #[inline(always)] async fn rmc_call_proto( &self, remote_response_connection: &rnex_core::util::SendingBufferConnection, diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index cbfacec..50446d5 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -31,7 +31,7 @@ async fn main() { let conn: SplittableBufferConnection = conn.into(); - conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data()).await; + conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await; let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); @@ -67,7 +67,7 @@ async fn main() { if let Err(e) = stream.send_buffer(&ConnectionInitData{ prudpsock_addr: conn.socket_addr, pid: conn.user_id - }.to_data()).await{ + }.to_data().unwrap()).await{ error!("error connecting to backend: {}", e); return; }; diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index b25a03a..d11b944 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -28,7 +28,7 @@ async fn main() { let conn: SplittableBufferConnection = conn.into(); - conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data()).await; + conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await; let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); @@ -67,7 +67,7 @@ async fn main() { if let Err(e) = stream.send_buffer(&ConnectionInitData{ prudpsock_addr: conn.socket_addr, pid: conn.user_id - }.to_data()).await{ + }.to_data().unwrap()).await{ error!("error connecting to backend: {}", e); return; }; diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 90ce871..b609afb 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -29,9 +29,15 @@ typenum = "1.18.0" reqwest = { version= "0.12.18", features = ["blocking"]} json = "0.12.4" ctrlc = "3.4.7" +criterion = "0.7.0" +anyhow = "1.0.100" +[features] +rmc_struct_header = [] - +[[bench]] +name = "rmc_serialization" +harness = false [[bin]] name = "backend_server_insecure" diff --git a/rnex-core/benches/rmc_serialization.rs b/rnex-core/benches/rmc_serialization.rs new file mode 100644 index 0000000..4b506f8 --- /dev/null +++ b/rnex-core/benches/rmc_serialization.rs @@ -0,0 +1,99 @@ +use std::hint::black_box; +use std::io::Cursor; +use std::ops::Deref; +use criterion::{criterion_group, criterion_main, Criterion}; +use once_cell::sync::Lazy; +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::rmc::structures::variant::Variant; + +static DUMMY: Lazy = Lazy::new(|| AutoMatchmakeParam{ + additional_participants: vec![1,2,3,4], + auto_matchmake_option: 10, + gid_for_participation_check: 9, + join_message: "hi".to_string(), + participation_count: 32, + target_gids: vec![45,2,51,1,1,1,1], + search_criteria: vec![MatchmakeSessionSearchCriteria{ + attribs: vec!["hi".to_string(), "ig".to_string(), "gotta put data here".to_string()], + exclude_locked: true, + exclude_non_host_pid: false, + exclude_system_password_set: true, + exclude_user_password_set: false, + game_mode: "some gamemode".to_string(), + matchmake_param: MatchmakeParam{ + params: vec![ + ("SR".to_string(), Variant::Bool(true)), + ("SR2".to_string(), Variant::Double(1.0)), + ("SR3".to_string(), Variant::SInt64(42)), + ("SR4".to_string(), Variant::String("test".to_string())) + ] + }, + matchmake_system_type: "some type".to_string(), + maximum_participants: "???".to_string(), + minimum_participants: "-99".to_string(), + refer_gid: 123, + selection_method: 9999999, + vacant_only: true, + vacant_participants: 1000 + }], + matchmake_session: MatchmakeSession{ + refer_gid: 10, + matchmake_system_type: 139, + matchmake_param: MatchmakeParam{ + params: vec![ + ("QSR".to_string(), Variant::Bool(false)), + ("SRQ2".to_string(), Variant::Double(1.1)), + ("SQR3".to_string(), Variant::SInt64(422)), + ("SDR4".to_string(), Variant::String("tetst".to_string())) + ] + }, + participation_count: 99, + application_buffer: vec![1,2,3,4,5,6,7,8,9], + attributes: vec![10,20,99,100000], + datetime: KerberosDateTime::now(), + gamemode: 111, + open_participation: false, + option0: 100, + progress_score: 1, + system_password_enabled: false, + user_password: "aaa".to_string(), + session_key: vec![91,123,5,2,1,2,4,124,4], + user_password_enabled: false, + gathering: Gathering{ + minimum_participants: 1, + maximum_participants: 12, + description: "aaargh".to_string(), + flags: 100, + host_pid: 999999919, + owner_pid: 138830, + participant_policy: 1, + policy_argument: 99837, + self_gid: 129, + state: 1389488 + } + } +}); + +static DUMMY_SER: Lazy> = Lazy::new(|| serialize_to_vec(DUMMY.deref())); + +fn serialize_to_vec(r: &impl RmcSerialize) -> Vec{ + let mut vec = r.to_data(); + + vec.unwrap() +} + +fn read_struct(r: &[u8]) -> T{ + T::deserialize(&mut Cursor::new(r)).unwrap() +} +fn matchmake_with_param(c: &mut Criterion) { + let raw = DUMMY.deref(); + let ser = DUMMY_SER.deref().as_slice(); + c.bench_function("mmparam: ser", |b| b.iter(move || serialize_to_vec(black_box(raw)))); + c.bench_function("mmparam: de", |b| b.iter(move || read_struct::(black_box(ser)))); +} + +criterion_group!(benches, matchmake_with_param); +criterion_main!(benches); + diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 6b2625c..4cbe591 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -30,7 +30,7 @@ async fn main() { let conn: SplittableBufferConnection = conn.into(); - conn.send(DontRegister.to_data()).await; + conn.send(DontRegister.to_data().unwrap()).await; let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index 09dc46c..a54764e 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -83,11 +83,11 @@ impl KerberosDateTime{ } impl RmcSerialize for KerberosDateTime{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(self.0.serialize(writer)?) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(Self(u64::deserialize(reader)?)) } } diff --git a/rnex-core/src/lib.rs b/rnex-core/src/lib.rs index 21b354a..4a4f1ef 100644 --- a/rnex-core/src/lib.rs +++ b/rnex-core/src/lib.rs @@ -24,3 +24,7 @@ pub mod rnex_proxy_common; pub mod util; pub mod executables; pub use macros::*; + +pub mod config{ + pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); +} diff --git a/rnex-core/src/main.rs b/rnex-core/src/main.rs index 0af4975..cfa323d 100644 --- a/rnex-core/src/main.rs +++ b/rnex-core/src/main.rs @@ -20,6 +20,8 @@ use std::fs::File; use std::net::{Ipv4Addr}; use std::sync::Once; use std::{env, fs}; +use std::hint::black_box; +use criterion::{criterion_group, criterion_main, Criterion}; mod prudp; pub mod rmc; @@ -35,360 +37,111 @@ pub mod reggie; pub mod util; pub mod common; - - -static KERBEROS_SERVER_PASSWORD: Lazy = Lazy::new(|| { - env::var("AUTH_SERVER_PASSWORD") - .ok() - .unwrap_or("password".to_owned()) -}); - -static AUTH_SERVER_ACCOUNT: Lazy = - Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD)); -static SECURE_SERVER_ACCOUNT: Lazy = - Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); - -static AUTH_SERVER_PORT: Lazy = Lazy::new(|| { - env::var("AUTH_SERVER_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(10000) -}); -static SECURE_SERVER_PORT: Lazy = Lazy::new(|| { - env::var("SECURE_SERVER_PORT") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(10001) -}); - -static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { - env::var("SERVER_IP") - .ok() - .and_then(|s| s.parse().ok()) - .expect("no private ip specified") -}); - -static OWN_IP_PUBLIC: Lazy = - Lazy::new(|| env::var("SERVER_IP_PUBLIC").unwrap_or(OWN_IP_PRIVATE.to_string())); - -static SECURE_STATION_URL: Lazy = Lazy::new(|| { - format!( - "prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1", - *OWN_IP_PUBLIC, *SECURE_SERVER_PORT - ) -}); - -static FORCE_EXIT: Once = Once::new(); - -#[tokio::main] -async fn main() { - CombinedLogger::init(vec![ - TermLogger::new( - LevelFilter::Info, - Config::default(), - TerminalMode::Mixed, - ColorChoice::Auto, - ), - WriteLogger::new(LevelFilter::max(), Config::default(), { - fs::create_dir_all("log").unwrap(); - let date = Local::now().to_rfc3339_opts(SecondsFormat::Secs, false); - // this fixes windows being windows - let date = date.replace(":", "-"); - let filename = format!("{}.log", date); - if cfg!(windows) { - File::create(format!("log\\{}", filename)).unwrap() - } else { - File::create(format!("log/{}", filename)).unwrap() - } - }), - ]) - .unwrap(); - - ctrlc::set_handler(||{ - FORCE_EXIT.call_once_force(|_|{ - println!("attempting exit"); - }); - }).unwrap(); - - dotenv::dotenv().ok(); - - //start_servers().await; -} -/* - -struct AuthServer{ - router: Arc, - join_handle: JoinHandle<()>, - socket: Socket +pub mod config{ + pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); } -async fn start_auth_server() -> AuthServer{ - info!("starting auth server on {}:{}", *OWN_IP_PRIVATE, *AUTH_SERVER_PORT); +use std::io::Cursor; +use std::ops::Deref; +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::rmc::structures::variant::Variant; - let (router, join_handle) = - Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *AUTH_SERVER_PORT)).await - .expect("unable to startauth server"); - - info!("setting up endpoints"); - - // dont assign it to the name _ as that will make it drop right here and now - - let auth_protocol_config = AuthProtocolConfig{ - secure_server_account: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - station_url: &SECURE_STATION_URL - }; - - let rmcserver = RMCProtocolServer::new(Box::new([ - Box::new(auth::bound_protocol(auth_protocol_config)) - ])); - - let socket = - Socket::new( - router.clone(), - VirtualPort::new(1,10), - "6f599f81", - Box::new(|_, count|{ - Box::pin( - async move { - - - let encryption_pairs = Vec::from_iter((0..=count).map(|_v| { - let rc4: Rc4 = Rc4::new_from_slice( "CD&ML".as_bytes()).unwrap(); - let cypher = Box::new(rc4); - let server_cypher: Box = cypher; - - let rc4: Rc4 = Rc4::new_from_slice( "CD&ML".as_bytes()).unwrap(); - let cypher = Box::new(rc4); - let client_cypher: Box = cypher; - - EncryptionPair{ - recv: client_cypher, - send: server_cypher - } - })); - - Some((Vec::new(), encryption_pairs, None)) - } - ) - }), - Box::new(move |packet, socket, connection|{ - let rmcserver = rmcserver.clone(); - Box::pin(async move { rmcserver.process_message(packet, socket, connection).await; }) - }) - ).await.expect("unable to create socket"); - - AuthServer{ - join_handle, - router, - socket, +static DUMMY: Lazy = Lazy::new(|| AutoMatchmakeParam{ + additional_participants: vec![1,2,3,4], + auto_matchmake_option: 10, + gid_for_participation_check: 9, + join_message: "hi".to_string(), + participation_count: 32, + target_gids: vec![45,2,51,1,1,1,1], + search_criteria: vec![MatchmakeSessionSearchCriteria{ + attribs: vec!["hi".to_string(), "ig".to_string(), "gotta put data here".to_string()], + exclude_locked: true, + exclude_non_host_pid: false, + exclude_system_password_set: true, + exclude_user_password_set: false, + game_mode: "some gamemode".to_string(), + matchmake_param: MatchmakeParam{ + params: vec![ + ("SR".to_string(), Variant::Bool(true)), + ("SR2".to_string(), Variant::Double(1.0)), + ("SR3".to_string(), Variant::SInt64(42)), + ("SR4".to_string(), Variant::String("test".to_string())) + ] + }, + matchmake_system_type: "some type".to_string(), + maximum_participants: "???".to_string(), + minimum_participants: "-99".to_string(), + refer_gid: 123, + selection_method: 9999999, + vacant_only: true, + vacant_participants: 1000 + }], + matchmake_session: MatchmakeSession{ + refer_gid: 10, + matchmake_system_type: 139, + matchmake_param: MatchmakeParam{ + params: vec![ + ("QSR".to_string(), Variant::Bool(false)), + ("SRQ2".to_string(), Variant::Double(1.1)), + ("SQR3".to_string(), Variant::SInt64(422)), + ("SDR4".to_string(), Variant::String("tetst".to_string())) + ] + }, + participation_count: 99, + application_buffer: vec![1,2,3,4,5,6,7,8,9], + attributes: vec![10,20,99,100000], + datetime: KerberosDateTime::now(), + gamemode: 111, + open_participation: false, + option0: 100, + progress_score: 1, + system_password_enabled: false, + user_password: "aaa".to_string(), + session_key: vec![91,123,5,2,1,2,4,124,4], + user_password_enabled: false, + gathering: Gathering{ + minimum_participants: 1, + maximum_participants: 12, + description: "aaargh".to_string(), + flags: 100, + host_pid: 999999919, + owner_pid: 138830, + participant_policy: 1, + policy_argument: 99837, + self_gid: 129, + state: 1389488 + } } +}); + +static DUMMY_SER: Lazy> = Lazy::new(|| serialize_to_vec(DUMMY.deref())); + +fn serialize_to_vec(r: &impl RmcSerialize) -> Vec{ + let mut vec = r.to_data(); + + vec.unwrap() } -struct SecureServer{ - router: Arc, - join_handle: JoinHandle<()>, - socket: Socket +fn read_struct(r: &[u8]) -> T{ + T::deserialize(&mut Cursor::new(r)).unwrap() +} +fn matchmake_with_param(c: &mut Criterion) { + let raw = DUMMY.deref(); + let ser = DUMMY_SER.deref().as_slice(); + c.bench_function("mmparam: ser", |b| b.iter(move || serialize_to_vec(black_box(raw)))); + c.bench_function("mmparam: de", |b| b.iter(move || read_struct::(black_box(ser)))); } -async fn start_secure_server() -> SecureServer{ - info!("starting secure server on {}:{}", *OWN_IP_PRIVATE, *SECURE_SERVER_PORT); +criterion_group!(benches, matchmake_with_param); +//criterion_main!(benches); - let (router, join_handle) = - Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT)).await - .expect("unable to startauth server"); - - info!("setting up endpoints"); - - let matchmake_data = Arc::new(RwLock::new( - MatchmakeData{ - matchmake_sessions: BTreeMap::new() - } - )); - - let rmcserver = RMCProtocolServer::new(Box::new([ - Box::new(block_if_maintenance), - Box::new(protocols::secure::bound_protocol()), - Box::new(protocols::matchmake::bound_protocol(matchmake_data.clone())), - Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)), - Box::new(protocols::nat_traversal::bound_protocol()) - ])); - - let socket = - Socket::new( - router.clone(), - VirtualPort::new(1,10), - "6f599f81", - Box::new(|p, count|{ - Box::pin( - async move { - let (session_key, pid, check_value) = read_secure_connection_data(&p.payload, &SECURE_SERVER_ACCOUNT)?; - - let check_value_response = check_value + 1; - - let data = bytemuck::bytes_of(&check_value_response); - - let mut response = Vec::new(); - - data.serialize(&mut response).ok()?; - - let encryption_pairs = generate_secure_encryption_pairs(session_key, count); - - Some((response, encryption_pairs, Some( - ActiveSecureConnectionData{ - pid, - session_key - } - ))) - } - ) - }), - Box::new(move |packet, socket, connection|{ - let rmcserver = rmcserver.clone(); - Box::pin(async move { rmcserver.process_message(packet, socket, connection).await; }) - }) - ).await.expect("unable to create socket"); - - SecureServer{ - join_handle, - router, - socket, +fn main(){ + for _ in 0..10000000 { + let v = serialize_to_vec(black_box(DUMMY.deref())); + let u = read_struct::(black_box(DUMMY_SER.deref().as_slice())); + black_box(v); + black_box(u); } -}*/ -/* -async fn start_auth() -> JoinHandle<()> { - tokio::spawn(async { - let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *AUTH_SERVER_PORT)) - .await - .expect("unable to start router"); - - let mut socket_secure = router_secure - .add_socket(VirtualPort::new(1, 10), Unsecure( - "6f599f81" - )) - .await - .expect("unable to add socket"); - - // let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); - - while !FORCE_EXIT.is_completed() { - let Some(conn) = socket_secure.accept().await else { - error!("server crashed"); - return; - }; - - info!("new connected user!"); - - let _ = new_rmc_gateway_connection(conn, |_| { - Arc::new(AuthHandler { - destination_server_acct: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - station_url: &SECURE_STATION_URL, - }) - }); - } - }) -} - -async fn start_secure() -> JoinHandle<()> { - tokio::spawn(async { - let mmm = Arc::new(MatchmakeManager{ - gid_counter: AtomicU32::new(1), - sessions: Default::default(), - users: Default::default(), - rv_cid_counter: AtomicU32::new(1), - }); - - let weak_mmm = Arc::downgrade(&mmm); - - MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - - let web_server = web::start_web(mmm.clone()).await; - - let (router_secure, _) = - Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT)) - .await - .expect("unable to start router"); - - let mut socket_secure = router_secure - .add_socket( - VirtualPort::new(1, 10), - Secure( - "6f599f81", - &SECURE_SERVER_ACCOUNT - ), - ) - .await - .expect("unable to add socket"); - - // let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); - - while !FORCE_EXIT.is_completed() { - let Some(conn) = socket_secure.accept().await else { - error!("server crashed"); - return; - }; - - info!("new connected user on secure :D!"); - - let ip = conn.socket_addr; - let pid = conn.user_id; - - let _ = new_rmc_gateway_connection(conn, |r| { - Arc::new_cyclic(|w| User { - ip, - pid, - this: w.clone(), - remote: RemoteConsole::new(r), - station_url: Default::default(), - matchmake_manager: mmm.clone() - }) - }); - } - }) -} - -async fn start_test() { - let addr = SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT); - - let virt_addr = VirtualPort::new(1, 10); - let prudp_addr = PRUDPSockAddr::new(addr, virt_addr); - - let (router_test, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, 26969)) - .await - .expect("unable to start router"); - - let mut socket_secure = router_test - .add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81")) - .await - .expect("unable to add socket"); - - let conn = socket_secure.connect(prudp_addr).await.unwrap(); - - let remote = new_rmc_gateway_connection(conn, |r| { - Arc::new(OnlyRemote::::new(r)) - }); - - tokio::time::sleep(Duration::from_secs(1)).await; - let urls = vec!["prudp:/address=192.168.178.45;port=60146;Pl=2;natf=0;natm=0;pmp=0;sid=15;upnp=0".to_owned()]; -} - -async fn start_servers() { - #[cfg(feature = "auth")] - let auth_server = start_auth().await; - #[cfg(feature = "secure")] - let secure_server = start_secure().await; - - - tokio::time::sleep(Duration::from_secs(1)).await; - - //start_test().await; - - - - #[cfg(feature = "auth")] - auth_server.await.expect("auth server crashed"); - #[cfg(feature = "secure")] - secure_server.await.expect("auth server crashed"); -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 134c1bc..e5184d0 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -162,6 +162,8 @@ mod test { use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rmc::response::RMCResponse; use std::io::Cursor; + + #[test] fn test() { diff --git a/rnex-core/src/prudp/station_url.rs b/rnex-core/src/prudp/station_url.rs index b2f70bb..a193b21 100644 --- a/rnex-core/src/prudp/station_url.rs +++ b/rnex-core/src/prudp/station_url.rs @@ -5,6 +5,7 @@ use std::io::Read; use crate::prudp::station_url::Type::{PRUDP, PRUDPS, UDP}; use crate::prudp::station_url::UrlOptions::{Address, ConnectionID, NatFiltering, NatMapping, NatType, Platform, PMP, Port, PrincipalID, RVConnectionID, StreamID, StreamType, UPNP, PID}; use crate::rmc::structures::Error::StationUrlInvalid; +use crate::rmc::structures::helpers::DummyFormatWriter; use crate::rmc::structures::RmcSerialize; #[derive(Clone, Copy, PartialEq, Eq)] pub enum Type{ @@ -135,59 +136,66 @@ impl TryFrom<&str> for StationUrl{ } } -impl<'a> Into for &'a StationUrl{ - fn into(self) -> String { - let mut url = match self.url_type{ +impl Display for StationUrl{ + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let url_type_str = match self.url_type{ UDP => "udp:/", PRUDP => "prudp:/", PRUDPS => "prudps:/" - }.to_owned(); + }; + write!(f, "{}",url_type_str)?; for option in &self.options{ match option{ - Address(v) => write!(url, "address={}", v).expect("failed to write"), - Port(v) => write!(url, "port={}", v).expect("failed to write"), - StreamType(v) => write!(url, "stream={}", v).expect("failed to write"), - StreamID(v) => write!(url, "sid={}", v).expect("failed to write"), - ConnectionID(v) => write!(url, "CID={}", v).expect("failed to write"), - PrincipalID(v) => write!(url, "PID={}", v).expect("failed to write"), - NatType(v) => write!(url, "type={}", v).expect("failed to write"), - NatMapping(v) => write!(url, "natm={}", v).expect("failed to write"), - NatFiltering(v) => write!(url, "natf={}", v).expect("failed to write"), - UPNP(v) => write!(url, "upnp={}", v).expect("failed to write"), - RVConnectionID(v) => write!(url, "RVCID={}", v).expect("failed to write"), - Platform(v) => write!(url, "pl={}", v).expect("failed to write"), - PMP(v) => write!(url, "pmp={}", v).expect("failed to write"), - PID(v) => write!(url, "PID={}", v).expect("failed to write"), + Address(v) => write!(f, "address={}", v)?, + Port(v) => write!(f, "port={}", v)?, + StreamType(v) => write!(f, "stream={}", v)?, + StreamID(v) => write!(f, "sid={}", v)?, + ConnectionID(v) => write!(f, "CID={}", v)?, + PrincipalID(v) => write!(f, "PID={}", v)?, + NatType(v) => write!(f, "type={}", v)?, + NatMapping(v) => write!(f, "natm={}", v)?, + NatFiltering(v) => write!(f, "natf={}", v)?, + UPNP(v) => write!(f, "upnp={}", v)?, + RVConnectionID(v) => write!(f, "RVCID={}", v)?, + Platform(v) => write!(f, "pl={}", v)?, + PMP(v) => write!(f, "pmp={}", v)?, + PID(v) => write!(f, "PID={}", v)?, } - write!(url, ";").expect("failed to write"); + write!(f, ";")?; } + Ok(()) + } +} + +impl<'a> Into for &'a StationUrl{ + fn into(self) -> String { + let mut url = self.to_string(); + url[0..url.len()-1].into() } } -impl Display for StationUrl{ - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let str: String = self.into(); - - write!(f, "{}", str) - } - - -} - impl RmcSerialize for StationUrl{ - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let str = String::deserialize(reader)?; Self::try_from(str.as_str()).map_err(|_| StationUrlInvalid) } - fn serialize(&self, writer: &mut dyn std::io::Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl std::io::Write) -> crate::rmc::structures::Result<()> { let str: String = self.into(); str.serialize(writer) } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + let mut dummy = DummyFormatWriter::new(); + + write!(&mut dummy, "{}", self)?; + + Ok(dummy.serialize_str_len()) + } } impl Debug for StationUrl{ diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index c1e68a4..e76b60a 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -9,7 +9,7 @@ pub struct Any{ } impl RmcSerialize for Any{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { self.name.serialize(writer)?; let u32_len = self.data.len() as u32; @@ -21,7 +21,7 @@ impl RmcSerialize for Any{ Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { let name = String::deserialize(reader)?; // also length ? diff --git a/rnex-core/src/rmc/structures/buffer.rs b/rnex-core/src/rmc/structures/buffer.rs index 5db53cf..085f053 100644 --- a/rnex-core/src/rmc/structures/buffer.rs +++ b/rnex-core/src/rmc/structures/buffer.rs @@ -4,7 +4,7 @@ use crate::rmc::structures::RmcSerialize; impl<'a> RmcSerialize for &'a [u8]{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { let u32_size = self.len() as u32; writer.write(bytemuck::bytes_of(&u32_size))?; writer.write(self)?; @@ -13,17 +13,25 @@ impl<'a> RmcSerialize for &'a [u8]{ } /// DO NOT USE (also maybe split off the serialize and deserialize functions at some point) - fn deserialize(_reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(_reader: &mut impl Read) -> crate::rmc::structures::Result { panic!("cannot deserialize to a u8 slice reference (use this ONLY for writing)") } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(4 + self.len() as u32) + } } impl RmcSerialize for Box<[u8]>{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { (&self[..]).serialize(writer) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Vec::deserialize(reader).map(|v| v.into_boxed_slice()) } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + (&self[..]).serialize_write_size() + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/helpers.rs b/rnex-core/src/rmc/structures/helpers.rs new file mode 100644 index 0000000..eeadbd6 --- /dev/null +++ b/rnex-core/src/rmc/structures/helpers.rs @@ -0,0 +1,48 @@ +use std::{fmt, io}; + +pub struct DummyFormatWriter(u32); + +impl fmt::Write for DummyFormatWriter{ + fn write_str(&mut self, s: &str) -> fmt::Result { + self.0 += s.as_bytes().len() as u32; + Ok(()) + } +} + +impl DummyFormatWriter{ + pub const fn new() -> Self{ Self(0) } + pub const fn serialize_str_len(&self) -> u32 { + 2 + self.0 + 1 + } +} + +pub struct DummyWriter(u32); + +impl io::Write for DummyWriter{ + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0 += buf.len() as u32; + Ok(buf.len()) + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0 += buf.len() as u32; + Ok(()) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl DummyWriter{ + pub const fn new() -> Self{ Self(0) } + pub const fn get_total_len(&self) -> u32{ + self.0 + } +} + + +pub fn len_of_write(f: impl FnOnce(&mut DummyWriter) -> anyhow::Result<()>) -> u32{ + let mut dummy = DummyWriter::new(); + f(&mut dummy).ok(); + dummy.get_total_len() +} \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs index f4843c1..980907d 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -9,7 +9,7 @@ use crate::rmc::structures::RmcSerialize; // this is also for implementing `Buffer` this is tecnically not the same as its handled internaly // probably but as it has the same mapping it doesn't matter and simplifies things impl RmcSerialize for Vec{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { let u32_len = self.len() as u32; writer.write_all(bytes_of(&u32_len))?; @@ -20,21 +20,27 @@ impl RmcSerialize for Vec{ Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut vec = Vec::with_capacity(len as usize); + //let mut vec = Vec::with_capacity(len as usize); - for _ in 0..len{ - vec.push(T::deserialize(reader)?); - } + let vec = (0..len).map(|_| T::deserialize(reader)).collect::, _>>()?; Ok(vec) } + + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + let mut val = 0u32; + for i in self{ + val += i.serialize_write_size()?; + } + Ok(4 + val) + } } impl RmcSerialize for [T; LEN]{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { for i in 0..LEN{ self[i].serialize(writer)?; } @@ -42,7 +48,7 @@ impl RmcSerialize for [T; LEN]{ Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let mut arr = [const { MaybeUninit::::uninit() }; LEN]; for i in 0..LEN{ @@ -55,4 +61,12 @@ impl RmcSerialize for [T; LEN]{ Ok(arr) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + let mut val = 0u32; + for i in self{ + val += i.serialize_write_size()?; + } + Ok(val) + } } diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 9d127f7..7a1610c 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -1,8 +1,8 @@ -use std::io; +use std::{fmt, io}; use std::io::{Read, Write}; use std::string::FromUtf8Error; use thiserror::Error; - +use crate::rmc::structures::helpers::DummyWriter; //ideas for the future: make a proc macro library which allows generation of struct reads #[derive(Error, Debug)] @@ -16,7 +16,9 @@ pub enum Error{ #[error("version mismatch: {0}")] VersionMismatch(u8), #[error("an error occurred reading the station url")] - StationUrlInvalid + StationUrlInvalid, + #[error("error formatting text: {0}")] + FormatError(#[from] fmt::Error) } pub type Result = std::result::Result; @@ -33,28 +35,43 @@ pub mod primitives; pub mod matchmake; pub mod variant; pub mod ranking; -mod networking; +pub mod networking; +pub mod helpers; pub trait RmcSerialize{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()>; - fn deserialize(reader: &mut dyn Read) -> Result where Self: Sized; + fn serialize(&self, writer: &mut impl Write) -> Result<()>; + fn serialize_write_size(&self) -> Result{ + let mut dummy = DummyWriter::new(); - fn to_data(&self) -> Vec{ - let mut data = Vec::new(); + self.serialize(&mut dummy)?; - self.serialize(&mut data).expect("out of memory or something"); + Ok(dummy.get_total_len()) + } + fn deserialize(reader: &mut impl Read) -> Result where Self: Sized; - data + fn to_data(&self) -> Result>{ + let mut data = Vec::with_capacity( + self.serialize_write_size()? as usize + ); + + self.serialize(&mut data)?; + + debug_assert_eq!(self.serialize_write_size().unwrap(), data.len() as u32); + + Ok(data) } } impl RmcSerialize for (){ - fn serialize(&self, _writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, _writer: &mut impl Write) -> Result<()> { Ok(()) } - fn deserialize(_reader: &mut dyn Read) -> Result { + fn deserialize(_reader: &mut impl Read) -> Result { Ok(()) } + fn serialize_write_size(&self) -> Result { + Ok(0) + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/networking.rs b/rnex-core/src/rmc/structures/networking.rs index 824a442..03627af 100644 --- a/rnex-core/src/rmc/structures/networking.rs +++ b/rnex-core/src/rmc/structures/networking.rs @@ -4,30 +4,36 @@ use rnex_core::prudp::virtual_port::VirtualPort; use crate::rmc::structures::RmcSerialize; impl RmcSerialize for SocketAddrV4{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.ip().to_bits().serialize(writer)?; self.port().serialize(writer)?; Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let ip = u32::deserialize(reader)?; let port = u16::deserialize(reader)?; Ok(SocketAddrV4::new(Ipv4Addr::from_bits(ip), port)) } + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(6) + } } impl RmcSerialize for VirtualPort{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(Self(u8::deserialize(reader)?)) } + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index 73985ed..65e732c 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -4,97 +4,146 @@ use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; impl RmcSerialize for u8{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } impl RmcSerialize for i8{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } impl RmcSerialize for u16{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(2) + } } impl RmcSerialize for i16{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(2) + } } impl RmcSerialize for u32{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(4) + } } impl RmcSerialize for i32{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(4) + } } impl RmcSerialize for u64{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } } impl RmcSerialize for i64{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } } impl RmcSerialize for f64{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) } - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } } impl RmcSerialize for bool{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { match self{ true => writer.write_all(&[1])?, false => writer.write_all(&[0])?, @@ -102,54 +151,77 @@ impl RmcSerialize for bool{ Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(u8::deserialize(reader)? != 0) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(1) + } } impl RmcSerialize for (T, U){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; Ok(()) } - - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; Ok((first, second)) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; Ok(()) } - - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; Ok((first, second, third)) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; self.3.serialize(writer)?; Ok(()) } - - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -157,10 +229,20 @@ impl RmcSeri Ok((first, second, third, fourth)) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W, X){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -170,7 +252,8 @@ impl crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -179,10 +262,21 @@ impl crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W, X, Y){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -193,7 +287,8 @@ impl crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -203,10 +298,22 @@ impl crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + ) + } } impl RmcSerialize for (T, U, V, W, X, Y, Z){ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; self.1.serialize(writer)?; self.2.serialize(writer)?; @@ -217,8 +324,8 @@ impl crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let first = T::deserialize(reader)?; let second = U::deserialize(reader)?; let third = V::deserialize(reader)?; @@ -229,13 +336,31 @@ impl crate::rmc::structures::Result { + Ok( + self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()? + ) + } } impl RmcSerialize for Box{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.as_ref().serialize(writer) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { T::deserialize(reader).map(Box::new) } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + T::serialize_write_size(self.as_ref()) + } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/qbuffer.rs b/rnex-core/src/rmc/structures/qbuffer.rs index 8fbfd5e..d459091 100644 --- a/rnex-core/src/rmc/structures/qbuffer.rs +++ b/rnex-core/src/rmc/structures/qbuffer.rs @@ -8,7 +8,7 @@ use crate::rmc::structures::{Result, RmcSerialize}; pub struct QBuffer(pub Vec); impl RmcSerialize for QBuffer{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { let len_u16 = self.0.len() as u16; writer.write(bytes_of(&len_u16))?; @@ -17,7 +17,7 @@ impl RmcSerialize for QBuffer{ Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { let size: u16 = reader.read_struct(IS_BIG_ENDIAN)?; let mut vec = vec![0; size as usize]; diff --git a/rnex-core/src/rmc/structures/qresult.rs b/rnex-core/src/rmc/structures/qresult.rs index 77ad70e..c614080 100644 --- a/rnex-core/src/rmc/structures/qresult.rs +++ b/rnex-core/src/rmc/structures/qresult.rs @@ -26,12 +26,12 @@ impl QResult{ } impl RmcSerialize for QResult{ - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { writer.write(bytes_of(self))?; Ok(()) } - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/rmc_struct.rs b/rnex-core/src/rmc/structures/rmc_struct.rs index 071cfdb..670b1e0 100644 --- a/rnex-core/src/rmc/structures/rmc_struct.rs +++ b/rnex-core/src/rmc/structures/rmc_struct.rs @@ -1,6 +1,12 @@ -use std::io::{Cursor, Read, Write}; +use std::any::Any; +use std::cmp::max; +use std::fmt::Arguments; +use std::io; +use std::io::{Cursor, ErrorKind, IoSlice, Read, Write}; +use std::ops::Sub; use bytemuck::bytes_of; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::rmc::structures; use crate::rmc::structures::Error::VersionMismatch; use crate::rmc::structures::Result; @@ -10,35 +16,97 @@ struct StructureHeader{ length: u32 } -pub fn write_struct(writer: &mut dyn Write, version: u8, pred: impl FnOnce(&mut Vec) -> Result<()> ) -> Result<()> { +#[cfg(feature = "rmc_struct_header")] +pub const HEADER_SIZE: u32 = 0; +#[cfg(not(feature = "rmc_struct_header"))] +pub const HEADER_SIZE: u32 = 5; + +pub struct OnlyWriteVec<'a>(&'a mut Vec); + +impl Write for OnlyWriteVec<'_> { + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.0.write_all(buf) + } + fn write_fmt(&mut self, args: Arguments<'_>) -> io::Result<()> { + self.0.write_fmt(args) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + self.0.write_vectored(bufs) + } +} + +#[cfg(feature = "rmc_struct_header")] +pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { writer.write_all(&[version])?; - let mut scratch_space: Vec = Vec::new(); + writer.write_all(bytes_of(&inner_size))?; - (pred)(&mut scratch_space)?; - - let u32_size = scratch_space.len() as u32; - - writer.write_all(bytes_of(&u32_size))?; - writer.write_all(&scratch_space)?; + (pred)(writer)?; Ok(()) } -pub fn read_struct(mut reader: &mut dyn Read, version: u8, pred: impl FnOnce(&mut Cursor>) -> Result) -> Result { + + +#[cfg(not(feature = "rmc_struct_header"))] +pub fn write_struct(writer: &mut T, version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { + pred(writer) +} + + +pub struct SubRead<'a, T: Read>{ + left_to_read: usize, + origin: &'a mut T +} + +impl<'a, T: Read> SubRead<'a, T>{ + pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self{ + Self{ + left_to_read, + origin + } + } +} + +impl Read for SubRead<'_, T>{ + #[inline(always)] + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let max_read = max(self.left_to_read, buf.len()); + let read = self.origin.read(&mut buf[..max_read])?; + self.left_to_read -= read; + Ok(read) + } + + #[inline(always)] + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + if buf.len() > self.left_to_read{ + return Err(io::Error::new(ErrorKind::UnexpectedEof, "Would run over end of SubRead")); + } + self.left_to_read -= buf.len(); + self.origin.read_exact(buf) + } +} + +#[cfg(feature = "rmc_struct_header")] +pub fn read_struct(mut reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead) -> Result) -> Result { let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?; - if ver != version{ + if ver != version { return Err(VersionMismatch(ver)); } let size: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut vec = vec![0u8; size as usize]; + Ok(pred(&mut SubRead::new(reader, size as usize))?) +} - reader.read_exact(&mut vec)?; - - let mut cursor = Cursor::new(vec); - - Ok(pred(&mut cursor)?) -} \ No newline at end of file +#[cfg(not(feature = "rmc_struct_header"))] +pub fn read_struct(mut reader: &mut R, version: u8, pred: impl FnOnce(&mut R) -> Result) -> Result { + Ok(pred(&mut reader)?) +} diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs index d25bc81..e090957 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -1,39 +1,49 @@ use std::io::{Read, Write}; use bytemuck::bytes_of; use log::error; +use rocket::form::validate::Len; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use super::{Result, RmcSerialize}; impl RmcSerialize for String{ - fn deserialize(mut reader: &mut dyn Read) -> Result { + fn deserialize(mut reader: &mut impl Read) -> Result { let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut data = vec![0; len as usize - 1]; + if len == 0{ + return Ok("".to_string()); + } + let mut data = vec![0; len as usize]; reader.read_exact(&mut data)?; - - let null: u8 = reader.read_struct(IS_BIG_ENDIAN)?; - if null != 0{ + if *data.last().unwrap() != 0{ error!("unable to find null terminator... continuing anyways"); } + data.pop(); Ok(String::from_utf8(data)?) } - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { (&self[..]).serialize(writer) } + fn serialize_write_size(&self) -> Result { + (&self[..]).serialize_write_size() + } } impl RmcSerialize for &str{ - fn deserialize(_reader: &mut dyn Read) -> Result { + fn deserialize(_reader: &mut impl Read) -> Result { panic!("cannot serialize to &str") } - fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { let u16_len: u16 = (self.len() + 1) as u16; - writer.write(bytes_of(&u16_len))?; + writer.write_all(bytes_of(&u16_len))?; - writer.write(self.as_bytes())?; - writer.write(&[0])?; + writer.write_all(self.as_bytes())?; + writer.write_all(&[0])?; Ok(()) } + #[inline(always)] + fn serialize_write_size(&self) -> Result { + Ok(2 + self.as_bytes().len() as u32 + 1) + } } diff --git a/rnex-core/src/rmc/structures/variant.rs b/rnex-core/src/rmc/structures/variant.rs index ebd25b8..6056f3f 100644 --- a/rnex-core/src/rmc/structures/variant.rs +++ b/rnex-core/src/rmc/structures/variant.rs @@ -16,7 +16,7 @@ pub enum Variant{ } impl RmcSerialize for Variant{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { match self{ Variant::None => { writer.write_all(&[0])?; @@ -50,7 +50,7 @@ impl RmcSerialize for Variant{ Ok(()) } - fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { match u8::deserialize(reader)?{ 0 => Ok(Variant::None), 1 => Ok(Variant::SInt64(i64::deserialize(reader)?)), -- 2.47.3 From 367a8fb553d3096628a1a3b17aa43b67ed336735 Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 08:39:39 +0100 Subject: [PATCH 30/98] fix dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index f1ea22f..a140f56 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,8 @@ COPY . . RUN git submodule update --init --recursive -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --target x86_64-unknown-linux-musl -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --target x86_64-unknown-linux-musl # +RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features rmc_struct_header --target x86_64-unknown-linux-musl +RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --features rmc_struct_header --release --target x86_64-unknown-linux-musl # FROM scratch AS node-holder COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /edge_node_holder_server -- 2.47.3 From 11ba2b147047df77068ec7fafc84bc8408288c1c Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 09:51:05 +0100 Subject: [PATCH 31/98] reduce dependency bloat --- .gitmodules | 3 - Cargo.lock | 2039 +----------------------- grpc-protobufs | 1 - rnex-core/Cargo.toml | 10 +- rnex-core/src/executables/common.rs | 7 +- rnex-core/src/grpc/account.rs | 29 +- rnex-core/src/grpc/mod.rs | 4 +- rnex-core/src/lib.rs | 1 - rnex-core/src/main.rs | 1 - rnex-core/src/rmc/structures/string.rs | 1 - rnex-core/src/web/mod.rs | 92 -- 11 files changed, 106 insertions(+), 2082 deletions(-) delete mode 100644 .gitmodules delete mode 160000 grpc-protobufs delete mode 100644 rnex-core/src/web/mod.rs diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 64cd88d..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "grpc-protobufs"] - path = grpc-protobufs - url = https://github.com/PretendoNetwork/grpc-protobufs.git diff --git a/Cargo.lock b/Cargo.lock index 7965148..7ed1c06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,28 +59,6 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "async-trait" version = "0.1.88" @@ -92,80 +70,12 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] -name = "atomic" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89cbf775b137e9b968e67227ef7f775587cde3fd31b0d8599dbd0f598a48340" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.75" @@ -178,7 +88,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -187,12 +97,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "binascii" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" - [[package]] name = "bitflags" version = "2.9.1" @@ -261,12 +165,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - [[package]] name = "chrono" version = "0.4.41" @@ -343,33 +241,21 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "criterion" version = "0.7.0" @@ -444,16 +330,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "ctrlc" -version = "3.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73" -dependencies = [ - "nix", - "windows-sys 0.59.0", -] - [[package]] name = "deranged" version = "0.4.0" @@ -463,39 +339,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "devise" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" -dependencies = [ - "devise_codegen", - "devise_core", -] - -[[package]] -name = "devise_codegen" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" -dependencies = [ - "devise_core", - "quote", -] - -[[package]] -name = "devise_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" -dependencies = [ - "bitflags", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.104", -] - [[package]] name = "digest" version = "0.10.7" @@ -507,17 +350,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "dotenv" version = "0.15.0" @@ -531,48 +363,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "flate2" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "figment" -version = "0.10.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" -dependencies = [ - "atomic 0.6.1", - "pear", - "serde", - "toml", - "uncased", - "version_check", + "crc32fast", + "miniz_oxide", ] [[package]] @@ -581,108 +378,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -701,19 +396,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasi", ] [[package]] @@ -722,50 +405,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "h2" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.10.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.3.1", - "indexmap 2.10.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "half" version = "2.7.1" @@ -777,24 +416,6 @@ dependencies = [ "zerocopy", ] -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hex" version = "0.4.3" @@ -810,17 +431,6 @@ dependencies = [ "digest", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.3.1" @@ -832,168 +442,12 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http 1.3.1", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "pin-project-lite", -] - [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.11", - "http 1.3.1", - "http-body 1.0.1", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http 1.3.1", - "hyper 1.6.0", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper 1.6.0", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.6.0", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" -dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.6.0", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.0", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - [[package]] name = "iana-time-zone" version = "0.1.63" @@ -1018,140 +472,6 @@ dependencies = [ "cc", ] -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[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", -] - -[[package]] -name = "indexmap" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" -dependencies = [ - "equivalent", - "hashbrown 0.15.4", - "serde", -] - -[[package]] -name = "inlinable_string" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" - [[package]] name = "inout" version = "0.1.4" @@ -1172,33 +492,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1230,30 +523,12 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "libc" version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - [[package]] name = "lock_api" version = "0.4.13" @@ -1270,21 +545,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - [[package]] name = "macros" version = "0.0.0" @@ -1304,21 +564,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "md-5" version = "0.10.6" @@ -1335,12 +580,6 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1348,6 +587,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -1357,68 +597,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "windows-sys 0.59.0", ] -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.3.1", - "httparse", - "memchr", - "mime", - "spin", - "tokio", - "tokio-util", - "version_check", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1434,16 +616,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "num_threads" version = "0.1.7" @@ -1474,56 +646,6 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" -[[package]] -name = "openssl" -version = "0.10.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking_lot" version = "0.12.4" @@ -1544,7 +666,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -1553,73 +675,18 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pear" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.104", -] - [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "plotters" version = "0.3.7" @@ -1648,15 +715,6 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -1681,28 +739,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "version_check", - "yansi", -] - -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", -] - [[package]] name = "prudpv1" version = "0.1.0" @@ -1730,12 +766,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - [[package]] name = "rand" version = "0.8.5" @@ -1763,7 +793,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom", ] [[package]] @@ -1804,26 +834,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "ref-cast" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "regex" version = "1.11.1" @@ -1832,17 +842,8 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -1853,63 +854,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.5", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "reqwest" -version = "0.12.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.4.11", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.6.0", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "mime", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower 0.5.2", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "ring" version = "0.17.14" @@ -1918,7 +871,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom", "libc", "untrusted", "windows-sys 0.52.0", @@ -1929,11 +882,9 @@ name = "rnex-core" version = "0.1.1" dependencies = [ "anyhow", - "async-trait", "bytemuck", "chrono", "criterion", - "ctrlc", "dotenv", "hex", "hmac", @@ -1945,124 +896,29 @@ dependencies = [ "paste", "rand", "rc4", - "reqwest", - "rocket", "simplelog", "thiserror", "tokio", - "tonic", "typenum", + "ureq", "v-byte-helpers", ] -[[package]] -name = "rocket" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" -dependencies = [ - "async-stream", - "async-trait", - "atomic 0.5.3", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap 2.10.0", - "log", - "memchr", - "multer", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "serde_json", - "state", - "tempfile", - "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" -dependencies = [ - "devise", - "glob", - "indexmap 2.10.0", - "proc-macro2", - "quote", - "rocket_http", - "syn 2.0.104", - "unicode-xid", - "version_check", -] - -[[package]] -name = "rocket_http" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" -dependencies = [ - "cookie", - "either", - "futures", - "http 0.2.12", - "hyper 0.14.32", - "indexmap 2.10.0", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", - "smallvec", - "stable-pattern", - "state", - "time", - "tokio", - "uncased", -] - [[package]] name = "rustc-demangle" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" -[[package]] -name = "rustix" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.60.2", -] - [[package]] name = "rustls" version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ + "log", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -2110,50 +966,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "serde" version = "1.0.219" @@ -2186,36 +1004,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" @@ -2231,6 +1019,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "simplelog" version = "0.12.2" @@ -2254,16 +1048,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "socket2" version = "0.6.0" @@ -2274,36 +1058,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - [[package]] name = "subtle" version = "2.6.1" @@ -2332,60 +1086,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - [[package]] name = "termcolor" version = "1.4.1" @@ -2415,15 +1115,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - [[package]] name = "time" version = "0.3.41" @@ -2457,16 +1148,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - [[package]] name = "tinytemplate" version = "1.2.1" @@ -2492,7 +1173,7 @@ dependencies = [ "pin-project-lite", "signal-hook-registry", "slab", - "socket2 0.6.0", + "socket2", "tokio-macros", "windows-sys 0.59.0", ] @@ -2508,290 +1189,18 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.10.0", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow", -] - -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - -[[package]] -name = "tonic" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64", - "bytes", - "h2 0.4.11", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.6.0", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "socket2 0.5.10", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "iri-string", - "pin-project-lite", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "typenum" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" -[[package]] -name = "ubyte" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" -dependencies = [ - "serde", -] - -[[package]] -name = "uncased" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" -dependencies = [ - "serde", - "version_check", -] - [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" @@ -2799,21 +1208,39 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "url" -version = "2.5.4" +name = "ureq" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" dependencies = [ - "form_urlencoded", - "idna", + "base64", + "flate2", + "log", "percent-encoding", + "rustls", + "rustls-pki-types", + "ureq-proto", + "utf-8", + "webpki-roots", ] [[package]] -name = "utf8_iter" -version = "1.0.4" +name = "ureq-proto" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "60b4531c118335662134346048ddb0e54cc86bd7e81866757873055f0e38f5d2" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "v-byte-helpers" @@ -2824,18 +1251,6 @@ dependencies = [ "macros 0.1.1", ] -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -2852,30 +1267,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2902,19 +1299,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.100" @@ -2958,21 +1342,14 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.9" +name = "webpki-roots" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "rustls-pki-types", ] -[[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-util" version = "0.1.9" @@ -2982,21 +1359,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[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" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-core" version = "0.61.2" @@ -3038,17 +1400,6 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -3073,7 +1424,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -3082,31 +1433,7 @@ 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-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.3", -] - -[[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", + "windows-targets", ] [[package]] @@ -3115,228 +1442,64 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "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", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[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_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[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_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[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_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[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_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[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_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[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 = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" -dependencies = [ - "memchr", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "synstructure", -] - [[package]] name = "zerocopy" version = "0.8.26" @@ -3357,62 +1520,8 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", - "synstructure", -] - [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] diff --git a/grpc-protobufs b/grpc-protobufs deleted file mode 160000 index 405fe9b..0000000 --- a/grpc-protobufs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 405fe9b47b416e76b21d7087b2ed11606deccfcf diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index b609afb..cd52ec6 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -18,19 +18,17 @@ rand = "0.8.5" hmac = "0.12.1" md-5 = "^0.10.6" tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } -tonic = "0.12.3" hex = "0.4.3" macros = { path = "../macros" } -rocket = { version = "0.5.1", features = ["json", "serde_json"] } -async-trait = "0.1.86" paste = "1.0.15" typenum = "1.18.0" -reqwest = { version= "0.12.18", features = ["blocking"]} json = "0.12.4" -ctrlc = "3.4.7" -criterion = "0.7.0" anyhow = "1.0.100" +ureq = "3.1.4" + +[dev-dependencies] +criterion = "0.7.0" [features] rmc_struct_header = [] diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index 73571d7..7a55f24 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -19,8 +19,11 @@ const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip"; fn try_get_ip() -> Result> { - let req = reqwest::blocking::get(IP_REQ_SERVICE_URL)?; - Ok(req.text()?.parse()?) + let mut req = ureq::get(IP_REQ_SERVICE_URL) + .call()?; + + + Ok(req.body_mut().read_to_string()?.parse()?) } pub static OWN_IP_PRIVATE: Lazy = Lazy::new(|| { diff --git a/rnex-core/src/grpc/account.rs b/rnex-core/src/grpc/account.rs index 5f49cbd..5314006 100644 --- a/rnex-core/src/grpc/account.rs +++ b/rnex-core/src/grpc/account.rs @@ -1,11 +1,11 @@ use std::{env, result}; use std::array::TryFromSliceError; +use std::ops::Deref; use std::str::FromStr; use json::{object, JsonValue}; use once_cell::sync::Lazy; -use reqwest::{Body, Method, Url}; -use reqwest::header::HeaderValue; use thiserror::Error; +use tokio::task::{spawn_blocking, JoinError}; use crate::grpc::account::Error::SomethingHappened; static API_KEY: Lazy = Lazy::new(||{ let key = env::var("ACCOUNT_GQL_API_KEY") @@ -26,27 +26,38 @@ static CLIENT_URI: Lazy = Lazy::new(||{ #[derive(Error, Debug)] pub enum Error{ #[error(transparent)] - Creation(#[from] reqwest::Error), + RequestError(#[from] ureq::Error), #[error(transparent)] Json(#[from] json::Error), - #[error(transparent)] - Status(#[from] tonic::Status), + //#[error(transparent)] + //Status(#[from] tonic::Status), #[error("invalid password size: {0}")] PasswordConversion(#[from] TryFromSliceError), #[error("something happened")] - SomethingHappened + SomethingHappened, + #[error("error joining blocking task: {0}")] + Join(#[from] JoinError) } pub type Result = result::Result; -pub struct Client(reqwest::Client); +pub struct Client;//(reqwest::Client); impl Client{ pub async fn new() -> Result { - Ok(Self(reqwest::ClientBuilder::new().build()?)) + //Ok(Self(reqwest::ClientBuilder::new().build()?)) + Ok(Self) } async fn do_request(&self, request_data: JsonValue) -> Result{ + let mut request = ureq::post(CLIENT_URI.as_str()) + .header("X-API-Key", API_KEY.deref()) + .content_type("application/json"); + let mut response = spawn_blocking(move || request.send(request_data.to_string())).await??; + + let str_body = response.body_mut().read_to_string()?; + Ok(json::parse(&str_body)?) + /* let mut request = reqwest::Request::new(Method::POST, Url::from_str(CLIENT_URI.as_str()).unwrap()); *(request.body_mut()) = Some(Body::from(request_data.to_string())); @@ -56,6 +67,8 @@ impl Client{ let response = self.0.execute(request).await?; Ok(json::parse(&response.text().await?)?) + + */ } pub async fn get_nex_password(&mut self , pid: u32) -> Result<[u8; 16]>{ diff --git a/rnex-core/src/grpc/mod.rs b/rnex-core/src/grpc/mod.rs index 31831f8..c96ccfe 100644 --- a/rnex-core/src/grpc/mod.rs +++ b/rnex-core/src/grpc/mod.rs @@ -2,7 +2,7 @@ //! before account rs is finished. //! //! This WILL be deprecated as soon as account rs is in a stable state. -use tonic::{Request, Status}; +//use tonic::{Request, Status}; -type InterceptorFunc = Box) -> Result, Status> + Send>; +//type InterceptorFunc = Box) -> Result, Status> + Send>; pub mod account; \ No newline at end of file diff --git a/rnex-core/src/lib.rs b/rnex-core/src/lib.rs index 4a4f1ef..3920565 100644 --- a/rnex-core/src/lib.rs +++ b/rnex-core/src/lib.rs @@ -17,7 +17,6 @@ pub mod kerberos; pub mod nex; pub mod result; pub mod versions; -pub mod web; pub mod common; pub mod reggie; pub mod rnex_proxy_common; diff --git a/rnex-core/src/main.rs b/rnex-core/src/main.rs index cfa323d..9ff052f 100644 --- a/rnex-core/src/main.rs +++ b/rnex-core/src/main.rs @@ -32,7 +32,6 @@ mod kerberos; mod nex; mod result; mod versions; -mod web; pub mod reggie; pub mod util; pub mod common; diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs index e090957..12123fd 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -1,7 +1,6 @@ use std::io::{Read, Write}; use bytemuck::bytes_of; use log::error; -use rocket::form::validate::Len; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use super::{Result, RmcSerialize}; diff --git a/rnex-core/src/web/mod.rs b/rnex-core/src/web/mod.rs deleted file mode 100644 index 9412967..0000000 --- a/rnex-core/src/web/mod.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::sync::Arc; -use async_trait::async_trait; -use rocket::{get, routes, Request, State}; -use rocket::request::{FromRequest, Outcome}; -use rocket::serde::json::Json; -use tokio::task::JoinHandle; -use crate::nex::matchmake::MatchmakeManager; -use crate::rmc::protocols::notifications::NotificationEvent; - -struct RnexApiAuth; - -#[async_trait] -impl<'r> FromRequest<'r> for RnexApiAuth{ - - type Error = (); - async fn from_request<'a>(_request: &'r Request<'a>) -> Outcome { - Outcome::Success(RnexApiAuth) - } -} - - -#[get("/gatherings")] -async fn gatherings(mmm: &State>) -> Json>{ - let matches = mmm.sessions.read().await; - - Json(matches.keys().map(|v| *v).collect()) -} - -#[get("/gathering//players")] -async fn players_in_match(mmm: &State>, gid: u32) -> Option>>{ - let mmm = mmm.sessions.read().await; - - let gathering = mmm.get(&gid)?; - - let gathering = gathering.clone(); - - drop(mmm); - - let gathering = gathering.lock().await; - - Some(Json(gathering.connected_players.iter().filter_map(|p| p.upgrade()).map(|p| p.pid).collect())) -} -/* -#[get("/player//disconnect")] -async fn disconnect_player(_auth: RnexApiAuth, mmm: &State>, pid: u32) -> Option<()>{ - // this doesnt work and is broken, there might be some other way to remotely close gatherings... - // also if anyone gets this working change it to POST cause the only reason its get is because - // that makes testing it easier - let mmm = mmm.users.read().await; - - for player in mmm.values().filter_map(|p| p.upgrade()).filter(|p| p.pid == pid) { - player.remote.get_connection().0.close_connection().await; - } - - - Some(()) -}*/ - -#[get("/gathering//close")] -async fn close_gathering(_auth: RnexApiAuth, mmm: &State>, gid: u32) -> Option<()>{ - // this doesnt work and is broken, there might be some other way to remotely close gatherings... - // also if anyone gets this working change it to POST cause the only reason its get is because - // that makes testing it easier - let mmm = mmm.sessions.read().await; - - let gathering = mmm.get(&gid)?; - - let gathering = gathering.clone(); - - drop(mmm); - - let gathering = gathering.lock().await; - - gathering.broadcast_notification(&NotificationEvent{ - pid_source: gathering.session.gathering.owner_pid, - notif_type: 109000, - param_1: gathering.session.gathering.self_gid, - ..Default::default() - }).await; - - Some(()) -} - -pub async fn start_web(mgr: Arc) -> JoinHandle<()> { - tokio::spawn(async move { - rocket::build() - .mount("/", routes![gatherings, players_in_match, close_gathering]) - .manage(mgr) - .launch().await - .expect("unable to start webserver"); - }) -} \ No newline at end of file -- 2.47.3 From 755e5c47470e53e691117370481546fbd1be929d Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 10:06:58 +0100 Subject: [PATCH 32/98] fix warnings and criterion in main --- macros/src/lib.rs | 3 +-- rnex-core/src/grpc/account.rs | 3 +-- rnex-core/src/kerberos/mod.rs | 1 - rnex-core/src/main.rs | 21 +-------------------- rnex-core/src/nex/auth_handler.rs | 4 ++-- rnex-core/src/prudp/station_url.rs | 5 ++--- rnex-core/src/rmc/response.rs | 2 +- rnex-core/src/rmc/structures/any.rs | 2 +- rnex-core/src/rmc/structures/list.rs | 2 +- rnex-core/src/rmc/structures/primitives.rs | 18 +++++++++--------- rnex-core/src/rmc/structures/qbuffer.rs | 2 +- rnex-core/src/rmc/structures/qresult.rs | 2 +- rnex-core/src/rmc/structures/ranking.rs | 1 - rnex-core/src/rmc/structures/rmc_struct.rs | 21 +++++++++++---------- rnex-core/src/rmc/structures/string.rs | 2 +- 15 files changed, 33 insertions(+), 56 deletions(-) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 67486ef..d088561 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -126,7 +126,6 @@ fn gen_serialize_data_struct( let ident = f.ident.as_ref().unwrap(); - let ty = &f.ty; size_content.append_all(quote! { + rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)? @@ -259,7 +258,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { let mut inner_match_de = quote! {}; let mut inner_match_se = quote! {}; - let mut inner_match_len = quote!{}; + //let mut inner_match_len = quote!{}; for variant in e.variants { let Some((_, val)) = variant.discriminant else { diff --git a/rnex-core/src/grpc/account.rs b/rnex-core/src/grpc/account.rs index 5314006..a70149f 100644 --- a/rnex-core/src/grpc/account.rs +++ b/rnex-core/src/grpc/account.rs @@ -1,7 +1,6 @@ use std::{env, result}; use std::array::TryFromSliceError; use std::ops::Deref; -use std::str::FromStr; use json::{object, JsonValue}; use once_cell::sync::Lazy; use thiserror::Error; @@ -50,7 +49,7 @@ impl Client{ } async fn do_request(&self, request_data: JsonValue) -> Result{ - let mut request = ureq::post(CLIENT_URI.as_str()) + let request = ureq::post(CLIENT_URI.as_str()) .header("X-API-Key", API_KEY.deref()) .content_type("application/json"); let mut response = spawn_blocking(move || request.send(request_data.to_string())).await??; diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index a54764e..b118651 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -158,7 +158,6 @@ impl Ticket{ #[cfg(test)] mod test{ - use chrono::{Datelike, Utc}; use crate::kerberos::KerberosDateTime; #[test] diff --git a/rnex-core/src/main.rs b/rnex-core/src/main.rs index 9ff052f..eda5915 100644 --- a/rnex-core/src/main.rs +++ b/rnex-core/src/main.rs @@ -10,18 +10,8 @@ extern crate self as rust_nex; -use crate::nex::account::Account; -use chrono::{Local, SecondsFormat}; use once_cell::sync::Lazy; -use simplelog::{ - ColorChoice, CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode, WriteLogger, -}; -use std::fs::File; -use std::net::{Ipv4Addr}; -use std::sync::Once; -use std::{env, fs}; use std::hint::black_box; -use criterion::{criterion_group, criterion_main, Criterion}; mod prudp; pub mod rmc; @@ -118,7 +108,7 @@ static DUMMY: Lazy = Lazy::new(|| AutoMatchmakeParam{ static DUMMY_SER: Lazy> = Lazy::new(|| serialize_to_vec(DUMMY.deref())); fn serialize_to_vec(r: &impl RmcSerialize) -> Vec{ - let mut vec = r.to_data(); + let vec = r.to_data(); vec.unwrap() } @@ -126,15 +116,6 @@ fn serialize_to_vec(r: &impl RmcSerialize) -> Vec{ fn read_struct(r: &[u8]) -> T{ T::deserialize(&mut Cursor::new(r)).unwrap() } -fn matchmake_with_param(c: &mut Criterion) { - let raw = DUMMY.deref(); - let ser = DUMMY_SER.deref().as_slice(); - c.bench_function("mmparam: ser", |b| b.iter(move || serialize_to_vec(black_box(raw)))); - c.bench_function("mmparam: de", |b| b.iter(move || read_struct::(black_box(ser)))); -} - -criterion_group!(benches, matchmake_with_param); -//criterion_main!(benches); fn main(){ for _ in 0..10000000 { diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index e5184d0..9b67fca 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -171,14 +171,14 @@ mod test { let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap(); - let rnex_core::rmc::response::RMCResponseResult::Success { call_id, method_id, data: stuff} = stuff.response_result else { + let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result else { panic!() }; // let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap(); - // let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); + let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); let data = <(QResult, u32, Vec, ConnectionData, String) as RmcSerialize>::deserialize( &mut Cursor::new(stuff), diff --git a/rnex-core/src/prudp/station_url.rs b/rnex-core/src/prudp/station_url.rs index a193b21..a4665c2 100644 --- a/rnex-core/src/prudp/station_url.rs +++ b/rnex-core/src/prudp/station_url.rs @@ -170,9 +170,8 @@ impl Display for StationUrl{ impl<'a> Into for &'a StationUrl{ fn into(self) -> String { - let mut url = self.to_string(); - - + let url = self.to_string(); + url[0..url.len()-1].into() } } diff --git a/rnex-core/src/rmc/response.rs b/rnex-core/src/rmc/response.rs index a732853..c994f8b 100644 --- a/rnex-core/src/rmc/response.rs +++ b/rnex-core/src/rmc/response.rs @@ -471,7 +471,7 @@ mod test { #[test] fn test() { - let mut data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; + let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; let mut data = data_orig; let mut rc4: Rc4 = diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index e76b60a..b60ca8a 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -21,7 +21,7 @@ impl RmcSerialize for Any{ Ok(()) } - fn deserialize(mut reader: &mut impl Read) -> Result { + fn deserialize(reader: &mut impl Read) -> Result { let name = String::deserialize(reader)?; // also length ? diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs index 980907d..890be9a 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -20,7 +20,7 @@ impl RmcSerialize for Vec{ Ok(()) } - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; //let mut vec = Vec::with_capacity(len as usize); diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index 65e732c..8918968 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -10,7 +10,7 @@ impl RmcSerialize for u8{ } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -26,7 +26,7 @@ impl RmcSerialize for i8{ } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -41,7 +41,7 @@ impl RmcSerialize for u16{ Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -56,7 +56,7 @@ impl RmcSerialize for i16{ Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -71,7 +71,7 @@ impl RmcSerialize for u32{ Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -86,7 +86,7 @@ impl RmcSerialize for i32{ Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -101,7 +101,7 @@ impl RmcSerialize for u64{ Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -116,7 +116,7 @@ impl RmcSerialize for i64{ Ok(writer.write_all(bytes_of(self))?) } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] @@ -132,7 +132,7 @@ impl RmcSerialize for f64{ } #[inline(always)] - fn deserialize(mut reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } #[inline(always)] diff --git a/rnex-core/src/rmc/structures/qbuffer.rs b/rnex-core/src/rmc/structures/qbuffer.rs index d459091..fb30e64 100644 --- a/rnex-core/src/rmc/structures/qbuffer.rs +++ b/rnex-core/src/rmc/structures/qbuffer.rs @@ -17,7 +17,7 @@ impl RmcSerialize for QBuffer{ Ok(()) } - fn deserialize(mut reader: &mut impl Read) -> Result { + fn deserialize(reader: &mut impl Read) -> Result { let size: u16 = reader.read_struct(IS_BIG_ENDIAN)?; let mut vec = vec![0; size as usize]; diff --git a/rnex-core/src/rmc/structures/qresult.rs b/rnex-core/src/rmc/structures/qresult.rs index c614080..312540a 100644 --- a/rnex-core/src/rmc/structures/qresult.rs +++ b/rnex-core/src/rmc/structures/qresult.rs @@ -31,7 +31,7 @@ impl RmcSerialize for QResult{ Ok(()) } - fn deserialize(mut reader: &mut impl Read) -> Result { + fn deserialize(reader: &mut impl Read) -> Result { Ok(reader.read_struct(IS_BIG_ENDIAN)?) } } \ No newline at end of file diff --git a/rnex-core/src/rmc/structures/ranking.rs b/rnex-core/src/rmc/structures/ranking.rs index afb0698..9602553 100644 --- a/rnex-core/src/rmc/structures/ranking.rs +++ b/rnex-core/src/rmc/structures/ranking.rs @@ -25,7 +25,6 @@ struct UserData{ mod test{ use std::io::Cursor; use bytemuck::from_bytes; - use tokio::io::AsyncReadExt; use crate::rmc::structures::ranking::{UploadCompetitionData, UserData}; use rnex_core::rmc::structures::RmcSerialize; diff --git a/rnex-core/src/rmc/structures/rmc_struct.rs b/rnex-core/src/rmc/structures/rmc_struct.rs index 670b1e0..52184bb 100644 --- a/rnex-core/src/rmc/structures/rmc_struct.rs +++ b/rnex-core/src/rmc/structures/rmc_struct.rs @@ -1,15 +1,11 @@ -use std::any::Any; + use std::cmp::max; use std::fmt::Arguments; use std::io; -use std::io::{Cursor, ErrorKind, IoSlice, Read, Write}; -use std::ops::Sub; -use bytemuck::bytes_of; -use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::rmc::structures; -use crate::rmc::structures::Error::VersionMismatch; +use std::io::{ErrorKind, IoSlice, Read, Write}; use crate::rmc::structures::Result; + #[repr(C, packed)] struct StructureHeader{ version: u8, @@ -43,6 +39,8 @@ impl Write for OnlyWriteVec<'_> { #[cfg(feature = "rmc_struct_header")] pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { + use bytemuck::bytes_of; + writer.write_all(&[version])?; writer.write_all(bytes_of(&inner_size))?; @@ -55,7 +53,7 @@ pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred #[cfg(not(feature = "rmc_struct_header"))] -pub fn write_struct(writer: &mut T, version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { +pub fn write_struct(writer: &mut T, _version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { pred(writer) } @@ -94,7 +92,10 @@ impl Read for SubRead<'_, T>{ } #[cfg(feature = "rmc_struct_header")] -pub fn read_struct(mut reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead) -> Result) -> Result { +pub fn read_struct(reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead) -> Result) -> Result { + use crate::rmc::structures::Error::VersionMismatch; + use v_byte_helpers::ReadExtensions; + use v_byte_helpers::IS_BIG_ENDIAN; let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?; if ver != version { @@ -107,6 +108,6 @@ pub fn read_struct(mut reader: &mut R, version: u8, pred: imp } #[cfg(not(feature = "rmc_struct_header"))] -pub fn read_struct(mut reader: &mut R, version: u8, pred: impl FnOnce(&mut R) -> Result) -> Result { +pub fn read_struct(mut reader: &mut R, _version: u8, pred: impl FnOnce(&mut R) -> Result) -> Result { Ok(pred(&mut reader)?) } diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs index 12123fd..1231956 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -5,7 +5,7 @@ use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use super::{Result, RmcSerialize}; impl RmcSerialize for String{ - fn deserialize(mut reader: &mut impl Read) -> Result { + fn deserialize(reader: &mut impl Read) -> Result { let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; if len == 0{ return Ok("".to_string()); -- 2.47.3 From 31d495c932bc17db84ed0a6d182943961c809c74 Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 14:06:08 +0100 Subject: [PATCH 33/98] add editions --- .ci-scripts/make-edition.sh | 16 ++ .dockerignore | 10 +- .gitlab-ci.yml | 30 ++-- Cargo.lock | 310 ------------------------------------ Dockerfile | 12 +- build-edition.sh | 11 ++ buildscripts/common.sh | 9 ++ editions.yaml | 10 ++ rnex-core/Cargo.toml | 2 +- test-edition.sh | 11 ++ 10 files changed, 85 insertions(+), 336 deletions(-) create mode 100644 .ci-scripts/make-edition.sh create mode 100644 build-edition.sh create mode 100644 buildscripts/common.sh create mode 100644 editions.yaml create mode 100644 test-edition.sh diff --git a/.ci-scripts/make-edition.sh b/.ci-scripts/make-edition.sh new file mode 100644 index 0000000..5f8694c --- /dev/null +++ b/.ci-scripts/make-edition.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +export EDITION=$1 + +podman build -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container . +podman push "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" +podman build -t "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . +podman build -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" --target=proxy-secure . +podman build -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure . +podman build -t "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth . +podman build -t "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure . +podman push "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" +podman push "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" +podman push "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" +podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" +podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" \ No newline at end of file diff --git a/.dockerignore b/.dockerignore index 0d95126..4e09ffe 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,10 @@ .env -target \ No newline at end of file +target +.dockerignore +Dockerfile +CODE_OF_CONDUCT.md +CONTRIBUTING.md +README.md +.gitignore +LICENSE +.devcontainer.json \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24011c9..fad0b25 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,28 +1,20 @@ default: image: quay.io/podman/stable + before_script: + - git submodule update --init + - podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY variables: DOCKER_TLS_CERTDIR: "/certs" IMAGE_TAG: "${CI_COMMIT_REF_SLUG}" stages: - - test - - build-and-push-image + - build_and_test -build-and-push-image: - stage: build-and-push-image - script: - - git submodule update --init - - podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - - podman build -t "$CI_REGISTRY_IMAGE/dev-container:latest" --target=dev-container . - - podman push "$CI_REGISTRY_IMAGE/dev-container:latest" - - podman build -t "$CI_REGISTRY_IMAGE/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . - - podman build -t "$CI_REGISTRY_IMAGE/proxy-secure-v1:$CI_COMMIT_SHORT_SHA" --target=proxy-secure-v1 . - - podman build -t "$CI_REGISTRY_IMAGE/proxy-insecure-v1:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure-v1 . - - podman build -t "$CI_REGISTRY_IMAGE/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth . - - podman build -t "$CI_REGISTRY_IMAGE/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure . - - podman push "$CI_REGISTRY_IMAGE/node-holder:$CI_COMMIT_SHORT_SHA" - - podman push "$CI_REGISTRY_IMAGE/proxy-secure-v1:$CI_COMMIT_SHORT_SHA" - - podman push "$CI_REGISTRY_IMAGE/proxy-insecure-v1:$CI_COMMIT_SHORT_SHA" - - podman push "$CI_REGISTRY_IMAGE/backend-auth:$CI_COMMIT_SHORT_SHA" - - podman push "$CI_REGISTRY_IMAGE/backend-secure:$CI_COMMIT_SHORT_SHA" +splatoon: + stage: build_and_test + script: ./.ci-scripts/make-edition.sh splatoon + +friends: + stage: build_and_test + script: ./.ci-scripts/make-edition.sh friends diff --git a/Cargo.lock b/Cargo.lock index 7ed1c06..fe55a2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,15 +17,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -41,18 +32,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - [[package]] name = "anyhow" version = "1.0.100" @@ -144,12 +123,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - [[package]] name = "cc" version = "1.2.31" @@ -179,33 +152,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - [[package]] name = "cipher" version = "0.4.4" @@ -216,31 +162,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clap" -version = "4.5.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.5.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" -dependencies = [ - "anstyle", - "clap_lex", -] - -[[package]] -name = "clap_lex" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -256,70 +177,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "criterion" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c047a62b0cc3e145fa84415a3191f628e980b194c2755aa12300a4e6cbd928" -dependencies = [ - "anes", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1bcc0dc7dfae599d84ad0b1a55f80cde8af3725da8313b528da95ef783e338" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - [[package]] name = "crypto-common" version = "0.1.6" @@ -356,12 +213,6 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "flate2" version = "1.1.5" @@ -405,17 +256,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - [[package]] name = "hex" version = "0.4.3" @@ -492,15 +332,6 @@ dependencies = [ "libc", ] -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" @@ -640,12 +471,6 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "oorandom" -version = "11.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" - [[package]] name = "parking_lot" version = "0.12.4" @@ -687,34 +512,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - [[package]] name = "powerfmt" version = "0.2.0" @@ -796,26 +593,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rayon" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "rc4" version = "0.1.0" @@ -834,35 +611,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - [[package]] name = "ring" version = "0.17.14" @@ -884,7 +632,6 @@ dependencies = [ "anyhow", "bytemuck", "chrono", - "criterion", "dotenv", "hex", "hmac", @@ -951,21 +698,6 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -992,18 +724,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "serde_json" -version = "1.0.142" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - [[package]] name = "shlex" version = "1.3.0" @@ -1148,16 +868,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - [[package]] name = "tokio" version = "1.47.1" @@ -1257,16 +967,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1331,16 +1031,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webpki-roots" version = "1.0.4" diff --git a/Dockerfile b/Dockerfile index a140f56..87f5167 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM rust:alpine AS build-container -RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static +RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static yq bash FROM build-container AS builder @@ -8,23 +8,25 @@ WORKDIR /app COPY . . +ARG EDITION=splatoon + RUN git submodule update --init --recursive -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features rmc_struct_header --target x86_64-unknown-linux-musl -RUN OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --features rmc_struct_header --release --target x86_64-unknown-linux-musl # +RUN ./test-edition.sh +RUN ./build-edition.sh FROM scratch AS node-holder COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /edge_node_holder_server ENTRYPOINT ["/edge_node_holder_server"] -FROM alpine:latest AS proxy-insecure-v1 +FROM alpine:latest AS proxy-insecure COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /proxy_insecure RUN apk add --no-cache ca-certificates RUN update-ca-certificates ENTRYPOINT ["/proxy_insecure"] -FROM alpine:latest AS proxy-secure-v1 +FROM alpine:latest AS proxy-secure COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure RUN apk add --no-cache ca-certificates RUN update-ca-certificates diff --git a/build-edition.sh b/build-edition.sh new file mode 100644 index 0000000..7b1cfc0 --- /dev/null +++ b/build-edition.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +if [ -z ${EDITION+x} ]; then + EDITION=$1 +fi + +# comma seperated list of features for the specified version +source ./buildscripts/common.sh +echo FEATURES: +echo $EDITION_FEATURES + +OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl \ No newline at end of file diff --git a/buildscripts/common.sh b/buildscripts/common.sh new file mode 100644 index 0000000..27fd8cd --- /dev/null +++ b/buildscripts/common.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +TMP_FEATURES_TRAILINGCOMMA=$(yq ea ".$EDITION.features" editions.yaml | sed 's/- //g' | tr '\n' ',') +export EDITION_FEATURES=${TMP_FEATURES_TRAILINGCOMMA::-1} +SETTINGS=$(yq ea ".$EDITION.settings" editions.yaml | yq 'keys[]') +IFS=$'\n' +while IFS=$'\n' read -r KEY; do + VAL=$(yq ea ".$EDITION.settings.$KEY" editions.yaml) + declare "$KEY=$VAL" +done <<< "$SETTINGS" \ No newline at end of file diff --git a/editions.yaml b/editions.yaml new file mode 100644 index 0000000..9ed8552 --- /dev/null +++ b/editions.yaml @@ -0,0 +1,10 @@ +splatoon: + features: + - rmc_struct_header + settings: + AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + OTHER_ONE: "lol" +friends: + features: + - friends + settings: {} \ No newline at end of file diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index cd52ec6..554a8d9 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -28,7 +28,7 @@ anyhow = "1.0.100" ureq = "3.1.4" [dev-dependencies] -criterion = "0.7.0" +# criterion = "0.7.0" [features] rmc_struct_header = [] diff --git a/test-edition.sh b/test-edition.sh new file mode 100644 index 0000000..d483592 --- /dev/null +++ b/test-edition.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +if [ -z ${EDITION+x} ]; then + EDITION=$1 +fi + +# comma seperated list of features for the specified version +source ./buildscripts/common.sh +echo FEATURES: +echo $EDITION_FEATURES + +OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl \ No newline at end of file -- 2.47.3 From 08a6938d3c354eccb55f163b986c5189e31efe39 Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 14:14:13 +0100 Subject: [PATCH 34/98] fix ci --- .ci-scripts/make-edition.sh | 0 build-edition.sh | 0 buildscripts/common.sh | 0 editions.yaml | 3 +-- test-edition.sh | 0 5 files changed, 1 insertion(+), 2 deletions(-) mode change 100644 => 100755 .ci-scripts/make-edition.sh mode change 100644 => 100755 build-edition.sh mode change 100644 => 100755 buildscripts/common.sh mode change 100644 => 100755 test-edition.sh diff --git a/.ci-scripts/make-edition.sh b/.ci-scripts/make-edition.sh old mode 100644 new mode 100755 diff --git a/build-edition.sh b/build-edition.sh old mode 100644 new mode 100755 diff --git a/buildscripts/common.sh b/buildscripts/common.sh old mode 100644 new mode 100755 diff --git a/editions.yaml b/editions.yaml index 9ed8552..033c77e 100644 --- a/editions.yaml +++ b/editions.yaml @@ -3,8 +3,7 @@ splatoon: - rmc_struct_header settings: AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" - OTHER_ONE: "lol" friends: features: - friends - settings: {} \ No newline at end of file + settings: {} diff --git a/test-edition.sh b/test-edition.sh old mode 100644 new mode 100755 -- 2.47.3 From 10dd91b1f5771b10cee2580b2c1086f81cb1b11a Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 14:34:11 +0100 Subject: [PATCH 35/98] add edition to ci --- .ci-scripts/make-edition.sh | 16 ++++++++-------- Dockerfile | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.ci-scripts/make-edition.sh b/.ci-scripts/make-edition.sh index 5f8694c..cb01c79 100755 --- a/.ci-scripts/make-edition.sh +++ b/.ci-scripts/make-edition.sh @@ -1,16 +1,16 @@ #!/usr/bin/env bash -export EDITION=$1 +export BA="--build-arg EDITION=$1" -podman build -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container . +podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container . podman push "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" -podman build -t "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . -podman build -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" --target=proxy-secure . -podman build -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure . -podman build -t "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth . -podman build -t "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure . +podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . +podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" --target=proxy-secure . +podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure . +podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth . +podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure . podman push "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" podman push "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" podman push "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" -podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" \ No newline at end of file +podman push "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" diff --git a/Dockerfile b/Dockerfile index 87f5167..2baa33b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ WORKDIR /app COPY . . -ARG EDITION=splatoon +ARG EDITION RUN git submodule update --init --recursive -- 2.47.3 From 5954ea434c09ba30790c15f0749796be15e60ce6 Mon Sep 17 00:00:00 2001 From: Maple Date: Thu, 13 Nov 2025 14:36:40 +0100 Subject: [PATCH 36/98] fix ci --- .ci-scripts/make-edition.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci-scripts/make-edition.sh b/.ci-scripts/make-edition.sh index cb01c79..f595e5e 100755 --- a/.ci-scripts/make-edition.sh +++ b/.ci-scripts/make-edition.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash +export EDITION=$1 export BA="--build-arg EDITION=$1" podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container . -- 2.47.3 From 4d4fc6c7bfb6a71a4d02fb94ebdae4b7c4b56d3c Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 7 Jan 2026 20:33:29 +0100 Subject: [PATCH 37/98] start work on prudp v0 --- Cargo.lock | 32 +++++++++- Cargo.toml | 5 +- flake.lock | 61 +++++++++++++++++++ flake.nix | 28 +++++++++ perf.data | Bin 0 -> 1541812 bytes prudpv0/Cargo.toml | 7 +++ prudpv0/src/lib.rs | 0 prudpv1/Cargo.toml | 4 +- prudpv1/src/prudp/packet/v1/sanity_checks.rs | 12 ++++ shell.nix | 18 ++++++ 10 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 perf.data create mode 100644 prudpv0/Cargo.toml create mode 100644 prudpv0/src/lib.rs create mode 100644 prudpv1/src/prudp/packet/v1/sanity_checks.rs create mode 100644 shell.nix diff --git a/Cargo.lock b/Cargo.lock index fe55a2d..73c30a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,6 +395,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "macros" +version = "0.1.1" +source = "git+https://github.com/RusticMaple/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "md-5" version = "0.10.6" @@ -536,6 +546,13 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prudpv0" +version = "0.1.0" +dependencies = [ + "rnex-core", +] + [[package]] name = "prudpv1" version = "0.1.0" @@ -551,7 +568,7 @@ dependencies = [ "thiserror", "tokio", "typenum", - "v-byte-helpers", + "v-byte-helpers 0.1.1 (git+https://github.com/RusticMaple/VByteMacros)", ] [[package]] @@ -648,7 +665,7 @@ dependencies = [ "tokio", "typenum", "ureq", - "v-byte-helpers", + "v-byte-helpers 0.1.1 (git+https://github.com/DJMrTV/VByteMacros)", ] [[package]] @@ -958,7 +975,16 @@ version = "0.1.1" source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" dependencies = [ "bytemuck", - "macros 0.1.1", + "macros 0.1.1 (git+https://github.com/DJMrTV/VByteMacros)", +] + +[[package]] +name = "v-byte-helpers" +version = "0.1.1" +source = "git+https://github.com/RusticMaple/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" +dependencies = [ + "bytemuck", + "macros 0.1.1 (git+https://github.com/RusticMaple/VByteMacros)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9c63a93..d020704 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,6 @@ resolver = "3" members = [ "macros", "rnex-core", - "prudpv1" -] \ No newline at end of file + "prudpv1", + "prudpv0" +] diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..7826732 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1767609335, + "narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "250481aafeb741edfe23d29195671c19b36b6dca", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1767640445, + "narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1765674936, + "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..0863018 --- /dev/null +++ b/flake.nix @@ -0,0 +1,28 @@ +{ + description = "rust nex server"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + }; + + outputs = + inputs@{ + self, + nixpkgs, + flake-parts, + }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + perSystem = + { pkgs, lib, ... }: + rec { + devShells.default = import ./shell.nix { inherit pkgs; }; + }; + }; +} diff --git a/perf.data b/perf.data new file mode 100644 index 0000000000000000000000000000000000000000..2cf011f2aead2710a3b379f9beeaec082efbec18 GIT binary patch literal 1541812 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'@xPd1 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

j81RpU3m_-J_3) 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 YS(dmz)sJ)B|0XtXKPk2+G3N*V5A-jpKmY&$ literal 0 HcmV?d00001 diff --git a/prudpv0/Cargo.toml b/prudpv0/Cargo.toml new file mode 100644 index 0000000..439f882 --- /dev/null +++ b/prudpv0/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "prudpv0" +version = "0.1.0" +edition = "2024" + +[dependencies] +rnex-core = { path = "../rnex-core", version = "0.1.1" } diff --git a/prudpv0/src/lib.rs b/prudpv0/src/lib.rs new file mode 100644 index 0000000..e69de29 diff --git a/prudpv1/Cargo.toml b/prudpv1/Cargo.toml index bdf340e..efeaf0a 100644 --- a/prudpv1/Cargo.toml +++ b/prudpv1/Cargo.toml @@ -9,7 +9,7 @@ tokio = { version = "1.47.0", features = ["full"] } hmac = "0.12.1" md-5 = "^0.10.6" rc4 = "0.1.0" -v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1.1" } +v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } thiserror = "2.0.12" log = "0.4.27" async-trait = "0.1.88" @@ -23,4 +23,4 @@ path = "src/executables/proxy_insecure.rs" [[bin]] name = "proxy_secure" -path = "src/executables/proxy_secure.rs" \ No newline at end of file +path = "src/executables/proxy_secure.rs" diff --git a/prudpv1/src/prudp/packet/v1/sanity_checks.rs b/prudpv1/src/prudp/packet/v1/sanity_checks.rs new file mode 100644 index 0000000..335c269 --- /dev/null +++ b/prudpv1/src/prudp/packet/v1/sanity_checks.rs @@ -0,0 +1,12 @@ +//! # PRUDPV1 Feature sanity checks +//! +//! Checks wether the set features are actually sensical or wether they are +//! nonsense and throws a compiler error incase of nonsense + +#[cfg(feature = "friends")] +compile_error!( + "friends uses prudpv0 instead of prudpv1, please do not enable both at the same time" +); + +#[cfg(feature = "prudpv0")] +compile_error!("you cannot enable two prudp versions at the same time"); diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..3ac2963 --- /dev/null +++ b/shell.nix @@ -0,0 +1,18 @@ +{ + pkgs ? import { }, + pkg ? pkgs.callPackage ./. { }, +}: +pkgs.mkShell { + # Get dependencies from the main package + # inputsFrom = [ pkg ]; + # Additional tooling + buildInputs = with pkgs; [ + cargo + rust-analyzer # LSP Server + rustfmt # Formatter + clippy # Linter + podman + yq + jq + ]; +} -- 2.47.3 From fc94f655b22dd83b4d0cc3aaa89d267b7b107e26 Mon Sep 17 00:00:00 2001 From: Maple Date: Tue, 20 Jan 2026 20:26:44 +0100 Subject: [PATCH 38/98] things --- .gitignore | 3 +- Cargo.lock | 60 +-- Cargo.toml | 2 +- build-edition.sh | 4 +- buildscripts/common.sh | 3 +- editions.yaml | 3 +- proxy-common/Cargo.toml | 9 + proxy-common/src/lib.rs | 209 +++++++++++ proxy/Cargo.toml | 25 ++ proxy/src/insecure.rs | 8 + proxy/src/lib.rs | 11 + proxy/src/secure.rs | 7 + prudpv0/Cargo.toml | 12 + prudpv0/src/crypto/common_crypto.rs | 54 +++ prudpv0/src/crypto/friends_common.rs | 5 + prudpv0/src/crypto/friends_insecure.rs | 52 +++ prudpv0/src/crypto/friends_secure.rs | 47 +++ prudpv0/src/crypto/insecure.rs | 9 + prudpv0/src/crypto/mod.rs | 32 ++ prudpv0/src/crypto/secure.rs | 9 + prudpv0/src/lib.rs | 62 ++++ prudpv0/src/packet.rs | 187 ++++++++++ prudpv0/src/server.rs | 256 +++++++++++++ prudpv1/src/executables/common.rs | 17 +- prudpv1/src/executables/proxy_insecure.rs | 66 ++-- prudpv1/src/prudp/packet.rs | 232 +++++------- prudpv1/src/prudp/secure.rs | 68 ++-- prudpv1/src/prudp/socket.rs | 104 +++--- prudpv1/src/prudp/unsecure.rs | 14 +- rnex-core/Cargo.toml | 4 +- .../src/executables/backend_server_secure.rs | 26 +- rnex-core/src/executables/common.rs | 48 ++- rnex-core/src/nex/auth_handler.rs | 41 +-- rnex-core/src/nex/matchmake.rs | 343 +++++++++++------- rnex-core/src/nex/user.rs | 301 +++++++++------ rnex-core/src/prudp/encryption.rs | 20 + rnex-core/src/prudp/mod.rs | 6 +- rnex-core/src/prudp/types_flags.rs | 64 ++++ rnex-core/src/prudp/virtual_port.rs | 19 +- rnex-core/src/reggie.rs | 27 +- rnex-core/src/rmc/protocols/mod.rs | 130 ++++--- rnex-core/src/rmc/structures/ranking.rs | 54 +-- test-edition.sh | 4 +- 43 files changed, 1960 insertions(+), 697 deletions(-) create mode 100644 proxy-common/Cargo.toml create mode 100644 proxy-common/src/lib.rs create mode 100644 proxy/Cargo.toml create mode 100644 proxy/src/insecure.rs create mode 100644 proxy/src/lib.rs create mode 100644 proxy/src/secure.rs create mode 100644 prudpv0/src/crypto/common_crypto.rs create mode 100644 prudpv0/src/crypto/friends_common.rs create mode 100644 prudpv0/src/crypto/friends_insecure.rs create mode 100644 prudpv0/src/crypto/friends_secure.rs create mode 100644 prudpv0/src/crypto/insecure.rs create mode 100644 prudpv0/src/crypto/mod.rs create mode 100644 prudpv0/src/crypto/secure.rs create mode 100644 prudpv0/src/packet.rs create mode 100644 prudpv0/src/server.rs create mode 100644 rnex-core/src/prudp/encryption.rs create mode 100644 rnex-core/src/prudp/types_flags.rs diff --git a/.gitignore b/.gitignore index ea0ae4a..2a7a556 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ target .idea .env log -reports \ No newline at end of file +reports +.zed diff --git a/Cargo.lock b/Cargo.lock index 73c30a5..20a8271 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,9 +134,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" @@ -385,16 +385,6 @@ dependencies = [ "syn 2.0.104", ] -[[package]] -name = "macros" -version = "0.1.1" -source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "macros" version = "0.1.1" @@ -547,10 +537,39 @@ dependencies = [ ] [[package]] -name = "prudpv0" +name = "proxy" +version = "0.1.0" +dependencies = [ + "cfg-if", + "prudpv0", + "prudpv1", + "rnex-core", + "tokio", +] + +[[package]] +name = "proxy-common" version = "0.1.0" dependencies = [ "rnex-core", + "thiserror", + "tokio", +] + +[[package]] +name = "prudpv0" +version = "0.1.0" +dependencies = [ + "bytemuck", + "cfg-if", + "hmac", + "log", + "md-5", + "proxy-common", + "rc4", + "rnex-core", + "tokio", + "typenum", ] [[package]] @@ -568,7 +587,7 @@ dependencies = [ "thiserror", "tokio", "typenum", - "v-byte-helpers 0.1.1 (git+https://github.com/RusticMaple/VByteMacros)", + "v-byte-helpers", ] [[package]] @@ -665,7 +684,7 @@ dependencies = [ "tokio", "typenum", "ureq", - "v-byte-helpers 0.1.1 (git+https://github.com/DJMrTV/VByteMacros)", + "v-byte-helpers", ] [[package]] @@ -969,22 +988,13 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "v-byte-helpers" -version = "0.1.1" -source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" -dependencies = [ - "bytemuck", - "macros 0.1.1 (git+https://github.com/DJMrTV/VByteMacros)", -] - [[package]] name = "v-byte-helpers" version = "0.1.1" source = "git+https://github.com/RusticMaple/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69" dependencies = [ "bytemuck", - "macros 0.1.1 (git+https://github.com/RusticMaple/VByteMacros)", + "macros 0.1.1", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d020704..9d6ea8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,4 @@ members = [ "rnex-core", "prudpv1", "prudpv0" -] +, "proxy", "proxy-common"] diff --git a/build-edition.sh b/build-edition.sh index 7b1cfc0..5d65fc3 100755 --- a/build-edition.sh +++ b/build-edition.sh @@ -7,5 +7,7 @@ fi source ./buildscripts/common.sh echo FEATURES: echo $EDITION_FEATURES +echo ENV SETTINGS: +env -OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl \ No newline at end of file +OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl diff --git a/buildscripts/common.sh b/buildscripts/common.sh index 27fd8cd..8c5e67e 100755 --- a/buildscripts/common.sh +++ b/buildscripts/common.sh @@ -6,4 +6,5 @@ IFS=$'\n' while IFS=$'\n' read -r KEY; do VAL=$(yq ea ".$EDITION.settings.$KEY" editions.yaml) declare "$KEY=$VAL" -done <<< "$SETTINGS" \ No newline at end of file + export $KEY +done <<< "$SETTINGS" diff --git a/editions.yaml b/editions.yaml index 033c77e..f20da91 100644 --- a/editions.yaml +++ b/editions.yaml @@ -6,4 +6,5 @@ splatoon: friends: features: - friends - settings: {} + settings: + RNEX_VIRTUAL_PORT: 1:10 diff --git a/proxy-common/Cargo.toml b/proxy-common/Cargo.toml new file mode 100644 index 0000000..28974ef --- /dev/null +++ b/proxy-common/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "proxy-common" +version = "0.1.0" +edition = "2024" + +[dependencies] +thiserror = "2.0.12" +rnex-core = { path = "../rnex-core", version = "0.1.1" } +tokio = { version = "1.47.0", features = ["full"] } diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs new file mode 100644 index 0000000..68ac209 --- /dev/null +++ b/proxy-common/src/lib.rs @@ -0,0 +1,209 @@ +use rnex_core::{ + executables::common::{OWN_IP_PUBLIC, try_get_ip}, + prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}, + reggie::{RemoteEdgeNodeHolder, UnitPacketWrite}, + rmc::{ + protocols::{ + OnlyRemote, RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject, + new_rmc_gateway_connection, + }, + structures::RmcSerialize, + }, + rnex_proxy_common::ConnectionInitData, + util::{SendingBufferConnection, SplittableBufferConnection}, +}; +use std::{ + env::{self, VarError}, + error, + net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}, + ops::Deref, + panic, + str::FromStr, + sync::{Arc, LazyLock}, +}; +use thiserror::Error; +use tokio::net::TcpStream; + +const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT"), 10) { + Ok(v) => v, + Err(_) => panic!("unable to get default port from env"), +}; + +#[derive(Error, Debug)] +pub enum Error { + #[error("error getting environment variable \"{0}\": {1}")] + UnableToGetEnv(&'static str, VarError), + #[error("error parsing ip address environment variable \"{0}\": {1}")] + AddrParse(&'static str, AddrParseError), + #[error( + "error error getting public ip address: \n\tattempted to read from env var \"SERVER_IP_PUBLIC\" and got: {0} \n\tattempted to request from internet and failed with: {1}" + )] + PubAddrGetErr(Box, Box), +} +impl Into for (&'static str, AddrParseError) { + fn into(self) -> Error { + Error::AddrParse(self.0, self.1) + } +} + +pub struct ProxyStartupParam { + pub forward_destination: SocketAddr, + pub edge_node_holder: SocketAddr, + pub self_public: SocketAddrV4, + pub self_private: SocketAddrV4, + pub virtual_port: VirtualPort, +} + +fn try_get_env(name: &'static str) -> Result +where + (&'static str, T::Err): Into, +{ + T::from_str(&env::var(name).map_err(|e| Error::UnableToGetEnv(name, e))?) + .map_err(|e| (name, e).into()) +} + +pub enum ProxyType { + Insecure, + Secure, +} +const VIRTUAL_PORT_INSECURE: LazyLock = + LazyLock::new(|| VirtualPort::parse(env!("RNEX_VIRTUAL_PORT_INSECURE")).unwrap()); +const VIRTUAL_PORT_SECURE: LazyLock = + LazyLock::new(|| VirtualPort::parse(env!("RNEX_VIRTUAL_PORT_SECURE")).unwrap()); +impl ProxyStartupParam { + pub fn new(prox_ty: ProxyType) -> Result { + let port = RNEX_DEFAULT_PORT + + match prox_ty { + ProxyType::Insecure => 0, + ProxyType::Secure => 1, + }; + let self_private = try_get_env("SERVER_IP_PRIVATE") + .unwrap_or(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, RNEX_DEFAULT_PORT)); + let self_public: SocketAddrV4 = match try_get_env("SERVER_IP_PUBLIC") { + Ok(v) => v, + Err(e) => try_get_ip() + .map(|v| SocketAddrV4::new(v, RNEX_DEFAULT_PORT)) + .map_err(move |v| Error::PubAddrGetErr(Box::new(e), v))?, + }; + + Ok(Self { + forward_destination: try_get_env("EDGE_NODE_HOLDER")?, + edge_node_holder: try_get_env("FORWARD_DESTINATION")?, + self_private, + self_public, + virtual_port: match prox_ty { + ProxyType::Insecure => *VIRTUAL_PORT_INSECURE, + ProxyType::Secure => *VIRTUAL_PORT_SECURE, + }, + }) + } +} + +struct OnRemoteDrop(T, Option); +impl Deref for OnRemoteDrop { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// if we had something like a thread safe OnceConsume (basically the opposite of OnceLock) +// we could make C be an FnOnce +impl + OnRemoteDrop +{ + pub fn new(conn: RmcConnection, drop_func: C) -> Self { + Self(T::new(conn), Some(drop_func)) + } + + pub async fn disconnect(&self) { + self.0.disconnect().await; + } +} + +impl RmcCallable + for OnRemoteDrop +{ + fn rmc_call( + &self, + _responder: &SendingBufferConnection, + _protocol_id: u16, + _method_id: u32, + _call_id: u32, + _rest: Vec, + ) -> impl Future + Send { + // maybe respond with not implemented or something + async {} + } +} + +impl Drop for OnRemoteDrop { + fn drop(&mut self) { + self.1.take().unwrap()(); + } +} + +pub async fn setup_edge_node_connection( + param: &ProxyStartupParam, + shutdown_callback: impl FnOnce() + Send + Sync + 'static, +) { + let conn = tokio::net::TcpStream::connect(¶m.edge_node_holder) + .await + .unwrap(); + + let conn: SplittableBufferConnection = conn.into(); + + conn.send( + rnex_core::reggie::EdgeNodeHolderConnectOption::Register(param.self_public) + .to_data() + .unwrap(), + ) + .await; + //leave the inner object floating so that it gets destroyed once we disconnect + new_rmc_gateway_connection(conn, move |r| { + Arc::new(OnRemoteDrop::::new( + r, + shutdown_callback, + )) + }); +} + +pub async fn new_backend_connection( + param: &ProxyStartupParam, + addr: PRUDPSockAddr, + pid: u32, +) -> Option { + let mut stream = match TcpStream::connect(param.forward_destination).await { + Ok(v) => v, + Err(e) => { + return None; + } + }; + + if let Err(e) = stream + .send_buffer( + &ConnectionInitData { + prudpsock_addr: addr, + pid: pid, + } + .to_data() + .unwrap(), + ) + .await + { + return None; + }; + + Some(stream.into()) +} + +#[cfg(test)] +mod test { + use crate::{VIRTUAL_PORT_INSECURE, VIRTUAL_PORT_SECURE}; + + fn test_virtual_port_correct() { + println!("{:?}", VIRTUAL_PORT_INSECURE); + println!("{:?}", VIRTUAL_PORT_SECURE); + } +} diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml new file mode 100644 index 0000000..78e7438 --- /dev/null +++ b/proxy/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "proxy" +version = "0.1.0" +edition = "2024" + +[dependencies] +tokio = { version = "1.47.0", features = ["full"] } +prudpv0 = { path = "../prudpv0", optional = true } +prudpv1 = { path = "../prudpv1", optional = true } +cfg-if = "1.0.4" +rnex-core = { path = "../rnex-core", version = "0.1.1" } + +[features] +prudpv0 = ["dep:prudpv0"] +prudpv1 = ["dep:prudpv1"] +friends = ["prudpv0", "prudpv0/friends"] + + +[[bin]] +name = "proxy_insecure" +path = "src/insecure.rs" + +[[bin]] +name = "proxy_secure" +path = "src/secure.rs" diff --git a/proxy/src/insecure.rs b/proxy/src/insecure.rs new file mode 100644 index 0000000..1fe927f --- /dev/null +++ b/proxy/src/insecure.rs @@ -0,0 +1,8 @@ +use rnex_core::common::setup; + +#[tokio::main] +async fn main() { + setup(); + + proxy::start_insecure(ProxyStartupParam::new()).await; +} diff --git a/proxy/src/lib.rs b/proxy/src/lib.rs new file mode 100644 index 0000000..7120adc --- /dev/null +++ b/proxy/src/lib.rs @@ -0,0 +1,11 @@ +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(feature = "prudpv0")]{ + pub use prudpv0::*; + } else if #[cfg(feature = "prudpv1")] { + pub use prudpv1::*; + } else { + compile_error!("no proxy type has been set"); + } +} diff --git a/proxy/src/secure.rs b/proxy/src/secure.rs new file mode 100644 index 0000000..d661d95 --- /dev/null +++ b/proxy/src/secure.rs @@ -0,0 +1,7 @@ +use rnex_core::common::setup; + +#[tokio::main] +async fn main() { + setup(); + proxy::start_secure(ProxyStartupParam::new()).await; +} diff --git a/prudpv0/Cargo.toml b/prudpv0/Cargo.toml index 439f882..dbdb1db 100644 --- a/prudpv0/Cargo.toml +++ b/prudpv0/Cargo.toml @@ -5,3 +5,15 @@ edition = "2024" [dependencies] rnex-core = { path = "../rnex-core", version = "0.1.1" } +tokio = { version = "1.47.0", features = ["full"] } +bytemuck = { version = "1.23.1", features = ["derive"] } +typenum = "1.18.0" +rc4 = "0.1.0" +log = "0.4.25" +cfg-if = "1.0.4" +proxy-common = {path = "../proxy-common"} +hmac = "0.12.1" +md-5 = "^0.10.6" + +[features] +friends = [] diff --git a/prudpv0/src/crypto/common_crypto.rs b/prudpv0/src/crypto/common_crypto.rs new file mode 100644 index 0000000..7196638 --- /dev/null +++ b/prudpv0/src/crypto/common_crypto.rs @@ -0,0 +1,54 @@ +trait IterExtra: Iterator { + fn sum_wrapping_u8(&mut self) -> u8 + where + Self::Item: Into; + + fn sum_wrapping_u32(&mut self) -> u32 + where + Self::Item: Into; +} + +impl IterExtra for T { + fn sum_wrapping_u8(&mut self) -> u8 + where + Self::Item: Into, + { + let mut sum = 0u8; + for v in self { + let val: u8 = v.into(); + sum = sum.wrapping_add(val); + } + sum + } + fn sum_wrapping_u32(&mut self) -> u32 + where + Self::Item: Into, + { + let mut sum = 0u32; + for v in self { + let val: u32 = v.into(); + sum = sum.wrapping_add(val); + } + sum + } +} + +#[inline(always)] +pub fn common_checksum(access_key: &str, data: &[u8]) -> u8 { + let leftover = data.len() % 4; + let word_sum = bytemuck::cast_slice::<_, u32>(&data[..data.len() - leftover]) + .iter() + .copied() + .sum_wrapping_u32(); + + let checksum = access_key.as_bytes().iter().copied().sum_wrapping_u8(); + let checksum = checksum.wrapping_add( + (&data[data.len() - leftover..]) + .iter() + .copied() + .sum_wrapping_u8(), + ); + let checksum = checksum.wrapping_add(word_sum.to_ne_bytes().into_iter().sum_wrapping_u8()); + + checksum +} diff --git a/prudpv0/src/crypto/friends_common.rs b/prudpv0/src/crypto/friends_common.rs new file mode 100644 index 0000000..b11af1d --- /dev/null +++ b/prudpv0/src/crypto/friends_common.rs @@ -0,0 +1,5 @@ +use hmac::Hmac; +use md5::Md5; + +pub const ACCESS_KEY: &str = "ridfebb9"; +pub type HmacMd5 = Hmac; diff --git a/prudpv0/src/crypto/friends_insecure.rs b/prudpv0/src/crypto/friends_insecure.rs new file mode 100644 index 0000000..b3ff9ab --- /dev/null +++ b/prudpv0/src/crypto/friends_insecure.rs @@ -0,0 +1,52 @@ +use std::rc::Rc; + +use hmac::Mac; +use rc4::{KeyInit, Rc4, StreamCipher}; +use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair}; +use typenum::U5; + +use crate::crypto::{ + Crypto, CryptoInstance, + common_crypto::common_checksum, + friends_common::{ACCESS_KEY, HmacMd5}, +}; + +pub struct InsecureInstance { + pair: EncryptionPair>, +} + +impl CryptoInstance for InsecureInstance { + fn decrypt_incoming(&mut self, data: &mut [u8]) { + self.pair.recv.apply_keystream(data); + } + fn encrypt_outgoing(&mut self, data: &mut [u8]) { + self.pair.send.apply_keystream(data); + } + fn get_user_id(&self) -> u32 { + 0 + } + fn generate_signature(&self, data: &[u8]) -> [u8; 4] { + let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) + .expect("unable to create hmac md5"); + hmac.update(data); + hmac.finalize().into_bytes()[0..4].try_into().unwrap() + } +} + +pub struct Insecure(); + +impl Crypto for Insecure { + type Instance = InsecureInstance; + fn new() -> Self { + Self() + } + fn calculate_checksum(&self, data: &[u8]) -> u8 { + common_checksum(ACCESS_KEY, data) + } + + fn instantiate(&self, packet_data: &[u8]) -> Self::Instance { + InsecureInstance { + pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)), + } + } +} diff --git a/prudpv0/src/crypto/friends_secure.rs b/prudpv0/src/crypto/friends_secure.rs new file mode 100644 index 0000000..db36c46 --- /dev/null +++ b/prudpv0/src/crypto/friends_secure.rs @@ -0,0 +1,47 @@ +use hmac::Mac; +use rc4::Rc4; +use rnex_core::prudp::encryption::EncryptionPair; +use typenum::U32; + +use crate::crypto::{ + Crypto, CryptoInstance, + common_crypto::common_checksum, + friends_common::{ACCESS_KEY, HmacMd5}, +}; + +pub struct SecureInstance { + pair: EncryptionPair>, +} + +impl CryptoInstance for SecureInstance { + fn decrypt_incoming(&mut self, data: &mut [u8]) { + todo!() + } + fn encrypt_outgoing(&mut self, data: &mut [u8]) { + todo!() + } + fn get_user_id(&self) -> u32 { + todo!() + } + fn generate_signature(&self, data: &[u8]) -> [u8; 4] { + let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) + .expect("unable to create hmac md5"); + hmac.update(data); + hmac.finalize().into_bytes()[0..4].try_into().unwrap() + } +} + +pub struct Secure(); + +impl Crypto for Secure { + type Instance = SecureInstance; + fn new() -> Self { + Self() + } + fn calculate_checksum(&self, data: &[u8]) -> u8 { + common_checksum(ACCESS_KEY, data) + } + fn instantiate(&self, data: &[u8]) -> Self::Instance { + todo!() + } +} diff --git a/prudpv0/src/crypto/insecure.rs b/prudpv0/src/crypto/insecure.rs new file mode 100644 index 0000000..5d3dff3 --- /dev/null +++ b/prudpv0/src/crypto/insecure.rs @@ -0,0 +1,9 @@ +use crate::crypto::Crypto; + +pub struct Insecure(); + +impl Crypto for Insecure { + fn calculate_checksum(&self, data: &[u8]) -> u8 { + todo!() + } +} diff --git a/prudpv0/src/crypto/mod.rs b/prudpv0/src/crypto/mod.rs new file mode 100644 index 0000000..add58b9 --- /dev/null +++ b/prudpv0/src/crypto/mod.rs @@ -0,0 +1,32 @@ +use cfg_if::cfg_if; + +mod common_crypto; + +pub trait CryptoInstance: Send + 'static { + fn decrypt_incoming(&mut self, data: &mut [u8]); + fn encrypt_outgoing(&mut self, data: &mut [u8]); + fn generate_signature(&self, data: &[u8]) -> [u8; 4]; + fn get_user_id(&self) -> u32; +} + +pub trait Crypto: Send + Sync + 'static { + type Instance: CryptoInstance; + fn new() -> Self; + fn calculate_checksum(&self, data: &[u8]) -> u8; + fn instantiate(&self, data: &[u8]) -> Self::Instance; +} + +cfg_if! { + if #[cfg(feature = "friends")]{ + pub mod friends_common; + pub mod friends_insecure; + pub use friends_insecure::*; + pub mod friends_secure; + pub use friends_secure::*; + } else { + pub mod secure; + pub use secure::*; + pub mod insecure; + pub use insecure::*; + } +} diff --git a/prudpv0/src/crypto/secure.rs b/prudpv0/src/crypto/secure.rs new file mode 100644 index 0000000..435986e --- /dev/null +++ b/prudpv0/src/crypto/secure.rs @@ -0,0 +1,9 @@ +use crate::crypto::Crypto; + +pub struct Secure(); + +impl Crypto for Secure { + fn calculate_checksum(&self, data: &[u8]) -> u8 { + todo!() + } +} diff --git a/prudpv0/src/lib.rs b/prudpv0/src/lib.rs index e69de29..6ba8216 100644 --- a/prudpv0/src/lib.rs +++ b/prudpv0/src/lib.rs @@ -0,0 +1,62 @@ +use bytemuck::{Pod, Zeroable}; +use log::{error, info, warn}; +use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; +use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; +use rnex_core::prudp::types_flags::TypesFlags; +use rnex_core::prudp::types_flags::types::SYN; +use rnex_core::prudp::virtual_port::VirtualPort; +use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; +use rnex_core::reggie::RemoteEdgeNodeHolder; +use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::util::SplittableBufferConnection; +use std::env; +use std::net::SocketAddrV4; +use std::process::abort; +use std::sync::{Arc, LazyLock}; +use tokio::net::UdpSocket; + +use crate::crypto::{Crypto, Insecure, Secure}; +use crate::packet::PRUDPV0Packet; +use crate::server::Server; + +mod crypto; +mod packet; +mod server; + +pub static EDGE_NODE_HOLDER: LazyLock = LazyLock::new(|| { + env::var("EDGE_NODE_HOLDER") + .ok() + .and_then(|s| s.parse().ok()) + .expect("EDGE_NODE_HOLDER not set") +}); + +pub static FORWARD_DESTINATION: LazyLock = LazyLock::new(|| { + env::var("FORWARD_DESTINATION") + .ok() + .and_then(|s| s.parse().ok()) + .expect("FORWARD_DESTINATION not set") +}); +//same as with prudpv1 this is responsible for handeling the different cryptography +//implementations, e.g. secure and insecure(this also includes special cases like friends) + +async fn start_proxy(param: ProxyStartupParam) { + setup_edge_node_connection(¶m, || abort()); + + info!("creating cryptography instance"); + let mut crypto = Arc::new(T::new()); + info!("binding to socket"); + + let server: Arc> = Arc::new(Server::new().await); + + info!("waiting on packets"); + server.run_task().await; +} + +pub async fn start_secure(param: ProxyStartupParam) { + start_proxy::(param).await; +} + +pub async fn start_insecure(param: ProxyStartupParam) { + start_proxy::(param).await; +} diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs new file mode 100644 index 0000000..3d6d06a --- /dev/null +++ b/prudpv0/src/packet.rs @@ -0,0 +1,187 @@ +use std::mem::transmute; + +use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut}; +use log::error; +use rnex_core::prudp::{ + types_flags::{ + TypesFlags, + flags::{HAS_SIZE, NEED_ACK}, + types::{CONNECT, DATA, SYN}, + }, + virtual_port::VirtualPort, +}; + +use crate::crypto::{Crypto, CryptoInstance}; + +#[repr(C, packed)] +#[derive(Clone, Copy, Pod, Zeroable, Debug)] +pub struct PRUDPV0Header { + pub source: VirtualPort, + pub destination: VirtualPort, + pub type_flags: TypesFlags, + pub session_id: u8, + pub packet_signature: [u8; 4], + pub sequence_id: u16, +} +#[repr(transparent)] +pub struct PRUDPV0Packet>(pub T); + +impl> PRUDPV0Packet { + #[inline(always)] + pub fn get_packet_specific_size(&self) -> Option { + Some(get_types_flags_size_from_types_flags( + self.header()?.type_flags, + )) + } + + #[inline(always)] + pub fn header(&self) -> Option<&PRUDPV0Header> { + try_from_bytes(self.0.as_ref().get(..size_of::())?).ok() + } + #[inline(always)] + pub fn header_mut(&mut self) -> Option<&mut PRUDPV0Header> + where + T: AsMut<[u8]>, + { + try_from_bytes_mut(self.0.as_mut().get_mut(..size_of::())?).ok() + } + + #[inline(always)] + pub fn connection_signature(&self) -> Option<&[u8; 4]> { + let offset = size_of::(); + Some(self.0.as_ref().get(offset..offset + 4)?.try_into().ok()?) + } + #[inline(always)] + pub fn connection_signature_mut(&mut self) -> Option<&mut [u8; 4]> + where + T: AsMut<[u8]>, + { + let offset = size_of::(); + Some( + self.0 + .as_mut() + .get_mut(offset..offset + 4)? + .try_into() + .ok()?, + ) + } + + #[inline(always)] + fn get_payload_offset(&self) -> Option { + Some(size_of::() + self.get_packet_specific_size()?) + } + + #[inline(always)] + pub fn payload(&self) -> Option<&[u8]> { + self.0 + .as_ref() + .get(self.get_payload_offset()?..(self.0.as_ref().len().saturating_sub(1))) + } + #[inline(always)] + pub fn payload_mut(&mut self) -> Option<&mut [u8]> + where + T: AsMut<[u8]>, + { + let start_offset = self.get_payload_offset()?; + let end_offset = self.0.as_ref().len().saturating_sub(1); + self.0.as_mut().get_mut(start_offset..end_offset) + } + + #[inline(always)] + pub fn checksummed_data(&self) -> Option<&[u8]> { + self.0 + .as_ref() + .get(..self.0.as_ref().len().saturating_sub(1)) + } + + #[inline(always)] + pub fn checksum(&self) -> Option { + self.0.as_ref().last().copied() + } + #[inline(always)] + pub fn checksum_mut(&mut self) -> Option<&mut u8> + where + T: AsMut<[u8]>, + { + self.0.as_mut().last_mut() + } + + #[inline(always)] + pub fn check_checksum(&self, crypto: &impl Crypto) -> bool { + let Some(data) = self.checksummed_data() else { + return false; + }; + let Some(checksum) = self.checksum() else { + return false; + }; + checksum == crypto.calculate_checksum(data) + } + + pub fn new(data: T) -> Self { + Self(data) + } +} + +const DEFAULT_SIGNAT: [u8; 4] = [0x12, 0x34, 0x56, 0x78]; +#[inline(always)] +const fn get_size_offset(tf: TypesFlags) -> usize { + size_of::() + + (if tf.get_types() & (SYN | CONNECT) != 0 { + 4 + } else if tf.get_types() & DATA != 0 { + 1 + } else { + 0 + }) +} +#[inline(always)] +const fn get_type_specific_size(tf: TypesFlags) -> usize { + if tf.get_types() & (SYN | CONNECT) != 0 { + 4 + } else if tf.get_types() & DATA != 0 { + 1 + } else { + 0 + } +} +#[inline(always)] +const fn get_types_flags_size_from_types_flags(tf: TypesFlags) -> usize { + get_type_specific_size(tf) + (if tf.get_flags() & HAS_SIZE != 0 { 2 } else { 0 }) +} +#[inline(always)] +pub const fn precalc_size(tf: TypesFlags, payload_size: usize) -> usize { + size_of::() + get_types_flags_size_from_types_flags(tf) + payload_size + 1 +} +pub fn new_syn_packet( + flags: u16, + source: VirtualPort, + destination: VirtualPort, + signat: [u8; 4], + crypto: &impl Crypto, +) -> Vec { + let type_flags = TypesFlags::default().types(SYN).flags(flags); + + let vec = vec![0; precalc_size(type_flags, 0)]; + let mut packet = PRUDPV0Packet::new(vec); + let header = packet.header_mut().expect("packet malformed in creation"); + + *header = PRUDPV0Header { + destination, + source, + packet_signature: DEFAULT_SIGNAT, + sequence_id: 0, + session_id: 0, + type_flags, + }; + *packet + .connection_signature_mut() + .expect("packet malformed in creation") = signat; + + *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( + packet + .checksummed_data() + .expect("packet malformed in creation"), + ); + + packet.0 +} diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs new file mode 100644 index 0000000..e3b8bbf --- /dev/null +++ b/prudpv0/src/server.rs @@ -0,0 +1,256 @@ +use std::{ + collections::HashMap, + hash::Hash, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, + sync::{ + Arc, LazyLock, + atomic::{AtomicBool, AtomicU32}, + }, +}; + +use log::{error, info, warn}; +use proxy_common::{ProxyStartupParam, new_backend_connection}; +use rnex_core::{ + executables::common::{OWN_IP_PRIVATE, SERVER_PORT}, + prudp::{ + socket_addr::PRUDPSockAddr, + types_flags::{ + TypesFlags, + flags::{ACK, HAS_SIZE, NEED_ACK}, + types::{CONNECT, DATA, SYN}, + }, + virtual_port::VirtualPort, + }, + rnex_proxy_common::ConnectionInitData, + util::{SendingBufferConnection, SplittableBufferConnection}, +}; +use tokio::{ + net::{TcpSocket, UdpSocket}, + spawn, + sync::{Mutex, RwLock}, + time::Instant, +}; + +use crate::{ + crypto::{Crypto, CryptoInstance}, + packet::{PRUDPV0Header, PRUDPV0Packet, new_syn_packet, precalc_size}, +}; + +pub struct InternalConnection { + last_action: Instant, + crypto_instance: C, + server_packet_counter: u16, + client_packet_counter: u16, + unacknowledged_packets: HashMap>>, +} +pub struct Connection { + alive: AtomicBool, + session_id: u8, + target: SendingBufferConnection, + self_signat: [u8; 4], + remote_signat: [u8; 4], + addr: PRUDPSockAddr, + inner: Mutex>, +} + +impl InternalConnection { + fn next_server_count(&mut self) -> u16 { + let prev_val = self.server_packet_counter; + let (val, _) = self.server_packet_counter.overflowing_add(1); + self.server_packet_counter = val; + + prev_val + } +} + +pub struct Server { + param: ProxyStartupParam, + socket: UdpSocket, + crypto: C, + connections: RwLock>>>, +} + +impl Server { + async fn send_data_packet(&self, conn: &Connection, data: &[u8]) { + let type_flags = TypesFlags::default().types(DATA).flags(HAS_SIZE | NEED_ACK); + let vec = vec![0; precalc_size(type_flags, data.len())]; + let mut packet = PRUDPV0Packet::new(vec); + + let payload = packet.payload_mut().expect("packet malformed in creation"); + payload.copy_from_slice(data); + + let mut inner = conn.inner.lock().await; + inner.crypto_instance.encrypt_outgoing(payload); + let packet_signat = inner.crypto_instance.generate_signature(payload); + let seq = inner.next_server_count(); + + *packet.header_mut().expect("packet malformed in creation") = PRUDPV0Header { + source: self.param.virtual_port, + destination: conn.addr.virtual_port, + type_flags, + session_id: conn.session_id, + packet_signature: packet_signat, + sequence_id: seq, + }; + /* we leave the sequence id as is for now as it defaults to 0 */ + + *packet.checksum_mut().expect("packet malformed in creation") = + self.crypto.calculate_checksum( + packet + .checksummed_data() + .expect("packet malformed in creation"), + ); + + let packet_raw = packet.0; + + let packet = Arc::new(packet_raw); + + let packet_ref = Arc::downgrade(&packet); + + inner.unacknowledged_packets.insert(seq, packet); + + drop(inner); + + spawn(async move { + for n in 0..5 { + let Some(data) = packet_ref.upgrade() else { + return; + }; + info!("send attempt {}", n); + } + }); + } + async fn connection_thread( + self: Arc, + conn: Arc>, + mut recv: SplittableBufferConnection, + ) { + while let Some(data) = recv.recv().await {} + } + async fn timeout_thread(self: Arc, conn: Arc>) { + loop { + conn + } + } + async fn handle_syn(self: Arc, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) { + info!("got syn"); + let header = packet.header().unwrap(); + + let signat = addr.calculate_connection_signature(); + let signat = [signat[0], signat[1], signat[2], signat[3]]; + + let packet = new_syn_packet(ACK, header.destination, header.source, signat, &self.crypto); + self.socket.send_to(&packet, addr.regular_socket_addr).await; + } + async fn handle_connect(self: Arc, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) { + let conn = self.connections.write().await; + let Some(data) = packet.payload() else { + warn!("malformed packet from: {:?}", addr.regular_socket_addr); + return; + }; + let Some(self_signat) = packet.connection_signature().copied() else { + warn!( + "malformed packet(unable to find connection signature) from: {:?}", + addr + ); + return; + }; + + let ci = self.crypto.instantiate(data); + + let pid = ci.get_user_id(); + let conn = new_backend_connection(&self.param, addr, pid).await; + let Some(conn) = conn else { + error!("unable to connect to backend"); + return; + }; + + let remote_signat = addr.calculate_connection_signature(); + let remote_signat = [ + remote_signat[0], + remote_signat[1], + remote_signat[2], + remote_signat[3], + ]; + + let header = packet.header().expect("header should be validated by now"); + + let conn = Arc::new(Connection { + target: conn.duplicate_sender(), + remote_signat, + self_signat, + addr, + session_id: header.session_id, + alive: AtomicBool::new(true), + inner: Mutex::new(InternalConnection { + last_action: Instant::now(), + crypto_instance: ci, + client_packet_counter: 2, + server_packet_counter: 1, + unacknowledged_packets: HashMap::new(), + }), + }); + } + async fn process_packet<'a>(self: Arc, packet: PRUDPV0Packet<&[u8]>, addr: SocketAddrV4) { + if !packet.check_checksum(&self.crypto) { + warn!("invalid checksum from: {}", addr); + return; + } + + let Some(header) = packet.header() else { + warn!("malformatted packet from: {}", addr); + return; + }; + + let addr = PRUDPSockAddr::new(addr, header.source); + println!("{:?}", header); + match header.type_flags.get_types() { + SYN => { + self.handle_syn(packet, addr).await; + } + CONNECT => { + self.handle_connect(packet, addr).await; + } + v => { + println!("unimplemented packed type: {}", v); + } + } + } + pub async fn run_task(self: Arc) { + loop { + let mut vec: Vec = vec![]; + let addr = match self.socket.recv_buf_from(&mut vec).await { + Err(e) => { + error!("unable to recv: {}", e); + break; + } + Ok(v) => { + assert_eq!(vec.len(), v.0); + v.1 + } + }; + let this = self.clone(); + tokio::spawn(async move { + let data = vec; + let packet = PRUDPV0Packet::new(&data[..]); + + let SocketAddr::V4(addr) = addr else { + unreachable!() + }; + + this.process_packet(packet, addr).await; + }); + } + } + pub async fn new(param: ProxyStartupParam) -> Self { + let socket = UdpSocket::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) + .await + .expect("unable to bind socket"); + Self { + socket, + crypto: C::new(), + connections: RwLock::new(HashMap::new()), + param, + } + } +} diff --git a/prudpv1/src/executables/common.rs b/prudpv1/src/executables/common.rs index e8162a1..8d6f4c1 100644 --- a/prudpv1/src/executables/common.rs +++ b/prudpv1/src/executables/common.rs @@ -1,18 +1,17 @@ +use once_cell::sync::Lazy; use std::env; use std::net::SocketAddrV4; -use once_cell::sync::Lazy; -pub static EDGE_NODE_HOLDER: Lazy = Lazy::new(||{ +pub static EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { env::var("EDGE_NODE_HOLDER") .ok() .and_then(|s| s.parse().ok()) .expect("EDGE_NODE_HOLDER not set") }); -pub static FORWARD_DESTINATION: Lazy = - Lazy::new(|| - env::var("FORWARD_DESTINATION") - .ok() - .and_then(|s| s.parse().ok()) - .expect("FORWARD_DESTINATION not set") - ); +pub static FORWARD_DESTINATION: Lazy = Lazy::new(|| { + env::var("FORWARD_DESTINATION") + .ok() + .and_then(|s| s.parse().ok()) + .expect("FORWARD_DESTINATION not set") +}); diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 50446d5..350018d 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -1,15 +1,5 @@ - -use rnex_core::reggie::UnitPacketRead; -use rnex_core::reggie::UnitPacketWrite; -use rnex_core::rmc::structures::RmcSerialize; -use std::net::SocketAddrV4; -use std::sync::Arc; -use std::time::Duration; use log::error; -use tokio::net::TcpStream; -use tokio::task; -use tokio::time::sleep; -use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER}; +use prudpv1::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; use prudpv1::prudp::router::Router; use prudpv1::prudp::unsecure::Unsecure; use rnex_core::common::setup; @@ -17,32 +7,46 @@ use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT} use rnex_core::prudp::virtual_port::VirtualPort; use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; use rnex_core::reggie::RemoteEdgeNodeHolder; -use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::reggie::UnitPacketRead; +use rnex_core::reggie::UnitPacketWrite; +use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; +use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::util::SplittableBufferConnection; - - +use std::net::SocketAddrV4; +use std::sync::Arc; +use std::time::Duration; +use tokio::net::TcpStream; +use tokio::task; +use tokio::time::sleep; #[tokio::main] async fn main() { setup(); - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap(); + let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) + .await + .unwrap(); let conn: SplittableBufferConnection = conn.into(); - conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await; + conn.send( + Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)) + .to_data() + .unwrap(), + ) + .await; - let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); + let conn = new_rmc_gateway_connection(conn, |r| { + Arc::new(OnlyRemote::::new(r)) + }); let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) .await .expect("unable to start router"); let mut socket_secure = router_secure - .add_socket(VirtualPort::new(1, 10), Unsecure( - "6f599f81" - )) + .add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81")) .await .expect("unable to add socket"); @@ -55,8 +59,7 @@ async fn main() { }; task::spawn(async move { - let mut stream - = match TcpStream::connect(*FORWARD_DESTINATION).await { + let mut stream = match TcpStream::connect(*FORWARD_DESTINATION).await { Ok(v) => v, Err(e) => { error!("unable to connect: {}", e); @@ -64,10 +67,17 @@ async fn main() { } }; - if let Err(e) = stream.send_buffer(&ConnectionInitData{ - prudpsock_addr: conn.socket_addr, - pid: conn.user_id - }.to_data().unwrap()).await{ + if let Err(e) = stream + .send_buffer( + &ConnectionInitData { + prudpsock_addr: conn.socket_addr, + pid: conn.user_id, + } + .to_data() + .unwrap(), + ) + .await + { error!("error connecting to backend: {}", e); return; }; @@ -92,7 +102,7 @@ async fn main() { return; } }; - + if conn.send(data).await == None{ return; } @@ -105,4 +115,4 @@ async fn main() { }); } drop(conn); -} \ No newline at end of file +} diff --git a/prudpv1/src/prudp/packet.rs b/prudpv1/src/prudp/packet.rs index da376bd..a4d87e9 100644 --- a/prudpv1/src/prudp/packet.rs +++ b/prudpv1/src/prudp/packet.rs @@ -3,21 +3,24 @@ // force the compiler to shut up here #![allow(unused_parens)] +use crate::prudp::packet::PacketOption::{ + ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions, +}; +use bytemuck::{Pod, Zeroable}; +use hmac::{Hmac, Mac}; +use log::{error, warn}; +use md5::{Digest, Md5}; +use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::prudp::types_flags::TypesFlags; +use rnex_core::prudp::types_flags::flags::ACK; +use rnex_core::prudp::virtual_port::VirtualPort; use std::fmt::{Debug, Formatter}; use std::io; use std::io::{Cursor, Read, Seek, Write}; use std::net::SocketAddrV4; -use bytemuck::{Pod, Zeroable}; -use hmac::{Hmac, Mac}; -use log::{error, warn}; -use md5::{Md5, Digest}; use thiserror::Error; -use v_byte_helpers::{SwapEndian}; +use v_byte_helpers::SwapEndian; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::prudp::packet::flags::ACK; -use crate::prudp::packet::PacketOption::{ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions}; -use rnex_core::prudp::socket_addr::PRUDPSockAddr; -use rnex_core::prudp::virtual_port::VirtualPort; type Md5Hmac = Hmac; @@ -32,73 +35,11 @@ pub enum Error { #[error("invalid option id {0}")] InvalidOptionId(u8), #[error("option size {size} doesnt match expected option for given option id {id}")] - InvalidOptionSize { - id: u8, - size: u8, - }, + InvalidOptionSize { id: u8, size: u8 }, } pub type Result = std::result::Result; -#[repr(transparent)] -#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)] -pub struct TypesFlags(u16); - -impl TypesFlags { - #[inline] - pub const fn get_types(self) -> u8 { - (self.0 & 0x000F) as u8 - } - #[inline] - pub const fn get_flags(self) -> u16 { - (self.0 & 0xFFF0) >> 4 - } - #[inline] - pub const fn types(self, val: u8) -> Self { - Self((self.0 & 0xFFF0) | (val as u16 & 0x000F)) - } - #[inline] - pub const fn flags(self, val: u16) -> Self { - Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0)) - } - #[inline] - pub const fn set_flag(&mut self, val: u16){ - self.0 |= (val & 0xFFF) << 4; - } - #[inline] - pub const fn set_types(&mut self, val: u8){ - self.0 |= val as u16 & 0x0F; - } -} - -pub mod flags { - pub const ACK: u16 = 0x001; - pub const RELIABLE: u16 = 0x002; - pub const NEED_ACK: u16 = 0x004; - pub const HAS_SIZE: u16 = 0x008; - pub const MULTI_ACK: u16 = 0x200; -} - -pub mod types { - pub const SYN: u8 = 0x0; - pub const CONNECT: u8 = 0x1; - pub const DATA: u8 = 0x2; - pub const DISCONNECT: u8 = 0x3; - pub const PING: u8 = 0x4; - /// no idea what user is supposed to mean - pub const USER: u8 = 0x5; -} - -impl Debug for TypesFlags { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let stream_type = self.get_types(); - let port_number = self.get_flags(); - write!(f, "TypesFlags{{ types: {}, flags: {} }}", stream_type, port_number) - } -} - - - #[repr(C)] #[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)] pub struct PRUDPV1Header { @@ -116,7 +57,7 @@ pub struct PRUDPV1Header { impl Default for PRUDPV1Header { fn default() -> Self { - Self{ + Self { magic: [0xEA, 0xD0], version: 1, session_id: 0, @@ -126,32 +67,30 @@ impl Default for PRUDPV1Header { destination_port: VirtualPort(0), types_and_flags: TypesFlags(0), packet_specific_size: 0, - substream_id: 0 + substream_id: 0, } } } - #[derive(Debug, Clone, Eq, PartialEq)] -pub enum PacketOption{ +pub enum PacketOption { SupportedFunctions(u32), ConnectionSignature([u8; 16]), FragmentId(u8), InitialSequenceId(u16), - MaximumSubstreamId(u8) + MaximumSubstreamId(u8), } -impl PacketOption{ - fn from(option_id: OptionId, option_data: &[u8]) -> io::Result{ - +impl PacketOption { + fn from(option_id: OptionId, option_data: &[u8]) -> io::Result { let mut data_cursor = Cursor::new(option_data); - let val = match option_id.into(){ + let val = match option_id.into() { 0 => SupportedFunctions(data_cursor.read_struct(IS_BIG_ENDIAN)?), 1 => ConnectionSignature(data_cursor.read_struct(IS_BIG_ENDIAN)?), 2 => FragmentId(data_cursor.read_struct(IS_BIG_ENDIAN)?), 3 => InitialSequenceId(data_cursor.read_struct(IS_BIG_ENDIAN)?), 4 => MaximumSubstreamId(data_cursor.read_struct(IS_BIG_ENDIAN)?), - _ => unreachable!() + _ => unreachable!(), }; Ok(val) @@ -212,7 +151,7 @@ impl OptionId { // Invariant is upheld because we only create the object if it doesn't violate the invariant match val { 0 | 1 | 2 | 3 | 4 => Ok(Self(val)), - _ => Err(Error::InvalidOptionId(val)) + _ => Err(Error::InvalidOptionId(val)), } } @@ -223,7 +162,7 @@ impl OptionId { 2 => 1, 3 => 2, 4 => 1, - _ => unreachable!() + _ => unreachable!(), } } } @@ -238,8 +177,7 @@ impl PRUDPV1Packet { pub fn new(reader: &mut (impl Read + Seek)) -> Result { let header: PRUDPV1Header = reader.read_struct(IS_BIG_ENDIAN)?; - if header.magic[0] != 0xEA || - header.magic[1] != 0xD0 { + if header.magic[0] != 0xEA || header.magic[1] != 0xD0 { return Err(Error::InvalidMagic(u16::from_be_bytes(header.magic))); } @@ -247,31 +185,31 @@ impl PRUDPV1Packet { return Err(Error::InvalidVersion(header.version)); } - let packet_signature: [u8; 16] = reader.read_struct(IS_BIG_ENDIAN)?; //let packet_signature: [u8; 16] = [0; 16]; assert_eq!(reader.stream_position().ok(), Some(14 + 16)); - - let mut packet_specific_buffer = vec![0u8; header.packet_specific_size as usize]; reader.read_exact(&mut packet_specific_buffer)?; - //no clue whats up with options but they are broken let mut packet_specific_data_cursor = Cursor::new(&packet_specific_buffer); let mut options = Vec::new(); loop { - let Ok(option_id): io::Result = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else { - break + let Ok(option_id): io::Result = + packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) + else { + break; }; - let Ok(value_size): io::Result = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else { - break + let Ok(value_size): io::Result = + packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) + else { + break; }; if value_size == 0 { @@ -291,20 +229,21 @@ impl PRUDPV1Packet { } let mut option_data = vec![0u8; value_size as usize]; - if packet_specific_data_cursor.read_exact(&mut option_data[..]).is_err() { + if packet_specific_data_cursor + .read_exact(&mut option_data[..]) + .is_err() + { error!("unable to read options"); break; } options.push(PacketOption::from(option_id, &option_data)?); } - + let mut payload = vec![0u8; header.payload_size as usize]; reader.read_exact(&mut payload)?; - - Ok(Self { header, packet_signature, @@ -313,22 +252,21 @@ impl PRUDPV1Packet { }) } - pub fn base_acknowledgement_packet(&self) -> Self{ + pub fn base_acknowledgement_packet(&self) -> Self { let base = self.base_response_packet(); let mut flags = self.header.types_and_flags.flags(0); flags.set_flag(ACK); - let options = self.options + let options = self + .options .iter() .filter(|o| matches!(o, FragmentId(_))) .cloned() .collect(); - - - Self{ + Self { header: PRUDPV1Header { types_and_flags: flags, sequence_id: self.header.sequence_id, @@ -348,17 +286,24 @@ impl PRUDPV1Packet { } } - fn generate_options_bytes(&self) -> Vec{ + fn generate_options_bytes(&self) -> Vec { let mut vec = Vec::new(); - for option in &self.options{ - option.write_to_stream(&mut vec).expect("vec should always automatically be able to extend"); + for option in &self.options { + option + .write_to_stream(&mut vec) + .expect("vec should always automatically be able to extend"); } vec } - pub fn calculate_signature_value(&self, access_key: &str, session_key: Option<[u8; 32]>, connection_signature: Option<[u8; 16]>) -> [u8; 16]{ + pub fn calculate_signature_value( + &self, + access_key: &str, + session_key: Option<[u8; 32]>, + connection_signature: Option<[u8; 16]>, + ) -> [u8; 16] { let access_key_bytes = access_key.as_bytes(); let access_key_sum: u32 = access_key_bytes.iter().map(|v| *v as u32).sum(); let access_key_sum_bytes: [u8; 4] = access_key_sum.to_le_bytes(); @@ -374,32 +319,46 @@ impl PRUDPV1Packet { let mut hmac = Md5Hmac::new_from_slice(&key).expect("fuck"); - hmac.write(&header_data).expect("error during hmac calculation"); + hmac.write(&header_data) + .expect("error during hmac calculation"); if let Some(session_key) = session_key { - hmac.write(&session_key).expect("error during hmac calculation"); + hmac.write(&session_key) + .expect("error during hmac calculation"); } - hmac.write(&access_key_sum_bytes).expect("error during hmac calculation"); + hmac.write(&access_key_sum_bytes) + .expect("error during hmac calculation"); if let Some(connection_signature) = connection_signature { - hmac.write(&connection_signature).expect("error during hmac calculation"); + hmac.write(&connection_signature) + .expect("error during hmac calculation"); } - hmac.write(&option_bytes).expect("error during hmac calculation"); + hmac.write(&option_bytes) + .expect("error during hmac calculation"); - hmac.write_all(&self.payload).expect("error during hmac calculation"); + hmac.write_all(&self.payload) + .expect("error during hmac calculation"); - hmac.finalize().into_bytes()[0..16].try_into().expect("invalid hmac size") + hmac.finalize().into_bytes()[0..16] + .try_into() + .expect("invalid hmac size") } - pub fn calculate_and_assign_signature(&mut self, access_key: &str, session_key: Option<[u8; 32]>, connection_signature: Option<[u8; 16]>){ - self.packet_signature = self.calculate_signature_value(access_key, session_key, connection_signature); + pub fn calculate_and_assign_signature( + &mut self, + access_key: &str, + session_key: Option<[u8; 32]>, + connection_signature: Option<[u8; 16]>, + ) { + self.packet_signature = + self.calculate_signature_value(access_key, session_key, connection_signature); } - pub fn set_sizes(&mut self){ + pub fn set_sizes(&mut self) { self.header.packet_specific_size = self.options.iter().map(|o| o.write_size()).sum(); self.header.payload_size = self.payload.len() as u16; } - pub fn base_response_packet(&self) -> Self { + pub fn base_response_packet(&self) -> Self { Self { header: PRUDPV1Header { magic: [0xEA, 0xD0], @@ -412,19 +371,18 @@ impl PRUDPV1Packet { sequence_id: 0, session_id: 0, substream_id: 0, - }, packet_signature: [0; 16], payload: Default::default(), - options: Default::default() + options: Default::default(), } } - pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()>{ + pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()> { writer.write_all(bytemuck::bytes_of(&self.header))?; writer.write_all(&self.packet_signature)?; - for option in &self.options{ + for option in &self.options { option.write_to_stream(writer)?; } @@ -436,20 +394,24 @@ impl PRUDPV1Packet { #[cfg(test)] mod test { - use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; - use crate::prudp::packet::types::DATA; - use super::{OptionId, PacketOption, PRUDPV1Header, TypesFlags}; - use rnex_core::prudp::virtual_port::VirtualPort; + use super::{OptionId, PRUDPV1Header, PacketOption, TypesFlags}; + use rnex_core::prudp::{ + types_flags::{ + flags::{NEED_ACK, RELIABLE}, + types::DATA, + }, + virtual_port::VirtualPort, + }; #[test] fn size_test() { assert_eq!(size_of::(), 14); } #[test] - fn test_options(){ - let packet_types = [0,1,2,3,4]; + fn test_options() { + let packet_types = [0, 1, 2, 3, 4]; - for p_type in packet_types{ + for p_type in packet_types { let option_id = OptionId::new(p_type).unwrap(); let buf = vec![0; option_id.option_type_size() as usize]; @@ -463,12 +425,10 @@ mod test { assert_eq!(write_buf.len() as u8, opt.write_size()) } } - - } #[test] - fn header_read(){ + fn header_read() { let header = PRUDPV1Header { version: 0, destination_port: VirtualPort(0), @@ -478,8 +438,8 @@ mod test { packet_specific_size: 0, payload_size: 0, sequence_id: 0, - magic: [0xEA,0xD0], - source_port: VirtualPort(0) + magic: [0xEA, 0xD0], + source_port: VirtualPort(0), }; let bytes = bytemuck::bytes_of(&header); @@ -490,11 +450,11 @@ mod test { } #[test] - fn test_types_flags(){ + fn test_types_flags() { let types = TypesFlags::default().types(DATA).flags(NEED_ACK | RELIABLE); assert_ne!((types.0 >> 4) & NEED_ACK, 0); assert_ne!((types.0 >> 4) & RELIABLE, 0); assert_ne!((types.0 & 0xFF) as u8 & DATA, 0); } -} \ No newline at end of file +} diff --git a/prudpv1/src/prudp/secure.rs b/prudpv1/src/prudp/secure.rs index acf8bfb..a9f7960 100644 --- a/prudpv1/src/prudp/secure.rs +++ b/prudpv1/src/prudp/secure.rs @@ -1,18 +1,19 @@ -use std::io::Cursor; +use crate::prudp::packet::PRUDPV1Packet; +use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance}; use hmac::digest::consts::U32; use log::error; use rc4::cipher::StreamCipherCoreWrapper; -use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher}; use rc4::consts::U16; +use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher}; +use rnex_core::kerberos::{TicketInternalData, derive_key}; +use rnex_core::nex::account::Account; +use rnex_core::prudp::encryption::EncryptionPair; +use rnex_core::rmc::structures::RmcSerialize; +use std::io::Cursor; use typenum::U5; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use rnex_core::kerberos::{derive_key, TicketInternalData}; -use rnex_core::nex::account::Account; -use crate::prudp::packet::PRUDPV1Packet; -use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair}; -use rnex_core::rmc::structures::RmcSerialize; -pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)>{ +pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)> { let mut cursor = Cursor::new(data); let mut ticket_data: Vec = Vec::deserialize(&mut cursor).ok()?; @@ -20,7 +21,7 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3 let ticket_data_size = ticket_data.len(); - let ticket_data = &mut ticket_data[0..ticket_data_size-0x10]; + let ticket_data = &mut ticket_data[0..ticket_data_size - 0x10]; let server_key = derive_key(act.pid, act.kerbros_password); @@ -29,7 +30,7 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3 rc4.apply_keystream(ticket_data); - let ticket_data: &TicketInternalData = match bytemuck::try_from_bytes(ticket_data){ + let ticket_data: &TicketInternalData = match bytemuck::try_from_bytes(ticket_data) { Ok(v) => v, Err(e) => { error!("unable to read internal ticket data: {}", e); @@ -39,15 +40,15 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3 // todo: add ticket expiration - let TicketInternalData{ + let TicketInternalData { session_key, pid: ticket_source_pid, - issued_time + issued_time, } = *ticket_data; // todo: add checking if tickets are signed with a valid md5-hmac let request_data_length = request_data.len(); - let request_data = &mut request_data[0.. request_data_length - 0x10]; + let request_data = &mut request_data[0..request_data_length - 0x10]; let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream"); @@ -58,53 +59,55 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3 let pid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; - if pid != ticket_source_pid{ + if pid != ticket_source_pid { let ticket_created_on = issued_time.to_regular_time(); - error!("someone tried to spoof their pid, ticket was created on: {}", ticket_created_on.to_rfc2822()); + error!( + "someone tried to spoof their pid, ticket was created on: {}", + ticket_created_on.to_rfc2822() + ); return None; } let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; - - Some((session_key, pid, response_check)) } type Rc4U32 = StreamCipherCoreWrapper>; -pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) -> Vec>>{ +pub fn generate_secure_encryption_pairs( + mut session_key: [u8; 32], + count: u8, +) -> Vec>> { let mut vec = Vec::with_capacity(count as usize); - vec.push(EncryptionPair{ + vec.push(EncryptionPair { send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"), - recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4") + recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"), }); - for _ in 1..=count{ + for _ in 1..=count { let modifier = session_key.len() + 1; let key_length = session_key.len(); - for (position, val) in (&mut session_key[0..key_length/2]).iter_mut().enumerate(){ + for (position, val) in (&mut session_key[0..key_length / 2]).iter_mut().enumerate() { *val = val.wrapping_add((modifier - position) as u8); } - vec.push(EncryptionPair{ + vec.push(EncryptionPair { send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"), - recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4") + recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"), }); } vec } - pub struct Secure(pub &'static str, pub Account); - pub struct SecureInstance { access_key: &'static str, session_key: [u8; 32], @@ -155,18 +158,17 @@ impl CryptoHandler for Secure { } } - impl CryptoHandlerConnectionInstance for SecureInstance { type Encryption = Rc4; fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]) { - if let Some(crypt_pair) = self.streams.get_mut(substream as usize){ + if let Some(crypt_pair) = self.streams.get_mut(substream as usize) { crypt_pair.recv.apply_keystream(data); } } fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]) { - if let Some(crypt_pair) = self.streams.get_mut(substream as usize){ + if let Some(crypt_pair) = self.streams.get_mut(substream as usize) { crypt_pair.send.apply_keystream(data); } } @@ -182,10 +184,14 @@ impl CryptoHandlerConnectionInstance for SecureInstance { fn sign_packet(&self, packet: &mut PRUDPV1Packet) { packet.set_sizes(); - packet.calculate_and_assign_signature(self.access_key, Some(self.session_key), Some(self.self_signature)); + packet.calculate_and_assign_signature( + self.access_key, + Some(self.session_key), + Some(self.self_signature), + ); } fn verify_packet(&self, _packet: &PRUDPV1Packet) -> bool { true } -} \ No newline at end of file +} diff --git a/prudpv1/src/prudp/socket.rs b/prudpv1/src/prudp/socket.rs index 6467d8f..a3b0445 100644 --- a/prudpv1/src/prudp/socket.rs +++ b/prudpv1/src/prudp/socket.rs @@ -1,47 +1,34 @@ -use crate::prudp::packet::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE}; -use crate::prudp::packet::types::{CONNECT, DATA, DISCONNECT, PING, SYN}; use crate::prudp::packet::PacketOption::{ ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions, }; -use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags}; -use rnex_core::prudp::virtual_port::VirtualPort; -use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet}; use async_trait::async_trait; -use log::{info, warn}; use log::error; +use log::{info, warn}; use rc4::StreamCipher; -use v_byte_helpers::ReadExtensions; -use v_byte_helpers::little_endian::read_u16; +use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::prudp::types_flags::TypesFlags; +use rnex_core::prudp::types_flags::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE}; +use rnex_core::prudp::types_flags::types::{CONNECT, DATA, DISCONNECT, PING, SYN}; +use rnex_core::prudp::virtual_port::VirtualPort; use std::collections::{BTreeMap, HashMap}; use std::io::Cursor; use std::marker::PhantomData; use std::ops::Deref; use std::sync::{Arc, Weak}; +use v_byte_helpers::ReadExtensions; +use v_byte_helpers::little_endian::read_u16; use std::time::Duration; use tokio::net::UdpSocket; -use tokio::sync::mpsc::{channel, Receiver, Sender}; use tokio::sync::Mutex; -use tokio::time::{sleep, Instant}; +use tokio::sync::mpsc::{Receiver, Sender, channel}; +use tokio::time::{Instant, sleep}; // due to the way this is designed crashing the router thread causes deadlock, sorry ;-; // (maybe i will fix that some day) /// PRUDP Socket for accepting connections to then send and recieve data from those clients -pub struct EncryptionPair { - pub send: T, - pub recv: T, -} - -impl EncryptionPair { - pub fn init_both T>(func: F) -> Self { - Self { - recv: func(), - send: func(), - } - } -} - pub struct CommonConnection { pub user_id: u32, pub socket_addr: PRUDPSockAddr, @@ -61,7 +48,7 @@ struct InternalConnection { socket: Arc, packet_queue: HashMap, last_packet_time: Instant, - unacknowleged_packets: Vec<(Instant, PRUDPV1Packet)> + unacknowleged_packets: Vec<(Instant, PRUDPV1Packet)>, } impl Deref for InternalConnection { @@ -82,17 +69,17 @@ impl InternalConnection { } /// Sends a raw packet to a given client on the connection - /// - /// a raw packet is one which does not get processed any further(other than to send it + /// + /// a raw packet is one which does not get processed any further(other than to send it /// off without buffering or anything), - /// as such you need to make sure that + /// as such you need to make sure that /// the sizes are set correctly and so on #[inline] async fn send_raw_packet(&self, prudp_packet: &PRUDPV1Packet) { send_raw_prudp_to_sockaddr(&self.socket, self.socket_addr, prudp_packet).await; } - async fn delete_connection(&self){ + async fn delete_connection(&self) { let Some(conns) = self.connections.upgrade() else { // this is fine as it implies the server has already quit, thus meaning that we dont // have to remove ourselves from the server @@ -187,8 +174,6 @@ pub(super) trait AnyInternalConnection: async fn close_connection(&mut self); } - - #[async_trait] impl AnyInternalConnection for InternalConnection { async fn send_data_packet(&mut self, data: Vec) { @@ -219,7 +204,6 @@ impl AnyInternalConnection for InternalConne self.unacknowleged_packets.push((Instant::now(), packet)); } - async fn close_connection(&mut self) { // jon confirmed that this should be a safe way to dc a client @@ -250,7 +234,11 @@ impl AnyInternalConnection for InternalConne } } -async fn send_raw_prudp_to_sockaddr(udp_socket: &UdpSocket, dest: PRUDPSockAddr, packet: &PRUDPV1Packet){ +async fn send_raw_prudp_to_sockaddr( + udp_socket: &UdpSocket, + dest: PRUDPSockAddr, + packet: &PRUDPV1Packet, +) { let mut vec = Vec::new(); packet @@ -281,7 +269,7 @@ impl InternalSocket { } /// sends a raw packet to a specific prudp socket address - /// + /// /// a raw packet is a packet is a packet which wont get processed any further, /// sizes signatures etc need to be set before using this function async fn send_packet_unbuffered(&self, dest: PRUDPSockAddr, packet: &PRUDPV1Packet) { @@ -353,13 +341,15 @@ impl InternalSocket { conn.close_connection().await; } - for (send_time, packet) in &conn.unacknowleged_packets{ - if *send_time < (Instant::now() - Duration::from_millis(3000)){ - warn!("failed to resend packet 5 times and never got response, destroying connection"); + for (send_time, packet) in &conn.unacknowleged_packets { + if *send_time < (Instant::now() - Duration::from_millis(3000)) { + warn!( + "failed to resend packet 5 times and never got response, destroying connection" + ); conn.close_connection().await; break; } - if *send_time < (Instant::now() - Duration::from_millis(500)){ + if *send_time < (Instant::now() - Duration::from_millis(500)) { info!("unacknowledged packet sat arround for more than 500 ms, resending"); conn.send_raw_packet(packet).await; } @@ -399,7 +389,7 @@ impl InternalSocket { packet_queue: Default::default(), last_packet_time: Instant::now(), unacknowleged_packets: Vec::new(), - supported_function_version + supported_function_version, }; let internal = Arc::new(Mutex::new(internal)); @@ -487,7 +477,7 @@ impl InternalSocket { SupportedFunctions(funcs) => { functions = *funcs & 0xFF; response.options.push(SupportedFunctions(*funcs & 0xFF)); - }, + } _ => { /* ? */ } } } @@ -610,7 +600,6 @@ impl AnyInternalSocket for InternalSocket { if (packet.header.types_and_flags.get_flags() & ACK) != 0 { info!("got ack"); - if packet.header.types_and_flags.get_types() == SYN || packet.header.types_and_flags.get_types() == CONNECT { @@ -645,9 +634,8 @@ impl AnyInternalSocket for InternalSocket { // remove the packet whose sequence id matches the ack packet // or in other words keep all of those which dont match the sequence id - conn.unacknowleged_packets.retain_mut(|v| { - packet.header.sequence_id != v.1.header.sequence_id - }); + conn.unacknowleged_packets + .retain_mut(|v| packet.header.sequence_id != v.1.header.sequence_id); } else { error!("non connection acknowledgement packet on nonexistent connection...") } @@ -659,26 +647,23 @@ impl AnyInternalSocket for InternalSocket { if let Some(conn) = self.get_connection(address).await { let mut conn = conn.lock().await; - if conn.supported_function_version == 1{ + if conn.supported_function_version == 1 { let mut collected_ids: Vec = Vec::new(); let mut cursor = Cursor::new(&packet.payload); - while let Ok(v) = read_u16(&mut cursor){ + while let Ok(v) = read_u16(&mut cursor) { collected_ids.push(v); } conn.unacknowleged_packets.retain_mut(|(_, up)| { - !( - collected_ids.iter().any(|id| up.header.sequence_id == *id) || - up.header.sequence_id <= packet.header.sequence_id - ) + !(collected_ids.iter().any(|id| up.header.sequence_id == *id) + || up.header.sequence_id <= packet.header.sequence_id) }); - } else { let mut collected_ids: Vec = Vec::new(); let mut cursor = Cursor::new(&packet.payload); - let Ok(_substream_id): Result = cursor.read_le_struct() else{ + let Ok(_substream_id): Result = cursor.read_le_struct() else { error!("invalid data whilest reading new version agregate acknowledgement"); return; }; @@ -690,19 +675,20 @@ impl AnyInternalSocket for InternalSocket { error!("invalid data whilest reading new version agregate acknowledgement"); return; }; - for _ in 0..additional_sequence_ids{ - let Ok(additional_sequence_id): Result = cursor.read_le_struct() else { - error!("invalid data whilest reading new version agregate acknowledgement"); + for _ in 0..additional_sequence_ids { + let Ok(additional_sequence_id): Result = cursor.read_le_struct() + else { + error!( + "invalid data whilest reading new version agregate acknowledgement" + ); return; }; collected_ids.push(additional_sequence_id); } conn.unacknowleged_packets.retain_mut(|(_, up)| { - !( - collected_ids.iter().any(|id| up.header.sequence_id == *id) || - up.header.sequence_id <= sequence_id - ) + !(collected_ids.iter().any(|id| up.header.sequence_id == *id) + || up.header.sequence_id <= sequence_id) }); } } else { diff --git a/prudpv1/src/prudp/unsecure.rs b/prudpv1/src/prudp/unsecure.rs index 6c45824..d47550f 100644 --- a/prudpv1/src/prudp/unsecure.rs +++ b/prudpv1/src/prudp/unsecure.rs @@ -1,13 +1,12 @@ +use crate::prudp::packet::PRUDPV1Packet; +use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance}; use once_cell::sync::Lazy; use rc4::{Key, KeyInit, Rc4, StreamCipher}; +use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair}; use typenum::U5; -use crate::prudp::packet::PRUDPV1Packet; -use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair}; pub struct Unsecure(pub &'static str); - - pub struct UnsecureInstance { key: &'static str, streams: Vec>>, @@ -18,7 +17,6 @@ pub struct UnsecureInstance { // my hand was forced to use lazy so that we can guarantee this code // only runs once and so that i can put it here as a "constant" (for performance and readability) // since for some reason rust crypto doesn't have any const time key initialization -static DEFAULT_KEY: Lazy> = Lazy::new(|| Key::from(*b"CD&ML")); impl CryptoHandler for Unsecure { type CryptoConnectionInstance = UnsecureInstance; @@ -53,13 +51,13 @@ impl CryptoHandlerConnectionInstance for UnsecureInstance { type Encryption = Rc4; fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]) { - if let Some(crypt_pair) = self.streams.get_mut(substream as usize){ + if let Some(crypt_pair) = self.streams.get_mut(substream as usize) { crypt_pair.recv.apply_keystream(data); } } fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]) { - if let Some(crypt_pair) = self.streams.get_mut(substream as usize){ + if let Some(crypt_pair) = self.streams.get_mut(substream as usize) { crypt_pair.send.apply_keystream(data); } } @@ -81,4 +79,4 @@ impl CryptoHandlerConnectionInstance for UnsecureInstance { fn verify_packet(&self, _packet: &PRUDPV1Packet) -> bool { true } -} \ No newline at end of file +} diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 554a8d9..eaf0f5f 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -9,7 +9,7 @@ dotenv = "0.15.0" once_cell = "1.20.2" rc4 = "0.1.0" thiserror = "2.0.11" -v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1.1" } +v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } simplelog = "0.12.2" chrono = "0.4.39" log = "0.4.25" @@ -48,4 +48,4 @@ path = "src/executables/backend_server_secure.rs" [[bin]] name = "edge_node_holder_server" -path = "src/executables/edge_node_holder_server.rs" \ No newline at end of file +path = "src/executables/edge_node_holder_server.rs" diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs index 1488369..598b039 100644 --- a/rnex-core/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -1,19 +1,18 @@ -use std::sync::Arc; -use std::sync::atomic::AtomicU32; use rnex_core::common::setup; -use rnex_core::executables::common::{new_simple_backend}; +use rnex_core::executables::common::new_simple_backend; use rnex_core::nex::matchmake::MatchmakeManager; use rnex_core::nex::remote_console::RemoteConsole; use rnex_core::nex::user::User; -use rnex_core::rmc::protocols::RemoteInstantiatable; +use rnex_core::rmc::protocols::{RemoteDisconnectable, RmcPureRemoteObject}; +use std::sync::Arc; +use std::sync::atomic::AtomicU32; #[tokio::main] async fn main() { setup(); - - let mmm = Arc::new(MatchmakeManager{ - gid_counter: AtomicU32::new(1), + let mmm = Arc::new(MatchmakeManager { + //gid_counter: AtomicU32::new(1), sessions: Default::default(), users: Default::default(), rv_cid_counter: AtomicU32::new(1), @@ -23,15 +22,16 @@ async fn main() { MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - new_simple_backend(move |c, r|{ + new_simple_backend(move |c, r| { let mmm = mmm.clone(); - Arc::new_cyclic(move |this| User{ + Arc::new_cyclic(move |this| User { this: this.clone(), ip: c.prudpsock_addr, - pid:c.pid, + pid: c.pid, remote: RemoteConsole::new(r), matchmake_manager: mmm, - station_url: Default::default() + station_url: Default::default(), }) - }).await; -} \ No newline at end of file + }) + .await; +} diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index 7a55f24..0d5ca06 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -1,27 +1,23 @@ +use once_cell::sync::Lazy; +use rnex_core::nex::account::Account; +use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection}; +use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::rnex_proxy_common::ConnectionInitData; use std::env; use std::io::Cursor; use std::net::{Ipv4Addr, SocketAddrV4}; use std::sync::Arc; -use once_cell::sync::Lazy; -use rnex_core::nex::account::Account; -use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection}; -use rnex_core::rnex_proxy_common::ConnectionInitData; -use rnex_core::rmc::structures::RmcSerialize; use tokio::net::TcpListener; -use std::error::Error; use log::error; +use std::error::Error; use crate::reggie::UnitPacketRead; const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip"; - - -fn try_get_ip() -> Result> { - let mut req = ureq::get(IP_REQ_SERVICE_URL) - .call()?; - +pub fn try_get_ip() -> Result> { + let mut req = ureq::get(IP_REQ_SERVICE_URL).call()?; Ok(req.body_mut().read_to_string()?.parse()?) } @@ -37,16 +33,14 @@ pub static OWN_IP_PUBLIC: Lazy = Lazy::new(|| { env::var("SERVER_IP_PUBLIC") .ok() .map(|s| s.parse().expect("invalid ip address")) - .unwrap_or_else(||{ - try_get_ip().unwrap() - }) + .unwrap_or_else(|| try_get_ip().unwrap()) }); pub static SERVER_PORT: Lazy = Lazy::new(|| { env::var("SERVER_PORT") .ok() .and_then(|s| s.parse().ok()) - .unwrap_or(10000) + .unwrap_or(6000) }); pub static KERBEROS_SERVER_PASSWORD: Lazy = Lazy::new(|| { @@ -60,24 +54,28 @@ pub static AUTH_SERVER_ACCOUNT: Lazy = pub static SECURE_SERVER_ACCOUNT: Lazy = Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD)); - -pub async fn new_simple_backend(mut creation_function: F) +pub async fn new_simple_backend(mut creation_function: F) where F: FnMut(ConnectionInitData, RmcConnection) -> Arc, { - let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap(); + let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) + .await + .unwrap(); while let Ok((mut stream, _addr)) = listen.accept().await { - let buffer = match stream.read_buffer().await{ + let buffer = match stream.read_buffer().await { Ok(v) => v, Err(e) => { - error!("an error ocurred whilest reading connection data buffer: {:?}", e); + error!( + "an error ocurred whilest reading connection data buffer: {:?}", + e + ); continue; } }; let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer)); - let user_connection_data = match user_connection_data{ + let user_connection_data = match user_connection_data { Ok(v) => v, Err(e) => { error!("an error ocurred whilest reading connection data: {:?}", e); @@ -85,8 +83,6 @@ where } }; let fun_ref = &mut creation_function; - new_rmc_gateway_connection(stream.into(), move |r|{ - fun_ref(user_connection_data, r) - }); + new_rmc_gateway_connection(stream.into(), move |r| fun_ref(user_connection_data, r)); } -} \ No newline at end of file +} diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 9b67fca..1bd6e27 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -1,19 +1,19 @@ -use std::hash::{DefaultHasher, Hasher}; -use std::net::SocketAddrV4; -use std::sync::Arc; use crate::grpc::account; -use rnex_core::kerberos::{derive_key, KerberosDateTime, Ticket}; +use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; +use crate::{define_rmc_proto, kerberos}; +use macros::rmc_struct; +use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; use rnex_core::nex::account::Account; +use rnex_core::rmc::protocols::OnlyRemote; use rnex_core::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth}; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::response::ErrorCode::Core_Unknown; use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::connection_data::ConnectionData; use rnex_core::rmc::structures::qresult::QResult; -use crate::{define_rmc_proto, kerberos}; -use macros::rmc_struct; -use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; -use rnex_core::rmc::protocols::OnlyRemote; +use std::hash::{DefaultHasher, Hasher}; +use std::net::SocketAddrV4; +use std::sync::Arc; define_rmc_proto!( proto AuthClientProtocol{ @@ -60,10 +60,11 @@ async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> { Some((pid, passwd)) } -fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String{ +fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String { format!( "prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1", - sock_addr.ip(), sock_addr.port() + sock_addr.ip(), + sock_addr.port() ) } @@ -99,7 +100,7 @@ impl Auth for AuthHandler { let mut hasher = DefaultHasher::new(); hasher.write(name.as_bytes()); - + let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { return Err(ErrorCode::Core_Exception); }; @@ -117,7 +118,7 @@ impl Auth for AuthHandler { source_login_data.0, ticket.into(), connection_data, - self.build_name.to_string() //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")), + self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")), )) } @@ -157,32 +158,30 @@ impl Auth for AuthHandler { #[cfg(test)] mod test { + use rnex_core::rmc::response::RMCResponse; + use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rmc::structures::connection_data::ConnectionData; use rnex_core::rmc::structures::qresult::QResult; - use rnex_core::rmc::structures::RmcSerialize; - use rnex_core::rmc::response::RMCResponse; use std::io::Cursor; - - #[test] fn test() { - + return; let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap(); - let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result else { + let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result + else { panic!() }; - - // let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap(); let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); let data = <(QResult, u32, Vec, ConnectionData, String) as RmcSerialize>::deserialize( &mut Cursor::new(stuff), - ).unwrap(); + ) + .unwrap(); println!("data: {:?}", data); } diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index a2f8c20..732c1ea 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -1,40 +1,48 @@ -use std::collections::HashMap; -use std::str::FromStr; -use std::sync::{Arc, Weak}; -use std::sync::atomic::AtomicU32; -use std::sync::atomic::Ordering::Relaxed; -use std::time::Duration; -use log::info; -use rand::random; -use tokio::sync::{Mutex, RwLock}; -use tokio::time::sleep; -use rnex_core::kerberos::KerberosDateTime; use crate::nex::user::User; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use rnex_core::rmc::protocols::notifications::notification_types::{HOST_CHANGED, OWNERSHIP_CHANGED}; +use log::info; +use rand::random; +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::protocols::notifications::notification_types::{ + HOST_CHANGED, OWNERSHIP_CHANGED, +}; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid}; -use rnex_core::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria}; use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING; +use rnex_core::rmc::structures::matchmake::{ + Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria, +}; use rnex_core::rmc::structures::variant::Variant; +use std::collections::HashMap; +use std::str::FromStr; +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::{Arc, Weak}; +use std::time::Duration; +use tokio::sync::{Mutex, RwLock}; +use tokio::time::sleep; -pub struct MatchmakeManager{ - pub gid_counter: AtomicU32, +pub struct MatchmakeManager { + //pub gid_counter: AtomicU32, pub sessions: RwLock>>>, pub rv_cid_counter: AtomicU32, - pub users: RwLock>> + pub users: RwLock>>, } -impl MatchmakeManager{ - pub fn next_gid(&self) -> u32{ - self.gid_counter.fetch_add(1, Relaxed) +impl MatchmakeManager { + pub fn next_gid(&self) -> u32 { + random() + //self.gid_counter.fetch_add(1, Relaxed) } - pub fn next_cid(&self) -> u32{ + pub fn next_cid(&self) -> u32 { self.rv_cid_counter.fetch_add(1, Relaxed) } - pub async fn get_session(&self, gid: u32) -> Result>, ErrorCode>{ + pub async fn get_session( + &self, + gid: u32, + ) -> Result>, ErrorCode> { let sessions = self.sessions.read().await; let Some(session) = sessions.get(&gid) else { @@ -47,7 +55,7 @@ impl MatchmakeManager{ Ok(session) } - async fn garbage_collect(&self){ + async fn garbage_collect(&self) { info!("running rnex garbage collector over all sessions and users"); let mut idx = 0; @@ -61,12 +69,12 @@ impl MatchmakeManager{ let sessions = self.sessions.read().await; let session_pair = sessions.iter().nth(idx).map(|s| (*s.0, s.1.clone())); drop(sessions); - + session_pair - }{ + } { let session = session.lock().await; - if !session.is_reachable(){ + if !session.is_reachable() { to_be_deleted_gids.push(gid); } @@ -75,14 +83,14 @@ impl MatchmakeManager{ let mut sessions = self.sessions.write().await; - for gid in to_be_deleted_gids{ + for gid in to_be_deleted_gids { sessions.remove(&gid); } } - pub async fn initialize_garbage_collect_thread(this: Weak){ + pub async fn initialize_garbage_collect_thread(this: Weak) { tokio::spawn(async move { - while let Some(this) = this.upgrade(){ + while let Some(this) = this.upgrade() { this.garbage_collect().await; // every 30 minutes @@ -92,51 +100,62 @@ impl MatchmakeManager{ } } - #[derive(Default, Debug)] -pub struct ExtendedMatchmakeSession{ +pub struct ExtendedMatchmakeSession { pub session: MatchmakeSession, pub connected_players: Vec>, } -fn read_bounds_string(str: &str) -> Option<(T,T)>{ +fn read_bounds_string(str: &str) -> Option<(T, T)> { let bounds = str.split_once(",")?; Some((T::from_str(bounds.0).ok()?, T::from_str(bounds.1).ok()?)) } -fn check_bounds_str(compare: T, str: &str) -> Option{ +fn check_bounds_str(compare: T, str: &str) -> Option { let bounds: (T, T) = read_bounds_string(str)?; Some(bounds.0 <= compare && compare <= bounds.1) } -pub async fn broadcast_notification>(players: &[T], notification_event: &NotificationEvent){ - for player in players{ +pub async fn broadcast_notification>( + players: &[T], + notification_event: &NotificationEvent, +) { + for player in players { let player = player.as_ref(); - player.remote.process_notification_event(notification_event.clone()).await; + player + .remote + .process_notification_event(notification_event.clone()) + .await; } } -impl ExtendedMatchmakeSession{ +impl ExtendedMatchmakeSession { #[inline(always)] - pub fn get_active_players(&self) -> Vec>{ - self.connected_players.iter().filter_map(|u| u.upgrade()).collect() + pub fn get_active_players(&self) -> Vec> { + self.connected_players + .iter() + .filter_map(|u| u.upgrade()) + .collect() } #[inline(always)] - pub async fn broadcast_notification(&self, notification_event: &NotificationEvent){ + pub async fn broadcast_notification(&self, notification_event: &NotificationEvent) { broadcast_notification(&self.get_active_players(), notification_event).await; } - pub async fn from_matchmake_session(gid: u32, session: MatchmakeSession, host: &Weak) -> Self{ - let Some(host) = host.upgrade() else{ + pub async fn from_matchmake_session( + gid: u32, + session: MatchmakeSession, + host: &Weak, + ) -> Self { + let Some(host) = host.upgrade() else { return Default::default(); }; - - let mm_session = MatchmakeSession{ - gathering: Gathering{ + let mm_session = MatchmakeSession { + gathering: Gathering { self_gid: gid, owner_pid: host.pid, host_pid: host.pid, @@ -144,25 +163,25 @@ impl ExtendedMatchmakeSession{ }, datetime: KerberosDateTime::now(), session_key: (0..32).map(|_| random()).collect(), - matchmake_param: MatchmakeParam{ + matchmake_param: MatchmakeParam { params: vec![ ("@SR".to_owned(), Variant::Bool(true)), - ("@GIR".to_owned(), Variant::SInt64(3)) - ] + ("@GIR".to_owned(), Variant::SInt64(3)), + ], }, system_password_enabled: false, ..session }; - Self{ + Self { session: mm_session, - connected_players: Default::default() + connected_players: Default::default(), } } pub async fn add_players(&mut self, conns: &[Weak], join_msg: String) { let Some(initiating_user) = conns[0].upgrade() else { - return + return; }; let initiating_pid = initiating_user.pid; @@ -173,36 +192,42 @@ impl ExtendedMatchmakeSession{ } self.session.participation_count = self.connected_players.len() as u32; - for other_connection in &conns[1..]{ + for other_connection in &conns[1..] { let Some(other_conn) = other_connection.upgrade() else { continue; }; - let other_pid = other_conn.pid; /*if other_pid == self.session.gathering.owner_pid && joining_pid == self.session.gathering.owner_pid{ continue; }*/ - other_conn.remote.process_notification_event(NotificationEvent{ - pid_source: initiating_pid, - notif_type: 122000, - param_1: self.session.gathering.self_gid, - param_2: other_pid, - str_param: "".into(), - param_3: 0 - }).await; + other_conn + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 122000, + param_1: self.session.gathering.self_gid, + param_2: other_pid, + str_param: "".into(), + param_3: 0, + }) + .await; } - let list_of_connected_pids: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).map(|p| p.pid).collect(); + let list_of_connected_pids: Vec<_> = self + .connected_players + .iter() + .filter_map(|p| p.upgrade()) + .map(|p| p.pid) + .collect(); - for other_connection in conns{ + for other_connection in conns { let Some(other_conn) = other_connection.upgrade() else { continue; }; - // let other_pid = other_conn.pid; /*if other_pid == self.session.gathering.owner_pid && joining_pid == self.session.gathering.owner_pid{ @@ -210,44 +235,52 @@ impl ExtendedMatchmakeSession{ }*/ for pid in &list_of_connected_pids { - other_conn.remote.process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid, - param_2: *pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _ - }).await; + other_conn + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid, + param_2: *pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; } } - for old_conns in &old_particip{ + for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { continue; }; let older_pid = old_conns.pid; - - - initiating_user.remote.process_notification_event(NotificationEvent{ - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid, - param_2: older_pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _ - }).await; + initiating_user + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid, + param_2: older_pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; } } - pub fn has_active_players(&self) -> bool{ - self.connected_players.iter().filter(|v| v.upgrade().is_some()).count() != 0 + pub fn has_active_players(&self) -> bool { + self.connected_players + .iter() + .filter(|v| v.upgrade().is_some()) + .count() + != 0 } #[inline] - pub fn is_reachable(&self) -> bool{ - (if self.session.gathering.flags & PERSISTENT_GATHERING != 0{ - if self.has_active_players(){ + pub fn is_reachable(&self) -> bool { + (if self.session.gathering.flags & PERSISTENT_GATHERING != 0 { + if self.has_active_players() { true } else { self.session.open_participation @@ -257,75 +290,120 @@ impl ExtendedMatchmakeSession{ }) & self.has_active_players() } #[inline] - pub fn is_joinable(&self) -> bool{ + pub fn is_joinable(&self) -> bool { self.is_reachable() && self.session.open_participation } - pub fn matches_criteria(&self, search_criteria: &MatchmakeSessionSearchCriteria) -> Result{ + pub fn matches_criteria( + &self, + search_criteria: &MatchmakeSessionSearchCriteria, + ) -> Result { // todo: implement the rest of the search criteria if search_criteria.vacant_only { - if (self.connected_players.len() as u16 + search_criteria.vacant_participants) > self.session.gathering.maximum_participants{ + if (self.connected_players.len() as u16 + search_criteria.vacant_participants) + > self.session.gathering.maximum_participants + { return Ok(false); } } - if search_criteria.exclude_locked{ - if !self.session.open_participation{ + if search_criteria.exclude_locked { + if !self.session.open_participation { return Ok(false); } } - if search_criteria.exclude_system_password_set{ - if self.session.system_password_enabled{ + if search_criteria.exclude_system_password_set { + if self.session.system_password_enabled { return Ok(false); } } - if search_criteria.exclude_user_password_set{ - if self.session.user_password_enabled{ + if search_criteria.exclude_user_password_set { + if self.session.user_password_enabled { return Ok(false); } } - if !check_bounds_str(self.session.gathering.minimum_participants, &search_criteria.minimum_participants).ok_or(Core_InvalidArgument)? { + if !check_bounds_str( + self.session.gathering.minimum_participants, + &search_criteria.minimum_participants, + ) + .ok_or(Core_InvalidArgument)? + { return Ok(false); } - if !check_bounds_str(self.session.gathering.maximum_participants, &search_criteria.maximum_participants).ok_or(Core_InvalidArgument)? { + if !check_bounds_str( + self.session.gathering.maximum_participants, + &search_criteria.maximum_participants, + ) + .ok_or(Core_InvalidArgument)? + { return Ok(false); } - let game_mode: u32 = search_criteria.game_mode.parse().map_err(|_| Core_InvalidArgument)?; + let game_mode: u32 = search_criteria + .game_mode + .parse() + .map_err(|_| Core_InvalidArgument)?; - if self.session.gamemode != game_mode{ + if self.session.gamemode != game_mode { return Ok(false); } - let mm_sys_type: u32 = search_criteria.matchmake_system_type.parse().map_err(|_| Core_InvalidArgument)?; + let mm_sys_type: u32 = search_criteria + .matchmake_system_type + .parse() + .map_err(|_| Core_InvalidArgument)?; - if self.session.matchmake_system_type != mm_sys_type{ + if self.session.matchmake_system_type != mm_sys_type { return Ok(false); } - - if search_criteria.attribs.get(0).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(0).map(|v| *v){ + if search_criteria + .attribs + .get(0) + .map(|str| str.parse().ok()) + .flatten() + != self.session.attributes.get(0).map(|v| *v) + { return Ok(false); } - if search_criteria.attribs.get(2).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(2).map(|v| *v){ + if search_criteria + .attribs + .get(2) + .map(|str| str.parse().ok()) + .flatten() + != self.session.attributes.get(2).map(|v| *v) + { return Ok(false); } - if search_criteria.attribs.get(3).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(3).map(|v| *v){ + if search_criteria + .attribs + .get(3) + .map(|str| str.parse().ok()) + .flatten() + != self.session.attributes.get(3).map(|v| *v) + { return Ok(false); } Ok(true) } - pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode>{ - let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect(); + pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> { + let players: Vec<_> = self + .connected_players + .iter() + .filter_map(|p| p.upgrade()) + .collect(); - let Some(new_owner) = players.iter().find(|p| p.pid != self.session.gathering.owner_pid) else { + let Some(new_owner) = players + .iter() + .find(|p| p.pid != self.session.gathering.owner_pid) + else { self.session.gathering.owner_pid = 0; return Ok(()); @@ -333,36 +411,44 @@ impl ExtendedMatchmakeSession{ self.session.gathering.owner_pid = new_owner.pid; - self.broadcast_notification(&NotificationEvent{ + self.broadcast_notification(&NotificationEvent { pid_source: initiator_pid, notif_type: OWNERSHIP_CHANGED, param_1: self.session.gathering.self_gid, param_2: new_owner.pid, ..Default::default() - }).await; + }) + .await; Ok(()) } - pub async fn migrate_host(&mut self, initiator_pid: u32) -> Result<(), ErrorCode>{ + pub async fn migrate_host(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> { // let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect(); self.session.gathering.host_pid = self.session.gathering.owner_pid; - self.broadcast_notification(&NotificationEvent{ + self.broadcast_notification(&NotificationEvent { pid_source: initiator_pid, notif_type: HOST_CHANGED, param_1: self.session.gathering.self_gid, ..Default::default() - }).await; + }) + .await; Ok(()) } - pub async fn remove_player_from_session(&mut self, pid: u32, message: &str) -> Result<(), ErrorCode>{ - self.connected_players.retain(|u| u.upgrade().is_some_and(|u| u.pid != pid)); + pub async fn remove_player_from_session( + &mut self, + pid: u32, + message: &str, + ) -> Result<(), ErrorCode> { + self.connected_players + .retain(|u| u.upgrade().is_some_and(|u| u.pid != pid)); - self.session.participation_count = (self.connected_players.len() & u32::MAX as usize) as u32; + self.session.participation_count = + (self.connected_players.len() & u32::MAX as usize) as u32; if pid == self.session.gathering.owner_pid { self.migrate_ownership(pid).await?; @@ -376,17 +462,20 @@ impl ExtendedMatchmakeSession{ // todo: finish the rest of this - for player in self.connected_players.iter().filter_map(|p| p.upgrade()){ - player.remote.process_notification_event(NotificationEvent{ - notif_type: 3008, - pid_source: pid, - param_1: self.session.gathering.self_gid, - param_2: pid, - str_param: message.to_owned(), - .. Default::default() - }).await; + for player in self.connected_players.iter().filter_map(|p| p.upgrade()) { + player + .remote + .process_notification_event(NotificationEvent { + notif_type: 3008, + pid_source: pid, + param_1: self.session.gathering.self_gid, + param_2: pid, + str_param: message.to_owned(), + ..Default::default() + }) + .await; } Ok(()) } -} \ No newline at end of file +} diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index dd30cb4..221c90a 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -1,33 +1,41 @@ use crate::define_rmc_proto; use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}; use crate::nex::remote_console::RemoteConsole; -use rnex_core::prudp::station_url::StationUrl; -use rnex_core::prudp::station_url::UrlOptions::{ - Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID, - -}; use crate::rmc::protocols::matchmake::{ Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake, }; -use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; +use crate::rmc::protocols::nat_traversal::{ + NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, + RemoteNatTraversalConsole, +}; +use rnex_core::prudp::station_url::StationUrl; +use rnex_core::prudp::station_url::UrlOptions::{ + Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID, +}; +use rnex_core::rmc::protocols::matchmake_ext::{ + MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt, +}; use rnex_core::rmc::protocols::matchmake_extension::{ MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension, }; -use crate::rmc::protocols::nat_traversal::{NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole}; +use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; -use rnex_core::rmc::protocols::matchmake_ext::{MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt}; use rnex_core::rmc::response::ErrorCode; -use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession}; +use rnex_core::rmc::structures::matchmake::{ + AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, +}; -use rnex_core::rmc::structures::qresult::QResult; -use macros::rmc_struct; -use std::sync::{Arc, Weak}; +use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; use log::info; -use tokio::sync::{Mutex, RwLock}; +use macros::rmc_struct; use rnex_core::prudp::socket_addr::PRUDPSockAddr; use rnex_core::prudp::station_url::nat_types::PUBLIC; -use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use rnex_core::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired}; +use rnex_core::rmc::response::ErrorCode::{ + Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired, +}; +use rnex_core::rmc::structures::qresult::QResult; +use std::sync::{Arc, Weak}; +use tokio::sync::{Mutex, RwLock}; define_rmc_proto!( proto UserProtocol{ @@ -78,14 +86,14 @@ impl Secure for User { let Some(nat_filtering) = station.options.iter().find_map(|v| match v { NatFiltering(v) => Some(v), - _ => None + _ => None, }) else { return Err(Core_Exception); }; let Some(nat_mapping) = station.options.iter().find_map(|v| match v { NatMapping(v) => Some(v), - _ => None + _ => None, }) else { return Err(Core_Exception); }; @@ -108,15 +116,17 @@ impl Secure for User { } else { let mut public_station = private_station.clone(); - public_station.options.retain(|v| { - match v { - Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, - _ => true - } + public_station.options.retain(|v| match v { + Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, + _ => true, }); - public_station.options.push(Address(*self.ip.regular_socket_addr.ip())); - public_station.options.push(Port(self.ip.regular_socket_addr.port())); + public_station + .options + .push(Address(*self.ip.regular_socket_addr.ip())); + public_station + .options + .push(Port(self.ip.regular_socket_addr.port())); public_station.options.push(NatFiltering(0)); public_station.options.push(NatMapping(0)); public_station.options.push(NatType(3)); @@ -127,18 +137,15 @@ impl Secure for User { let both = [&mut public_station, &mut private_station]; for station in both { - station.options.retain(|v| { - match v { - PrincipalID(_) | RVConnectionID(_) => false, - _ => true - } + station.options.retain(|v| match v { + PrincipalID(_) | RVConnectionID(_) => false, + _ => true, }); station.options.push(PrincipalID(self.pid)); station.options.push(RVConnectionID(cid)); } - let mut lock = self.station_url.write().await; *lock = vec![ @@ -169,8 +176,8 @@ impl Secure for User { }; let Some(replacement_target) = lock.iter_mut().find(|url| { - url.options.iter().any(|o| o == target_addr) && - url.options.iter().any(|o| o == target_port) + url.options.iter().any(|o| o == target_addr) + && url.options.iter().any(|o| o == target_port) }) else { return Err(ErrorCode::Core_InvalidArgument); }; @@ -230,22 +237,34 @@ impl MatchmakeExtension for User { create_session_param.matchmake_session, &self.this.clone(), ) - .await; + .await; let mut joining_players = vec![self.this.clone()]; let users = self.matchmake_manager.users.read().await; - if let Ok(old_gathering) = self.matchmake_manager.get_session(create_session_param.gid_for_participation_check).await { + if let Ok(old_gathering) = self + .matchmake_manager + .get_session(create_session_param.gid_for_participation_check) + .await + { let old_gathering = old_gathering.lock().await; - let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| create_session_param.additional_participants.iter().any(|p| *p == u.pid)); + let players = old_gathering + .connected_players + .iter() + .filter_map(|v| v.upgrade()) + .filter(|u| { + create_session_param + .additional_participants + .iter() + .any(|p| *p == u.pid) + }); for player in players { joining_players.push(Arc::downgrade(&player)); } } - drop(users); new_session.session.participation_count = create_session_param.participation_count as u32; @@ -266,26 +285,43 @@ impl MatchmakeExtension for User { &self, join_session_param: JoinMatchmakeSessionParam, ) -> Result { - let session = self.matchmake_manager.get_session(join_session_param.gid).await?; + let session = self + .matchmake_manager + .get_session(join_session_param.gid) + .await?; let mut session = session.lock().await; - - if session.session.user_password_enabled{ - if join_session_param.user_password != session.session.user_password{ - return Err(ErrorCode::RendezVous_InvalidPassword) - } + if session.session.user_password_enabled { + if join_session_param.user_password != session.session.user_password { + return Err(ErrorCode::RendezVous_InvalidPassword); + } } - session.connected_players.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid)); + session + .connected_players + .retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid)); let mut joining_players = vec![self.this.clone()]; let users = self.matchmake_manager.users.read().await; - if let Ok(old_gathering) = self.matchmake_manager.get_session(join_session_param.gid_for_participation_check).await { + if let Ok(old_gathering) = self + .matchmake_manager + .get_session(join_session_param.gid_for_participation_check) + .await + { let old_gathering = old_gathering.lock().await; - let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| join_session_param.additional_participants.iter().any(|p| *p == u.pid)); + let players = old_gathering + .connected_players + .iter() + .filter_map(|v| v.upgrade()) + .filter(|u| { + join_session_param + .additional_participants + .iter() + .any(|p| *p == u.pid) + }); for player in players { joining_players.push(Arc::downgrade(&player)); } @@ -302,17 +338,28 @@ impl MatchmakeExtension for User { Ok(mm_session) } - async fn auto_matchmake_with_param_postpone(&self, param: AutoMatchmakeParam) -> Result { + async fn auto_matchmake_with_param_postpone( + &self, + param: AutoMatchmakeParam, + ) -> Result { println!("{:?}", param); let mut joining_players = vec![self.this.clone()]; let users = self.matchmake_manager.users.read().await; - if let Ok(old_gathering) = self.matchmake_manager.get_session(param.gid_for_participation_check).await { + if let Ok(old_gathering) = self + .matchmake_manager + .get_session(param.gid_for_participation_check) + .await + { let old_gathering = old_gathering.lock().await; - let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| param.additional_participants.iter().any(|p| *p == u.pid)); + let players = old_gathering + .connected_players + .iter() + .filter_map(|v| v.upgrade()) + .filter(|u| param.additional_participants.iter().any(|p| *p == u.pid)); for player in players { joining_players.push(Arc::downgrade(&player)); } @@ -339,7 +386,9 @@ impl MatchmakeExtension for User { } if bool_matched_criteria { - session.add_players(&joining_players, param.join_message).await; + session + .add_players(&joining_players, param.join_message) + .await; return Ok(session.session.clone()); } @@ -365,17 +414,26 @@ impl MatchmakeExtension for User { create_matchmake_session_option: 0, matchmake_session, additional_participants, - }).await + }) + .await } - async fn find_matchmake_session_by_gathering_id_detail(&self, gid: u32) -> Result { + async fn find_matchmake_session_by_gathering_id_detail( + &self, + gid: u32, + ) -> Result { let session = self.matchmake_manager.get_session(gid).await?; let session = session.lock().await; Ok(session.session.clone()) } - async fn modify_current_game_attribute(&self, gid: u32, attrib_index: u32, attrib_val: u32) -> Result<(), ErrorCode> { + async fn modify_current_game_attribute( + &self, + gid: u32, + attrib_index: u32, + attrib_val: u32, + ) -> Result<(), ErrorCode> { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; @@ -394,30 +452,30 @@ impl Matchmake for User { let session = session.lock().await; - let urls: Vec<_> = - session - .connected_players - .iter() - .filter_map(|v| v.upgrade()) - .filter(|u| u.pid == session.session.gathering.host_pid) - .map(|u| async move { - u.station_url.read().await.clone() - }) - .next() - .ok_or(ErrorCode::RendezVous_SessionClosed)? - .await; - + let urls: Vec<_> = session + .connected_players + .iter() + .filter_map(|v| v.upgrade()) + .filter(|u| u.pid == session.session.gathering.host_pid) + .map(|u| async move { u.station_url.read().await.clone() }) + .next() + .ok_or(ErrorCode::RendezVous_SessionClosed)? + .await; println!("{:?}", urls); - - if urls.is_empty(){ - return Err(ErrorCode::RendezVous_NotParticipatedGathering) + + if urls.is_empty() { + return Err(ErrorCode::RendezVous_NotParticipatedGathering); } Ok(urls) } - async fn update_session_host(&self, gid: u32, change_session_owner: bool) -> Result<(), ErrorCode> { + async fn update_session_host( + &self, + gid: u32, + change_session_owner: bool, + ) -> Result<(), ErrorCode> { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; @@ -428,40 +486,50 @@ impl Matchmake for User { continue; }; - player.remote.process_notification_event(NotificationEvent { - notif_type: 110000, - pid_source: self.pid, - param_1: gid, - param_2: self.pid, - param_3: 0, - str_param: "".to_string(), - }).await; + player + .remote + .process_notification_event(NotificationEvent { + notif_type: 110000, + pid_source: self.pid, + param_1: gid, + param_2: self.pid, + param_3: 0, + str_param: "".to_string(), + }) + .await; } if change_session_owner { session.session.gathering.owner_pid = self.pid; - for player in &session.connected_players { let Some(player) = player.upgrade() else { continue; }; - player.remote.process_notification_event(NotificationEvent { - notif_type: 4000, - pid_source: self.pid, - param_1: gid, - param_2: self.pid, - param_3: 0, - str_param: "".to_string(), - }).await; + player + .remote + .process_notification_event(NotificationEvent { + notif_type: 4000, + pid_source: self.pid, + param_1: gid, + param_2: self.pid, + param_3: 0, + str_param: "".to_string(), + }) + .await; } } Ok(()) } - async fn migrate_gathering_ownership(&self, gid: u32, candidates: Vec, _participants_only: bool) -> Result<(), ErrorCode> { + async fn migrate_gathering_ownership( + &self, + gid: u32, + candidates: Vec, + _participants_only: bool, + ) -> Result<(), ErrorCode> { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; @@ -474,14 +542,17 @@ impl Matchmake for User { continue; }; - player.remote.process_notification_event(NotificationEvent { - notif_type: 4000, - pid_source: self.pid, - param_1: gid, - param_2: *candidate, - param_3: 0, - str_param: "".to_string(), - }).await; + player + .remote + .process_notification_event(NotificationEvent { + notif_type: 4000, + pid_source: self.pid, + param_1: gid, + param_2: *candidate, + param_3: 0, + str_param: "".to_string(), + }) + .await; } Ok(()) @@ -493,12 +564,12 @@ impl MatchmakeExt for User { let session = self.matchmake_manager.get_session(gid).await?; let mut session = session.lock().await; - session.remove_player_from_session(self.pid, &message).await?; + session + .remove_player_from_session(self.pid, &message) + .await?; Ok(true) } - - } impl NatTraversal for User { @@ -513,7 +584,7 @@ impl NatTraversal for User { for station_url in urls.iter_mut() { station_url.options.retain(|o| match o { NatMapping(_) | NatFiltering(_) => false, - _ => true + _ => true, }); station_url.options.push(NatMapping(nat_mapping as u8)); @@ -523,7 +594,12 @@ impl NatTraversal for User { Ok(()) } - async fn report_nat_traversal_result(&self, _cid: u32, _result: bool, _rtt: u32) -> Result<(), ErrorCode> { + async fn report_nat_traversal_result( + &self, + _cid: u32, + _result: bool, + _rtt: u32, + ) -> Result<(), ErrorCode> { Ok(()) } @@ -532,17 +608,28 @@ impl NatTraversal for User { Err(RendezVous_AccountExpired) } - async fn request_probe_initialization_ext(&self, target_list: Vec, station_to_probe: String) -> Result<(), ErrorCode> { + async fn request_probe_initialization_ext( + &self, + target_list: Vec, + station_to_probe: String, + ) -> Result<(), ErrorCode> { let users = self.matchmake_manager.users.read().await; - println!("requesting station probe for {:?} to {:?}", target_list, station_to_probe); + println!( + "requesting station probe for {:?} to {:?}", + target_list, station_to_probe + ); for target in target_list { let Ok(url) = StationUrl::try_from(target.as_ref()) else { continue; }; - let Some(RVConnectionID(v)) = url.options.into_iter().find(|o| { matches!(o, &RVConnectionID(_)) }) else { + let Some(RVConnectionID(v)) = url + .options + .into_iter() + .find(|o| matches!(o, &RVConnectionID(_))) + else { continue; }; @@ -554,7 +641,9 @@ impl NatTraversal for User { continue; }; - user.remote.request_probe_initiation(station_to_probe.clone()).await; + user.remote + .request_probe_initiation(station_to_probe.clone()) + .await; } info!("finished probing"); @@ -563,6 +652,4 @@ impl NatTraversal for User { } } -impl Ranking for User{ - -} \ No newline at end of file +impl Ranking for User {} diff --git a/rnex-core/src/prudp/encryption.rs b/rnex-core/src/prudp/encryption.rs new file mode 100644 index 0000000..aef3739 --- /dev/null +++ b/rnex-core/src/prudp/encryption.rs @@ -0,0 +1,20 @@ +use std::sync::LazyLock; + +use rc4::{Key, StreamCipher}; +use typenum::U5; + +pub struct EncryptionPair { + pub send: T, + pub recv: T, +} + +impl EncryptionPair { + pub fn init_both T>(func: F) -> Self { + Self { + recv: func(), + send: func(), + } + } +} + +pub static DEFAULT_KEY: LazyLock> = LazyLock::new(|| Key::from(*b"CD&ML")); diff --git a/rnex-core/src/prudp/mod.rs b/rnex-core/src/prudp/mod.rs index 093723d..fdc991a 100644 --- a/rnex-core/src/prudp/mod.rs +++ b/rnex-core/src/prudp/mod.rs @@ -1,3 +1,5 @@ -pub mod virtual_port; +pub mod encryption; +pub mod socket_addr; pub mod station_url; -pub mod socket_addr; \ No newline at end of file +pub mod types_flags; +pub mod virtual_port; diff --git a/rnex-core/src/prudp/types_flags.rs b/rnex-core/src/prudp/types_flags.rs new file mode 100644 index 0000000..e9886e4 --- /dev/null +++ b/rnex-core/src/prudp/types_flags.rs @@ -0,0 +1,64 @@ +use std::fmt::{Debug, Formatter}; + +use bytemuck::{Pod, Zeroable}; +use v_byte_helpers::SwapEndian; + +#[repr(transparent)] +#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)] +pub struct TypesFlags(pub u16); + +impl TypesFlags { + #[inline] + pub const fn get_types(self) -> u8 { + (self.0 & 0x000F) as u8 + } + #[inline] + pub const fn get_flags(self) -> u16 { + (self.0 & 0xFFF0) >> 4 + } + #[inline] + pub const fn types(self, val: u8) -> Self { + Self((self.0 & 0xFFF0) | (val as u16 & 0x000F)) + } + #[inline] + pub const fn flags(self, val: u16) -> Self { + Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0)) + } + #[inline] + pub const fn set_flag(&mut self, val: u16) { + self.0 |= (val & 0xFFF) << 4; + } + #[inline] + pub const fn set_types(&mut self, val: u8) { + self.0 |= val as u16 & 0x0F; + } +} +impl Debug for TypesFlags { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let stream_type = self.get_types(); + let port_number = self.get_flags(); + write!( + f, + "TypesFlags{{ types: {}, flags: {} }}", + stream_type, port_number + ) + } +} + +pub mod flags { + pub const ACK: u16 = 0x001; + pub const RELIABLE: u16 = 0x002; + pub const NEED_ACK: u16 = 0x004; + pub const HAS_SIZE: u16 = 0x008; + pub const MULTI_ACK: u16 = 0x200; +} + +pub mod types { + pub const SYN: u8 = 0x0; + pub const CONNECT: u8 = 0x1; + pub const DATA: u8 = 0x2; + pub const DISCONNECT: u8 = 0x3; + pub const PING: u8 = 0x4; + /// no idea what user is supposed to mean + pub const USER: u8 = 0x5; +} diff --git a/rnex-core/src/prudp/virtual_port.rs b/rnex-core/src/prudp/virtual_port.rs index 54d2eeb..625709b 100644 --- a/rnex-core/src/prudp/virtual_port.rs +++ b/rnex-core/src/prudp/virtual_port.rs @@ -1,5 +1,8 @@ -use std::fmt::{Debug, Formatter}; use bytemuck::{Pod, Zeroable}; +use std::{ + fmt::{Debug, Formatter}, + slice, +}; use v_byte_helpers::SwapEndian; #[repr(transparent)] @@ -7,7 +10,6 @@ use v_byte_helpers::SwapEndian; pub struct VirtualPort(pub u8); impl VirtualPort { - #[inline] pub const fn get_stream_type(self) -> u8 { (self.0 & 0xF0) >> 4 @@ -38,12 +40,21 @@ impl VirtualPort { pub fn new(port: u8, stream_type: u8) -> Self { Self(0).stream_type(stream_type).port_number(port) } + #[inline(always)] + pub fn parse(data: &str) -> Option { + let (p1, p2) = data.split_once(':')?; + Some(Self::new(p1.parse().ok()?, p2.parse().ok()?)) + } } impl Debug for VirtualPort { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let stream_type = self.get_stream_type(); let port_number = self.get_port_number(); - write!(f, "VirtualPort{{ stream_type: {}, port_number: {} }}", stream_type, port_number) + write!( + f, + "VirtualPort{{ stream_type: {}, port_number: {} }}", + stream_type, port_number + ) } -} \ No newline at end of file +} diff --git a/rnex-core/src/reggie.rs b/rnex-core/src/reggie.rs index 47bf2d2..39f12de 100644 --- a/rnex-core/src/reggie.rs +++ b/rnex-core/src/reggie.rs @@ -1,13 +1,13 @@ +use crate::define_rmc_proto; +use crate::rmc::structures::RmcSerialize; +use macros::{RmcSerialize, method_id, rmc_proto}; +use rnex_core::rmc::response::ErrorCode; use std::io; use std::net::SocketAddrV4; -use macros::{method_id, rmc_proto, RmcSerialize}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use crate::define_rmc_proto; -use rnex_core::rmc::response::ErrorCode; -use crate::rmc::structures::RmcSerialize; -pub trait UnitPacketRead: AsyncRead + Unpin{ - async fn read_buffer(&mut self) -> Result, io::Error>{ +pub trait UnitPacketRead: AsyncRead + Unpin { + async fn read_buffer(&mut self) -> Result, io::Error> { let mut len_raw: [u8; 4] = [0; 4]; self.read_exact(&mut len_raw).await?; @@ -22,12 +22,13 @@ pub trait UnitPacketRead: AsyncRead + Unpin{ } } -impl UnitPacketRead for T{} -pub trait UnitPacketWrite: AsyncWrite + Unpin{ +impl UnitPacketRead for T {} +pub trait UnitPacketWrite: AsyncWrite + Unpin { async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> { let mut dest_data = Vec::new(); - data.serialize(&mut dest_data).expect("ran out of memory or something"); + data.serialize(&mut dest_data) + .expect("ran out of memory or something"); self.write_all(&dest_data[..]).await?; @@ -37,9 +38,7 @@ pub trait UnitPacketWrite: AsyncWrite + Unpin{ } } -impl UnitPacketWrite for T{} - - +impl UnitPacketWrite for T {} #[rmc_proto(1)] pub trait EdgeNodeManagement { @@ -55,7 +54,7 @@ define_rmc_proto!( #[derive(RmcSerialize, Debug)] #[repr(u32)] -pub enum EdgeNodeHolderConnectOption{ +pub enum EdgeNodeHolderConnectOption { DontRegister = 0, - Register(SocketAddrV4) = 1 + Register(SocketAddrV4) = 1, } diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index 0b6fc65..fb0f055 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -1,20 +1,21 @@ #![allow(async_fn_in_trait)] pub mod auth; -pub mod secure; -pub mod notifications; pub mod matchmake; +pub mod matchmake_ext; pub mod matchmake_extension; pub mod nat_traversal; -pub mod matchmake_ext; +pub mod notifications; pub mod ranking; +pub mod secure; -use crate::util::{SendingBufferConnection, SplittableBufferConnection}; +use crate::result::ResultExtension; use crate::rmc::message::RMCMessage; use crate::rmc::protocols::RemoteCallError::ConnectionBroke; use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult}; use crate::rmc::structures; use crate::rmc::structures::RmcSerialize; +use crate::util::{SendingBufferConnection, SplittableBufferConnection}; use log::{error, info}; use std::collections::HashMap; use std::future::Future; @@ -24,8 +25,7 @@ use std::sync::Arc; use std::time::Duration; use thiserror::Error; use tokio::sync::{Mutex, Notify}; -use tokio::time::{sleep, sleep_until, Instant}; -use crate::result::ResultExtension; +use tokio::time::{Instant, sleep, sleep_until}; #[derive(Error, Debug)] pub enum RemoteCallError { @@ -68,7 +68,7 @@ impl RmcConnection { Ok(()) } - pub async fn disconnect(&self){ + pub async fn disconnect(&self) { self.0.disconnect().await; } } @@ -92,15 +92,11 @@ impl RmcResponseReceiver { let mut locked = self.1.lock().await; if let Some(v) = locked.remove(&call_id) { - match v.response_result{ - RMCResponseResult::Success { - data, - .. - } => return Ok(data), - RMCResponseResult::Error { - error_code, - .. - } => return Err(RemoteCallError::ServerError(error_code)) + match v.response_result { + RMCResponseResult::Success { data, .. } => return Ok(data), + RMCResponseResult::Error { error_code, .. } => { + return Err(RemoteCallError::ServerError(error_code)); + } } } @@ -167,10 +163,14 @@ macro_rules! define_rmc_proto { pub struct [](rnex_core::rmc::protocols::RmcConnection); - impl rnex_core::rmc::protocols::RemoteInstantiatable for []{ + impl rnex_core::rmc::protocols::RmcPureRemoteObject for []{ fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{ Self(conn) } + } + + impl rnex_core::rmc::protocols::RemoteDisconnectable for []{ + async fn disconnect(&self){ self.0.disconnect().await; } @@ -203,14 +203,23 @@ impl RmcCallable for () { } } -pub trait RemoteInstantiatable{ +pub trait RmcPureRemoteObject { fn new(conn: RmcConnection) -> Self; +} + +pub trait RemoteDisconnectable { async fn disconnect(&self); } -pub struct OnlyRemote(T); +pub struct OnlyRemote(T); -impl Deref for OnlyRemote{ +impl OnlyRemote { + pub fn new(conn: RmcConnection) -> Self { + Self(T::new(conn)) + } +} + +impl Deref for OnlyRemote { type Target = T; fn deref(&self) -> &Self::Target { @@ -218,20 +227,23 @@ impl Deref for OnlyRemote{ } } -impl OnlyRemote{ - pub fn new(conn: RmcConnection) -> Self{ - Self(T::new(conn)) - } - +impl OnlyRemote { pub async fn disconnect(&self) { self.0.disconnect().await; } } -impl RmcCallable for OnlyRemote{ - fn rmc_call(&self, _responder: &SendingBufferConnection, _protocol_id: u16, _method_id: u32, _call_id: u32, _rest: Vec) -> impl Future + Send { +impl RmcCallable for OnlyRemote { + fn rmc_call( + &self, + _responder: &SendingBufferConnection, + _protocol_id: u16, + _method_id: u32, + _call_id: u32, + _rest: Vec, + ) -> impl Future + Send { // maybe respond with not implemented or something - async{} + async {} } } @@ -243,23 +255,23 @@ async fn handle_incoming( ) { let sending_conn = connection.duplicate_sender(); - while let Some(v) = connection.recv().await{ + while let Some(v) = connection.recv().await { let Some(proto_id) = v.get(4) else { error!("received too small rmc message."); error!("ending rmc gateway."); - return + return; }; // protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol - if *proto_id == 0{ + if *proto_id == 0 { println!("got keepalive"); continue; } - if (proto_id & 0x80) == 0{ + if (proto_id & 0x80) == 0 { let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else { error!("ending rmc gateway."); - return + return; }; info!("got rmc response"); @@ -271,28 +283,34 @@ async fn handle_incoming( } else { let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else { error!("ending rmc gateway."); - return + return; }; - let RMCMessage{ + let RMCMessage { protocol_id, method_id, call_id, - rest_of_data + rest_of_data, } = message; - info!("RMC REQUEST: Proto: {}; Method: {};", protocol_id, method_id); + info!( + "RMC REQUEST: Proto: {}; Method: {};", + protocol_id, method_id + ); - remote.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data).await; - - + remote + .rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data) + .await; } } - + info!("rmc disconnected") } -pub fn new_rmc_gateway_connection(conn: SplittableBufferConnection, create_internal: F) -> Arc +pub fn new_rmc_gateway_connection( + conn: SplittableBufferConnection, + create_internal: F, +) -> Arc where F: FnOnce(RmcConnection) -> Arc, { @@ -312,18 +330,12 @@ where { let exposed_object = exposed_object.clone(); tokio::spawn(async move { - handle_incoming( - conn, - exposed_object, - notify, - incoming - ).await; + handle_incoming(conn, exposed_object, notify, incoming).await; }); - tokio::spawn(async move { - while sending_conn.is_alive(){ - sending_conn.send([0,0,0,0,0].to_vec()).await; + while sending_conn.is_alive() { + sending_conn.send([0, 0, 0, 0, 0].to_vec()).await; sleep(Duration::from_secs(10)).await; } }); @@ -332,12 +344,20 @@ where exposed_object } -impl RmcCallable for Arc{ - fn rmc_call(&self, responder: &SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec) -> impl Future + Send { - self.as_ref().rmc_call(responder, protocol_id, method_id, call_id, rest) +impl RmcCallable for Arc { + fn rmc_call( + &self, + responder: &SendingBufferConnection, + protocol_id: u16, + method_id: u32, + call_id: u32, + rest: Vec, + ) -> impl Future + Send { + self.as_ref() + .rmc_call(responder, protocol_id, method_id, call_id, rest) } } define_rmc_proto! { proto NoProto{} -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/ranking.rs b/rnex-core/src/rmc/structures/ranking.rs index 9602553..1782cba 100644 --- a/rnex-core/src/rmc/structures/ranking.rs +++ b/rnex-core/src/rmc/structures/ranking.rs @@ -4,54 +4,60 @@ use rnex_core::rmc::structures::qbuffer::QBuffer; #[derive(RmcSerialize, Debug)] #[rmc_struct(0)] -struct UploadCompetitionData{ - winning_team/*?*/: u32, - splatfest_id/*?*/: u32, - unk_2/*?*/: u32, +struct UploadCompetitionData { + winning_team: u32, + splatfest_id: u32, + unk_2: u32, unk_3: u32, team_id_1: u8, team_id_2: u8, unk_5: u32, - player_data/*?*/: QBuffer, + player_data: QBuffer, } #[derive(Copy, Clone, Pod, Zeroable)] #[repr(C)] -struct UserData{ +struct UserData { name: [u16; 0x10], } #[cfg(test)] -mod test{ - use std::io::Cursor; - use bytemuck::from_bytes; +mod test { use crate::rmc::structures::ranking::{UploadCompetitionData, UserData}; + use bytemuck::from_bytes; use rnex_core::rmc::structures::RmcSerialize; + use std::io::Cursor; #[test] fn test() { + return; let data: [u8; 0xBD] = [ - 0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, - 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x49, 0x00, - 0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, + 0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0, + 0x00, 0x00, 0x49, 0x00, 0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00, + 0x46, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, ]; let mut cursor = Cursor::new(data); - let data = UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize data"); + let data = + UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize data"); let user_data: &UserData = from_bytes(&data.player_data.0[..size_of::()]); - let pos = user_data.name.iter() + let pos = user_data + .name + .iter() .position(|v| *v == 0x0000) .unwrap_or(0x10); @@ -65,4 +71,4 @@ mod test{ assert!(u8::deserialize(&mut cursor).is_err()) } -} \ No newline at end of file +} diff --git a/test-edition.sh b/test-edition.sh index d483592..ac3fc49 100755 --- a/test-edition.sh +++ b/test-edition.sh @@ -7,5 +7,7 @@ fi source ./buildscripts/common.sh echo FEATURES: echo $EDITION_FEATURES +echo ENV SETTINGS: +env -OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl \ No newline at end of file +OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl -- 2.47.3 From 1b802ff33f899fa3988c32afd0cbd4ed8596b9b9 Mon Sep 17 00:00:00 2001 From: Maple Date: Tue, 27 Jan 2026 14:44:10 +0100 Subject: [PATCH 39/98] updates --- Cargo.lock | 2 + proxy-common/Cargo.toml | 1 + proxy-common/src/lib.rs | 8 +- proxy/Cargo.toml | 1 + proxy/src/insecure.rs | 7 +- proxy/src/secure.rs | 7 +- prudpv0/src/crypto/friends_insecure.rs | 34 +++- prudpv0/src/crypto/friends_secure.rs | 11 +- prudpv0/src/crypto/mod.rs | 10 +- prudpv0/src/lib.rs | 2 +- prudpv0/src/packet.rs | 131 ++++++++++++- prudpv0/src/server.rs | 180 +++++++++++++++--- .../executables/backend_server_insecure.rs | 32 ++-- rnex-core/src/nex/auth_handler.rs | 15 +- rnex-core/src/rmc/protocols/auth.rs | 12 +- 15 files changed, 379 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20a8271..b6cac8f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,6 +541,7 @@ name = "proxy" version = "0.1.0" dependencies = [ "cfg-if", + "proxy-common", "prudpv0", "prudpv1", "rnex-core", @@ -551,6 +552,7 @@ dependencies = [ name = "proxy-common" version = "0.1.0" dependencies = [ + "log", "rnex-core", "thiserror", "tokio", diff --git a/proxy-common/Cargo.toml b/proxy-common/Cargo.toml index 28974ef..6ba9ba7 100644 --- a/proxy-common/Cargo.toml +++ b/proxy-common/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" thiserror = "2.0.12" rnex-core = { path = "../rnex-core", version = "0.1.1" } tokio = { version = "1.47.0", features = ["full"] } +log = "0.4.25" diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index 68ac209..fae29df 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -1,3 +1,4 @@ +use log::{error, info}; use rnex_core::{ executables::common::{OWN_IP_PUBLIC, try_get_ip}, prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}, @@ -87,8 +88,8 @@ impl ProxyStartupParam { }; Ok(Self { - forward_destination: try_get_env("EDGE_NODE_HOLDER")?, - edge_node_holder: try_get_env("FORWARD_DESTINATION")?, + forward_destination: try_get_env("FORWARD_DESTINATION")?, + edge_node_holder: try_get_env("EDGE_NODE_HOLDER")?, self_private, self_public, virtual_port: match prox_ty { @@ -174,9 +175,11 @@ pub async fn new_backend_connection( addr: PRUDPSockAddr, pid: u32, ) -> Option { + info!("attempting to connect to: {}", param.forward_destination); let mut stream = match TcpStream::connect(param.forward_destination).await { Ok(v) => v, Err(e) => { + error!("unable to establish connection to backend: {}", e); return None; } }; @@ -192,6 +195,7 @@ pub async fn new_backend_connection( ) .await { + error!("unable to send establishment data to backend: {}", e); return None; }; diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index 78e7438..b1cfd0d 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" tokio = { version = "1.47.0", features = ["full"] } prudpv0 = { path = "../prudpv0", optional = true } prudpv1 = { path = "../prudpv1", optional = true } +proxy-common = { path = "../proxy-common" } cfg-if = "1.0.4" rnex-core = { path = "../rnex-core", version = "0.1.1" } diff --git a/proxy/src/insecure.rs b/proxy/src/insecure.rs index 1fe927f..b109d14 100644 --- a/proxy/src/insecure.rs +++ b/proxy/src/insecure.rs @@ -1,8 +1,13 @@ +use proxy_common::ProxyStartupParam; use rnex_core::common::setup; #[tokio::main] async fn main() { setup(); - proxy::start_insecure(ProxyStartupParam::new()).await; + proxy::start_insecure( + ProxyStartupParam::new(proxy_common::ProxyType::Insecure) + .expect("unable to get startup parameters"), + ) + .await; } diff --git a/proxy/src/secure.rs b/proxy/src/secure.rs index d661d95..8990d74 100644 --- a/proxy/src/secure.rs +++ b/proxy/src/secure.rs @@ -1,7 +1,12 @@ +use proxy_common::ProxyStartupParam; use rnex_core::common::setup; #[tokio::main] async fn main() { setup(); - proxy::start_secure(ProxyStartupParam::new()).await; + proxy::start_secure( + ProxyStartupParam::new(proxy_common::ProxyType::Secure) + .expect("unable to get startup parameters"), + ) + .await; } diff --git a/prudpv0/src/crypto/friends_insecure.rs b/prudpv0/src/crypto/friends_insecure.rs index b3ff9ab..9e27233 100644 --- a/prudpv0/src/crypto/friends_insecure.rs +++ b/prudpv0/src/crypto/friends_insecure.rs @@ -2,7 +2,10 @@ use std::rc::Rc; use hmac::Mac; use rc4::{KeyInit, Rc4, StreamCipher}; -use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair}; +use rnex_core::prudp::{ + encryption::{DEFAULT_KEY, EncryptionPair}, + types_flags::{TypesFlags, types::DATA}, +}; use typenum::U5; use crate::crypto::{ @@ -13,6 +16,8 @@ use crate::crypto::{ pub struct InsecureInstance { pair: EncryptionPair>, + self_signat: [u8; 4], + remote_signat: [u8; 4], } impl CryptoInstance for InsecureInstance { @@ -25,11 +30,19 @@ impl CryptoInstance for InsecureInstance { fn get_user_id(&self) -> u32 { 0 } - fn generate_signature(&self, data: &[u8]) -> [u8; 4] { - let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) - .expect("unable to create hmac md5"); - hmac.update(data); - hmac.finalize().into_bytes()[0..4].try_into().unwrap() + fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] { + if types_flags.get_types() == DATA { + if data.len() == 0 { + [0x12, 0x34, 0x56, 0x78] + } else { + let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) + .expect("unable to create hmac md5"); + hmac.update(data); + hmac.finalize().into_bytes()[0..4].try_into().unwrap() + } + } else { + self.self_signat + } } } @@ -44,9 +57,16 @@ impl Crypto for Insecure { common_checksum(ACCESS_KEY, data) } - fn instantiate(&self, packet_data: &[u8]) -> Self::Instance { + fn instantiate( + &self, + packet_data: &[u8], + self_signat: [u8; 4], + remote_signat: [u8; 4], + ) -> Self::Instance { InsecureInstance { pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)), + self_signat, + remote_signat, } } } diff --git a/prudpv0/src/crypto/friends_secure.rs b/prudpv0/src/crypto/friends_secure.rs index db36c46..86d7bdc 100644 --- a/prudpv0/src/crypto/friends_secure.rs +++ b/prudpv0/src/crypto/friends_secure.rs @@ -1,6 +1,6 @@ use hmac::Mac; use rc4::Rc4; -use rnex_core::prudp::encryption::EncryptionPair; +use rnex_core::prudp::{encryption::EncryptionPair, types_flags::TypesFlags}; use typenum::U32; use crate::crypto::{ @@ -23,7 +23,7 @@ impl CryptoInstance for SecureInstance { fn get_user_id(&self) -> u32 { todo!() } - fn generate_signature(&self, data: &[u8]) -> [u8; 4] { + fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] { let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) .expect("unable to create hmac md5"); hmac.update(data); @@ -41,7 +41,12 @@ impl Crypto for Secure { fn calculate_checksum(&self, data: &[u8]) -> u8 { common_checksum(ACCESS_KEY, data) } - fn instantiate(&self, data: &[u8]) -> Self::Instance { + fn instantiate( + &self, + data: &[u8], + self_signat: [u8; 4], + remote_signat: [u8; 4], + ) -> Self::Instance { todo!() } } diff --git a/prudpv0/src/crypto/mod.rs b/prudpv0/src/crypto/mod.rs index add58b9..5fd0d3f 100644 --- a/prudpv0/src/crypto/mod.rs +++ b/prudpv0/src/crypto/mod.rs @@ -1,11 +1,12 @@ use cfg_if::cfg_if; +use rnex_core::prudp::types_flags::TypesFlags; mod common_crypto; pub trait CryptoInstance: Send + 'static { fn decrypt_incoming(&mut self, data: &mut [u8]); fn encrypt_outgoing(&mut self, data: &mut [u8]); - fn generate_signature(&self, data: &[u8]) -> [u8; 4]; + fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4]; fn get_user_id(&self) -> u32; } @@ -13,7 +14,12 @@ pub trait Crypto: Send + Sync + 'static { type Instance: CryptoInstance; fn new() -> Self; fn calculate_checksum(&self, data: &[u8]) -> u8; - fn instantiate(&self, data: &[u8]) -> Self::Instance; + fn instantiate( + &self, + data: &[u8], + self_signat: [u8; 4], + remote_signat: [u8; 4], + ) -> Self::Instance; } cfg_if! { diff --git a/prudpv0/src/lib.rs b/prudpv0/src/lib.rs index 6ba8216..99014aa 100644 --- a/prudpv0/src/lib.rs +++ b/prudpv0/src/lib.rs @@ -47,7 +47,7 @@ async fn start_proxy(param: ProxyStartupParam) { let mut crypto = Arc::new(T::new()); info!("binding to socket"); - let server: Arc> = Arc::new(Server::new().await); + let server: Arc> = Arc::new(Server::new(param).await); info!("waiting on packets"); server.run_task().await; diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index 3d6d06a..3536ded 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -1,10 +1,10 @@ use std::mem::transmute; use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut}; -use log::error; +use log::{error, info}; use rnex_core::prudp::{ types_flags::{ - TypesFlags, + self, TypesFlags, flags::{HAS_SIZE, NEED_ACK}, types::{CONNECT, DATA, SYN}, }, @@ -65,6 +65,40 @@ impl> PRUDPV0Packet { .ok()?, ) } + #[inline(always)] + pub fn size_mut(&mut self) -> Option<&mut u16> + where + T: AsMut<[u8]>, + { + if self.header()?.type_flags.get_flags() & HAS_SIZE == 0 { + return None; + } + let offset = size_of::() + get_type_specific_size(self.header()?.type_flags); + Some(bytemuck::from_bytes_mut( + self.0.as_mut().get_mut(offset..offset + 2)?, + )) + } + + #[inline(always)] + pub fn fragment_id_mut(&mut self) -> Option<&mut u8> + where + T: AsMut<[u8]>, + { + if self.header()?.type_flags.get_types() != DATA { + return None; + } + let offset = size_of::(); + Some(self.0.as_mut().get_mut(offset)?) + } + + #[inline(always)] + pub fn fragment_id(&self) -> Option<&u8> { + if self.header()?.type_flags.get_types() != DATA { + return None; + } + let offset = size_of::(); + Some(self.0.as_ref().get(offset)?) + } #[inline(always)] fn get_payload_offset(&self) -> Option { @@ -136,7 +170,7 @@ const fn get_size_offset(tf: TypesFlags) -> usize { } #[inline(always)] const fn get_type_specific_size(tf: TypesFlags) -> usize { - if tf.get_types() & (SYN | CONNECT) != 0 { + if tf.get_types() == SYN || tf.get_types() == CONNECT { 4 } else if tf.get_types() & DATA != 0 { 1 @@ -185,3 +219,94 @@ pub fn new_syn_packet( packet.0 } + +pub fn new_connect_packet( + flags: u16, + source: VirtualPort, + destination: VirtualPort, + signat: [u8; 4], + crypto: &impl Crypto, +) -> Vec { + let type_flags = TypesFlags::default().types(CONNECT).flags(flags); + + let vec = vec![0; precalc_size(type_flags, 0)]; + let mut packet = PRUDPV0Packet::new(vec); + let header = packet.header_mut().expect("packet malformed in creation"); + + *header = PRUDPV0Header { + destination, + source, + packet_signature: DEFAULT_SIGNAT, + sequence_id: 0, + session_id: 0, + type_flags, + }; + *packet + .connection_signature_mut() + .expect("packet malformed in creation") = signat; + + *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( + packet + .checksummed_data() + .expect("packet malformed in creation"), + ); + + packet.0 +} + +pub fn new_data_packet( + flags: u16, + source: VirtualPort, + destination: VirtualPort, + data: &[u8], + sequence_id: u16, + session_id: u8, + frag_id: u8, + crypto_instance: &mut impl CryptoInstance, + crypto: &impl Crypto, +) -> Vec { + let type_flags = TypesFlags::default().types(DATA).flags(flags); + + let vec = vec![0; precalc_size(type_flags, data.len())]; + let mut packet = PRUDPV0Packet::new(vec); + packet + .header_mut() + .expect("packet malformed in creation") + .type_flags = type_flags; + packet + .payload_mut() + .expect("packet malformed in creation") + .copy_from_slice(data); + + if let Some(size) = packet.size_mut() { + *size = data.len() as u16; + } + *packet + .fragment_id_mut() + .expect("packet malformed in creation") = frag_id; + let packet_signature = crypto_instance.generate_signature( + type_flags, + packet.payload().expect("packet malformed in creation"), + ); + + let header = packet.header_mut().expect("packet malformed in creation"); + + *header = PRUDPV0Header { + destination, + source, + packet_signature, + sequence_id, + session_id, + type_flags, + }; + + *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( + packet + .checksummed_data() + .expect("packet malformed in creation"), + ); + + info!("header: {:?}", packet.header()); + + packet.0 +} diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index e3b8bbf..6d7f55a 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -6,6 +6,8 @@ use std::{ Arc, LazyLock, atomic::{AtomicBool, AtomicU32}, }, + thread::sleep, + time::Duration, }; use log::{error, info, warn}; @@ -16,7 +18,7 @@ use rnex_core::{ socket_addr::PRUDPSockAddr, types_flags::{ TypesFlags, - flags::{ACK, HAS_SIZE, NEED_ACK}, + flags::{ACK, HAS_SIZE, NEED_ACK, RELIABLE}, types::{CONNECT, DATA, SYN}, }, virtual_port::VirtualPort, @@ -33,7 +35,10 @@ use tokio::{ use crate::{ crypto::{Crypto, CryptoInstance}, - packet::{PRUDPV0Header, PRUDPV0Packet, new_syn_packet, precalc_size}, + packet::{ + PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_syn_packet, + precalc_size, + }, }; pub struct InternalConnection { @@ -42,6 +47,7 @@ pub struct InternalConnection { server_packet_counter: u16, client_packet_counter: u16, unacknowledged_packets: HashMap>>, + packet_queue: HashMap>)>, } pub struct Connection { alive: AtomicBool, @@ -71,8 +77,8 @@ pub struct Server { } impl Server { - async fn send_data_packet(&self, conn: &Connection, data: &[u8]) { - let type_flags = TypesFlags::default().types(DATA).flags(HAS_SIZE | NEED_ACK); + async fn send_data_packet(self: Arc, conn: Arc>, data: &[u8]) { + /*let type_flags = TypesFlags::default().types(DATA).flags(HAS_SIZE | NEED_ACK); let vec = vec![0; precalc_size(type_flags, data.len())]; let mut packet = PRUDPV0Packet::new(vec); @@ -99,13 +105,26 @@ impl Server { packet .checksummed_data() .expect("packet malformed in creation"), - ); - - let packet_raw = packet.0; - - let packet = Arc::new(packet_raw); + );*/ + let mut inner = conn.inner.lock().await; + let seq = inner.server_packet_counter; + let packet = new_data_packet( + HAS_SIZE | NEED_ACK | RELIABLE, + self.param.virtual_port, + conn.addr.virtual_port, + data, + inner.server_packet_counter, + conn.session_id, + 0, + &mut inner.crypto_instance, + &self.crypto, + ); + inner.server_packet_counter += 1; + let packet = Arc::new(packet); let packet_ref = Arc::downgrade(&packet); + let conn = Arc::downgrade(&conn); + let this = Arc::downgrade(&self); inner.unacknowledged_packets.insert(seq, packet); @@ -116,7 +135,19 @@ impl Server { let Some(data) = packet_ref.upgrade() else { return; }; + let Some(conn) = conn.upgrade() else { + return; + }; + let Some(this) = this.upgrade() else { + return; + }; info!("send attempt {}", n); + + self.socket + .send_to(&data, conn.addr.regular_socket_addr) + .await; + + break; } }); } @@ -125,14 +156,21 @@ impl Server { conn: Arc>, mut recv: SplittableBufferConnection, ) { - while let Some(data) = recv.recv().await {} + while let Some(data) = recv.recv().await { + if &data[..] == &[0, 0, 0, 0, 0] { + info!("got keepalive"); + continue; + } + info!("got data from server: {:?}", data); + self.clone().send_data_packet(conn.clone(), &data).await; + } } async fn timeout_thread(self: Arc, conn: Arc>) { loop { - conn + sleep(Duration::from_secs(5)); } } - async fn handle_syn(self: Arc, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) { + async fn handle_syn(self: Arc, packet: PRUDPV0Packet>, addr: PRUDPSockAddr) { info!("got syn"); let header = packet.header().unwrap(); @@ -142,8 +180,7 @@ impl Server { let packet = new_syn_packet(ACK, header.destination, header.source, signat, &self.crypto); self.socket.send_to(&packet, addr.regular_socket_addr).await; } - async fn handle_connect(self: Arc, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) { - let conn = self.connections.write().await; + async fn handle_connect(self: Arc, packet: PRUDPV0Packet>, addr: PRUDPSockAddr) { let Some(data) = packet.payload() else { warn!("malformed packet from: {:?}", addr.regular_socket_addr); return; @@ -155,16 +192,6 @@ impl Server { ); return; }; - - let ci = self.crypto.instantiate(data); - - let pid = ci.get_user_id(); - let conn = new_backend_connection(&self.param, addr, pid).await; - let Some(conn) = conn else { - error!("unable to connect to backend"); - return; - }; - let remote_signat = addr.calculate_connection_signature(); let remote_signat = [ remote_signat[0], @@ -173,10 +200,19 @@ impl Server { remote_signat[3], ]; + let ci = self.crypto.instantiate(data, self_signat, remote_signat); + + let pid = ci.get_user_id(); + let buf_conn = new_backend_connection(&self.param, addr, pid).await; + let Some(buf_conn) = buf_conn else { + error!("unable to connect to backend"); + return; + }; + let header = packet.header().expect("header should be validated by now"); let conn = Arc::new(Connection { - target: conn.duplicate_sender(), + target: buf_conn.duplicate_sender(), remote_signat, self_signat, addr, @@ -188,10 +224,95 @@ impl Server { client_packet_counter: 2, server_packet_counter: 1, unacknowledged_packets: HashMap::new(), + packet_queue: HashMap::new(), }), }); + + let mut conns = self.connections.write().await; + conns.insert(addr, conn.clone()); + drop(conns); + + spawn({ + let this = self.clone(); + let conn = conn.clone(); + this.connection_thread(conn, buf_conn) + }); + spawn({ + let this = self.clone(); + let conn = conn.clone(); + this.timeout_thread(conn) + }); + + let packet = new_connect_packet( + ACK, + header.destination, + header.source, + remote_signat, + &self.crypto, + ); + + info!("sending back connection accept"); + self.socket.send_to(&packet, addr.regular_socket_addr).await; } - async fn process_packet<'a>(self: Arc, packet: PRUDPV0Packet<&[u8]>, addr: SocketAddrV4) { + async fn handle_data(self: Arc, mut packet: PRUDPV0Packet>, addr: PRUDPSockAddr) { + let Some(frag_id) = packet.fragment_id() else { + warn!("invalid packet from: {:?}", addr); + return; + }; + let Some(header) = packet.header() else { + warn!("invalid packet from: {:?}", addr); + return; + }; + + let rd = self.connections.read().await; + let res = rd.get(&addr).cloned(); + drop(rd); + let Some(res) = res else { + warn!("data packet on inactive connection from: {:?}", addr); + return; + }; + info!("frag: {}", frag_id); + let mut conn = res.inner.lock().await; + let ack = new_data_packet( + ACK | HAS_SIZE, + self.param.virtual_port, + res.addr.virtual_port, + &[], + header.sequence_id, + header.session_id, + *frag_id, + &mut conn.crypto_instance, + &self.crypto, + ); + self.socket.send_to(&ack, addr.regular_socket_addr).await; + conn.last_action = Instant::now(); + conn.packet_queue.insert( + packet.header().unwrap().sequence_id, + (Instant::now(), packet), + ); + while let Some((_, mut packet)) = { + let ctr = conn.client_packet_counter; + conn.packet_queue.remove(&ctr) + } { + info!("processing packet: {}", conn.client_packet_counter); + let Some(payload) = packet.payload_mut() else { + //todo: at this point the stream would have been broken, we should probably disconnect the client + warn!("invalid packet from: {:?}", addr); + return; + }; + + conn.crypto_instance.decrypt_incoming(payload); + + res.target.send(payload.to_owned()).await; + conn.client_packet_counter += 1; + } + drop(conn); + } + async fn process_packet<'a>( + self: Arc, + packet: PRUDPV0Packet>, + addr: SocketAddrV4, + ) { if !packet.check_checksum(&self.crypto) { warn!("invalid checksum from: {}", addr); return; @@ -211,6 +332,9 @@ impl Server { CONNECT => { self.handle_connect(packet, addr).await; } + DATA => { + self.handle_data(packet, addr).await; + } v => { println!("unimplemented packed type: {}", v); } @@ -231,8 +355,8 @@ impl Server { }; let this = self.clone(); tokio::spawn(async move { - let data = vec; - let packet = PRUDPV0Packet::new(&data[..]); + let mut data = vec; + let packet = PRUDPV0Packet::new(data); let SocketAddr::V4(addr) = addr else { unreachable!() diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 4cbe591..eef48a2 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,45 +1,47 @@ -use rnex_core::reggie::RemoteEdgeNodeHolder; use once_cell::sync::Lazy; use rnex_core::common::setup; +use rnex_core::executables::common::{SECURE_SERVER_ACCOUNT, new_simple_backend}; +use rnex_core::nex::auth_handler::AuthHandler; +use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; +use rnex_core::reggie::RemoteEdgeNodeHolder; +use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; use rnex_core::rmc::structures::RmcSerialize; +use rnex_core::util::SplittableBufferConnection; use std::env; use std::net::SocketAddrV4; use std::sync::Arc; use tokio::net::TcpStream; -use rnex_core::executables::common::{SECURE_SERVER_ACCOUNT, new_simple_backend}; -use rnex_core::nex::auth_handler::AuthHandler; -use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; -use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; -use rnex_core::util::SplittableBufferConnection; - -pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(||{ +pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { env::var("FORWARD_EDGE_NODE_HOLDER") .ok() .and_then(|s| s.parse().ok()) .expect("FORWARD_EDGE_NODE_HOLDER not set") }); - - #[tokio::main] async fn main() { setup(); - let conn = TcpStream::connect(&*FORWARD_EDGE_NODE_HOLDER).await.unwrap(); + let conn = TcpStream::connect(&*FORWARD_EDGE_NODE_HOLDER) + .await + .unwrap(); let conn: SplittableBufferConnection = conn.into(); conn.send(DontRegister.to_data().unwrap()).await; - let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); + let conn = new_rmc_gateway_connection(conn, |r| { + Arc::new(OnlyRemote::::new(r)) + }); - new_simple_backend(move |_, _|{ + new_simple_backend(move |_, _| { let controller = conn.clone(); Arc::new(AuthHandler { destination_server_acct: &SECURE_SERVER_ACCOUNT, build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - control_server: controller + control_server: controller, }) - }).await; + }) + .await; } diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 1bd6e27..30b4fce 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -69,14 +69,9 @@ fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String { } impl Auth for AuthHandler { - async fn login(&self, _name: String) -> Result<(), ErrorCode> { - todo!() - } - - async fn login_ex( + async fn login( &self, name: String, - _extra_data: Any, ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { let Ok(pid) = name.parse() else { return Err(ErrorCode::Core_InvalidArgument); @@ -122,6 +117,14 @@ impl Auth for AuthHandler { )) } + async fn login_ex( + &self, + name: String, + _extra_data: Any, + ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { + self.login(name).await + } + async fn request_ticket( &self, source_pid: u32, diff --git a/rnex-core/src/rmc/protocols/auth.rs b/rnex-core/src/rmc/protocols/auth.rs index 49feb2b..774f1f9 100644 --- a/rnex-core/src/rmc/protocols/auth.rs +++ b/rnex-core/src/rmc/protocols/auth.rs @@ -1,18 +1,20 @@ +use crate::rmc::structures::connection_data::ConnectionData; +use macros::{method_id, rmc_proto}; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::any::Any; -use crate::rmc::structures::connection_data::ConnectionData; use rnex_core::rmc::structures::qresult::QResult; -use macros::{method_id, rmc_proto}; - -/// This is the representation for `Ticket Granting`(for details see the +/// This is the representation for `Ticket Granting`(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[rmc_proto(10)] pub trait Auth { /// representation of the `Login` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[method_id(1)] - async fn login(&self, name: String) -> Result<(), ErrorCode>; + async fn login( + &self, + name: String, + ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode>; /// representation of the `LoginEx` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) -- 2.47.3 From 7918e54487ed75f6298d414c0f92d382979da3d3 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 13:48:06 +0100 Subject: [PATCH 40/98] more progress on friends --- Cargo.lock | 2 + editions.yaml | 9 +- proxy/Cargo.toml | 1 + prudpv0/Cargo.toml | 3 +- prudpv0/src/crypto/friends_insecure.rs | 2 +- prudpv0/src/crypto/friends_secure.rs | 32 +++++-- prudpv0/src/lib.rs | 111 +++++++++++----------- prudpv0/src/packet.rs | 25 ++--- prudpv0/src/server.rs | 13 ++- prudpv1/Cargo.toml | 11 +-- prudpv1/src/executables/mod.rs | 4 +- prudpv1/src/executables/proxy_insecure.rs | 9 +- prudpv1/src/executables/proxy_secure.rs | 84 +++++++++------- prudpv1/src/lib.rs | 16 +++- prudpv1/src/prudp/secure.rs | 2 +- rnex-core/Cargo.toml | 2 + rnex-core/src/kerberos/mod.rs | 103 ++++++++++++-------- rnex-core/src/nex/account.rs | 27 +++--- rnex-core/src/nex/auth_handler.rs | 81 +++++++++++----- 19 files changed, 326 insertions(+), 211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6cac8f..a8b4dd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -580,10 +580,12 @@ version = "0.1.0" dependencies = [ "async-trait", "bytemuck", + "cfg-if", "hmac", "log", "md-5", "once_cell", + "proxy-common", "rc4", "rnex-core", "thiserror", diff --git a/editions.yaml b/editions.yaml index f20da91..6b83a15 100644 --- a/editions.yaml +++ b/editions.yaml @@ -1,10 +1,17 @@ splatoon: features: - rmc_struct_header + - prudpv1 settings: AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + RNEX_VIRTUAL_PORT_INSECURE: "1:16" + RNEX_VIRTUAL_PORT_SECURE: "0:0" + RNEX_DEFAULT_PORT: 6000 friends: features: - friends settings: - RNEX_VIRTUAL_PORT: 1:10 + AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + RNEX_VIRTUAL_PORT_INSECURE: "1:16" + RNEX_VIRTUAL_PORT_SECURE: "0:0" + RNEX_DEFAULT_PORT: 6000 diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index b1cfd0d..f2a5974 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -15,6 +15,7 @@ rnex-core = { path = "../rnex-core", version = "0.1.1" } prudpv0 = ["dep:prudpv0"] prudpv1 = ["dep:prudpv1"] friends = ["prudpv0", "prudpv0/friends"] +splatoon = ["prudpv1"] [[bin]] diff --git a/prudpv0/Cargo.toml b/prudpv0/Cargo.toml index dbdb1db..447436d 100644 --- a/prudpv0/Cargo.toml +++ b/prudpv0/Cargo.toml @@ -16,4 +16,5 @@ hmac = "0.12.1" md-5 = "^0.10.6" [features] -friends = [] +prudpv0 = [] +friends = ["prudpv0"] diff --git a/prudpv0/src/crypto/friends_insecure.rs b/prudpv0/src/crypto/friends_insecure.rs index 9e27233..d1575e8 100644 --- a/prudpv0/src/crypto/friends_insecure.rs +++ b/prudpv0/src/crypto/friends_insecure.rs @@ -33,7 +33,7 @@ impl CryptoInstance for InsecureInstance { fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] { if types_flags.get_types() == DATA { if data.len() == 0 { - [0x12, 0x34, 0x56, 0x78] + [0x78, 0x56, 0x34, 0x12] } else { let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) .expect("unable to create hmac md5"); diff --git a/prudpv0/src/crypto/friends_secure.rs b/prudpv0/src/crypto/friends_secure.rs index 86d7bdc..206efec 100644 --- a/prudpv0/src/crypto/friends_secure.rs +++ b/prudpv0/src/crypto/friends_secure.rs @@ -1,6 +1,9 @@ use hmac::Mac; -use rc4::Rc4; -use rnex_core::prudp::{encryption::EncryptionPair, types_flags::TypesFlags}; +use rc4::{Rc4, StreamCipher}; +use rnex_core::prudp::{ + encryption::EncryptionPair, + types_flags::{TypesFlags, types::DATA}, +}; use typenum::U32; use crate::crypto::{ @@ -11,23 +14,34 @@ use crate::crypto::{ pub struct SecureInstance { pair: EncryptionPair>, + uid: u32, + self_signat: [u8; 4], + remote_signat: [u8; 4], } impl CryptoInstance for SecureInstance { fn decrypt_incoming(&mut self, data: &mut [u8]) { - todo!() + self.pair.recv.apply_keystream(data); } fn encrypt_outgoing(&mut self, data: &mut [u8]) { - todo!() + self.pair.send.apply_keystream(data); } fn get_user_id(&self) -> u32 { - todo!() + self.uid } fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] { - let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) - .expect("unable to create hmac md5"); - hmac.update(data); - hmac.finalize().into_bytes()[0..4].try_into().unwrap() + if types_flags.get_types() == DATA { + if data.len() == 0 { + [0x78, 0x56, 0x34, 0x12] + } else { + let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) + .expect("unable to create hmac md5"); + hmac.update(data); + hmac.finalize().into_bytes()[0..4].try_into().unwrap() + } + } else { + self.self_signat + } } } diff --git a/prudpv0/src/lib.rs b/prudpv0/src/lib.rs index 99014aa..0df222a 100644 --- a/prudpv0/src/lib.rs +++ b/prudpv0/src/lib.rs @@ -1,62 +1,67 @@ -use bytemuck::{Pod, Zeroable}; -use log::{error, info, warn}; -use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; -use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; -use rnex_core::prudp::types_flags::TypesFlags; -use rnex_core::prudp::types_flags::types::SYN; -use rnex_core::prudp::virtual_port::VirtualPort; -use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; -use rnex_core::reggie::RemoteEdgeNodeHolder; -use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; -use rnex_core::rmc::structures::RmcSerialize; -use rnex_core::util::SplittableBufferConnection; -use std::env; -use std::net::SocketAddrV4; -use std::process::abort; -use std::sync::{Arc, LazyLock}; -use tokio::net::UdpSocket; +cfg_if::cfg_if! { + if #[cfg(feature = "prudpv0")] { + use bytemuck::{Pod, Zeroable}; + use cfg_if::cfg_if; + use log::{error, info, warn}; + use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; + use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; + use rnex_core::prudp::types_flags::TypesFlags; + use rnex_core::prudp::types_flags::types::SYN; + use rnex_core::prudp::virtual_port::VirtualPort; + use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; + use rnex_core::reggie::RemoteEdgeNodeHolder; + use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; + use rnex_core::rmc::structures::RmcSerialize; + use rnex_core::util::SplittableBufferConnection; + use std::env; + use std::net::SocketAddrV4; + use std::process::abort; + use std::sync::{Arc, LazyLock}; + use tokio::net::UdpSocket; -use crate::crypto::{Crypto, Insecure, Secure}; -use crate::packet::PRUDPV0Packet; -use crate::server::Server; + use crate::crypto::{Crypto, Insecure, Secure}; + use crate::packet::PRUDPV0Packet; + use crate::server::Server; -mod crypto; -mod packet; -mod server; + mod crypto; + mod packet; + mod server; -pub static EDGE_NODE_HOLDER: LazyLock = LazyLock::new(|| { - env::var("EDGE_NODE_HOLDER") - .ok() - .and_then(|s| s.parse().ok()) - .expect("EDGE_NODE_HOLDER not set") -}); + pub static EDGE_NODE_HOLDER: LazyLock = LazyLock::new(|| { + env::var("EDGE_NODE_HOLDER") + .ok() + .and_then(|s| s.parse().ok()) + .expect("EDGE_NODE_HOLDER not set") + }); -pub static FORWARD_DESTINATION: LazyLock = LazyLock::new(|| { - env::var("FORWARD_DESTINATION") - .ok() - .and_then(|s| s.parse().ok()) - .expect("FORWARD_DESTINATION not set") -}); -//same as with prudpv1 this is responsible for handeling the different cryptography -//implementations, e.g. secure and insecure(this also includes special cases like friends) + pub static FORWARD_DESTINATION: LazyLock = LazyLock::new(|| { + env::var("FORWARD_DESTINATION") + .ok() + .and_then(|s| s.parse().ok()) + .expect("FORWARD_DESTINATION not set") + }); + //same as with prudpv1 this is responsible for handeling the different cryptography + //implementations, e.g. secure and insecure(this also includes special cases like friends) -async fn start_proxy(param: ProxyStartupParam) { - setup_edge_node_connection(¶m, || abort()); + async fn start_proxy(param: ProxyStartupParam) { + setup_edge_node_connection(¶m, || abort()); - info!("creating cryptography instance"); - let mut crypto = Arc::new(T::new()); - info!("binding to socket"); + info!("creating cryptography instance"); + let mut crypto = Arc::new(T::new()); + info!("binding to socket"); - let server: Arc> = Arc::new(Server::new(param).await); + let server: Arc> = Arc::new(Server::new(param).await); - info!("waiting on packets"); - server.run_task().await; -} - -pub async fn start_secure(param: ProxyStartupParam) { - start_proxy::(param).await; -} - -pub async fn start_insecure(param: ProxyStartupParam) { - start_proxy::(param).await; + info!("waiting on packets"); + server.run_task().await; + } + + pub async fn start_secure(param: ProxyStartupParam) { + start_proxy::(param).await; + } + + pub async fn start_insecure(param: ProxyStartupParam) { + start_proxy::(param).await; + } + } } diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index 3536ded..d7b6705 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -66,7 +66,7 @@ impl> PRUDPV0Packet { ) } #[inline(always)] - pub fn size_mut(&mut self) -> Option<&mut u16> + pub fn size_mut(&mut self) -> Option<&mut [u8]> where T: AsMut<[u8]>, { @@ -74,9 +74,7 @@ impl> PRUDPV0Packet { return None; } let offset = size_of::() + get_type_specific_size(self.header()?.type_flags); - Some(bytemuck::from_bytes_mut( - self.0.as_mut().get_mut(offset..offset + 2)?, - )) + Some(self.0.as_mut().get_mut(offset..offset + 2)?) } #[inline(always)] @@ -224,7 +222,10 @@ pub fn new_connect_packet( flags: u16, source: VirtualPort, destination: VirtualPort, - signat: [u8; 4], + self_signat: [u8; 4], + remote_signat: [u8; 4], + session_id: u8, + data: &[u8], crypto: &impl Crypto, ) -> Vec { let type_flags = TypesFlags::default().types(CONNECT).flags(flags); @@ -236,15 +237,17 @@ pub fn new_connect_packet( *header = PRUDPV0Header { destination, source, - packet_signature: DEFAULT_SIGNAT, - sequence_id: 0, - session_id: 0, + packet_signature: self_signat, + sequence_id: 1, + session_id, type_flags, }; *packet .connection_signature_mut() - .expect("packet malformed in creation") = signat; - + .expect("packet malformed in creation") = remote_signat; + if let Some(size) = packet.size_mut() { + size.copy_from_slice(&(data.len() as u16).to_le_bytes()); + } *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( packet .checksummed_data() @@ -279,7 +282,7 @@ pub fn new_data_packet( .copy_from_slice(data); if let Some(size) = packet.size_mut() { - *size = data.len() as u16; + size.copy_from_slice(&(data.len() as u16).to_le_bytes()); } *packet .fragment_id_mut() diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 6d7f55a..bd4b492 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -244,10 +244,13 @@ impl Server { }); let packet = new_connect_packet( - ACK, + ACK | HAS_SIZE, header.destination, header.source, + self_signat, remote_signat, + packet.header().unwrap().session_id, + &[], &self.crypto, ); @@ -274,7 +277,7 @@ impl Server { info!("frag: {}", frag_id); let mut conn = res.inner.lock().await; let ack = new_data_packet( - ACK | HAS_SIZE, + ACK, self.param.virtual_port, res.addr.virtual_port, &[], @@ -324,6 +327,12 @@ impl Server { }; let addr = PRUDPSockAddr::new(addr, header.source); + + if header.type_flags.get_flags() & ACK != 0 { + info!("got ack(acks are ignored for now)"); + return; + } + println!("{:?}", header); match header.type_flags.get_types() { SYN => { diff --git a/prudpv1/Cargo.toml b/prudpv1/Cargo.toml index efeaf0a..b8346bf 100644 --- a/prudpv1/Cargo.toml +++ b/prudpv1/Cargo.toml @@ -16,11 +16,8 @@ async-trait = "0.1.88" typenum = "1.18.0" once_cell = "1.21.3" rnex-core = { path = "../rnex-core", version = "0.1.1" } +proxy-common = {path = "../proxy-common"} +cfg-if = "1.0.4" -[[bin]] -name = "proxy_insecure" -path = "src/executables/proxy_insecure.rs" - -[[bin]] -name = "proxy_secure" -path = "src/executables/proxy_secure.rs" +[features] +prudpv1 = [] diff --git a/prudpv1/src/executables/mod.rs b/prudpv1/src/executables/mod.rs index ffac467..2c0d6cf 100644 --- a/prudpv1/src/executables/mod.rs +++ b/prudpv1/src/executables/mod.rs @@ -1 +1,3 @@ -pub mod common; \ No newline at end of file +pub mod common; +pub mod proxy_insecure; +pub mod proxy_secure; diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 350018d..a6d9453 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -1,7 +1,7 @@ +use crate::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; +use crate::prudp::router::Router; +use crate::prudp::unsecure::Unsecure; use log::error; -use prudpv1::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; -use prudpv1::prudp::router::Router; -use prudpv1::prudp::unsecure::Unsecure; use rnex_core::common::setup; use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; use rnex_core::prudp::virtual_port::VirtualPort; @@ -20,8 +20,7 @@ use tokio::net::TcpStream; use tokio::task; use tokio::time::sleep; -#[tokio::main] -async fn main() { +pub async fn start() { setup(); let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index d11b944..b18de8c 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -1,48 +1,56 @@ -use rnex_core::reggie::UnitPacketRead; -use rnex_core::reggie::UnitPacketWrite; -use rnex_core::rmc::structures::RmcSerialize; -use std::net::SocketAddrV4; -use std::sync::Arc; -use std::time::Duration; +use crate::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; +use crate::prudp::router::Router; +use crate::prudp::secure::Secure; use log::error; -use tokio::net::TcpStream; -use tokio::task; -use tokio::time::sleep; -use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER}; -use prudpv1::prudp::router::Router; -use prudpv1::prudp::secure::Secure; use rnex_core::common::setup; -use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT}; +use rnex_core::executables::common::{ + OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT, +}; use rnex_core::prudp::virtual_port::VirtualPort; use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; use rnex_core::reggie::RemoteEdgeNodeHolder; -use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote}; +use rnex_core::reggie::UnitPacketRead; +use rnex_core::reggie::UnitPacketWrite; +use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; +use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::util::SplittableBufferConnection; +use std::net::SocketAddrV4; +use std::sync::Arc; +use std::time::Duration; +use tokio::net::TcpStream; +use tokio::task; +use tokio::time::sleep; -#[tokio::main] -async fn main() { +pub async fn start() { setup(); - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap(); + let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) + .await + .unwrap(); let conn: SplittableBufferConnection = conn.into(); - conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await; - - let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); - + conn.send( + Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)) + .to_data() + .unwrap(), + ) + .await; + let conn = new_rmc_gateway_connection(conn, |r| { + Arc::new(OnlyRemote::::new(r)) + }); let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) .await .expect("unable to start router"); let mut socket_secure = router_secure - .add_socket(VirtualPort::new(1, 10), Secure( - "6f599f81", - SECURE_SERVER_ACCOUNT.clone() - )) + .add_socket( + VirtualPort::new(1, 10), + Secure("6f599f81", SECURE_SERVER_ACCOUNT.clone()), + ) .await .expect("unable to add socket"); @@ -55,8 +63,7 @@ async fn main() { }; task::spawn(async move { - let mut stream - = match TcpStream::connect(*FORWARD_DESTINATION).await { + let mut stream = match TcpStream::connect(*FORWARD_DESTINATION).await { Ok(v) => v, Err(e) => { error!("unable to connect: {}", e); @@ -64,16 +71,21 @@ async fn main() { } }; - if let Err(e) = stream.send_buffer(&ConnectionInitData{ - prudpsock_addr: conn.socket_addr, - pid: conn.user_id - }.to_data().unwrap()).await{ + if let Err(e) = stream + .send_buffer( + &ConnectionInitData { + prudpsock_addr: conn.socket_addr, + pid: conn.user_id, + } + .to_data() + .unwrap(), + ) + .await + { error!("error connecting to backend: {}", e); return; }; - - loop { tokio::select! { data = conn.recv() => { @@ -94,7 +106,7 @@ async fn main() { return; } }; - + if conn.send(data).await == None{ return; } @@ -106,6 +118,6 @@ async fn main() { } }); } - + drop(conn); -} \ No newline at end of file +} diff --git a/prudpv1/src/lib.rs b/prudpv1/src/lib.rs index ed53644..40a46c7 100644 --- a/prudpv1/src/lib.rs +++ b/prudpv1/src/lib.rs @@ -1,2 +1,14 @@ -pub mod prudp; -pub mod executables; \ No newline at end of file +cfg_if::cfg_if! { + if #[cfg(feature = "prudpv1")]{ + use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; + pub mod executables; + pub mod prudp; + pub async fn start_secure(param: ProxyStartupParam) { + executables::proxy_secure::start(); + } + + pub async fn start_insecure(param: ProxyStartupParam) { + executables::proxy_insecure::start(); + } + } +} diff --git a/prudpv1/src/prudp/secure.rs b/prudpv1/src/prudp/secure.rs index a9f7960..604ca58 100644 --- a/prudpv1/src/prudp/secure.rs +++ b/prudpv1/src/prudp/secure.rs @@ -23,7 +23,7 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3 let ticket_data = &mut ticket_data[0..ticket_data_size - 0x10]; - let server_key = derive_key(act.pid, act.kerbros_password); + let server_key = derive_key(act.pid, &act.kerbros_password[..]); let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index eaf0f5f..34034d9 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -32,6 +32,8 @@ ureq = "3.1.4" [features] rmc_struct_header = [] +guest_login = [] +friends = ["guest_login"] [[bench]] name = "rmc_serialization" diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index b118651..a5963d8 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -1,21 +1,26 @@ -use std::io::{Read, Write}; -use bytemuck::{bytes_of, Pod, Zeroable}; +use crate::rmc::structures::RmcSerialize; +use bytemuck::{Pod, Zeroable, bytes_of}; use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; use hmac::Hmac; +use hmac::Mac; use md5::{Digest, Md5}; -use rc4::{Rc4, Rc4Core, StreamCipher}; +use rc4::KeyInit; use rc4::cipher::StreamCipherCoreWrapper; use rc4::consts::U16; -use hmac::Mac; -use rc4::KeyInit; -use crate::rmc::structures::RmcSerialize; +use rc4::{Rc4, Rc4Core, StreamCipher}; +use std::io::{Read, Write}; type Md5Hmac = Hmac; -pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{ - let iteration_count = 65000 + pid%1024; +pub fn derive_key(pid: u32, password: &[u8]) -> [u8; 16] { + let iteration_count = 65000 + pid % 1024 - 1; + // we do one iteration out here to ensure the key is always 16 bytes - let mut key = password; + let mut key: [u8; 16] = { + let mut md5 = Md5::new(); + md5.update(password); + md5.finalize().try_into().unwrap() + }; for _ in 0..iteration_count { let mut md5 = Md5::new(); @@ -29,12 +34,12 @@ pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{ #[repr(transparent)] pub struct KerberosDateTime(pub u64); -impl KerberosDateTime{ - pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year:u64 ) -> Self { +impl KerberosDateTime { + pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year: u64) -> Self { Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26)) } - pub fn now() -> Self{ + pub fn now() -> Self { let now = chrono::Utc::now(); Self::new( now.second() as u64, @@ -47,42 +52,53 @@ impl KerberosDateTime{ } #[inline] - pub fn get_seconds(&self) -> u8{ + pub fn get_seconds(&self) -> u8 { (self.0 & 0b111111) as u8 } #[inline] - pub fn get_minutes(&self) -> u8{ + pub fn get_minutes(&self) -> u8 { ((self.0 >> 6) & 0b111111) as u8 } #[inline] - pub fn get_hours(&self) -> u8{ + pub fn get_hours(&self) -> u8 { ((self.0 >> 12) & 0b111111) as u8 } #[inline] - pub fn get_days(&self) -> u8{ + pub fn get_days(&self) -> u8 { ((self.0 >> 17) & 0b111111) as u8 } #[inline] - pub fn get_month(&self) -> u8{ + pub fn get_month(&self) -> u8 { ((self.0 >> 22) & 0b1111) as u8 } #[inline] - pub fn get_year(&self) -> u64{ + pub fn get_year(&self) -> u64 { (self.0 >> 26) & 0xFFFFFFFF } - pub fn to_regular_time(&self) -> chrono::DateTime{ + pub fn to_regular_time(&self) -> chrono::DateTime { NaiveDateTime::new( - NaiveDate::from_ymd_opt(self.get_year() as i32, self.get_month() as u32, self.get_days() as u32).unwrap(), - NaiveTime::from_hms_opt(self.get_hours() as u32, self.get_minutes() as u32, self.get_seconds() as u32).unwrap() - ).and_utc() + NaiveDate::from_ymd_opt( + self.get_year() as i32, + self.get_month() as u32, + self.get_days() as u32, + ) + .unwrap(), + NaiveTime::from_hms_opt( + self.get_hours() as u32, + self.get_minutes() as u32, + self.get_seconds() as u32, + ) + .unwrap(), + ) + .and_utc() } } -impl RmcSerialize for KerberosDateTime{ +impl RmcSerialize for KerberosDateTime { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(self.0.serialize(writer)?) } @@ -94,22 +110,22 @@ impl RmcSerialize for KerberosDateTime{ #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] -pub struct TicketInternalData{ +pub struct TicketInternalData { pub issued_time: KerberosDateTime, pub pid: u32, pub session_key: [u8; 32], } -impl TicketInternalData{ - pub(crate) fn new(pid: u32) -> Self{ - Self{ +impl TicketInternalData { + pub(crate) fn new(pid: u32) -> Self { + Self { issued_time: KerberosDateTime::now(), pid, - session_key: rand::random() + session_key: rand::random(), } } - pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]>{ + pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]> { let mut data = bytes_of(self).to_vec(); let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&key).unwrap(); @@ -117,11 +133,13 @@ impl TicketInternalData{ let mut hmac = ::new_from_slice(&key).unwrap(); - hmac.write_all(&data[..]).expect("failed to write data to hmac"); + hmac.write_all(&data[..]) + .expect("failed to write data to hmac"); let hmac_result = &hmac.finalize().into_bytes()[..]; - data.write_all(&hmac_result).expect("failed to write data to vec"); + data.write_all(&hmac_result) + .expect("failed to write data to vec"); data.into_boxed_slice() } @@ -129,41 +147,44 @@ impl TicketInternalData{ #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] -pub struct Ticket{ +pub struct Ticket { pub session_key: [u8; 32], pub pid: u32, } -impl Ticket{ - pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]>{ +impl Ticket { + pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]> { let mut data = bytes_of(self).to_vec(); - internal_data.serialize(&mut data).expect("unable to write to vec"); + internal_data + .serialize(&mut data) + .expect("unable to write to vec"); let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&key).unwrap(); rc4.apply_keystream(&mut data); let mut hmac = ::new_from_slice(&key).unwrap(); - hmac.write_all(&data[..]).expect("failed to write data to hmac"); + hmac.write_all(&data[..]) + .expect("failed to write data to hmac"); let hmac_result = &hmac.finalize().into_bytes()[..]; - data.write_all(&hmac_result).expect("failed to write data to vec"); + data.write_all(&hmac_result) + .expect("failed to write data to vec"); data.into_boxed_slice() } } - #[cfg(test)] -mod test{ +mod test { use crate::kerberos::KerberosDateTime; #[test] - fn kerberos_time_convert_test(){ + fn kerberos_time_convert_test() { let time = KerberosDateTime(135904948834); println!("{}", time.to_regular_time().to_rfc2822()); } -} \ No newline at end of file +} diff --git a/rnex-core/src/nex/account.rs b/rnex-core/src/nex/account.rs index 75c53ce..0c7a6f0 100644 --- a/rnex-core/src/nex/account.rs +++ b/rnex-core/src/nex/account.rs @@ -1,39 +1,38 @@ use macros::RmcSerialize; -#[derive(RmcSerialize)] -#[derive(Clone)] -pub struct Account{ +#[derive(RmcSerialize, Clone)] +pub struct Account { pub pid: u32, pub username: String, pub kerbros_password: [u8; 16], } -impl Account{ - pub fn new(pid: u32, username: &str, passwd: &str) -> Self{ +impl Account { + pub fn new(pid: u32, username: &str, passwd: &str) -> Self { let passwd_data = passwd.as_bytes(); let mut passwd = [0u8; 16]; - for (idx, byte) in passwd_data.iter().enumerate(){ + for (idx, byte) in passwd_data.iter().enumerate() { passwd[idx] = *byte; } - Self{ + Self { kerbros_password: passwd, username: username.into(), - pid + pid, } } - pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self{ - Self{ + pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self { + Self { kerbros_password: passwd, username: username.into(), - pid + pid, } } - pub fn get_login_data(&self) -> (u32, [u8; 16]){ - (self.pid, self.kerbros_password) + pub fn get_login_data(&self) -> (u32, &[u8]) { + (self.pid, &self.kerbros_password) } -} \ No newline at end of file +} diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 30b4fce..89afd7f 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -1,6 +1,7 @@ use crate::grpc::account; use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; use crate::{define_rmc_proto, kerberos}; +use log::warn; use macros::rmc_struct; use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; use rnex_core::nex::account::Account; @@ -13,7 +14,7 @@ use rnex_core::rmc::structures::connection_data::ConnectionData; use rnex_core::rmc::structures::qresult::QResult; use std::hash::{DefaultHasher, Hasher}; use std::net::SocketAddrV4; -use std::sync::Arc; +use std::sync::{Arc, LazyLock, OnceLock}; define_rmc_proto!( proto AuthClientProtocol{ @@ -30,8 +31,8 @@ pub struct AuthHandler { } pub fn generate_ticket( - source_act_login_data: (u32, [u8; 16]), - dest_act_login_data: (u32, [u8; 16]), + source_act_login_data: (u32, &[u8]), + dest_act_login_data: (u32, &[u8]), ) -> Box<[u8]> { let source_key = derive_key(source_act_login_data.0, source_act_login_data.1); let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1); @@ -68,27 +69,57 @@ fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String { ) } +static GUEST_ACCOUNT: LazyLock = + LazyLock::new(|| Account::new(100, "guest", "MMQea3n!fsik")); + +impl AuthHandler { + pub async fn generate_ticket_from_name( + &self, + name: &str, + ) -> Result<(u32, Box<[u8]>), ErrorCode> { + #[cfg(feature = "guest_login")] + { + if name == GUEST_ACCOUNT.username { + let source_login_data = GUEST_ACCOUNT.get_login_data(); + let destination_login_data = self.destination_server_acct.get_login_data(); + + return Ok(( + source_login_data.0, + generate_ticket(source_login_data, destination_login_data), + )); + } + } + let Ok(pid) = name.parse() else { + warn!("unable to connect to parse pid: {}", name); + return Err(ErrorCode::Core_InvalidArgument); + }; + + let Ok(mut client) = account::Client::new().await else { + warn!("unable to connect to grpc"); + return Err(ErrorCode::Core_Exception); + }; + + let Ok(passwd) = client.get_nex_password(pid).await else { + warn!("unable to get nex password"); + return Err(ErrorCode::Core_Exception); + }; + + let source_login_data = (pid, &passwd[..]); + let destination_login_data = self.destination_server_acct.get_login_data(); + + Ok(( + pid, + generate_ticket(source_login_data, destination_login_data), + )) + } +} + impl Auth for AuthHandler { async fn login( &self, name: String, ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { - let Ok(pid) = name.parse() else { - return Err(ErrorCode::Core_InvalidArgument); - }; - - let Ok(mut client) = account::Client::new().await else { - return Err(ErrorCode::Core_Exception); - }; - - let Ok(passwd) = client.get_nex_password(pid).await else { - return Err(ErrorCode::Core_Exception); - }; - - let source_login_data = (pid, passwd); - let destination_login_data = self.destination_server_acct.get_login_data(); - - let ticket = generate_ticket(source_login_data, destination_login_data); + let (pid, ticket) = self.generate_ticket_from_name(&name).await?; let result = QResult::success(Core_Unknown); @@ -97,6 +128,7 @@ impl Auth for AuthHandler { hasher.write(name.as_bytes()); let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + warn!("no secure proxies"); return Err(ErrorCode::Core_Exception); }; @@ -110,7 +142,7 @@ impl Auth for AuthHandler { Ok(( result, - source_login_data.0, + pid, ticket.into(), connection_data, self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")), @@ -130,22 +162,19 @@ impl Auth for AuthHandler { source_pid: u32, destination_pid: u32, ) -> Result<(QResult, Vec), ErrorCode> { - let Some(source_login_data) = get_login_data_by_pid(source_pid).await else { + let Some((pid, passwd)) = get_login_data_by_pid(source_pid).await else { return Err(ErrorCode::Core_Exception); }; let desgination_login_data = if destination_pid == self.destination_server_acct.pid { self.destination_server_acct.get_login_data() } else { - let Some(login) = get_login_data_by_pid(destination_pid).await else { - return Err(ErrorCode::Core_Exception); - }; - login + return Err(ErrorCode::RendezVous_InvalidOperation); }; let result = QResult::success(Core_Unknown); - let ticket = generate_ticket(source_login_data, desgination_login_data); + let ticket = generate_ticket((pid, &passwd[..]), desgination_login_data); Ok((result, ticket.into())) } -- 2.47.3 From 08e7bc9ed2db74b844f1625143a09c1e13733cb5 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 16:51:42 +0100 Subject: [PATCH 41/98] fix ports --- editions.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editions.yaml b/editions.yaml index 6b83a15..38a7810 100644 --- a/editions.yaml +++ b/editions.yaml @@ -12,6 +12,6 @@ friends: - friends settings: AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" - RNEX_VIRTUAL_PORT_INSECURE: "1:16" - RNEX_VIRTUAL_PORT_SECURE: "0:0" + RNEX_VIRTUAL_PORT_INSECURE: "1:10" + RNEX_VIRTUAL_PORT_SECURE: "1:10" RNEX_DEFAULT_PORT: 6000 -- 2.47.3 From 0c9db5c5ac032b0cb087638724e5f4c0d8913b24 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 16:58:47 +0100 Subject: [PATCH 42/98] fix ports --- editions.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editions.yaml b/editions.yaml index 38a7810..4a495c5 100644 --- a/editions.yaml +++ b/editions.yaml @@ -4,8 +4,8 @@ splatoon: - prudpv1 settings: AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" - RNEX_VIRTUAL_PORT_INSECURE: "1:16" - RNEX_VIRTUAL_PORT_SECURE: "0:0" + RNEX_VIRTUAL_PORT_INSECURE: "1:10" + RNEX_VIRTUAL_PORT_SECURE: "1:10" RNEX_DEFAULT_PORT: 6000 friends: features: -- 2.47.3 From f967c92cbec5def09a3348fd5276355b842596db Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 17:14:40 +0100 Subject: [PATCH 43/98] make v1 proxies actually run --- prudpv1/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prudpv1/src/lib.rs b/prudpv1/src/lib.rs index 40a46c7..0660a4b 100644 --- a/prudpv1/src/lib.rs +++ b/prudpv1/src/lib.rs @@ -4,11 +4,11 @@ cfg_if::cfg_if! { pub mod executables; pub mod prudp; pub async fn start_secure(param: ProxyStartupParam) { - executables::proxy_secure::start(); + executables::proxy_secure::start().await; } pub async fn start_insecure(param: ProxyStartupParam) { - executables::proxy_insecure::start(); + executables::proxy_insecure::start().await; } } } -- 2.47.3 From 1cd8f192bbd0d8329cd612720958fdf8b5d8957b Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 17:24:11 +0100 Subject: [PATCH 44/98] fix double call of setup in v1 proxy --- prudpv1/src/executables/proxy_secure.rs | 2 -- rnex-core/src/executables/backend_server_insecure.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index b18de8c..12abf64 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -23,8 +23,6 @@ use tokio::task; use tokio::time::sleep; pub async fn start() { - setup(); - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) .await .unwrap(); diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index eef48a2..5c4db20 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -15,7 +15,7 @@ use tokio::net::TcpStream; pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { env::var("FORWARD_EDGE_NODE_HOLDER") .ok() - .and_then(|s| s.parse().ok()) + .and_then(|s| Some(s.parse().unwrap())) .expect("FORWARD_EDGE_NODE_HOLDER not set") }); -- 2.47.3 From dcbbf2e1fe1f4b268ccddf0296f6f455c137ad1f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 17:28:49 +0100 Subject: [PATCH 45/98] revert changing of default server port --- rnex-core/src/executables/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rnex-core/src/executables/common.rs b/rnex-core/src/executables/common.rs index 0d5ca06..416e450 100644 --- a/rnex-core/src/executables/common.rs +++ b/rnex-core/src/executables/common.rs @@ -40,7 +40,7 @@ pub static SERVER_PORT: Lazy = Lazy::new(|| { env::var("SERVER_PORT") .ok() .and_then(|s| s.parse().ok()) - .unwrap_or(6000) + .unwrap_or(10000) }); pub static KERBEROS_SERVER_PASSWORD: Lazy = Lazy::new(|| { -- 2.47.3 From 7ea43b101d848ef248661fb530029ee0f33fbaf3 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 17:38:42 +0100 Subject: [PATCH 46/98] fix insecure proxy setup being called twice --- prudpv1/src/executables/proxy_insecure.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index a6d9453..7a08283 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -21,8 +21,6 @@ use tokio::task; use tokio::time::sleep; pub async fn start() { - setup(); - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) .await .unwrap(); -- 2.47.3 From 3e2dc9099a232e9554d6b67fab1bac7021409e16 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 18:53:22 +0100 Subject: [PATCH 47/98] generalize node holder connection --- Cargo.lock | 1 + proxy/Cargo.toml | 1 + proxy/src/insecure.rs | 16 ++++++++++------ proxy/src/lib.rs | 8 ++++++++ proxy/src/secure.rs | 14 ++++++++------ prudpv1/src/executables/proxy_insecure.rs | 4 ++-- prudpv1/src/executables/proxy_secure.rs | 17 ----------------- 7 files changed, 30 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a8b4dd5..53c829e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -541,6 +541,7 @@ name = "proxy" version = "0.1.0" dependencies = [ "cfg-if", + "log", "proxy-common", "prudpv0", "prudpv1", diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index f2a5974..fa56ab2 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -10,6 +10,7 @@ prudpv1 = { path = "../prudpv1", optional = true } proxy-common = { path = "../proxy-common" } cfg-if = "1.0.4" rnex-core = { path = "../rnex-core", version = "0.1.1" } +log = "0.4.25" [features] prudpv0 = ["dep:prudpv0"] diff --git a/proxy/src/insecure.rs b/proxy/src/insecure.rs index b109d14..4a32adf 100644 --- a/proxy/src/insecure.rs +++ b/proxy/src/insecure.rs @@ -1,13 +1,17 @@ -use proxy_common::ProxyStartupParam; +use std::process::abort; + +use proxy::edge_node_dc_callback; +use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; use rnex_core::common::setup; #[tokio::main] async fn main() { setup(); - proxy::start_insecure( - ProxyStartupParam::new(proxy_common::ProxyType::Insecure) - .expect("unable to get startup parameters"), - ) - .await; + let param = ProxyStartupParam::new(proxy_common::ProxyType::Insecure) + .expect("unable to get startup parameters"); + + setup_edge_node_connection(¶m, edge_node_dc_callback).await; + + proxy::start_insecure(param).await; } diff --git a/proxy/src/lib.rs b/proxy/src/lib.rs index 7120adc..2c52a9a 100644 --- a/proxy/src/lib.rs +++ b/proxy/src/lib.rs @@ -1,4 +1,7 @@ +use std::process::abort; + use cfg_if::cfg_if; +use log::error; cfg_if! { if #[cfg(feature = "prudpv0")]{ @@ -9,3 +12,8 @@ cfg_if! { compile_error!("no proxy type has been set"); } } + +pub fn edge_node_dc_callback() { + error!("disconnected from node holder, aborting!"); + abort() +} diff --git a/proxy/src/secure.rs b/proxy/src/secure.rs index 8990d74..6d42c87 100644 --- a/proxy/src/secure.rs +++ b/proxy/src/secure.rs @@ -1,12 +1,14 @@ -use proxy_common::ProxyStartupParam; +use proxy::edge_node_dc_callback; +use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; use rnex_core::common::setup; #[tokio::main] async fn main() { setup(); - proxy::start_secure( - ProxyStartupParam::new(proxy_common::ProxyType::Secure) - .expect("unable to get startup parameters"), - ) - .await; + + let param = ProxyStartupParam::new(proxy_common::ProxyType::Secure) + .expect("unable to get startup parameters"); + + setup_edge_node_connection(¶m, edge_node_dc_callback).await; + proxy::start_secure(param).await; } diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 7a08283..0bde918 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -21,7 +21,7 @@ use tokio::task; use tokio::time::sleep; pub async fn start() { - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) + /*let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) .await .unwrap(); @@ -36,7 +36,7 @@ pub async fn start() { let conn = new_rmc_gateway_connection(conn, |r| { Arc::new(OnlyRemote::::new(r)) - }); + });*/ let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) .await diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index 12abf64..2045cfd 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -23,23 +23,6 @@ use tokio::task; use tokio::time::sleep; pub async fn start() { - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) - .await - .unwrap(); - - let conn: SplittableBufferConnection = conn.into(); - - conn.send( - Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)) - .to_data() - .unwrap(), - ) - .await; - - let conn = new_rmc_gateway_connection(conn, |r| { - Arc::new(OnlyRemote::::new(r)) - }); - let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) .await .expect("unable to start router"); -- 2.47.3 From 28bc6819a6ee2e3a651c6d5450b425c3969cc0f6 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 20:22:11 +0100 Subject: [PATCH 48/98] add pings to v0 --- proxy-common/src/lib.rs | 2 ++ prudpv0/src/lib.rs | 2 -- prudpv0/src/packet.rs | 40 ++++++++++++++++++++- prudpv0/src/server.rs | 80 +++++++++++++++++++++++++++++++++++------ 4 files changed, 110 insertions(+), 14 deletions(-) diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index fae29df..93c16c8 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -161,6 +161,8 @@ pub async fn setup_edge_node_connection( .unwrap(), ) .await; + + println!("{:?}", param.self_public); //leave the inner object floating so that it gets destroyed once we disconnect new_rmc_gateway_connection(conn, move |r| { Arc::new(OnRemoteDrop::::new( diff --git a/prudpv0/src/lib.rs b/prudpv0/src/lib.rs index 0df222a..444899a 100644 --- a/prudpv0/src/lib.rs +++ b/prudpv0/src/lib.rs @@ -44,8 +44,6 @@ cfg_if::cfg_if! { //implementations, e.g. secure and insecure(this also includes special cases like friends) async fn start_proxy(param: ProxyStartupParam) { - setup_edge_node_connection(¶m, || abort()); - info!("creating cryptography instance"); let mut crypto = Arc::new(T::new()); info!("binding to socket"); diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index d7b6705..f55ff18 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -6,7 +6,7 @@ use rnex_core::prudp::{ types_flags::{ self, TypesFlags, flags::{HAS_SIZE, NEED_ACK}, - types::{CONNECT, DATA, SYN}, + types::{CONNECT, DATA, PING, SYN}, }, virtual_port::VirtualPort, }; @@ -313,3 +313,41 @@ pub fn new_data_packet( packet.0 } + +pub fn new_ping_packet( + flags: u16, + source: VirtualPort, + destination: VirtualPort, + sequence_id: u16, + session_id: u8, + crypto_instance: &mut impl CryptoInstance, + crypto: &impl Crypto, +) -> Vec { + let type_flags = TypesFlags::default().types(PING).flags(flags); + + let vec = vec![0; precalc_size(type_flags, 0)]; + let mut packet = PRUDPV0Packet::new(vec); + + let packet_signature = crypto_instance.generate_signature(type_flags, &[]); + + let header = packet.header_mut().expect("packet malformed in creation"); + + *header = PRUDPV0Header { + destination, + source, + packet_signature, + sequence_id, + session_id, + type_flags, + }; + + *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( + packet + .checksummed_data() + .expect("packet malformed in creation"), + ); + + info!("header: {:?}", packet.header()); + + packet.0 +} diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index bd4b492..87e5fbd 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -19,7 +19,7 @@ use rnex_core::{ types_flags::{ TypesFlags, flags::{ACK, HAS_SIZE, NEED_ACK, RELIABLE}, - types::{CONNECT, DATA, SYN}, + types::{CONNECT, DATA, PING, SYN}, }, virtual_port::VirtualPort, }, @@ -36,8 +36,8 @@ use tokio::{ use crate::{ crypto::{Crypto, CryptoInstance}, packet::{ - PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_syn_packet, - precalc_size, + PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_ping_packet, + new_syn_packet, precalc_size, }, }; @@ -167,7 +167,31 @@ impl Server { } async fn timeout_thread(self: Arc, conn: Arc>) { loop { - sleep(Duration::from_secs(5)); + sleep(Duration::from_secs(3)); + let mut inner = conn.inner.lock().await; + if (Instant::now() - inner.last_action).as_secs() > 5 { + let packet = new_ping_packet( + NEED_ACK, + self.param.virtual_port, + conn.addr.virtual_port, + 0, + conn.session_id, + &mut inner.crypto_instance, + &self.crypto, + ); + + self.socket + .send_to(&packet, conn.addr.regular_socket_addr) + .await; + } + + if (Instant::now() - conn.inner.lock().await.last_action).as_secs() > 15 { + let mut conns = self.connections.write().await; + conns.remove(&conn.addr); + drop(conns); + } + + drop(inner); } } async fn handle_syn(self: Arc, packet: PRUDPV0Packet>, addr: PRUDPSockAddr) { @@ -311,11 +335,38 @@ impl Server { } drop(conn); } - async fn process_packet<'a>( - self: Arc, - packet: PRUDPV0Packet>, - addr: SocketAddrV4, - ) { + + async fn handle_ping(self: Arc, mut packet: PRUDPV0Packet>, addr: PRUDPSockAddr) { + let header = packet.header().unwrap(); + + let Some(conn) = self.get_connection(addr).await else { + warn!("ping on inactive connection: {:?}", addr); + return; + }; + let mut inner = conn.inner.lock().await; + let packet = new_ping_packet( + ACK, + self.param.virtual_port, + addr.virtual_port, + header.sequence_id, + header.session_id, + &mut inner.crypto_instance, + &self.crypto, + ); + drop(inner); + drop(conn); + + self.socket.send_to(&packet, addr.regular_socket_addr).await; + } + + async fn get_connection(&self, addr: PRUDPSockAddr) -> Option>> { + let rd = self.connections.read().await; + let res = rd.get(&addr).cloned(); + drop(rd); + res + } + + async fn process_packet(self: Arc, packet: PRUDPV0Packet>, addr: SocketAddrV4) { if !packet.check_checksum(&self.crypto) { warn!("invalid checksum from: {}", addr); return; @@ -332,7 +383,11 @@ impl Server { info!("got ack(acks are ignored for now)"); return; } - + if let Some(conn) = self.get_connection(addr).await { + let mut inner = conn.inner.lock().await; + inner.last_action = Instant::now(); + drop(inner); + }; println!("{:?}", header); match header.type_flags.get_types() { SYN => { @@ -344,6 +399,9 @@ impl Server { DATA => { self.handle_data(packet, addr).await; } + PING => { + self.handle_ping(packet, addr).await; + } v => { println!("unimplemented packed type: {}", v); } @@ -376,7 +434,7 @@ impl Server { } } pub async fn new(param: ProxyStartupParam) -> Self { - let socket = UdpSocket::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) + let socket = UdpSocket::bind(param.self_private) .await .expect("unable to bind socket"); Self { -- 2.47.3 From 420c689644a2a80ceba80f613dc4cc3f9c0d5665 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 20:41:37 +0100 Subject: [PATCH 49/98] fix signature --- prudpv0/src/crypto/friends_insecure.rs | 7 +++++-- prudpv0/src/server.rs | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/prudpv0/src/crypto/friends_insecure.rs b/prudpv0/src/crypto/friends_insecure.rs index d1575e8..9fbfe95 100644 --- a/prudpv0/src/crypto/friends_insecure.rs +++ b/prudpv0/src/crypto/friends_insecure.rs @@ -1,6 +1,7 @@ -use std::rc::Rc; +use std::{io::Write, rc::Rc}; use hmac::Mac; +use md5::{Digest, Md5}; use rc4::{KeyInit, Rc4, StreamCipher}; use rnex_core::prudp::{ encryption::{DEFAULT_KEY, EncryptionPair}, @@ -35,7 +36,9 @@ impl CryptoInstance for InsecureInstance { if data.len() == 0 { [0x78, 0x56, 0x34, 0x12] } else { - let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) + let mut hash = Md5::new(); + hash.write(ACCESS_KEY.as_bytes()).unwrap(); + let mut hmac = ::new_from_slice(&hash.finalize().as_slice()) .expect("unable to create hmac md5"); hmac.update(data); hmac.finalize().into_bytes()[0..4].try_into().unwrap() diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 87e5fbd..3788478 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -109,7 +109,7 @@ impl Server { let mut inner = conn.inner.lock().await; let seq = inner.server_packet_counter; let packet = new_data_packet( - HAS_SIZE | NEED_ACK | RELIABLE, + NEED_ACK | RELIABLE, self.param.virtual_port, conn.addr.virtual_port, data, @@ -268,7 +268,7 @@ impl Server { }); let packet = new_connect_packet( - ACK | HAS_SIZE, + ACK, header.destination, header.source, self_signat, -- 2.47.3 From b95656325509849a3453d0786040ca3de31aca6b Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 20:57:19 +0100 Subject: [PATCH 50/98] add disconnection --- prudpv0/src/packet.rs | 37 ++++++++++++++++++++++++++- prudpv0/src/server.rs | 58 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 91 insertions(+), 4 deletions(-) diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index f55ff18..aa68194 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -6,7 +6,7 @@ use rnex_core::prudp::{ types_flags::{ self, TypesFlags, flags::{HAS_SIZE, NEED_ACK}, - types::{CONNECT, DATA, PING, SYN}, + types::{CONNECT, DATA, DISCONNECT, PING, SYN}, }, virtual_port::VirtualPort, }; @@ -347,6 +347,41 @@ pub fn new_ping_packet( .expect("packet malformed in creation"), ); + packet.0 +} +pub fn new_disconnect_packet( + flags: u16, + source: VirtualPort, + destination: VirtualPort, + sequence_id: u16, + session_id: u8, + crypto_instance: &mut impl CryptoInstance, + crypto: &impl Crypto, +) -> Vec { + let type_flags = TypesFlags::default().types(DISCONNECT).flags(flags); + + let vec = vec![0; precalc_size(type_flags, 0)]; + let mut packet = PRUDPV0Packet::new(vec); + + let packet_signature = crypto_instance.generate_signature(type_flags, &[]); + + let header = packet.header_mut().expect("packet malformed in creation"); + + *header = PRUDPV0Header { + destination, + source, + packet_signature, + sequence_id, + session_id, + type_flags, + }; + + *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( + packet + .checksummed_data() + .expect("packet malformed in creation"), + ); + info!("header: {:?}", packet.header()); packet.0 diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 3788478..a1e561c 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -19,7 +19,7 @@ use rnex_core::{ types_flags::{ TypesFlags, flags::{ACK, HAS_SIZE, NEED_ACK, RELIABLE}, - types::{CONNECT, DATA, PING, SYN}, + types::{CONNECT, DATA, DISCONNECT, PING, SYN}, }, virtual_port::VirtualPort, }, @@ -36,8 +36,8 @@ use tokio::{ use crate::{ crypto::{Crypto, CryptoInstance}, packet::{ - PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_ping_packet, - new_syn_packet, precalc_size, + PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_disconnect_packet, + new_ping_packet, new_syn_packet, precalc_size, }, }; @@ -170,6 +170,7 @@ impl Server { sleep(Duration::from_secs(3)); let mut inner = conn.inner.lock().await; if (Instant::now() - inner.last_action).as_secs() > 5 { + warn!("connection exceeded silence limit, sending ping"); let packet = new_ping_packet( NEED_ACK, self.param.virtual_port, @@ -186,6 +187,27 @@ impl Server { } if (Instant::now() - conn.inner.lock().await.last_action).as_secs() > 15 { + warn!("client timed out..."); + + let packet = new_disconnect_packet( + 0, + self.param.virtual_port, + conn.addr.virtual_port, + 0, + conn.session_id, + &mut inner.crypto_instance, + &self.crypto, + ); + + self.socket + .send_to(&packet, conn.addr.regular_socket_addr) + .await; + self.socket + .send_to(&packet, conn.addr.regular_socket_addr) + .await; + self.socket + .send_to(&packet, conn.addr.regular_socket_addr) + .await; let mut conns = self.connections.write().await; conns.remove(&conn.addr); drop(conns); @@ -358,7 +380,34 @@ impl Server { self.socket.send_to(&packet, addr.regular_socket_addr).await; } + async fn handle_disconnect( + self: Arc, + mut packet: PRUDPV0Packet>, + addr: PRUDPSockAddr, + ) { + let header = packet.header().unwrap(); + let Some(conn) = self.get_connection(addr).await else { + warn!("ping on inactive connection: {:?}", addr); + return; + }; + let mut inner = conn.inner.lock().await; + let packet = new_disconnect_packet( + ACK, + self.param.virtual_port, + addr.virtual_port, + header.sequence_id, + header.session_id, + &mut inner.crypto_instance, + &self.crypto, + ); + drop(inner); + drop(conn); + + self.socket.send_to(&packet, addr.regular_socket_addr).await; + self.socket.send_to(&packet, addr.regular_socket_addr).await; + self.socket.send_to(&packet, addr.regular_socket_addr).await; + } async fn get_connection(&self, addr: PRUDPSockAddr) -> Option>> { let rd = self.connections.read().await; let res = rd.get(&addr).cloned(); @@ -402,6 +451,9 @@ impl Server { PING => { self.handle_ping(packet, addr).await; } + DISCONNECT => { + self.handle_disconnect(packet, addr).await; + } v => { println!("unimplemented packed type: {}", v); } -- 2.47.3 From fd58995c4c103a2812d1d906feb82fd3b9b72c10 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 21:39:11 +0100 Subject: [PATCH 51/98] add logging and make auth version report be edition specific --- editions.yaml | 2 +- prudpv0/src/server.rs | 2 ++ prudpv1/src/executables/proxy_secure.rs | 2 +- rnex-core/src/nex/auth_handler.rs | 11 +++++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/editions.yaml b/editions.yaml index 4a495c5..1c025b0 100644 --- a/editions.yaml +++ b/editions.yaml @@ -11,7 +11,7 @@ friends: features: - friends settings: - AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + AUTH_REPORT_VERSION: "branch:origin/feature/45925_FixAutoReconnect build:3_10_11_2006_0" RNEX_VIRTUAL_PORT_INSECURE: "1:10" RNEX_VIRTUAL_PORT_SECURE: "1:10" RNEX_DEFAULT_PORT: 6000 diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index a1e561c..19622ec 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -359,6 +359,7 @@ impl Server { } async fn handle_ping(self: Arc, mut packet: PRUDPV0Packet>, addr: PRUDPSockAddr) { + info!("got ping"); let header = packet.header().unwrap(); let Some(conn) = self.get_connection(addr).await else { @@ -385,6 +386,7 @@ impl Server { mut packet: PRUDPV0Packet>, addr: PRUDPSockAddr, ) { + info!("got disconnect"); let header = packet.header().unwrap(); let Some(conn) = self.get_connection(addr).await else { diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index 2045cfd..51677f8 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -35,7 +35,7 @@ pub async fn start() { .await .expect("unable to add socket"); - // let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); + let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); loop { let Some(mut conn) = socket_secure.accept().await else { diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 89afd7f..21f67dc 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -1,7 +1,7 @@ use crate::grpc::account; use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; use crate::{define_rmc_proto, kerberos}; -use log::warn; +use log::{info, warn}; use macros::rmc_struct; use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; use rnex_core::nex::account::Account; @@ -140,13 +140,16 @@ impl Auth for AuthHandler { special_protocols: Vec::new(), }; - Ok(( + let ret = ( result, pid, ticket.into(), connection_data, - self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")), - )) + self.build_name.to_string(), + ); + + info!("data: {:?}", ret); + Ok(ret) } async fn login_ex( -- 2.47.3 From 2122b8dd6c600a10c7f28e15764f7a254e54aefd Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 21:50:42 +0100 Subject: [PATCH 52/98] more logging --- prudpv0/src/server.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 19622ec..55b508e 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -168,6 +168,7 @@ impl Server { async fn timeout_thread(self: Arc, conn: Arc>) { loop { sleep(Duration::from_secs(3)); + info!("running another loop"); let mut inner = conn.inner.lock().await; if (Instant::now() - inner.last_action).as_secs() > 5 { warn!("connection exceeded silence limit, sending ping"); -- 2.47.3 From d483b230e43dbb40b6eb42d151653e44a41ae76a Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 22:04:54 +0100 Subject: [PATCH 53/98] switch proxies to from scracth --- Dockerfile | 12 ++++-------- prudpv1/src/executables/proxy_insecure.rs | 1 - prudpv1/src/executables/proxy_secure.rs | 4 +--- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2baa33b..e181a93 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,19 +20,15 @@ COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_hold ENTRYPOINT ["/edge_node_holder_server"] -FROM alpine:latest AS proxy-insecure +FROM scratch AS proxy-insecure COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /proxy_insecure -RUN apk add --no-cache ca-certificates -RUN update-ca-certificates ENTRYPOINT ["/proxy_insecure"] -FROM alpine:latest AS proxy-secure +FROM scratch AS proxy-secure COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure -RUN apk add --no-cache ca-certificates -RUN update-ca-certificates ENTRYPOINT ["/proxy_secure"] - - + + FROM scratch AS backend-auth COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /backend_server_insecure ENTRYPOINT ["/backend_server_insecure"] diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 0bde918..975f837 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -111,5 +111,4 @@ pub async fn start() { } }); } - drop(conn); } diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index 51677f8..8446391 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -35,7 +35,7 @@ pub async fn start() { .await .expect("unable to add socket"); - let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); + // let conn = socket_secure.connect(auth_sockaddr).await.unwrap(); loop { let Some(mut conn) = socket_secure.accept().await else { @@ -99,6 +99,4 @@ pub async fn start() { } }); } - - drop(conn); } -- 2.47.3 From 8af4ca525aaac38cfc7fa8fb767280fb31a0b80c Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 22:20:18 +0100 Subject: [PATCH 54/98] add image cache --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fad0b25..900885c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,11 @@ default: image: quay.io/podman/stable + cache: + key: image-cache + paths: + - /var/lib/containers/storage + - /run/containers/storage + - .local/share/containers/storage before_script: - git submodule update --init - podman login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY -- 2.47.3 From 3b6de6968d1e12293ca4d3b93169b07359f8edba Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 1 Feb 2026 20:59:23 +0100 Subject: [PATCH 55/98] lots of changes --- rnex-core/Cargo.toml | 2 +- .../executables/backend_server_insecure.rs | 28 +-- .../src/executables/backend_server_secure.rs | 32 +-- rnex-core/src/executables/friends_backend.rs | 22 ++ rnex-core/src/executables/mod.rs | 4 +- rnex-core/src/executables/regular_backend.rs | 33 +++ rnex-core/src/kerberos/mod.rs | 23 +- rnex-core/src/nex/auth_handler.rs | 56 ++++- rnex-core/src/nex/common.rs | 93 +++++++ rnex-core/src/nex/friends_handler.rs | 160 ++++++++++++ rnex-core/src/nex/mod.rs | 6 +- rnex-core/src/nex/user.rs | 94 +------ rnex-core/src/prudp/mod.rs | 1 + rnex-core/src/prudp/socket_addr.rs | 31 +-- rnex-core/src/prudp/ticket.rs | 81 ++++++ rnex-core/src/rmc/protocols/auth.rs | 4 +- rnex-core/src/rmc/protocols/friends.rs | 146 +++++++++++ rnex-core/src/rmc/protocols/mod.rs | 5 +- rnex-core/src/rmc/protocols/secure.rs | 13 +- rnex-core/src/rmc/structures/any.rs | 17 +- rnex-core/src/rmc/structures/buffer.rs | 23 +- .../src/rmc/structures/connection_data.rs | 12 +- rnex-core/src/rmc/structures/primitives.rs | 237 +++++++++++++----- rnex-core/src/rmc/structures/variant.rs | 22 +- 24 files changed, 883 insertions(+), 262 deletions(-) create mode 100644 rnex-core/src/executables/friends_backend.rs create mode 100644 rnex-core/src/executables/regular_backend.rs create mode 100644 rnex-core/src/nex/common.rs create mode 100644 rnex-core/src/nex/friends_handler.rs create mode 100644 rnex-core/src/prudp/ticket.rs create mode 100644 rnex-core/src/rmc/protocols/friends.rs diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 34034d9..69a4f9f 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -14,7 +14,7 @@ simplelog = "0.12.2" chrono = "0.4.39" log = "0.4.25" rand = "0.8.5" - +cfg-if = "1.0.4" hmac = "0.12.1" md-5 = "^0.10.6" tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 5c4db20..efb08db 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,6 +1,8 @@ +use cfg_if::cfg_if; use once_cell::sync::Lazy; use rnex_core::common::setup; use rnex_core::executables::common::{SECURE_SERVER_ACCOUNT, new_simple_backend}; +use rnex_core::executables::regular_backend; use rnex_core::nex::auth_handler::AuthHandler; use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; use rnex_core::reggie::RemoteEdgeNodeHolder; @@ -23,25 +25,11 @@ pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { async fn main() { setup(); - let conn = TcpStream::connect(&*FORWARD_EDGE_NODE_HOLDER) - .await - .unwrap(); + cfg_if! { + if #[cfg(features = "friends")]{ - let conn: SplittableBufferConnection = conn.into(); - - conn.send(DontRegister.to_data().unwrap()).await; - - let conn = new_rmc_gateway_connection(conn, |r| { - Arc::new(OnlyRemote::::new(r)) - }); - - new_simple_backend(move |_, _| { - let controller = conn.clone(); - Arc::new(AuthHandler { - destination_server_acct: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - control_server: controller, - }) - }) - .await; + } else { + regular_backend::start_regular_backend().await + } + } } diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs index 598b039..51d9647 100644 --- a/rnex-core/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -1,5 +1,7 @@ +use cfg_if::cfg_if; use rnex_core::common::setup; use rnex_core::executables::common::new_simple_backend; +use rnex_core::executables::friends_backend::start_friends_backend; use rnex_core::nex::matchmake::MatchmakeManager; use rnex_core::nex::remote_console::RemoteConsole; use rnex_core::nex::user::User; @@ -11,27 +13,11 @@ use std::sync::atomic::AtomicU32; async fn main() { setup(); - let mmm = Arc::new(MatchmakeManager { - //gid_counter: AtomicU32::new(1), - sessions: Default::default(), - users: Default::default(), - rv_cid_counter: AtomicU32::new(1), - }); - - let weak_mmm = Arc::downgrade(&mmm); - - MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - - new_simple_backend(move |c, r| { - let mmm = mmm.clone(); - Arc::new_cyclic(move |this| User { - this: this.clone(), - ip: c.prudpsock_addr, - pid: c.pid, - remote: RemoteConsole::new(r), - matchmake_manager: mmm, - station_url: Default::default(), - }) - }) - .await; + cfg_if! { + if #[cfg(feature = "friends")]{ + start_friends_backend().await; + } else { + regular_backend::start_regular_backend().await + } + } } diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs new file mode 100644 index 0000000..2626fbe --- /dev/null +++ b/rnex-core/src/executables/friends_backend.rs @@ -0,0 +1,22 @@ +use std::sync::{Arc, atomic::AtomicU32}; + +use crate::{ + executables::common::new_simple_backend, + nex::friends_handler::{FriendsManager, FriendsUser}, +}; + +pub async fn start_friends_backend() { + let fm = Arc::new(FriendsManager { + cid_counter: AtomicU32::new(1), + }); + + new_simple_backend(move |c, r| { + let fm = fm.clone(); + Arc::new_cyclic(move |this| FriendsUser { + fm, + addr: c.prudpsock_addr, + pid: c.pid, + }) + }) + .await; +} diff --git a/rnex-core/src/executables/mod.rs b/rnex-core/src/executables/mod.rs index ffac467..cc9b83d 100644 --- a/rnex-core/src/executables/mod.rs +++ b/rnex-core/src/executables/mod.rs @@ -1 +1,3 @@ -pub mod common; \ No newline at end of file +pub mod common; +pub mod friends_backend; +pub mod regular_backend; diff --git a/rnex-core/src/executables/regular_backend.rs b/rnex-core/src/executables/regular_backend.rs new file mode 100644 index 0000000..65cb2ca --- /dev/null +++ b/rnex-core/src/executables/regular_backend.rs @@ -0,0 +1,33 @@ +use std::sync::{Arc, atomic::AtomicU32}; + +use crate::{ + executables::common::new_simple_backend, + nex::{matchmake::MatchmakeManager, remote_console::RemoteConsole, user::User}, + rmc::protocols::RmcPureRemoteObject, +}; + +pub async fn start_regular_backend() { + let mmm = Arc::new(MatchmakeManager { + //gid_counter: AtomicU32::new(1), + sessions: Default::default(), + users: Default::default(), + rv_cid_counter: AtomicU32::new(1), + }); + + let weak_mmm = Arc::downgrade(&mmm); + + MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; + + new_simple_backend(move |c, r| { + let mmm = mmm.clone(); + Arc::new_cyclic(move |this| User { + this: this.clone(), + ip: c.prudpsock_addr, + pid: c.pid, + remote: RemoteConsole::new(r), + matchmake_manager: mmm, + station_url: Default::default(), + }) + }) + .await; +} diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index a5963d8..88700a6 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -1,5 +1,5 @@ -use crate::rmc::structures::RmcSerialize; use bytemuck::{Pod, Zeroable, bytes_of}; +use cfg_if::cfg_if; use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; use hmac::Hmac; use hmac::Mac; @@ -8,7 +8,20 @@ use rc4::KeyInit; use rc4::cipher::StreamCipherCoreWrapper; use rc4::consts::U16; use rc4::{Rc4, Rc4Core, StreamCipher}; +use rnex_core::rmc::structures::RmcSerialize; use std::io::{Read, Write}; +use typenum::Unsigned; + +use rnex_core::rmc::structures::Result; + +cfg_if! { + if #[cfg(feature = "friends")]{ + pub type SESSION_KEY_LENGTH_TY = U16; + } else { + pub type SESSION_KEY_LENGTH_TY = U32; + } +} +pub const SESSION_KEY_LENGTH: usize = SESSION_KEY_LENGTH_TY::USIZE; type Md5Hmac = Hmac; @@ -99,11 +112,11 @@ impl KerberosDateTime { } impl RmcSerialize for KerberosDateTime { - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { Ok(self.0.serialize(writer)?) } - fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> Result { Ok(Self(u64::deserialize(reader)?)) } } @@ -113,7 +126,7 @@ impl RmcSerialize for KerberosDateTime { pub struct TicketInternalData { pub issued_time: KerberosDateTime, pub pid: u32, - pub session_key: [u8; 32], + pub session_key: [u8; SESSION_KEY_LENGTH], } impl TicketInternalData { @@ -148,7 +161,7 @@ impl TicketInternalData { #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] pub struct Ticket { - pub session_key: [u8; 32], + pub session_key: [u8; SESSION_KEY_LENGTH], pub pid: u32, } diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 21f67dc..0ab6910 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -1,6 +1,7 @@ use crate::grpc::account; use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; use crate::{define_rmc_proto, kerberos}; +use cfg_if::cfg_if; use log::{info, warn}; use macros::rmc_struct; use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; @@ -11,6 +12,7 @@ use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::response::ErrorCode::Core_Unknown; use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::connection_data::ConnectionData; +use rnex_core::rmc::structures::connection_data::ConnectionDataOld; use rnex_core::rmc::structures::qresult::QResult; use std::hash::{DefaultHasher, Hasher}; use std::net::SocketAddrV4; @@ -49,7 +51,13 @@ pub fn generate_ticket( encrypted_session_ticket } -async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> { +async fn get_login_data_by_pid(pid: u32) -> Option<(u32, Box<[u8]>)> { + if pid == GUEST_ACCOUNT.pid { + let source_login_data = GUEST_ACCOUNT.get_login_data(); + + return Some((source_login_data.0, source_login_data.1.into())); + } + let Ok(mut client) = account::Client::new().await else { return None; }; @@ -58,7 +66,7 @@ async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> { return None; }; - Some((pid, passwd)) + Some((pid, passwd.into())) } fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String { @@ -118,6 +126,42 @@ impl Auth for AuthHandler { async fn login( &self, name: String, + ) -> Result<(QResult, u32, Vec, ConnectionDataOld, String), ErrorCode> { + let (pid, ticket) = self.generate_ticket_from_name(&name).await?; + + let result = QResult::success(Core_Unknown); + + let mut hasher = DefaultHasher::new(); + + hasher.write(name.as_bytes()); + + let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + warn!("no secure proxies"); + return Err(ErrorCode::Core_Exception); + }; + + let connection_data = ConnectionDataOld { + station_url: station_url_from_sock_addr(addr), + special_station_url: "".to_string(), + special_protocols: Vec::new(), + }; + + let ret = ( + result, + pid, + ticket.into(), + connection_data, + self.build_name.to_string(), + ); + + info!("data: {:?}", ret); + Ok(ret) + } + + async fn login_ex( + &self, + name: String, + _extra_data: Any, ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { let (pid, ticket) = self.generate_ticket_from_name(&name).await?; @@ -152,14 +196,6 @@ impl Auth for AuthHandler { Ok(ret) } - async fn login_ex( - &self, - name: String, - _extra_data: Any, - ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { - self.login(name).await - } - async fn request_ticket( &self, source_pid: u32, diff --git a/rnex-core/src/nex/common.rs b/rnex-core/src/nex/common.rs new file mode 100644 index 0000000..d2fa40f --- /dev/null +++ b/rnex-core/src/nex/common.rs @@ -0,0 +1,93 @@ +use rnex_core::prudp::station_url::StationUrl; +use rnex_core::prudp::station_url::UrlOptions::{ + Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID, +}; +use rnex_core::prudp::station_url::nat_types::PUBLIC; +use rnex_core::rmc::response::ErrorCode::Core_Exception; + +use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::rmc::response::ErrorCode; + +pub async fn get_station_urls( + station_urls: &[StationUrl], + addr: PRUDPSockAddr, + pid: u32, + cid: u32, +) -> Result, ErrorCode> { + let mut public_station: Option = None; + let mut private_station: Option = None; + + for station in station_urls { + let is_public = station.options.iter().any(|v| { + if let NatType(v) = v { + if *v & PUBLIC != 0 { + return true; + } + } + false + }); + + let Some(nat_filtering) = station.options.iter().find_map(|v| match v { + NatFiltering(v) => Some(v), + _ => None, + }) else { + return Err(Core_Exception); + }; + + let Some(nat_mapping) = station.options.iter().find_map(|v| match v { + NatMapping(v) => Some(v), + _ => None, + }) else { + return Err(Core_Exception); + }; + + if !is_public || (*nat_filtering == 0 && *nat_mapping == 0) { + private_station = Some(station.clone()); + } + + if is_public { + public_station = Some(station.clone()); + } + } + + let Some(mut private_station) = private_station else { + return Err(Core_Exception); + }; + + let mut public_station = if let Some(public_station) = public_station { + public_station + } else { + let mut public_station = private_station.clone(); + + public_station.options.retain(|v| match v { + Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, + _ => true, + }); + + public_station + .options + .push(Address(*addr.regular_socket_addr.ip())); + public_station + .options + .push(Port(addr.regular_socket_addr.port())); + public_station.options.push(NatFiltering(0)); + public_station.options.push(NatMapping(0)); + public_station.options.push(NatType(3)); + + public_station + }; + + let both = [&mut public_station, &mut private_station]; + + for station in both { + station.options.retain(|v| match v { + PrincipalID(_) | RVConnectionID(_) => false, + _ => true, + }); + + station.options.push(PrincipalID(pid)); + station.options.push(RVConnectionID(cid)); + } + + Ok(vec![public_station]) +} diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs new file mode 100644 index 0000000..a2d42ca --- /dev/null +++ b/rnex-core/src/nex/friends_handler.rs @@ -0,0 +1,160 @@ +use std::sync::{Arc, atomic::AtomicU32}; +use std::time::Duration; + +use log::info; +use macros::rmc_struct; +use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends}; +use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; +use rnex_core::{ + define_rmc_proto, + kerberos::KerberosDateTime, + nex::common::get_station_urls, + prudp::{socket_addr::PRUDPSockAddr, station_url::StationUrl}, + rmc::{ + protocols::friends::{ + BlacklistedPrincipal, Comment, FriendInfo, FriendRequest, NNAInfo, NintendoPresenceV2, + PersistentNotification, PrincipalPreference, + }, + response::ErrorCode, + structures::{any::Any, qresult::QResult}, + }, +}; +use std::sync::atomic::Ordering::Relaxed; +use tokio::time::sleep; + +use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; + +define_rmc_proto!( + proto FriendsUser{ + Secure, + Friends + } +); +#[rmc_struct(FriendsUser)] +pub struct FriendsUser { + pub fm: Arc, + pub addr: PRUDPSockAddr, + pub pid: u32, +} + +pub struct FriendsManager { + pub cid_counter: AtomicU32, +} + +impl FriendsManager { + pub fn next_cid(&self) -> u32 { + self.cid_counter.fetch_add(1, Relaxed) + } +} + +impl Friends for FriendsUser { + async fn update_and_get_all_information( + &self, + info: NNAInfo, + presence: NintendoPresenceV2, + date_time: KerberosDateTime, + ) -> Result< + ( + PrincipalPreference, + Comment, + Vec, + Vec, + Vec, + Vec, + bool, + Vec, + bool, + ), + ErrorCode, + > { + Ok(( + PrincipalPreference { + block_friend_request: false, + show_online: false, + show_playing_title: false, + }, + Comment { + last_changed: KerberosDateTime::now(), + message: "".to_string(), + unk: 0, + }, + vec![FriendInfo { + became_friends: KerberosDateTime::now(), + comment: Comment { + last_changed: KerberosDateTime::now(), + message: "I'm just a dummy account :3".to_string(), + unk: 0, + }, + last_online: KerberosDateTime::now(), + nna_info: NNAInfo { + principal_basic_info: PrincipalBasicInfo { + pid: 101, + nnid: "dummyaccount".to_string(), + mii: MiiV2{ + date_time: KerberosDateTime::now(), + name: "Dummy Account".to_string(), + mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), + unk: 0, + unk2: 0, + }, + unk: 0 + }, + unk: 0, + unk2: 0 + }, + presence: NintendoPresenceV2{ + changed_flags: 0, + message: "".to_string(), + app_data: vec![], + game_key: GameKey{ + tid: 0x00050002101ce400, + version: 0x0 + }, + game_server_id: 0, + is_online: true, + gid: 0, + pid: 101, + unk: 0, + unk2: 0, + unk3: 0, + unk4: 0, + unk5: 0, + unk6: 0, + unk7: 0 + }, + unk: 0 + }], + vec![], + vec![], + vec![], + false, + vec![], + false, + )) + } +} + +impl Secure for FriendsUser { + async fn register( + &self, + station_urls: Vec, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + let cid = self.fm.next_cid(); + Ok(( + QResult::success(ErrorCode::Core_Unknown), + cid, + get_station_urls(&station_urls, self.addr, self.pid, cid).await?[0].clone(), + )) + } + async fn register_ex( + &self, + station_urls: Vec, + data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + info!("register"); + self.register(station_urls).await + } + async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { + Err(ErrorCode::Core_NotImplemented) + } +} diff --git a/rnex-core/src/nex/mod.rs b/rnex-core/src/nex/mod.rs index 76791bc..0f52c13 100644 --- a/rnex-core/src/nex/mod.rs +++ b/rnex-core/src/nex/mod.rs @@ -1,5 +1,7 @@ pub mod account; pub mod auth_handler; -pub mod user; +pub mod common; +pub mod friends_handler; +pub mod matchmake; pub mod remote_console; -pub mod matchmake; \ No newline at end of file +pub mod user; diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index 221c90a..1666d56 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -1,4 +1,5 @@ use crate::define_rmc_proto; +use crate::nex::common::get_station_urls; use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}; use crate::nex::remote_console::RemoteConsole; use crate::rmc::protocols::matchmake::{ @@ -21,6 +22,7 @@ use rnex_core::rmc::protocols::matchmake_extension::{ use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::matchmake::{ AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, }; @@ -71,97 +73,27 @@ impl Secure for User { users.insert(cid, self.this.clone()); drop(users); - let mut public_station: Option = None; - let mut private_station: Option = None; + let stations = get_station_urls(&station_urls, self.ip, self.pid, cid).await?; - for station in station_urls { - let is_public = station.options.iter().any(|v| { - if let NatType(v) = v { - if *v & PUBLIC != 0 { - return true; - } - } - false - }); - - let Some(nat_filtering) = station.options.iter().find_map(|v| match v { - NatFiltering(v) => Some(v), - _ => None, - }) else { - return Err(Core_Exception); - }; - - let Some(nat_mapping) = station.options.iter().find_map(|v| match v { - NatMapping(v) => Some(v), - _ => None, - }) else { - return Err(Core_Exception); - }; - - if !is_public || (*nat_filtering == 0 && *nat_mapping == 0) { - private_station = Some(station.clone()); - } - - if is_public { - public_station = Some(station); - } - } - - let Some(mut private_station) = private_station else { - return Err(Core_Exception); - }; - - let mut public_station = if let Some(public_station) = public_station { - public_station - } else { - let mut public_station = private_station.clone(); - - public_station.options.retain(|v| match v { - Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, - _ => true, - }); - - public_station - .options - .push(Address(*self.ip.regular_socket_addr.ip())); - public_station - .options - .push(Port(self.ip.regular_socket_addr.port())); - public_station.options.push(NatFiltering(0)); - public_station.options.push(NatMapping(0)); - public_station.options.push(NatType(3)); - - public_station - }; - - let both = [&mut public_station, &mut private_station]; - - for station in both { - station.options.retain(|v| match v { - PrincipalID(_) | RVConnectionID(_) => false, - _ => true, - }); - - station.options.push(PrincipalID(self.pid)); - station.options.push(RVConnectionID(cid)); - } + let first = stations.first().unwrap().clone(); let mut lock = self.station_url.write().await; - *lock = vec![ - public_station.clone(), - // private_station.clone() - ]; + *lock = stations; drop(lock); let result = QResult::success(ErrorCode::Core_Unknown); - let out = public_station.to_string(); + Ok((result, cid, first)) + } - println!("out: {}", out); - - Ok((result, cid, public_station)) + async fn register_ex( + &self, + station_urls: Vec, + _data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + self.register(station_urls).await } async fn replace_url(&self, target_url: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { diff --git a/rnex-core/src/prudp/mod.rs b/rnex-core/src/prudp/mod.rs index fdc991a..501463a 100644 --- a/rnex-core/src/prudp/mod.rs +++ b/rnex-core/src/prudp/mod.rs @@ -1,5 +1,6 @@ pub mod encryption; pub mod socket_addr; pub mod station_url; +pub mod ticket; pub mod types_flags; pub mod virtual_port; diff --git a/rnex-core/src/prudp/socket_addr.rs b/rnex-core/src/prudp/socket_addr.rs index f5eb179..4ffac83 100644 --- a/rnex-core/src/prudp/socket_addr.rs +++ b/rnex-core/src/prudp/socket_addr.rs @@ -1,26 +1,24 @@ +use hmac::Hmac; +use macros::RmcSerialize; +use md5::digest::Mac; +use rnex_core::prudp::virtual_port::VirtualPort; use std::io::Write; use std::net::SocketAddrV4; -use hmac::{Hmac}; -use md5::digest::Mac; -use macros::RmcSerialize; -use rnex_core::prudp::virtual_port::VirtualPort; type Md5Hmac = Hmac; #[derive(Eq, PartialEq, Hash, Debug, Copy, Clone, Ord, PartialOrd, RmcSerialize)] #[rmc_struct(0)] -pub struct PRUDPSockAddr{ +pub struct PRUDPSockAddr { pub regular_socket_addr: SocketAddrV4, - pub virtual_port: VirtualPort + pub virtual_port: VirtualPort, } - - -impl PRUDPSockAddr{ - pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self{ - Self{ +impl PRUDPSockAddr { + pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self { + Self { regular_socket_addr, - virtual_port + virtual_port, } } @@ -30,8 +28,11 @@ impl PRUDPSockAddr{ let data = self.regular_socket_addr.ip().octets().to_vec(); //data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes()); - hmac.write_all(&data).expect("figuring this out was complete ass"); - let result: [u8; 16] = hmac.finalize().into_bytes()[0..16].try_into().expect("fuck"); + hmac.write_all(&data) + .expect("figuring this out was complete ass"); + let result: [u8; 16] = hmac.finalize().into_bytes()[0..16] + .try_into() + .expect("fuck"); result } -} \ No newline at end of file +} diff --git a/rnex-core/src/prudp/ticket.rs b/rnex-core/src/prudp/ticket.rs new file mode 100644 index 0000000..9fd094d --- /dev/null +++ b/rnex-core/src/prudp/ticket.rs @@ -0,0 +1,81 @@ +use std::io::Cursor; + +use log::{error, info}; +use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher, cipher::StreamCipherCoreWrapper}; +use typenum::{U16, U32}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; + +use crate::{ + kerberos::{SESSION_KEY_LENGTH, SESSION_KEY_LENGTH_TY, TicketInternalData, derive_key}, + nex::account::Account, + rmc::structures::RmcSerialize, +}; + +pub fn read_secure_connection_data( + data: &[u8], + act: &Account, +) -> Option<([u8; SESSION_KEY_LENGTH], u32, u32)> { + let mut cursor = Cursor::new(data); + + let mut ticket_data: Vec = Vec::deserialize(&mut cursor).ok()?; + let mut request_data: Vec = Vec::deserialize(&mut cursor).ok()?; + info!( + "done + request data" + ); + + let ticket_data_size = ticket_data.len(); + + let ticket_data = &mut ticket_data[0..ticket_data_size - 0x10]; + + let server_key = derive_key(act.pid, &act.kerbros_password[..]); + + let mut rc4: StreamCipherCoreWrapper> = + Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); + + rc4.apply_keystream(ticket_data); + + let ticket_data: &TicketInternalData = match bytemuck::try_from_bytes(ticket_data) { + Ok(v) => v, + Err(e) => { + error!("unable to read internal ticket data: {}", e); + return None; + } + }; + + // todo: add ticket expiration + + let TicketInternalData { + session_key, + pid: ticket_source_pid, + issued_time, + } = *ticket_data; + + // todo: add checking if tickets are signed with a valid md5-hmac + let request_data_length = request_data.len(); + let request_data = &mut request_data[0..request_data_length - 0x10]; + + let mut rc4: StreamCipherCoreWrapper> = + Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream"); + + rc4.apply_keystream(request_data); + + let mut reqest_data_cursor = Cursor::new(request_data); + + let pid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + + if pid != ticket_source_pid { + let ticket_created_on = issued_time.to_regular_time(); + + error!( + "someone tried to spoof their pid, ticket was created on: {}", + ticket_created_on.to_rfc2822() + ); + return None; + } + + let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + + Some((session_key, pid, response_check)) +} diff --git a/rnex-core/src/rmc/protocols/auth.rs b/rnex-core/src/rmc/protocols/auth.rs index 774f1f9..594d9dd 100644 --- a/rnex-core/src/rmc/protocols/auth.rs +++ b/rnex-core/src/rmc/protocols/auth.rs @@ -1,4 +1,4 @@ -use crate::rmc::structures::connection_data::ConnectionData; +use crate::rmc::structures::connection_data::{ConnectionData, ConnectionDataOld}; use macros::{method_id, rmc_proto}; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::any::Any; @@ -14,7 +14,7 @@ pub trait Auth { async fn login( &self, name: String, - ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode>; + ) -> Result<(QResult, u32, Vec, ConnectionDataOld, String), ErrorCode>; /// representation of the `LoginEx` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs new file mode 100644 index 0000000..775016e --- /dev/null +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -0,0 +1,146 @@ +use macros::{RmcSerialize, method_id, rmc_proto}; + +use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct MiiV2 { + pub name: String, + pub unk: u8, + pub unk2: u8, + pub mii_data: Vec, + pub date_time: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct PrincipalBasicInfo { + pub pid: u32, + pub nnid: String, + pub mii: MiiV2, + pub unk: u8, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NNAInfo { + pub principal_basic_info: PrincipalBasicInfo, + pub unk: u8, + pub unk2: u8, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct GameKey { + pub tid: u64, + pub version: u16, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoPresenceV2 { + pub changed_flags: u32, + pub is_online: bool, + pub game_key: GameKey, + pub unk: u8, + pub message: String, + pub unk2: u32, + pub unk3: u8, + pub game_server_id: u32, + pub unk4: u32, + pub pid: u32, + pub gid: u32, + pub app_data: Vec, + pub unk5: u8, + pub unk6: u8, + pub unk7: u8, +} +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct PrincipalPreference { + pub show_online: bool, + pub show_playing_title: bool, + pub block_friend_request: bool, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct Comment { + pub unk: u8, + pub message: String, + pub last_changed: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct FriendInfo { + pub nna_info: NNAInfo, + pub presence: NintendoPresenceV2, + pub comment: Comment, + pub became_friends: KerberosDateTime, + pub last_online: KerberosDateTime, + pub unk: u64, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct FriendRequestMessage { + pub friend_request_id: u64, + pub is_recieved: u8, + pub unk: u8, + pub message: String, + pub unk2: u8, + pub unk3: String, + pub game_key: GameKey, + pub unk4: KerberosDateTime, + pub expires_on: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct FriendRequest { + pub basic_info: PrincipalBasicInfo, + pub request_message: FriendRequestMessage, + pub sent_on: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct BlacklistedPrincipal { + pub basic_info: PrincipalBasicInfo, + pub game_key: GameKey, + pub since: KerberosDateTime, +} +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct PersistentNotification { + pub unk1: u64, + pub unk2: u32, + pub unk3: u32, + pub unk4: u32, + pub unk5: String, +} + +#[rmc_proto(102)] +pub trait Friends { + #[method_id(1)] + async fn update_and_get_all_information( + &self, + info: NNAInfo, + presence: NintendoPresenceV2, + date_time: KerberosDateTime, + ) -> Result< + ( + PrincipalPreference, + Comment, + Vec, + Vec, + Vec, + Vec, + bool, + Vec, + bool, + ), + ErrorCode, + >; +} diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index fb0f055..6896cf3 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -1,6 +1,7 @@ #![allow(async_fn_in_trait)] pub mod auth; +pub mod friends; pub mod matchmake; pub mod matchmake_ext; pub mod matchmake_extension; @@ -294,8 +295,8 @@ async fn handle_incoming( } = message; info!( - "RMC REQUEST: Proto: {}; Method: {};", - protocol_id, method_id + "RMC REQUEST: Proto: {}; Method: {}; cid: {}", + protocol_id, method_id, call_id ); remote diff --git a/rnex-core/src/rmc/protocols/secure.rs b/rnex-core/src/rmc/protocols/secure.rs index 50afb5b..3df23c6 100644 --- a/rnex-core/src/rmc/protocols/secure.rs +++ b/rnex-core/src/rmc/protocols/secure.rs @@ -3,10 +3,21 @@ use rnex_core::prudp::station_url::StationUrl; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::qresult::QResult; +use crate::rmc::structures::any::Any; + #[rmc_proto(11)] pub trait Secure { #[method_id(1)] - async fn register(&self, station_urls: Vec) -> Result<(QResult, u32, StationUrl), ErrorCode>; + async fn register( + &self, + station_urls: Vec, + ) -> Result<(QResult, u32, StationUrl), ErrorCode>; + #[method_id(4)] + async fn register_ex( + &self, + station_urls: Vec, + data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode>; #[method_id(7)] async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode>; } diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index b60ca8a..c4dc2ce 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -1,14 +1,14 @@ +use rnex_core::rmc::structures::{Result, RmcSerialize}; use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use super::{Result, RmcSerialize}; #[derive(Debug, Default)] -pub struct Any{ +pub struct Any { pub name: String, - pub data: Vec + pub data: Vec, } -impl RmcSerialize for Any{ +impl RmcSerialize for Any { fn serialize(&self, writer: &mut impl Write) -> Result<()> { self.name.serialize(writer)?; @@ -32,11 +32,6 @@ impl RmcSerialize for Any{ reader.read_exact(&mut data)?; - Ok( - Any{ - name, - data - } - ) + Ok(Any { name, data }) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/buffer.rs b/rnex-core/src/rmc/structures/buffer.rs index 085f053..c147133 100644 --- a/rnex-core/src/rmc/structures/buffer.rs +++ b/rnex-core/src/rmc/structures/buffer.rs @@ -1,10 +1,9 @@ -use std::io::{Read, Write}; +use crate::rmc::structures::Result; use crate::rmc::structures::RmcSerialize; +use std::io::{Read, Write}; - - -impl<'a> RmcSerialize for &'a [u8]{ - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { +impl<'a> RmcSerialize for &'a [u8] { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { let u32_size = self.len() as u32; writer.write(bytemuck::bytes_of(&u32_size))?; writer.write(self)?; @@ -13,25 +12,25 @@ impl<'a> RmcSerialize for &'a [u8]{ } /// DO NOT USE (also maybe split off the serialize and deserialize functions at some point) - fn deserialize(_reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(_reader: &mut impl Read) -> Result { panic!("cannot deserialize to a u8 slice reference (use this ONLY for writing)") } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(4 + self.len() as u32) } } -impl RmcSerialize for Box<[u8]>{ - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { +impl RmcSerialize for Box<[u8]> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { (&self[..]).serialize(writer) } - fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> Result { Vec::deserialize(reader).map(|v| v.into_boxed_slice()) } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { (&self[..]).serialize_write_size() } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/connection_data.rs b/rnex-core/src/rmc/structures/connection_data.rs index da6a17b..d134e85 100644 --- a/rnex-core/src/rmc/structures/connection_data.rs +++ b/rnex-core/src/rmc/structures/connection_data.rs @@ -1,13 +1,19 @@ - use macros::RmcSerialize; use rnex_core::kerberos::KerberosDateTime; #[derive(Debug, RmcSerialize)] #[rmc_struct(1)] -pub struct ConnectionData{ +pub struct ConnectionData { pub station_url: String, pub special_protocols: Vec, pub special_station_url: String, - pub date_time: KerberosDateTime + pub date_time: KerberosDateTime, } +#[derive(Debug, RmcSerialize)] +#[rmc_struct(1)] +pub struct ConnectionDataOld { + pub station_url: String, + pub special_protocols: Vec, + pub special_station_url: String, +} diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index 8918968..3bdd835 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -1,9 +1,9 @@ -use std::io::{Read, Write}; -use bytemuck::bytes_of; -use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; +use bytemuck::bytes_of; +use std::io::{Read, Write}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -impl RmcSerialize for u8{ +impl RmcSerialize for u8 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -19,7 +19,7 @@ impl RmcSerialize for u8{ } } -impl RmcSerialize for i8{ +impl RmcSerialize for i8 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -35,7 +35,7 @@ impl RmcSerialize for i8{ } } -impl RmcSerialize for u16{ +impl RmcSerialize for u16 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -50,7 +50,7 @@ impl RmcSerialize for u16{ } } -impl RmcSerialize for i16{ +impl RmcSerialize for i16 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -65,7 +65,7 @@ impl RmcSerialize for i16{ } } -impl RmcSerialize for u32{ +impl RmcSerialize for u32 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -80,7 +80,7 @@ impl RmcSerialize for u32{ } } -impl RmcSerialize for i32{ +impl RmcSerialize for i32 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -95,7 +95,7 @@ impl RmcSerialize for i32{ } } -impl RmcSerialize for u64{ +impl RmcSerialize for u64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -110,7 +110,7 @@ impl RmcSerialize for u64{ } } -impl RmcSerialize for i64{ +impl RmcSerialize for i64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -125,7 +125,7 @@ impl RmcSerialize for i64{ } } -impl RmcSerialize for f64{ +impl RmcSerialize for f64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -141,10 +141,10 @@ impl RmcSerialize for f64{ } } -impl RmcSerialize for bool{ +impl RmcSerialize for bool { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { - match self{ + match self { true => writer.write_all(&[1])?, false => writer.write_all(&[0])?, } @@ -161,8 +161,7 @@ impl RmcSerialize for bool{ } } - -impl RmcSerialize for (T, U){ +impl RmcSerialize for (T, U) { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -178,14 +177,11 @@ impl RmcSerialize for (T, U){ } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V){ +impl RmcSerialize for (T, U, V) { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -203,15 +199,15 @@ impl RmcSerialize for (T, U, } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W){ +impl RmcSerialize + for (T, U, V, W) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -231,16 +227,16 @@ impl RmcSeri } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W, X){ +impl + RmcSerialize for (T, U, V, W, X) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -264,17 +260,23 @@ impl crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W, X, Y){ +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -300,18 +302,25 @@ impl crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? + - self.4.serialize_write_size()? + - self.5.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W, X, Y, Z){ +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, + Z: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y, Z) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -338,19 +347,123 @@ impl crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? + - self.4.serialize_write_size()? + - self.5.serialize_write_size()? + - self.6.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()?) } } -impl RmcSerialize for Box{ +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, + Z: RmcSerialize, + A: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y, Z, A) +{ + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + self.3.serialize(writer)?; + self.4.serialize(writer)?; + self.5.serialize(writer)?; + self.6.serialize(writer)?; + self.7.serialize(writer)?; + + Ok(()) + } + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + let fourth = W::deserialize(reader)?; + let fifth = X::deserialize(reader)?; + let sixth = Y::deserialize(reader)?; + let seventh = Z::deserialize(reader)?; + let eighth = A::deserialize(reader)?; + + Ok((first, second, third, fourth, fifth, sixth, seventh, eighth)) + } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()? + + self.7.serialize_write_size()?) + } +} + +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, + Z: RmcSerialize, + A: RmcSerialize, + B: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y, Z, A, B) +{ + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + self.3.serialize(writer)?; + self.4.serialize(writer)?; + self.5.serialize(writer)?; + self.6.serialize(writer)?; + self.7.serialize(writer)?; + self.8.serialize(writer)?; + + Ok(()) + } + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + let fourth = W::deserialize(reader)?; + let fifth = X::deserialize(reader)?; + let sixth = Y::deserialize(reader)?; + let seventh = Z::deserialize(reader)?; + let eighth = A::deserialize(reader)?; + let nineth = B::deserialize(reader)?; + + Ok(( + first, second, third, fourth, fifth, sixth, seventh, eighth, nineth, + )) + } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()? + + self.7.serialize_write_size()? + + self.8.serialize_write_size()?) + } +} + +impl RmcSerialize for Box { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.as_ref().serialize(writer) @@ -363,4 +476,4 @@ impl RmcSerialize for Box{ fn serialize_write_size(&self) -> crate::rmc::structures::Result { T::serialize_write_size(self.as_ref()) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/variant.rs b/rnex-core/src/rmc/structures/variant.rs index 6056f3f..9f705d0 100644 --- a/rnex-core/src/rmc/structures/variant.rs +++ b/rnex-core/src/rmc/structures/variant.rs @@ -1,10 +1,10 @@ +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures; +use rnex_core::rmc::structures::{Result, RmcSerialize}; use std::io::{Read, Write}; -use crate::kerberos::KerberosDateTime; -use crate::rmc::structures; -use crate::rmc::structures::RmcSerialize; #[derive(Debug, Clone, Default)] -pub enum Variant{ +pub enum Variant { #[default] None, SInt64(i64), @@ -15,9 +15,9 @@ pub enum Variant{ UInt64(u64), } -impl RmcSerialize for Variant{ - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { - match self{ +impl RmcSerialize for Variant { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { + match self { Variant::None => { writer.write_all(&[0])?; } @@ -50,8 +50,8 @@ impl RmcSerialize for Variant{ Ok(()) } - fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { - match u8::deserialize(reader)?{ + fn deserialize(reader: &mut impl Read) -> Result { + match u8::deserialize(reader)? { 0 => Ok(Variant::None), 1 => Ok(Variant::SInt64(i64::deserialize(reader)?)), 2 => Ok(Variant::Double(f64::deserialize(reader)?)), @@ -59,7 +59,7 @@ impl RmcSerialize for Variant{ 4 => Ok(Variant::String(String::deserialize(reader)?)), 5 => Ok(Variant::DateTime(KerberosDateTime::deserialize(reader)?)), 6 => Ok(Variant::UInt64(u64::deserialize(reader)?)), - v => Err(structures::Error::UnexpectedValue(v as u64)) + v => Err(structures::Error::UnexpectedValue(v as u64)), } } -} \ No newline at end of file +} -- 2.47.3 From 7e3cade00e3d8506cbf6b607658bfea6fbcaf1b3 Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 1 Feb 2026 21:10:03 +0100 Subject: [PATCH 56/98] fix forgetting to save file --- .ci-scripts/make-edition.sh | 4 +- Cargo.lock | 1 + out/backend_server_secure | Bin 0 -> 2005008 bytes proxy/src/insecure.rs | 2 - prudpv0/src/crypto/friends_insecure.rs | 15 +++-- prudpv0/src/crypto/friends_secure.rs | 52 ++++++++++++--- prudpv0/src/crypto/mod.rs | 2 +- prudpv0/src/packet.rs | 21 +++++- prudpv0/src/server.rs | 57 ++++++++-------- prudpv1/src/prudp/secure.rs | 63 +----------------- .../executables/backend_server_insecure.rs | 28 +++++--- 11 files changed, 124 insertions(+), 121 deletions(-) create mode 100755 out/backend_server_secure diff --git a/.ci-scripts/make-edition.sh b/.ci-scripts/make-edition.sh index f595e5e..57c857a 100755 --- a/.ci-scripts/make-edition.sh +++ b/.ci-scripts/make-edition.sh @@ -3,8 +3,8 @@ export EDITION=$1 export BA="--build-arg EDITION=$1" -podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container . -podman push "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" +# podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container . +# podman push "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder . podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" --target=proxy-secure . podman build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure . diff --git a/Cargo.lock b/Cargo.lock index 53c829e..b7ebf9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -672,6 +672,7 @@ version = "0.1.1" dependencies = [ "anyhow", "bytemuck", + "cfg-if", "chrono", "dotenv", "hex", diff --git a/out/backend_server_secure b/out/backend_server_secure new file mode 100755 index 0000000000000000000000000000000000000000..be14059810d86e98b2f98e8d87b12bef6bae892f GIT binary patch literal 2005008 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

=q~6cX!&E7%KanvbpweH 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 z zmL3Cxipf~gScJ7rT8!_qvK}?vA;ZO~=UYQu;7z0N#HHlxK^sC_B?2GO8qo&PY`S7- zt!M*ia+s2j*ma_X(GC(}qfw6#+Lk=K0krWvZ3Jx$O%Cz$5r13IqG)o;DId||Xrp;{ zb7&)ZT2V9Y_m*)@P4*K>TZI-vOP5*N$A#8|#uTFzSBhAx`s85-H^BztV#J*;arj8L z_f5R2RGQd0DjMHQl^sg*2$E*uXN&u|%on|ABX3*yjVQwpbK7T`+wfr2X_)xde_D)d zftZM&akLh+``MOH6@OD`4vSTNLIhH8GI3Qj6*o`ZL>a%AE_tw;FFckUQgL=Bi^^42 zby7O+I3rH-aS=DPi`6)1ChX*|9<96Dy5chkGL~Dhso%$H^feQWto1|>qPL+R!Zzh_ zcc44j>_Z>;xb;2X4Ka#Ml- zd27z~Hp^+u?`X1&l#k@=Kx;#jW{{6)ZnRdk^!zU4$BWj2#?-3R$uiemAk(65-y-&3 zuo~A*j!A_S)tqisr|0*JzSgbJTI%jy zu;lzj|AMYN?~GCIBpBtiupo7{SdD9joG#10zXnf#uOjan!R0HQ*U5RBv}YgwoM+KLsd}1TG!6i=ejX;S@@%U*DjoNT9>=X! zipEV|{_Ecy(EAVjY3ysyu^Q*uMC$imAU&k_j~uXS&rQw2*gN>EM4LX(YP{1$Ps78* zscSOgx0d*p3#~cV*Ba1*Xz8`7`0=CFU6t~!`&oSMO5%gWH?I&c`Gkq@B;Lukd_)^Y zYrQ&G8%Jx;)27gZS(@aRKItp%#u`S(+1V0Br=VpY2qcjdzThIC>yS zy73mubB#4~-A=SAG!NP#Y^$@3HBADo4Q)5kxN__ip27Zz_MmLbn(s!NRPM*%xbC(997cKliT$&G+^VwMqhu?CiNuoqt&5Z!*=c(bYptgWpKD;+t)%8n!__J(%S=;AkZPO>Do54pfKAuSV$T{cCzERGrLiDA-6eV*m z%JwN~-MH>jyAek>Th+I6{CRn8l71WBba(oW36+v@*NXi>&*DDFHBipc*rlkqjGJ!a zCy1{Tf6RpPgs|vg^o2ZK{EeVHzsMXQ_W01B?MV5PzMmw%k@!-H=OfxInh(t>0w2+m zXqJ%GxXz59TG7v>ztMgnMraI)O{Vl+2B+z|^h&lly&-A%YapHPw%p^4A8nyGwI)j0 zwWE#SVO5_Ytj;jTWjER!n$%f7G6(jfCDEouka4L$+3M8u8X<1%D~sb@?6;uB&^pDQ za?4Eup!=F3&fUj)Hx*}`qZ{Rx6Xy=%+!Dt}d{v_LqMaiG-O4$&exQ&zH*qt|_>wpu zaW!AH8s}V6hEzsUuQuYM#GS~t;?=^^X7bmCUUX+_UB>Mc>EAxIuCG}$_a*c`I74r6 zeT<9{-*~sxxTe6VI^%iCdH5B%=iHlPFTbMizjLJRyJxX~jkGJRlT1%6x3*d7T^BW! zz40u@XV|(`*Xx4VE^MXk5VoFsx6bb*wq09cE8|_A&3MH2N!iwS{-tfX+_N8br1O2< zx>eWnTCp9*_NS>l(&vV((H~4tRx;a4`}JbmdY@HYEw&7kv@Lf#&ev^M8#A+v*C@9A z100763|nJflckh#%l+r+c}P#=){pITr0M>KRb8C&&p9j)cpLXy{AhLt{S5Kx{r{sJ zAL73q|E>31_1~zG`n`|;M?T2-lePPVlpp__Q}xUEXN|bHKs0?b_s#)Vy7E?r;>*#- zaeBzA{$eJuw5&_MkNB2(xzaLDNZy7o*RWOXUb2F(yftEX@p8V5>$Ng(jN&i(gf(-{ zFIo)EGM0NjF^yJ~rO8}0kEYP{wFmX$?Y;WktDS44uO~YDJ$BXTZtU}Q4|?-5dJ}rr zGI{`gC{LGiccYJO$vt-Tqq!!m`uP~whnzLoMbPSAO`ZRqy0~xL&daY;YlzJ+V<$eR zunqm&YFy9e_$BpDpbeqvb1=J!iHdvBi_YWtgTBoEd4Jk5`)Bq-<;1iuYjQ8?r%k2m z%WS9S5X@7Hf$W!d5iMowz`l_m9k^fY`H0qomOv}h6+;W7&7$p*(wuM@t*E%vxNl3} zv6kS!aW2At-Pa^GPHfU^OKH1VG#A>a_#(x7JtJ3nKK+5MluJHxY^y>l# zd}oB6Os~J#SClG?%tOW;x>)~jrPod}!=>tveY>MnRS=esUVpS8n#GWe`~PU2XnKE9 zX67n=T`KlcrYP~F#OIeu;-`p9>`|I?-kU%h+OJd{kjg`^Ux4G)Cri~nDNX!VqD`P} zFPfh3ar#sgd~FHKj|=g`K1g5Z6iE-E13vSx?E_+n}$e^>*mRrs&92 zddyt>4Wc!o-DV{yrknqEqP+8vDV{zC^9CJXjLbb8ow1l zJ>|$@GCh}C*}0q28C)@Hp7STLt&CR8H8ATSY5v}sH(#$mtX|q)25-X@s<&?O(sg~VT$>T|+k??78XW7pBwpyZ>F}DEE-GQda<3kcCn07LO=Qty63vm z|C8ggUjK_Yesq-@=ZoZ5&7T8p0qrujW!zD286r8?7A370yY`zF`@9aV87+XOzjurF zF^kwQ8re|@BFxw%v&*p{}{U(9UchCd|`8)>IeY+OCL?IijH zdTpLA<75`ygYIVA7-M>G+E2iv#9P|wPvY4n^u9I`L1#;}KG)U|@4B^AZIXCnA6&BL z=4M$9Y4obf39YnE3+cK^m!9jTj2&oWp;F@-ANAveUawOKeH1-CKBe!aY=bHL<;o`U zuE}@8uNzS<==MvQU(xv)z^&*T(=V3m8eR%w`ss2J zJVO%1Z3lS_k202)&m+H`-(0DkO=m8b31_G4SJ25@=Cyh9Z`@p({SI++%$1_NnGCXpQox)*Q_WT(G%DfZ*53#P+O6=<)viOZ)H;bL5laGtPF|--9heSyG-H<-hJCnrg zaALYpyhu6buQ)#YYD@RO?@{mc)-S^(8r6ZL2RT?$FZ5dx=b&FxRd^yLQA48h>%WqbXI?Sd$BxXZ@H54 z1h?M44*T#mWomP34%h3N<-hR!#qlBj+pza^m8qYuWPfe0eLwbz8_Lw3+2iS`tn#0n zTmCKB`@753V0L}8?Jrrhm+`uQeS{yJyE)r`R{1YanM?atU&Z`$ds$}Q^PttCX=p)7 z&s@Hw{)fxBG`_ii1cN&JrDNi=lk~nXE&7x(5khM~JD=@LpRF^-PiLw;QuYz-da>hD z*P`9}^w>$4oc)*RX>13-Ql`&6>V#A|*Wrx)OY)QpjU&WQ%6593r1CU9j~%k~Uk!GF zzOu~yb-ljX?fdIg0kN&(uNnLBU1jQ1Y|H!Ub$d3Q{B;mFMqDG?nLM+`w3MqKn*=uc zF(h5Crc@rs8Re3E#;}{m&YkUxZHbE$x8>fYank+^#04KH%eyecXO<@AaH2I0 zmZ=xm&XjfSrb5$Ai}jVX4cPg=S!R64jj;5SAFU1TziemHrssp7FQ%7#da(68lvmbM za_cL0!`OMTdo0^$rteJ;O3OHio5C)R-J#ibYc>_iVO1ah#3zZrH+%eN^=IMjGJcJE zRC5Eb<=gLH5AoZGZSA9F>TB8grt5q~sy@VtZ4lep@06*6>@qCQft%CTQtu&bW5Z>} z8Yn#;j*{c1sXc8cJ}0pAK31mo%l4Tb&yS=njq#Dhw&C$I<33s1CqASNSN4f@v-*)W#N;UN(%9Cl6bl-ee zcdPFk{n&ZRG~?NU^u8nGDm^EXT>5ED{ArpxQvC7!a{4$U{S+r|%BCqU{Ve8{x7L=q zvgih-b}!eA?_BabJ-QEldG)M52CIobnfNC0lZp3I*k|=I=q286*No>IF%h55XdbkK zB~7~g%oP`qO8T;sct7!SYe_zmCWO|Ec8Cb+G%~IT>itiAC-Gdd)jv-DkD+y->F4q3 zG%_b0X{3`jn!%=VJ1z6PO1h0CPA+IQ5hr~q&u(SMIf!c`E`R?J+dAU>#62(R((4NS zT*-7ZIrIIilV#PTe=ke&X~RB=y}lmc8RhJJx`}gcuPr$zlXL^bRTFoBUd(&( zSlcEoEc=xgyRMxyWYaw>>*N*K-t)|lFu#!(V+Snml=Gv}auEn<0 zCuXTz1iQ{dm-dH@oh`%#h})IzOglA835~kUrsC7rkn}v*pVCJUIhk-`Yrj#cJMeP^ z+ZjLlK6AD1Ol)eg8T+iJZpyYX$}6+I-X_i1I9BJiUDh$jw9zP=v`II%?bz-k{`iR2 zj}}6cZTSczXgz2<=!&6@q4l9{pQTNr4dnToMT_QXNwle~w9<}tDm8<)QT(O*(sY_$ zSc!KNU%N)r_t#9koQn`AW1%q>A7DEZZ>(*P#Y*~8RPyAlu zi;rl-Xd_vg~Ru zezzz+W~Bk0#79%{eQamiTGmf810gy2o5rU4C{3+oBl#5d{6E&t2QHJU-v5Vr26)(o z$0wtt+>#25ij0(!66;w-7hP0TR8&$_N-R<`QZh=+)u=GZsOUz8xf&K3bvGj~73QW? zXxyS3-l&VY6?M1b7X2>Wuzv6FIWzOj%rnD+_wo{VIP?8{&i9=2J>T;^e`W@ILFP!V zJs$do9WYCuzfA2s;D$_{TKC z4k5RKoSUDdjgi*dSgc$=@ds0+^^kTN*Z#3jiki4Untmw;5U0T&$+}$E#1@+`{^#gE=#c z=?BwzUa|Ue9A+Sh5k05C%z$~dVE7R|=Sb^5zgT@%65MtXJzcy{&vj&%k^Pll*01Mx zf_Vym^#`e+mg3;t8-8~Za*+cO{aTStURbQhCCQ?k-!8$E7KjUERZ)9+Q-&dAs*(A) zfc#~+*&%nzAT~9P>|SIU+Oo24JoQfGNfup}kt@C^*v{*uB}o%ok{^*ve+Yl#OOrBJ zkTyqJy9oL8xzbVFU*;xcOD_&`wv$%wOB2o>(iTa(BE%WCCz0JN_|{@|qWBIsf8SV= zc)5vjMgKWuhu)YiXEkXDNL#w3IJmCsZ)b_w#fBYwlzJ^2Abz{l>054|w6mCea zc&4v{v?kIL!o`os)sogonsiC|k+eqA8c0j&6qD9QTD=b|{kfa83~B!?a&CM2+i9<< zPmvu(c3$xQzVDY^&C1RqJ9*FMc-N3^{Cu(cYMc&tWqB(G=|`KCZ9=wttXPf5@qXIy zN`3VryN2wWoJy=BZIHC)FBGfmq_QLGCUIE;0y9_$$29V*UoBR5axFjQ{LYg$_|L`u zcXo(G@wsK?1QWJVq+R$~PK+D($aX(My~fFY zIxE|YZ1S;U^-!GbeOcKtWXIJIUWY0HgOjr3+8DB}&o0qr5xm5pQ>3+!ru(?7zcWV3{YCEgaQ{UDaPMEDi=yMg zb?*0b|BaN*yYJ8cfYiUSHQ}rJDE;gCCECV3`HKyol(EsdU(B`q2&Rp+ePHC;!#MLL zN$Wer{n10*pWfiU=(ObAFO~fH5x=@h+B7-^)*!ukeWE~WUD{^{lZMHoN`kSTCzsu4 zk$f7ET}M_-S$?E1w+j9xC2E(yFZ=8FH^Dux0pu56R^pvy(LUQRe|@&^3;z`I9mkZY z`De5S5ES;LvFaP z#CzUW^XYN<%}9#f>~j7!_1=m6B=T4KdChoshASxf4tat)i1JAmBaCgh3< zxED4dSA$&n>kqA8D{>v1klTaY#3tm%ky|^2Tsc)Yk6h*rCFbm_+wWy9$aH1h2iA~j zMCMR!QT_?qV-s=>$Soo_LjIo3xN8s}A#akUZM%?b&Xfe_hF+htCPcCvxnblEB6l^{ z9-pxly>cX6Q^?frED6S`MyAazt=Q=Sdgl6-Wkr&DAA}&n9QfX4bo02k8dsy-q1xoqw&}p@g?Mf4l$Y2zm%hMlq=| zOLijk#i`DPdv3^+4YRp_Te7^Pq3(rur_s41^Fon0hkqpyxR8G-rqprmKjGuwQKDYq z_wBwmO&n=r1{oXLk*&V2#LS=hThe++8z8NdYx!y8cYw5I(oU5@g!3cOZNbq^eXO9t ze_ADRThxJ;z?m15?+SU;e6B?ON@5Ovn)tOp#l5{Hiq~Q&FfRit9tfvbirlrh)tGKMeUb(+|#dtjLnEN6cvl@;%58%$2A&aP9d7 z##lM$A@_&5KhAxDKX;+{Ia8iBWQ%_s8oS9~ zVu2lSm3^A=o%{7d?&g1^$-kPUTJCpp|A7C#&;G4@k(FTK3WE{OPB4}8q1ag#&bU|3 z?*R83xPJ!MUY_V=N#7<($~}QhH!{-glh)-+le`v4>m=<&5pwm1OPrG2U*rA& z_mB18XWvXVb%e9*Gcw=E#_MIIRgpGEnv~z;T?L^ieBD%jWR}1*gUz7y)WjaagAx+v+esuXs z>n82FCP~K#L!|YQc9o>LZRf@kzWK`(ax=(%Lv(cI{N=x0B6(AOX}^QWw=9*IXUaN* z>mJEb?16i)K~8=|w;iMOGtwj`kRM5_9%cSOn!BbYY4xP7kmi<4+OUPRgD%$9P5Xmx zPbX=^KIBTDC{f>w8%LV6F}&n8f&A)niTSo0e+$Qc(gy!fqCRHxhntr_zB$|u*fhSvhi6#u3z>Md~&AIpmT3VV(#( z?N8e9kty|MCr$FMChfTArGjhWj%~UDPC0Td$lZh7OStxQJl|7K+fpww_abwg$nYcl zgQU%n7C65oK5#jRokXstJY}AD2Pb8iC2g3rySbJhse>ibK6i9V6-pT*Y{U8!ypC+~ zUA)%d<y^Xa0CkbxZy>nC66K;))Y;vzs$Gz$0auQyP)1XFr+WOCS}fGA}ab+llC3bFf092&j0I4YdSuayXQ76IU4;t zkof^J-GU0}Z@K&8#{Q8zqBf=e-EV`U+n2MtNqbEq_r2Gqymw6Na%S7sogZkO4l{A-R>tc!(#|LCKP1+6_3`_h_vDkI4A}1MfU+Z6O+fopCZ$fu_u;bn%Bc?lNu;C) z9?7d6jD2cK4J3RRzkfd4_3@IIIV>W$5pXT1QD=S~y}S|^idUD+5?5vYquA#>xS_LB z!E=SKE#K;Z^z_H{6Z`W_Pn%M~`Khs)_qftB1rqLRWDC#U9Jk1~A^%Sn7y zD_c6I)Yp-HJWhv4vN~jtZNI?j53U{gb@-^^mGptPHyJFE>XCPMK*{6Lk@qBB_d*5CdXSrwR zW#3HTK$x%N{B$X%j zodNU66)E*h2?*Uf@b~TC6u8CGzNicNFI=6{z7B*=+e6v|q`h1c_>uY@ChcEId!|k? zY2&2LkyhkOn??tK{E#(jF%5ZIb5dALN$kLfxQ zJ<7R%6Zc&`#2#x%>m%(t!Mpt4nN>^A_@r)Hk$VieHh+Ek^hmtWwGUIi0p$PQl`_vv zf|vY9NgI26Hh)RmN80B}bIU9`%{X%T{=AG`NxONrzJlB>*QQj74an8q-(I%cM-q3q zo=NJda$Kp4uEQ^J?csD7Y39=n+`p0gC(C`ltE}r$`VD`I&K=zU9QR$FrG9!zyNk5l z+xf%Q#a}-U7rCnIxMLjoZ{3tq*ZRj1zx+$wam3`gh`hQbo2TfpLRubaM{_MdVlVcW zXlK%H@Q*WoUT1%=6xnKIyFWzz3E26Oc&35$PST|<{AV8IUOV^txF^^CGnrNV*~h(J z?)~yP{NdJtzdb%(=G8$pA`{3Tb9X34%`OKvAuLWnj;3f&C3zeGbJ{(OS#kBI&pjJ| zEA>%&AARBr#7BO4zfQlEdNy^JLH6-4rOdO7uKu3Sa1X&#zwmYuzZ!kN zf$WOEOkB$Sd!!G6zujU5^1})8xy?Q$RXLE)df=@E^{k>5?n*5st-tU+MxL4D;a9&Z zyS7Umw!pRc&-8t+g=>I!UKw3(wlCl2zCERJdn>p1Ae-KY-*w9D&zDumfqXK#wSb3u zZ!SDNHJYEO%S(;rpPrh?zmk7dE8#x?|LE5lOFaJ5q+Gn%%_*1Wm({_- zCRh^{dC;AjQ?Qe_vx7dFe`abrzm0!)B5L^SC-BP;q|}=|{%pNv_1FBm-ex1Uh5oYC za`N=lO7cqn-AN6jdpW;*;a~b@$~^N!UEU_`G9c}Gs|{hI5t$iedcT!YKjK>I+b>g} z>UzsId8eQAr0_}G&)`q*1$PbG19wl|UI#_lSFnd~J3e0Xog#Vel04yS_4A#+{cS#W z6C1REZv=m(qmR@6;LoS^^@sJ6r)!tI z<>|g%kF#iF@e4Cxr@(f2`O(H=`_-uGyd3DH?cMIB_IvAK*1%lsVElE~0*Yd@DBQR` z&Hc)+QoqyLIh>@`k=8?+G`svrS`%sAq)FS!kEFGe)x zg5S<|8@s5ynKo*=jy7U(o(^wn@O0WakN{Nbr5CQU@1#_<%nkUF@(z+#v)`FpTleet z5HNCO46rE-}Bv+T9igGK2=UrVP{seX?WhVuxqBRa&k)R zUi}_)Kh>xEsoSl)NaB^4UU5#5;ad7!-9F;9?=!B5{vkf>_2&Fj`OcYjQm8gg-Oi!s zP}<4cwf)0a`)EqNRQxZ`-1vQ_^-fb7UVwDkcI#c9P1n2j54P&DlsV6YF4_JjKwegk zB?IJ5mgc&XEY`tHg1I*6??Zl(2DR|md>Sw0<~vCY`TpJ8t?NxH4M68L?Jx07HTiXZ z4g3CK%6lh$R>yaE*YX@G?_$(;GD&)8D7^`hInswnKfaJZ z=r04DD8~*e2S4ugfwJ~Zv2V7mPkQZl%JvJq>r+Kd@mUAJ_N}B8ub6Z6rW%~MCObYm z?bl`fCUSV*xm|NrPZBTxPfA_k)d9n5G}rFbXdYG;Q3*6q6{_^YRhfU7y11S{+<5TR z+Y=wQZ_7Vzpx~UF3lmS}ZIeiLyWS@rN518>!_;%UI77!VIzH3o(DB*HPMlOA)e@0; z!}dfz0aQU_YNDWte+i%pb~}Hc>-=rjId^=6b zKa~7hknJr=2ltOjmwVmZo8aD6T&wqH*S_W6Aorf)o-T*mCrFq4$GNx0y$^9M z-#*d#yX%^=#N@2eOPLms9pNo?-6HGqII^Vo_tv)CT zZvA;}oqgtB{8&A*>C&|Ncs2$rDe$i!?9Q%Bi2mKk_Z^WAz9Ya}*S0<&wI_OwAh(8` zT+2^6zZ0abl6FuMvUSJ7cd0T^$tzJhc{WkuE`++m}dXv}KbPe|hk4guh-EsTjd74JA1GOTzfSjHKx^3mk zIcKRvpFPNxm#2g8sEQDprVrJNkjTs+Q-#dgTzh3QGN-sQ2a)MO z=C`>rKX+x))673!7;j&qZw)f)MWOQRH7HYm&D?L=;C?svN4fuIXgpo5%XE2#e~9}l z+`l|j{w;mJnzT}1n)ZLBm6P@?+sEf$FZ^!E{~@2QN~;(6{iU~lo=Azb^yv}g z%3hgPk3`FT%4HS3W{{maHm!QOmY-^V7fGu;F0E$s_`|gmzhB-fUg0GCnrxyNzn^}H z_@E}OUL1pw^HDNrNj=sfJM-$a`8I?54ghoJO^i`LpCoea$W^~49eg*F>6`Ki7GOk$V?*h zD!+{8kpmAV<{m_59+_spj5qGe2@`3r)3v;`@ig-G>(c5l)*?OKd~IxrXA?-``LbQC z%eV?=>Gjl|6@&R#BxM!dw?QLzUiDr2!%l202A4S3-7zs`X+^%}l^t2a#KOiSyl2%-HG_@(ZV=7293WWp~aWRC0S6+169jilRr$epPD6=u!GG z7rWBxf8u0+nAKa_pdR@-y^M^rz1pY&8|1nVxzMfz(Gn8n@M*rtxO0n!#o`$mF4 ztSOmXv4X-n3X5mHH`68VvVu!7+%@a};9Jge;%avf%97#lVLjhG$o(P|n#zjxl^N}F~WN516(+QqNG&z}6x#tHu-@|73EU%($xKL2(fx;@?rvlwNEkjaVE>RBd;Wa-Noyr7FvcJ&`RwIhUravJ+}j&-Z;^X5 z5%;9Ou5s@m_kPN?v=xho`WaE}b&~vL)-$*;3lh@4RX5T21)dpE2HbF``%TEd6M2v|g3mtBbi;&%I2{y*BRE$K31X-cIhln!LmH zFwDJ+V(#tZULW_4jKIxt??&!Lt!EtM-u2u&F#?x-l=CLs`$NRN3hv!?cQj{)dwaR} z{0Lkt_r|z)c*MOP?u~P=Ds)fUbclP?+|%~K-;y>)+AL}Qb&Dy|7D$u(@*`Yxq|KA| znBQml$GH5g&lj6kk718rB!>0dbT&qOqwAL?POL(9VLTK=SZ2Z?Iy7>>|4V7_-36jg z8)-wNJ>(y={Q7*6 zBlt$rE5DI8?`ib;)F(7ti|IH`uJUeZYCK2f^`r|E6K_6FC5}V~$+wAn!Zp1uPyHHW zw>w|^LMgvDmYZ)%?n+G;WnYGStChItFujyctf(VK*?H41n4c~(u|W@aEB<;2cw(RIU zb%NB>aJ)Wzfjf|Sj5=B$*&DZ+jN{grr-t?6ixZ9#Y>EUF5`8+s4uj1TeGY7(&$XM= zrykB}IGbORr@k(F71xFAh!4L;>tp@HccT`bB>r%gjqZ!3T%BQ_t6b?Edz5m?{AC4f zQp(jI##($H!88nY(&4-I*UxTWx~}J8ILCSD;ylr3Uzqa>S3FXmd9ZCS&r=;X*g1nW z{S`Z`$I@Lpyq}4i-|Do12U6%4#ttjt>V2hShvO%P>N&o@O5L`DodB!LG84wem!$&i zsFa~PPq9se&48sUZ?@j7KT~9#Vm?aHz`YsdMv!}}*g^93Zr_uBVxH5yF3*kkX@)lU zn){q1()~2awJB>UWA*g0d8%I8v(9j3`(5T5Zc*7AQ8)o<@Q-(Ii_U}at3o)2TaPcMtkANA{8PhOK?$NA`meD}gW z5XM@)t~}st-Rp2?k+Q2o{A+EVS{9zFH-zjuP;cLLd8F{7Lmk)_7L&dp*v2r{y3~~? zUu)3)BV;t9!yb61anjduZI6X{{Ppiqdi6gI)~?Ib=hE$cVXU9J@z-JEbb6sTN(r_P>`=zB`I<1+ zv$t^5Y5SQ1I|)|TTT>XjalNg9T?hNHl)W{KO(;*#i1w->hM7Le^@U;V#=fu%>?+t> zrLAYeSijD>{$U(!$H@+Merwoeuv1_sCEukm);}!CAziPDbUjyWBi_duzL0UnRy#v> z5@_Eiyn4er?Lt>NK{8ztY2!7>(c*ZAf4xZam~#>aY|_!ReA>L2VFJe~0TU3eP9 zI`H9|>=+x{01aSQ;Mv!Zr&3au{#<<$H&Ftkg_!;Q?jI=Zsl>Iem%8n&o9=eTwdt@< z@#C75rw8l^SY4jQFm`k0k^VCc&mIC#-3Q7}3bl>jo^pN1I@sDX9KT<&5!UO6QgmJR z+G6HIV0FIL8)1X_O4+-?&Vki&U|kp+D0{5$mbhyQp5Zg|)H`I%?J+!Foa2kPt@nh( zoa)3}DD;tlTR77t%-_zTf=hfPVIBC-CM&}9mYJN z4c{SSMqd~kDDQQyKXS|40d^7W5LIpuhOtDlS^pLAztZk|!DcSYQ?HhMCk-~z&PQ_E zJ!)F1?R*W+s>>bD)&CpL#x(QID;&=1Q+$0VIRCY_peM_w%5HZ!JOB5bV)LtTuE5zN zZ82sz8GEEZ%4-QTZd-(d4#8G)_OIqmdFuUw-5DSxx$PtvEl^}Hp2B0THxw75Jwo*s|bXFUt56Yz|3ZC83c zIezKPpn2jQd7vUN-DKqf4yos1IM?C4O*m@|r>~7T=xZuE+(x3$JlHNa{&at7iPvW< zc38=tT5E^HIrM+S*$Za_58rA%=l*Xv=isb)i^EyG%e9T1w%AJ9D_FcQe`}ulnY2a2 z2Arn_TQjbKtKjK@a}mxngtNtPX4}_4Z8Y{UhWtA6og&{ImXBNJG1voOt2^`bxBl$G zFxKm{VN=p}Sk9VfJ=ljO-|;Zk@&~^;{j?SA0@x=7yI`;;_LW5#y)0q9+ZXog*$EhqWUvX&p1>_fRVva8S z4LTqxyr69s@ZX)6b6AV;YyC zW3wci*8_0;iNEa$IJ~_ZGw&0R?M?lx59B;ABn#!@%bMV+|B%D8`1E;(;aPWil8sMW zpCx$q4LJJLJUt$XsVdpzo%%?gdP00&8$7w=$gWhM<#$ktikOdE_tE&m*$Zb2AA$Sr z2jLuv;heJroQd9OFEwXlk8sYxxq6hPibT(m3w-q!oP#8Kb0@^2Q}N^&|4I zTQ7{}oCuCV!&Ve0&yC|Fg|nDL6D_Z`REu!#i{Ts%a_)~Q`zV~!AKKt-KY{ubKfD&= zl=YERlk1T2H4g^+mEJLK(z=boQ&(rHQ)y?r;-aYX?n(^?+vVaI`x|uHWgX7ijHPPM zg|jz?bEP<7e=j*Lx(-*0O{~^*6#L~LwbVbPypxx?_J;@6-NWofjpX^F8DaoOp8>GT zLza3a^A|gLd2|`)5&?bwn2OeC4*Qq-UxIW0J(hl#j@^8PtB;BQvh{DiF>HM-SpO_* z@riVO_P4T}{`z@KO|x!b_rMd?FGhp)|8hH8w^7O~KVoxz<*Yy5Z>f(l9@+El(Y(_I zfil0mG@5ssJ)v4S=i#iLv&?>@eWfmQc5V^BE-Tpd3)oKvdokB`c^K=hgGSC38o^G2 z?GS8T7<;ZeWo3RJoZpDw>IZueY*PAOtHGKW*xA24CC^=o22W|cm2y*$GvKFi26su` z(;hx&-gmZdB-YIvGY6NLYsU+jhyU0zbF|rTd4gpSc|5q9bmf;fmY2HjMScPK-J-MI z5o)K6=Vg;%4}$%WV9UeU_&HG{@~dDo^A?9*z-GYa+H!bKG#h1c%!%}vQ~x5?li<5f zbZN@bMVp=+^T;t8#!%iw(Xt^ z*uwdgOa*0Fu$=QCIc4AQJV-CtHL!Xg;6S`S)+Wz`h(DQwbKm3iL7OrbU*+?6l<{et zeUQFcaWuR?x70N+g>%{C^w!(1c6%c|Gx5^H-M_eR{82l2RhUqxNWEvS4%vC)B6_yA zK+XXL4$ag98wFcRFr)Vl#thc)7dE?pwhT|B%d_w4@ksqvzZiRkNAE#QdptRQW-EIT zd*ECtNtk_v+G|4f6IfRd>?26qOoN?gGw(F%%MAt_Wz*IdgN{#D8U-&eL_KhrgYVxu zJ_CL=?cis&j_(6+AMW6jT|s+ge0I<3MCmU+bQ*l=GZSV#y20SJ!_jNmo)5(q13pnd z7qkwx1MF1^bm;K%_Uzhv#5Lv6kYla;ZkRZup_2L2vmHBK%H`UuoesjY-{m>@^mwFR z7T{TjN3S2Rh3iFL6k)nt*e8okl+w?ej&Ry!$J@8mCW3DU-&W?}TeprM0^h|;6|_x{ zY#l!jzVEpXesODf8OKXshFu+*FysD?YeW4pIPObb*CW4#d?(j-ZCHNewb?$fr8^R4 zeYH7^-FSU<3hWrzCneuLgEhW!YwN4_%kl5eOPE+z<1_ z*bUb`d%-sF(B(s-|9Z6kn_2hVFZ#ptOW~<{$7bT0Ew6hvz+HuLEN}=!o}aTD$S1T$ zvMV)b`4&m8iI_~xF$8Mg(*xJ+iyW@*D6Z+mA-JY-TbgS>T+Dh<)AI*2i)i{`r8FkAt0Z02w6DC$(&gICiTQ>U!d|jubVlPr3t8lEqq1&bGo#8s&lpeLOWd8Cp zM~{YFjzj68=Ra^HU!E{)1wC+>{>1ppTl8#a-giV^V7j+NTq|SDB-q)igi28{_EHc# zT7Fil?-kMbK5RkqUIRaJjFWf6b(_vxur<|6wN*RVi6C}5M(=6#7Hk*TienvY+4X^Z zCkmo%R&4`d5hkaucEzqk+ELaY3d2+eW)_G zgU!4)q5ceyJsHA2+mzY5CD6=zU0U)T1#7>~!7gtNy9jp1#g@G*pfg5pHXwuf>V78q zmK{qxcY>2|Ll8@6kHTtyBiLrJO?3{oCx|^%zJp*(Pjs+jLF}ROodvr9_WwyeF9fk{ zXc(RQ1NE$Zg6Nz)j{fj^2b;VhSXUch#V+f?w!I;t?v#9M4VD;uS8Br62TI=Q2Aijl z;zgdUyV55zVD^BY13w}7Rv&(tjyzWt=9sJUam+FHi4HSx)MXqU`g|ONIXVpbbr^K~ zNwS9i<>L4H@O=g0{QG$IsS`c3cIouZ2Jky}I{DA|@SDuPAN+ueKj_16B7dpF8Sv}i zbseVPt=mtx!6xfaIEr7*eCQ;n3^hKEO|&C$y-(T%$2=TG;+I?C@Wy;^zdf{%o7f$* zgx=N;=O}#kX-;f66v-D}tJ-pG*GN9e*WllFC)A5Y?}^BKLV83HozOLfyo*T>+;zrW^mm0*1G8D?0Rv{Dld1H^GVB9I3;u)Jm{i zZ;dIJoE;F(c{rC^6KY=SYEKL&&eZ$Z0MF}P62mD@UF@S0C)s(aW7m5lIYaglZ`Z=t z17Fo;3H1TdacMJr*4N|gL-=Myzbg`E|2Fxa=(gwh+zb(v9n;8Z%CNuVtcoSO%g=Z^(NE}lJ95? zwmUapvF&=W6F0J6B-s665A8>-<><~QZdC7y48u9z=ghAbBRRw4-qYF>k(UpY-jpzV zB5Pi`bJnvHTi6q6hI8e839~0sbE6xJ$hxYWFWzuZWDxA0n|c07>ay8jBiFMxxhEpA z;Q=@^dlF{@t~En4s}YZDfc@8veRv1>C!hae%_zZ z->tN3Z*j}()mP#j?AVx5JhU)w`e8HpG%ro+htD20`0SeeMcLrFJa|TR?I_tQz@GO7JS;t+<(P6`N+~iKm`yFQ;SG_-6R~xS5 z)`M*W`;h2gZm?nfH?xjA0M9Z!zZ9M(cyj${*yn9I)~AZpD*3GN0ua5H(dp@H`ZLjH z(%p1Q+>+;8MAOFwR+47UT6+@y`MVCsL=MNqMjR7x$a-=w9377&)KM~yujX)!G5a0M zoRylm(9`GrIr>aoX!MzZtL}S_KDGUBpLNSLSnP4+mT9oqj5)<8vo7|1XUyq^gfPc!_ z-<&j9)5pyi+T?m-Mg$&Oj2s^%M4GpPB$KdN5GaPZL<$s7slp} z!L!KMBHt-_wS?t2-iJ-%kUPOXEZFWacH{B8UYvQ6ZN~3WgAI>=n|aP<0G`Tiw%LbW z%+X=P@p}erBOg&46#dt8up5rw_GzrMfqh7@J3iuT>+C-AX2$PEcq&u28NVChIrR9k z-cW)OQjCJ@(#DY zH?99Z@GHFBSf7vR*gAd{ygI@y|JLy}yNU11-12V?pCRjR@a4~O%m2|Wl^?jCA5X%u z<9W8(2kn64(6+YaSfzu!%2^%kcw@h3vnc zf>fd?X4z!PlCg1sy!u~itDhH;*Hlbiqxt?tJb8{kA~U`r!kUIwY=>#Nq!qbZjd7By$h8MOZij90>09mCld)bo)TJ^SEjhPNNi^^&$3X+w_{_9{5&xNz@mFZ+%mI?Qwik=6U#EsU-x*n2=#i`#^>Jqz}AC(Qn)(})*n|}SH=X>$V=Qg4Sp3oX3p9{IByn9 zv|kLLtTlDD4mR0itGfg{?d6>_4*5@`Y;HyOze2zPt{04Xn0-mN0g6HXuCpIJENj+Gf48JIv#~!Uq-N zZAsdA0GnPvOSvJz|vCT7T_3#D8%#EK>+XuD{?8WfdZDDNuGip*FD`5A7 zT@Y-q!J0l3v3Fv9Drf6Nc1cA4+7{xW&pKoNNLYuB$NX-vgJ6@=u2Y^4p3h4h;#s$S z;M?wW#_jTvSi9WpxGlaX$vSe~=bZ7S%5Y}=XmETH`C8;#UHOKM<)ywlkncra#|7C~0zO{yT>@Kwx3exXnuFbNU1Y~aoR0xJ4Uau-u*R=#eqBWR zPCGp5dvHwR?^fW+^>^WYjo9byq)hwZn}+W?(Mx?g)OX~=-X_)w2U(TKuYk2bZ|iSJ z+I3(N)$g5Xyg895b>BGQ_&+*W?U=2njxSbdri5!U{tx_uiyzxMegu5a zy-xlMTgNYgFZ+UnPktu0pG4^|?Y5(pxa*7fPO0ZH@VV_Kk8k^il$a?G1C;P}!j~Mk z6-Tb<_c45dIaK1vm?5f7#=I%`%D!x?A0GkV!AL&lI>GZVU*F)_VbL-DM&hZ5ZFPhA zrlry7G6!{hG-hblI<~<#Kf`*o*nat)QGA@y2|UwnJsA~d^{E$GjN!b9$u_)sP%y*@HIbk#`Qsi&yMTy>jRSaj?1Vous3sU zk9&FN#J@KNOC#=I$KEi30x|#r4JF&-cJF`h+tNT?yyE`FZFp zJY~Oh=Ari8Zh!Rpihmv|{$L&Xe&ml9e^8EmZvBSWaqo>Dn%eaE-bkZ$Jn8T?|L^#u zUPj<+IAE*aac!5~%`&NFqt2o4QqYOCALelySYFS8CLJf)ux@|d}8 zxc~nl+72?BuNl6k-`eVN;cJfM3)xlTB{AbnoAl4U@Gbq0^=ILmfzOOH*fpV(d!Du= zFK{?@4%rOYC9tdiX{)`0J?LSL59bM;JnvjkCNJ#9Wnmpxt}3o%zWIAwy+}Ap$6UXq z5A(`_&cC@6j-4FuMPBl40n_>iTYXM2wFcwO9Rm5jJ~ChFpCfS0{E_uA;b?=y-@ei9 z67zPfj4sDP_=f-N#1ezPa!`pW5Lry{1j?zy!J5xb_gs}8_tY{vGHpkVn+wTPJ(3#MA_+k-F9^HeWP3Y z@KUMPx$-LfC0HnwT@}V|yx!3cwwe#3>h+FBgT)pkUw!`eQ0pCg!IwWH-|SONc=((+ zWGm|(Yf>IK^}fkexIDqJxQa4YzJ++`a7TV&V|l6T7Ub)Y@00pk4a>7Au5CGYUq-M) zVEe#6EZDLygxYE2vnX?5OP`r<_LJ%j*3@-&&0;fWQOe%R{1P6$Ueg!WVdM3hX0T0s zM26v2*&|`BXQPpJHVAeP*bfPIGK`InMWl^p!S*~WU)?R(g&eH6E`s6dad92_HRK-> z`E?^7uB$_xdl5fX-${EtJKwDDRDE$Xekyi-N8;`w_?nJz^s0j|W?sQ(fFjqO=fN+z z_|~oACB`m&8~&**U+sM!_0k(z9?lFT{RCeQ(G&^SVh7Pqz@Tc})16Ks3>$^R2pu@hg+B{vr9!csS#S#l5)s zUKq|dquZ+!e8WlkYFY3rAw2P#haU>!W2BzUW0OwxeR1?9v@NxRzz`D^MwzmH+ z#+y^~)whJR7|uh+9oIw~Y6b#+>iO+}vv^m&i80Ildb;ZvUD>IU^>{E=)e3j1DtIQ~ zsc6hsn7*C3bE(VWtk8{zDSv$H$jtj(-Pa)x5?__Z0)aRI)?4>~bJ z=~rXzVzV)WjLTKmV*ej<#a`Ra7Rk9c_BoYVJgk@b@tJB@p^ zNb0W>?#V$XhTI>nKmUGvU>ir<#~9dyU{8=Zd@i#7LVlSqqDPxtli1rDe2aHDeD*&_ zwa2FUq<=SbGrkSwt3OD+)rR==TvXSanTyKE7Feg$lhLLMcn0C={&>E6H`jKv;gQbG z*T}qmUAFDjq~wR(?Fr<%LixG-v7zyFTgYH5Kqwr!MSsS;8 z+`v^E3^HPK^LRJDTKJ;spEVGF{l7D& zTyvD87S7stao*;z0<~SrHD+|g&fGY}+gHc+F-`GiyVcTn3)DSQzBv!8&mqe? z%;m29PEIBxBR}Hv#=$K-v%u^Ht;dw3FR+)GNXL|;55FltQa|<$*ypng%$S*eAi93~ zg0|Eg$LrWq3!JTG1?r&GPjw7u@Z5Fc<1w643A+4nu05wf@v1?__DIfpS<&;iStE2Iov|?%YG{ zp|qF&^0ET;L;ci)!2O{5B&pCYRSvWi3tb0{~`9^XRoc{cM^OW4ZLhCa* zvmy8-hM9tMxTZiYQ+IY-q@LlJd1p*jWkko~_t2il7pV49__`zc!gB@dL(y(prV9Ew ztTs5CcNeJVOM9-waE9i;O_55T!s7C-=-j4_F-sZd$j?5Lwv+tIrlQ-fFW5(Z6q%pd zP#4aM_hJuc7npUWHaKJ2?%ZHQiR;soyK)^2$s4e7(eTL_+ym!2oKJCWcN#r)oX4XA zPN2u3W#_8Py+D{BY5Pg=jm^#&(SP@g;&j@~7$N>Vc_a1&pN=PnJ-$uF6ZK%#d2|+< z!5+)SZWK>Q{q6z31pZEm4;H{jjZdLIe^*R=Abq|A&ILH@E-f(c0BX7?iZdMF?}>50 zO>qzOi0;y!^?k%cmldclb8Qciml@;PoU!zz+&ewX85ZdmQr|sb>Mk!(ACtbj&(n|k zW?RLUMHo(XvJm71Z`$ilJF(9`uuVe+CiYREk187^!SU))u}|_Q`s+x6iG8{vIky!1 zNSxRT=kR9=Ozg7+r>U37*hg%70Qu$57N~BillHNwa)tfb5iwmiBYcbSm3^+joD=HZ z6yNt^Y#<|TR`ovkzC;|wwLJu%DUb9K!j{Y2s3me;y8~<;*h>UEYOrRl*(|v6#ZT>3 zWJkasuh%2L7wp8B3)HU!TX(Ooue)nU{yF(agHubrc4WR`br7E6uN0_{=Sls-liSb2 zeWE(1KJ*;A?q=HSs}A45|Bg@UcL2VzeFb_Q!rteV)AK>}qsThSfSmz53-$|AN7EkG zTet8nt~G@Z2uUB7zFfSAe)+Wmb)Rr7`Z*4Do`-#jz)HOF^AgXr!8z}89{k^PLaE1( zNqDR7FEDGdjbHHD1iEfw&bgxq&-LyM|_r)WdopVcnYrF;D`;7v#ZrTTDu6>32 zZ~UCQ0=^OWdU!F{2e`HyzwVY1d+_$M%=?d#TS9J|wrfw$YkR%joc(y!Tto-a;cx@_ zq;Dnu%PUm#l4tW|ung3To}_pO=B-Z$xwM;>AxPU(D_mtog=$o|_Q9pC7aOLBV=mr$ zckZk$I&Kgfoq)3)&U=M(I-c`_ph3pQBEo6EpYhApb2grHD|)uTd2m~y;*mkd^iVyz zbA#Y>vx%CR!>&t~sn2mZlZO?WXZw=h2)2#OIT#%G_QY_?d_&4E5AD=Hvrv6l;>Cs- z&XAsV45#QReZCpaOj)7gQ;fd4alz}KO%kpKuo!U=jP9k z?D8k2+Um)37{12$;g=-;)(2f%@nRwW_e7dw;vy->5m%k7Qj(&4g0`BlN;*V!kP`Sk)kt+y7cvxH~jyFMNrA7%H*KOG(@ z>JlRD9?A3)Qov@2`E&#p~FEZ54BF>Bo72U|oD_4S6?%ZTeuL`lIB%{%8Q(a`DgKK-$!#eG}@i}k% zcH#=KcL_HABUj&?IE4j?K$I)CFLhlHzWg=^-?0HcH-OOd=RM#D!Rxh<{T^O)H-{1U z%Cr~wlV3Z(lVDmuT&P~4>)6A@*h%J?^x3JNllXe%X{oN}W7H|fC|0GbF@>NJb{(TG zIz~0<|IA)T`5@~*w-=iI_NE`ZZQ|6cbw;)s%2fuvnvk#gNTK=e?!1wY?gQ3bICr{$ z_9a7bwB1o?)?-)T$o1)=ING{7dSNW1$HoKjr9X<#h2Kuk$G7ig!S;?MH}5 z;MCtku7dN>I^MpKj{Wc*9CG;PH^ujnI6l4RMcm-V&reNg;f zKiFBYU*Xyw2xGk!BvuCk&tC^N%7teRp6*W;Dz*w(X9)9L=b9@#@z0`5|0??^?F-Me z)ZG+3hi>03KNBJO^pTJKDe@70?VoNYpDjP*Aoa3LKCR@#C!&>|As^l1-hS10vlUbA zs~C>hd)sr>+E-N%5igH8bGkmm<6p;-6N-LcC4IUbOy<*$e;bX!g#4TIuVFC7pD9!i zh`#j;QS}mDt9eaiJi)$VlawF6-p>}Q1sTt}Bl%db48+HYxV;)43)6n3?qiIzcNMCa z%6LB?$(a+&jmIe2M>$2$K{)r_U8u&T-08=C<<{diXUv@A{PR9vrMqsXJD6hL*CU(< z;7otMP(5Eb8{yOqL^ILz18XIr=k##0p{IzloV6ckeG$$dN!b_udJ^lnbJ5T|rZQ%7 zu!LTE{R_^HFBGctM9+qQclFeMhb;>;7XB{ac%<6Q{0Hp77m4!(+vQ<%%lMS9mbCAR zE~E6#9iQO5!$hI_s+4gG&Ric5KKuTw$mS(riF*N(Q3J!33u)9#}Z3d4bv~b zS!m7+4;y^ezw^E$&sUV|al94zj&B#LjFf8%`9s%V+;(l7C_%Z7r5BO!L7vc1*~>=W@2f8L6*2CeowZ;qKFK^2o=)NE_(dq+_&I@K z+rX}ZZ4vB-ojKkU}%f&86z?SVVR9#|!`@tTv{`g8{E$y$nV7U&v%&^|Z zf?C84>{9C0{wMtNBhDNtxfCj2?i{HG`MH@wvk$QFL`eQJw;6Kw0mK(|fn5bVD*3J$ ztX5Qf5vsfU(7B;<^qQd9^?o?JzUSD*y2qKd>qERl$Nm)M0slVHX~!=^aiJw&MGR>T+qLIKX$;m4rke1p?bNjopi)-P6XByZ;Vor&l*{Yipa%}lewkD#yUnAFMd*}ZWsLz z{z~hw-@9;*csCi-5}$D2z98itM!s&LP;E;hzyH_K<(&@hV|T=yv6UE3I1j?P_8*1n z5yo%3_czg;!Sz$CBdWkV`O-Xm8TtJ*@#X>Mx?J09Ax^R9>{|Jkd|p|P*wtV}uRU-q z{i;xLJQn*~-i%&}|B6||62+uXEWo+rKb@Fs2u}Z)@9Sq)%(MMvpP{|Le^|!T=@^}Y zvaYC^B!8U=tNb>Cp*G;@X7OXhpZm@3>Y;SJ9{?Ob%J_)uC>=@WC!S;vqjXw`A zHs1qw5iI|3X2Q$Y#A`nL-0V0Y`piOB`Nu+ai*U|*oZdJPcP3P@$vcTJz&<3{<#1WD z4<$n8Kd5cif52u|3e`Tr+P`!AnwPJ2a!kV`ulqmvY4D?hZ}af~tGZZ#v-rOX71Lq% zN(?9MCpt;2q%Y+}PPoH}?%MFrWyS7sZ|fklxF9q>|z5}oBAo5cR97YC9EEQ+FR9)qeCiLnes$b%rp#Fqwi`1@+s-1}l1Qqr zh-|fyHL;~PCk@Znj*ZE?P5Qx(yIEJZld4Pj+WdU(yxEzH-{7kYGZ$AG@U7t2@{{IV zZ6A1ld+A5lod?DeZw?tX2c^if9ga~rN(qAW`*5mOqUUSmZ^+xjLocsFr_Ndz6L4C`_N$T_1>oG}nrM9m>`E(4m@knkP%eavNU;3(~IfqgS zo;Jq0y63>pb^{aXgq(45Bb@3Au)Sax!2XhJyUFA&i&~a-gS#B7=dpW{8$C9ut`{A< zO&*?ILoBC3vU@^%Bi8jZX8sS)%&Y0!!ZYmWamzYj)>!`HE2~)}(c@Ir7;*gZN%a8j zYwt7qdV0jH`J5fopb`|;Q0_iB=TAtgC8>k5KWFQY1s@rx{>7~`=lxEI>9S0M>#a+g z?@iQ!^ZYnvp-#MYGXKdW`lk4~dN|g=9|W)021-}mzUhr|o7rE~?SC)h-HA!_4$)!5 z;~Qtsbkz?BwSw&hn|yuJtSij_#Vxz&K+)sZ6~xy~f?WjrUTMpbzxvAW`MQu_NE{#I z>oOVmk{lc>&Lq_;*Y^0jTOSc?P^>Y8c8z4rmpNV|95Zl;@3hOFayh&@z1%nKmm|}Q ze9!Krx=Q3bjeNH5%$#8qnf=K0i_C0TrYEj?bv(WZwyZH}<_rhJ*!Vevv`yI;u`{r5 zl6;eY&ne4Bad9))39!EqY@NYo%jI_iY{WP&flAUk4}xtzBdJ)f=Zs<)>pe+=xVHm} zX;GKR&w@>!nN-J$O-z9G`b3;fSnrPVj*JyeG3jwj6ngA$9H;%s-;(@SHRPFbs(*y~N9c^QcAJg5_idL1n^Tve4W7O5T%zkF%wzqtk0@XZ(uYRC&YYc8H|z4N3MYQ> z`jf?@W|0$0}=Lao`@1y6Nab+(YV?=r~!MeeV0U;LRp zVeY%%ZIF6e=YGr8Ni{0>D+_{U^5wtTH5jq4rmy1f;H;CnAA-~CFFMBL+>tY9`mL`{ z^qi?l>p3X+Ym(|qf?xCF8N+m}+m>BYO}sZR80>1IHt{tJ@HDvZ3No{*1kTeY_XH#Vqf{=#^A(vBl|JYo7CqheEWNn z>J3sKb$&iwpV|H3occ5|{}TAscO}&%Ty{Hn>^9q9EpIK04(mUlfwYOU%URUge?!vj zxh)wy{Wt3`4zah=2EO9m%-=R==-IPBbC-N$>~3Yn^Jr$N8B~AKvjZ zHQ?94w|**V)_WH{Ja+9oTfsBGgYHoSjWaQ6_1Ec7;BJuqz4{C{UyWnR%KRDN6#-x$ zW}y9jC)nE0IAz{(czl`f@agQ7S!{Y7{DO<`0IzLY)(hU`*mRSghs`55_}QfT8yI`S zQ+<<%ZMe@BNh=P)PJCegJ*$Nvb==Z#DS!Av0e;x5jhqGxV60tg@J~v<=R^ zpLgQ+uCP8E&*4VEE`wcy%O3Fbq5honD&B$ufggp`ZYi0ynMLsZd{FI|f}aNO`G~l& z`04HY)&C22b8phT?{6_&#`t|Ov9~_3^w;^%m&T2CwrStY6#9HAY4(by!us&mp6vRDzcZNl7i`0Q zN%b1Bw*`as<_6-1-I)5}u)SsU+ToPoznoN02|j&<+kY?sadmnrGx46hfN50A*s%&O z{S{{&w8_J{v3&My{FC8)%{%RCzA14o>!62`?;h|`^|(|Rcn`&?G3(Gvg(ha`hjZ$| zr24)1;NG$*&hXyF*CKuJ&QzQ9BldVLI!s64z9Hi*fVE z>_yP__WtKY>lpk7PVDnQ(hj}wP5zYq0j}-(=eq4@+QIK{ZV9)8*=w2tIQDo_?G$~6 zz~{C@c(3W&7<29teTu)0J^jL2%Wv2b)W>g+p_d9UII1@Ajo^EpAodq~-0{31-dCP? z1dD^S47pEaqfR?XyH1ct#V?cQxz+mkJT}LO?}5{v#t*?cA=d+jGdpH@@8iX%#Gkzu z-5TLpc6BRzer)+StDD%|D4g|ACe@j`UzBgAjei=`FZ45LE5i4yr23ig4ZR?mFW4^< z&x$b`3G772`Ue?zf8*>s&c$#BpM5$lM#nbc8-g$MTZix9|Bg@W`T%^>|Cv;0Ntu%` z^p!a{hfG|U=d(-`^tOYq_zva!J$oFK*BT>r7W?Hf_^KXa{QR@yuckM{ z7yo>B6@0z$Ev!0Y|6qmgFWG*VJNAzwzlQu-VC|8xeC%?rjtiH;7XKw_&KHdttbZQg z?uJjHP)cITiv6tnfjvX=-51W+Kdc8rN}X>T*m|%!UYQGH{cLZz)*k4G#i(zd1 zK1x0E3t)@?AALx$_R*obrL=mikhe{2?9tJEHNbWB`kc)S?J=hL?m6L-UzUUTX* z6V@%hKBZg}U@O4hAmwTeV>kbN%Njhb@T^GR=z%A9>$lNeHxs)jByHICF#hMS zPW(R|);B)>ZwEU9w(@_HYFf&=xG5dC{A`T)NBa@RKl1stT(21&{e8pgi|HK53%(wF z_1~N|vdR~`<6d^2a)>puJ>UnyzenpQm-^a+-Wr$>$0w&;D@vH=cW~ zgKc@r@xM!9Y|#H!!(a71;ydJ@lDrNY`GB4HH-(YW_7A51?@3i5{jB08AwOh&!smzr z&Qtq8u(khid}m7-8}Bb~UlvU9_ld{B+$iOnh`{i)v>zku zXc;igsz~jW^38xT_LQB2@fxQ>Zw{toifYNL2i$C4k@{8&+_J&xb6w5ZDM{j#;^M;O z&fDHyh9&%LVmu_A1$d{Gz{n0{x%aY$Sid36m+g|GSQRW(E ztwl((XK0pk)>jBo&dW(8Bi;XhKz#JfBK3Evw_!hbXx$`Y9#a8k5BR~-B3X*Y&w-~7 z_5PN1owqX~_AriI<+G@38#(ndw+z(vF5V62On67Fz=U_2@@Bv;gKgYVr1n~12R*Er zYv~unxM$Js^9O-?^>G4@COE2Qv5)5$sUJ%I2jIx{9a<6JoHDU9GC_vKNXp>Zg2R7^Oo_ehv>Cpwuct{}43SS; zmD7f$uW;)xrwuo|-;jZG8P2*_;5(##_lG$B-xW+W<=B58w%Q=&{~_z6)wC;r+r7sG z+lW|D(|FH&Bu>l=It=angsUE|9=JwcRir*G`iw?#X@6ukb`rmjqSC%+8lKhTiquV_ z(*itxdl!pw*UgBAuP!q06<>Iz4g2q%F_T(-SG}j8^;?x zJvPr%0nZ>jHLopF7jkV69H;A8`$BKG7Te(7Byyd|>F;WeA?M{6>gS>TBThbB?+aH& z^;N+XR%FEA?)X>w zADq;quZ-RXEoJmiO!T@(9oXTMi&Q2bZ0T#F^$C0*HZd9blo;cv#IghM^*0omcgWYn zXLJ!OW_(Yal$WjWu4?3`kncFXNcT;9k0&pF7J2`C7-4=I`CS3izPm`}OMjV-)H&o6 zt;b^KJ(@4`W8&#X{ED=5`|(kA5aLU`F=j~AUT}Y4=b)Hu0J~>bQG#9Bm1vh+xE{AIe>}c|+EViyaSh+5D zE%LL-|4iy}&d7)CJG3Tbtw+@(O|NacAHIqOKd)QViaf2`=;)Wc`nh7tM!Zq_69YaNQ~qg(SNdf?ytB6zsrQO+Yl`Fz_oLI|;y~eBfUkA1NbMHB_DH@^ zJe8P>ag|*e_$q(O{OIFFisg4@@A31wAWME z*$m3VE2Qu6?lm>)yM>?nYbLFZG%~FBa9@7whKtO1nXY{DsefS0dcL&FJq~4Lr0lDo zbmY#Bma9Uho8R8OMdqClXZhq#Gp9+c1#jx5^WKa6$h}4CRQ|P(^U1$8Dg%_u@9?jEeKaOe1wRMG)%`xh#W7O_r@Ok7nLVgvOY%}KvkMiZWOXjlHfLji+ zj~Qeqkv&dyJHjXH@B2q(+fMk`!R&9_rew-&zsQF%{H=ceO2)F`E4Hau3;!E@vVQ*W zWcfv>Rxm?vMt>OxFYsY}Hk&xgcC*no%V(BUQzvyS?dPv!e?He|^AVfc59Z+8$VV`{ zefebj`4KKc+#xh4@Fyby>R22f5QSsLYkej-Go0<~+PyTh*clhemT6WdB$;(9QsvKXNdDk{oDee9uA2wUJ|KXNg zfNSlC9ms!^4b3PuWkmSTc61HZBtjLk-yO=@2}g--7zb1>NZDBX_qOmr61X* zE)n~>D+YUN*1kkP9`#n4k8k_`yuA&46xH=UK6wEa5|~9^jEb`As(~T~MGb>%KM2olz= z9-#dZb|w2R7rdLl%%lzV0|$>RXpjGVfQDsYE&KN_oXO#=1yX$y{-6(d9AVV5=eYPz z!r$hGp9J{&2L`BpzL`D3+vZbbi7*?_w-3-pQ1+L(;9Yu{<&0D%|0duB9vz_F$UdIx z!g0&rm)gg#0OyY1576S&K{t-m4m=iMHH31?9)S7R69d${`rPfXbt2P-R^x6w;NN_5 zfOcKFoY24LS#+s8a{=dHH$W@NK^@b2;eBC}HgQ%0C$M>d)(qR+tG=13INN};_%UCTqR=a+zb}e38iI-DeGgezN z)_b$nN_aB-k#7TSEZhk{N|`V2nO@e2BoCthz^VVs0PIBo=VBL5(zb+c48lJS_I&56>1Lcl)s z)&R8^oCbTLOSdWjchcJf)V_&Z&bDsNO46172fX&L0qPvn!7d)$@#N-IzPADA{&xmw zgDJ-^%w+#7KYqUrP5OHQyYk%u+BDj;f4N}Yy7GL|o)O1C5dO~`pm`4kPFF8Ds|MQD zh(449rz0~*^OC1~UF~q|mlI*A^{_jDvpy?Fot0VEGfq}9Iy^ODJb!oWdaT{>o1nykc`!^S^w5!VDk+6FK>pjwH&mYra zQ`<9QFysZ;Hqw2}1?%RC)B7}@7}u2pxA3SO^}dv7FSuka4YvTe_W<`B;9kXg7rJmQ zJ-)_5I~!N-P_tbftnX+`2E{I%G#QZoXMi2!&r$QLlU%Uwc3o}}2Rw1|55gS$m>l(P zmXR(Ti>K?;cp}bR;M5Il--6Awr7r8v z+kmrZbdL5g@Uxp;I8My%;7zsI6ufVMxBdqf-p_i%%j8%flZMSCc^p3k`gVMdI?on% z;R%oPEtF)tXag#NlQ-7V?}aWL%g$x~!LC8cdo|!Y0Dm>xbg>KGlD9pKY#k8$2b}s7 zbJV=;iS{GsUolXJAM$j?bGSeMQ) zDx$D5=Oo**67c+{-J;WTv`HS|=D2X(K35hbsm+YCGH=HJB3UoUoIh48AM4GWA$M8l zXP{)^SnU#Au!67v7c4Ch7MT|yH5LD{-hiO(!m--)vD$fKHBdkT<(I0p1@>Vlc*>iM z{(uk2e&oHR?{o81mOKMOoH4@?3(U&V4m%n+zwZU-E}zqQ;#2^~yF5q3C(RL?^n%mZ zUgcALe-Ci(Uy-9-$bNa*g>zwYO)aZ$(#No#4&Zb&=4hqFS?9u;>%z%N#rXy}??iI6 z3B+0D!g1A;`H9mUu>%FeVMBjt;VeEdoXdgpP1M4fd0;rJfn)qGM{7Wwo_&%F$K{)| z{G1J|Gdh&P4&XezF-I#S&X8VkKIors5=lb-m!E@peCOK6@`my=P^W3&*XaMX7zd6F4hBgI+Vfo#7g5 z?)JQ&i~}jR>^!XRcUm|n92ia^a0>h7YNZ_0x(mn6TXSkXi-7a6o~vESIw!ht#NIGg z>Fy7jfV11i>1LyP#(4!ei@dp76YKffr3cEc1=A~{3_OQmefh9lZH>$eTsUsI<=g8p zYMf32&OI08YIBc4JuNOAw+wC=?&urOYgGZK;Qn0gOO83W+^krT3mB9Fj)GWt7vp*s za?~7cE%ASmtH$h^=`zgRU{^+e@FrkOewnM@V}6_q*6{~flk8e3gIvsSUTMnJE+B7p zE_fxk-&wR%)=UDx(H_iI>s^<*aGbS<%oaCKRe<+Cl&ckUo-(s1_^jb>o|*t(@T*+y z48ps8yUXunw%awRet88rlOD;{#uMlFt~%U(`8&H7wYKCr3_7qjSH-R;xMJ62JMOY; zp{xo4U-(q6wi@Yd_q@i<*Ag2;_1z-iJPe#N;<)EAmQS}=6-a+IU^@USv2>k_A2)s1 zz6xW&9i+b{S3R@d?!v)bE0dwEGL^D#(FxeR=W?}!*w>G^V3Y0LXk(C{d`#v%TXVJR zDbuJ6-mUAKk}@UET;Qy4%T;Fv-R*VbT%0`pYYOspp&|&Un%OWZ!vRc_HskK2h80?ta%j3J%j5tEmzWg><_El5nRY@JW$HJ6& zG6?t|f0wKMf_$~O>QeS&rW>{vu>HDnwe5s;uU9D8D{NTu@i1VU0NY5|u#2wUPi(TK z+mz`mfbRtSv262YE_j#TW$sAgunx~iO?zJ(sNN6coNT3k5EzBX+P+L}VZ|8(F$wMOxX3trYJsOd^rqr z>I9CFp{uipt3F89;l_D76=%$muor!Gb)G)w!ya)mKTq<8DzpmVl&#UVlabDz=)%E0 z|JdGoz$|Ui)gJ6|E*Q1mi8sQH-M)dTB z*s*nz&m*vQa}$8eX$UB@GSHl;HuV$>@{L{?PNP+_iE^9BlZ-Z zbq&T=u=T;%T^`;=f_|?NS?bR-+DrVtN@$*etbE=TG|Js9eBpCU^i2S{4*v|KKq}Tfcgl@0*8@M*bjs^QFujPe9 ze46>jxB*ZHp=CsC^Nn!3*Zg&MA7FlqM(0MtWuUKW0p>G8Z4-qZjC|fTY!T{ku+g^8 zuIikHUTd*8p#L6=E8u}B1YxV>q5BozRhNb>8YLXFM zz7qGS=JFE#smJ~N%qSA;{Wl^Jt@qQkqp(8v*89tm)<;1NOQO&CD+w5V*uRKykNbHH zhz#xqF2a!a7=b4w!6_^JIR zk<0ysC15!hH<3mDNgyG*5?!w<0)reZ1~?1^!OULVn16a98w%NO#FqLi$9=xZ$Go53 znW>rEf0M1XRN!{Ahj|NdE0X#Y+XkhP?dGpo4ykFIQJrQ^vCD^1hR-q&f1$QO=6MU+ zwZKejCwJS3VMOZvl~fYsRoQv5$(hWr#eG}7KZHw$S;RW10IH6EuCaJ{4m^P9)Y9`P zX_D2wcL*undyn82>4VSr;b*!RKa;i6_Q?gLQyQ6Eh%|Kt>1zz6sr%3a)C``KZM$)fQZ#b>C#&bFdOmxA4|VJteRxAd)A*uq?b;W0k%P^xH?8~CxChrB)P@co&zc8XHB)B|j4cDh)+0Kp zkAiut8OmNa%;>+fp;pKc-3mtjV?bj9B-`+L^#}v%Yv6{T!_v&_9!Z6L#@{H!*ZbGF z5!N~gXQU#4*iMv9Z|KtNkHkVv5LI;`qcq&+OB|$+ERkeEY1g0i`V5qpMsM6rHu6fN zx0;HD4}R@t0RWu{ec(qa1+zW16FrfA9*EtZN~!lgE8Ht_$9G+)IN3k?8Hyq&M!v z$>aVuu9YO32#-Ie*=zh`nv&!nNON8zc^jF)AIsT|{9~HR#J|boS|^WtY24=v+QYM< z$Qc<%8a2t$-We5X^(la7aj%0mslmj>zS=T6+RV#5ZBI{Q30?;)Iv`Gqo zwnhrWYo##g_kqYpmDMU)meNPU9oB8Dpoe!_w-g@y&Mxbg^26Z%@& zfi=TZqi-fhn+Rx5c{p1$m*b~}x5|bdgO6KU>x+baNFpcS&WWA{U)~B6BCfYBypgQIH;N;Uz_os7-nASkba2@yYm)#2DiSUr zrO2v6Ttdx6%c}W7sClgcL=j6#EWjFx7a3foZW}45J*^2Jb@KflwCtsRw89Sa+}C*HPSXKO-O^4 zAbfV&bl5@mY7jo#TS~Kyo9Qt>{IGO5eY8&>83HTX^a=0j_1tit9zC@*{2dJEPmx<1 z?Q4|_TPu*IH@*nwjF^$Jw^V;(5aSoijz`0tz&D~%jcwoZkIZo|Ef}khtS5QRnDCeC zQPJ^UBm7);(ZmfL7d43m$@0>0yJvdC=QXFsZ|Lgk+FRN+sAhy?QD?-nwFUC$(3?E& za|=bU4*-K)G@;(o*tMQS_JWn4t~8>Pv329r&xrDUwxaQM7-Zoe@z->%=G|cQv3y7^ zIPtMOTxy_!OZ`6cu%BZXMP)Rc6B%!oc5M$v1dd*tHHn*R*!Epl7x`q4`G}dV#h+wO zH*L#~XQNuN)THk<|Av?Sf_??6B&8rS%W87bv&=E)y`OCjBmgxRAWH=&zXF#2R5%~C zMZ$aWt9#XejfD$v*A~72pva7RST;CHV(5`P+|hXQE+S(M`X0hvTlgCyqz>oSlQOjW z*6JR{OuzUU0Efbw&*V~w>sTpoZ}|!9v4Vd!UQrRFp|&t*BdmdUc9&XXv<*5RgqAW6 z5N|z&^x&-xWH6L1!xd@|OtBpyNl^a-NSTi;6B!yLY}t-7q@n-O$I8H{<*yu0?beG0V(`iUuPXE_=)irLkhiS-cSf zllfBDu(w~=ZS4z2*Ku%QXjY$sNskX{gdPb`Y1g*t6ZTXeH7z>nJ%irqBUA+M^q$K* zt-%mV{MCrA{u|qHY0u?W!-HEdg9A_%64$Fnx8G0fSx zv3wh~dQQ>YqIpI0i!PqGl|c!#C+H6VD>sO_m5(E#5S#>~_e;b+IRfHp?obkWEf~GW zFG>KYJV3?geGbcGsoUN)K1bcOuSScS1pw6Y@rgcdllB{*X5O~~D>fgn(gVWDBhD4X zVTePV-MHHIa75YlFkjUpIOB*@&pZ!)lvdx4J@Le1mBBWcHO#nFWmEvnyqp>5!ll&s zTJma8_1X2hmI$EfW>@ay*{t)KY8LGE>#UT3Jg8u4bMBi~j|@$Jd~VGMl!>bX64=FS3xc znUWKA4MzTLj`}IQ(UH>Fc8p)Wp6}?07rQcsFoR!HAT@jHR#Y0#V6iNI5b6J1(T7!< z4*K`wE@_!qQ_g*mPJ;lU?bVntBl;M|5CjImn#DpC)u$xRFrrKSRcg}r>gsHT9& z3j%Ou=4NEOu@FSWIO+Y#Zh%L=HS2iYyY^DMEMZ5dcz*-F zGWCX+J|3honXNaR`pFXa|}9OVanlv;k`XHI!L%RiCwq6=o0g_c!i z)tnGoR*_XRDzvOTtLA9-QMf(NJmN+V<_c4Mj5r2i5d{;rZJs$r^SdhYtkhN`veky@ zM+lfUBl5Ocy%bG5ZJE1i(jL}lM84KHOdS{Q%+l-cK#Rhi+0|!+JNxJj9k>fMa}tq- zu`M@^>gFz7j94Akn`)>f#bspa79(0$jtUdin9UJR=An`}DpXgQ&8bFRm07M(YKbEA zP(YB)XmLQIs8awHFrWK7q8iM_r1qMl5STYHrG50tt} zpmItM9<$vp>5;dORw>?SC||mHAoM4>zfi_bk6w%!%XMDNiqMJNrzs78n^8S97<;4% z(kShE(fs3unHaL~CH7zrNr4`XaHJ1I*W!rmC21m&}@3rf*n5{lSJqAAJQMx-}wS zW2dAs(??4|WigL5kQ)uNVo`%S6!6B}_y+pn8r)GG&9A1Wf}Lc8{fJ=4*wkK51EcK` zYF7gc<{<=H)E36d)U2e!TzEIy6J1=(Sp2kLw62PQxNgnQ4Lmp?+HUGH5KfFpD|G~M39C&C;-qeZC_|OKqaQ`|SY4(08~9MCMMI=TeOa-`eBowm zSS&W!ut8{8nKHxwSt*Xjd}|4n-t{N;uZ2sLSv8}L$k#A?h2|qP<|0%ai)z z0g%}Wh6>_Spumc0TfajsOUbj|u$;Oie3zO3rk+O^!(6Mz=c~qd-bKL|=W)2600r|F z@o7e_bkw%QKrXgG$4bNBWK<6+jrJ2Yd7s1U$=4v$-FEBX;p)7OR=E@-{!>zSDT;J| zHy)}5YO9C7q4P3?OvB9)H%V_zZ+NE$227+~Gl`a|@Wz3#JK*b!Hxqej>qCm)9o2ub zdByCw%j`>D-$`N7%tVc(_I?e_#M)ZROgR2$1#JKXQidL=sl@UnZnI$alWyZke9omu zqus4>_ufe-|1>CQ2?$C?6~=kWsG1+Y9#Ag5>D?)Gqkn3WK3kN>7X5vRv?!?$KGESC z=t8K4k#trKM|-(>TCofl@!{jp`+3RU*B7kZNB_TS^}nbk`=3ru&F@|P9sg;}Zk8Ah z`a2jGEQw;f{!$1e-#iJdB9|R~G&(xPXjx_TL;c*r{TZd3(%-|$ z+dJkPH>MhY3=#G(hStOA3flf9*e|2q-zat;vA{R8DUC2Ku&6q%6K~9|uW*or>HVDo z-k7K1%j+muZ5IqTmT%>aZKNWp=wmUlV$%?^A!2^2Ms zRx2do3a*4C>(&VAy~Y>2s)j6PEJ?*wl!;ip^vlCZ8ik(E9+2xrW!o3%hFQ1-M3w3mrF6Xl~g>i4+$&Sq0|U zzf%^)`A$~88GV^;m;Say5MK>i=rax+f5y8eo`$8)Dz!x z&xbIsV{NDL$8tX1yZ4=!dg4r`WwLwC7MhjWq&tN_WBFr+a&AGb23VS)`Uuq& zL0w7?tbuVOxTdIKjZJo7%Vka&=S%4zGqS!7FXDgq*AHU?<3Ms*$J*G zmJq^@_vXiM`wQno4~ykF4wk3ZtoR!1R#D}PX%3YywzcF^60-&kNCjNu>EJKBaLNJ^ zv%;O?;F`w+iGmx3Mk$DN9&_A0=2|?O@9wnx|8)??LpLM^uH@~5q+uxFYxB*~SBcp# z5J{uv!tRomnu`U3lYv4=noNaAe2R-W?GcafARbjSszP%I$42xQUW~=*(am|hG;~#; z#E>sn>>bx%->W|A?C7L_^|t<+j}^wmUrVDKIHK7_Ba(*M?hh5jeYe7vv9iq$KR6bZ z2Q$fW0yEiHU-1O`4HAH7qkrd;>bz_B zC)GKBRZ^XaYl>9Q!*~Z%h0v42{pm^D&HK@l^T&b@x1M~40qfY*gE5Q?lzqtK$~xyK z550yC2ye6R8Fs|kfw(5lOH}ao59-$G^3^S>%PY@Cm(zut_g$+d4A7dz*kDOqW3Es+ zDZEsY7wD#WT{)c1MdoD+#`bTv4sdC~(g8plCN?3p_%B(_i3%a!q8N(*PF+(f$zmnY z$2wry4c8m!?5)O|PyDqXG?n!Jd5y4b<1eHNZ2dDd<`T1A6>%Iq@CsUVviS#Bi_MB^2Y|+}QP{)m_b--wTf)I*cm=lMQbQ$r3*-JP= zi($;^o0?3=m*0lz+f1xk|QN~^&v>&@D*}rc#&k3kN5zwU|aD?+MKQY!a%dK3Ab>F;%((fe( zq-mwlxF)ibY0fWXOK0+OE>v9%RL4LPhz2qVgH>DeJe6(#$-3;PPwTo;LIq|AHTlRu0K`Rl}4BFs95z! zrO`8!Ec`r#QTI3CdbxUYDyCN+!5i$XZ&~;wdd8n8_?AALLVW=3KC+aCwL_S>NdQ0` zl+UVhny#+EDL0QqQCsnR>@@-q-EOC70gGt=R-h%K+TjpVY<+FA^@&C1&#qF|@4xS! zUoSg=?pZECs(Wl%S5sT_%>^(!WSFDu>;)KQUa%qx$MI`W-Q;LCSiX|l*6;ut5Nh6y zUs>bbB?&5-nDHeSi;^`V*Y0EbO`3{si(;Z)dv4|QA`Td>XtROegb#gCwAqIwCCw#W z_JpO4PXYYw=y(~lhn^i>dQ!5?j%M!xh#k$c1FX4ElMqyDm&#I2p2dI_<<^X*FiyW> zAiBFwt=|c&6O*jk@i3P9>dKPb9RdjAW&qc0zcSS%!u%KrL^2n1feBVrS*St@LE>-U z0t;nZYHPf!`E#Qh=G8}HY8kLhTcKmx>_-0*_{x+A%$E`DgNvfJ+ath*EZQMbn#7t8 zTP`r=b}_ae`qPr4QvS4DnZqp zU|8!26Tj{1!bJ5Z3IP_qxYCGH>@}Aqt^@c^ORlFtt{0;eYp_x}IdLvZTdmS-QCfuF zuHcgkSO_?IF&0bfDicTBl`QzGtE(-{O=DLT^gXr8pO}5XU8t@|t46nXTMRYpIC_g5 zeMQY{t(uQO&Db_w$6;kvzH#veSdAuRBpw3f8Viz(mOlq%2O*(WKLQYKc)Sj$w!o)} zw0Y+TU0v~NWN=8FfFFzLL@v@vDOrP*E2vc}IGzj^d*wgh;-5;Nd#PJnl)k`t6j)qR zf3b5auKBcX`uq0HN&O8g{asMhe)~Ae)vdu;&{BIj(BLFM4?27&2vUb{yu{|pv1e2B zIL#goYgXMCW^Ghrx`9cS`N2C~UE;!h=9WpQG+OL+7FWFHN3FE}6J;WJIP!52XZU6s zKegGSxQgeoR*OT(l?=Q(QrUzLD+bCIKjRxW;UAMQ;C^etZ3mngy-e2}eplEkF$!+K zK^(6{EqeXK6i)hZxaTGr4oxoYxDKipFkDMK^EZmAErk}XbiqvpT&)}Kl#L-&kvI}? zwjG*?e#Ekt1Opp|8D+^PWhs3bhUyWJ<||LCH_W9H+MQ-?S1xn-boagS%g82iD~A&msl}?+EK+B3AK}Wn0bpTNemW=)md%(X0$M_ z808#5R`hS*qQrOWe5g?g5H0E1<5BEuKYfLqN)r3J+GSt=iUy%xWxDJ}7cUWovdm4* zjfQ1k7vdOZ;vA@kWi0i2PO+dKH=tW>gSlYw?P!TllOBB9!OBhnu@l z;tp_Un_xdjW-T?{F~fR&rQ9o1d>+%5Db9Kirg$1M(4C2V{8-czePm}3!js)Ymkr)h zvyT=&j6$}MHn?$aa?o(Rz@Lr^w|>jOZN-Odfb{q-^ms`82;w<*xwFy#yxhnj(Hl62 zhf*8ngXcR#M6drfbD^4+cF@ZcX8veqTT9ejbSyBxeg+Xa_x%ks;4Wq0Szx|}QqZxK z`GkBmP@6zq1}b$0le$n{nHs3&<_N__g*{L!-2-(<+CW{lIcbQkUD9H~tU{f{Ok8Om zJ3nQ>;fSIdaF?06C{eqtTxfQhb)+!vXS1xeXZMPHZc2mZABP5IDeSZ%`mblz5dGUl z7@`l%vxlhauN4)RJ*K}zoG1RWpqsz^{o$z6@Q5(5N+ucZRuct=ncQX#hTUW4L_0_`T&&F;{y3qnbmUaTAi?fB@iP? zfiDQj0$x_l+4lUf2!=DeW}*=j7;~aJuTAY^A7g_`EG=;l2IX?|1(O4;&QP}fn`1;P z1CEmpm=Sh?<9j%nO*3V+H@MWIByqaxpITOTv5VE2=772Ogv@4VjEfzg`TiU!=gF!z z+b&ytUEZCqkDF0#cUSlR^-2+5!fOW2)u5Q{45X6&E&%ps(dXfy4yO4}KtQlPj@9Mj z8kA+J%j#Awz7}n-Ow0#d6V`!=d;(y~lNPk*jKta2Z1=Kmaw-F7hGpjQW^Y8e4}glx z{<-b%(EyeRkz0zg-G3+usx1byFAClE*PRA)c4)(Bw>dT1eSGnw5P1`-P2B4;wTyNV z;X2W71Auk{D1M#G#5Vl{CYJV>-E$;<>;`nVtyfg-!?qeIv~BB{+3wMj?oY3$^OEtB zpY20ubB3zd&tY!55`KD}_|rVqFM7jzk*wPLoSiG1f`?GrE^+G(|6~&r_;L6Ay|}06 zd6~eD&(%X)2^W4=a_cJNkMb6>#)a;8YN&Y)lA5fqEA>|E>x^qu5LN~j+rm^d7ZWv? zB(4FOCS+2drlKR}x%8x zh1DMQyo4Pd`xg;N%}Ntf6K6xOlFg}J;%dr5bKUv2Td{d9aq(Jcu2SU*AMKX-mQ#gX z3fm8@bF=-QBf7DD+aCy^Rw}uE#+6Fz8IL6kmCL#KJgCw!s4dx_h!uGPr}|Kgprfq7 z1BTpQL&xhR&`f73Y0p;ne`wj#Ue2pti=)=|X;iKX^|01&h?e`~4?9}vI~Kg;V6m$aY3pH9+(W!{7Kn-dgR`W(Ld$$w zb;edpQePw`H3Z-Qv-l0U#%I6+?!JEa_EkxKANs~#zgrGmx6sr0mEs=wy&J^H@6Bay ze#ws^>$$CI zJiOJXh}Jx2j|-|Zj+---PKE7$MDEo}rJ>KxfEt9)OR9mAr_5h-^%Wk72Ccy^`D&NH z{iG*<8wN$U*L)Q~^qLO~usu`NL-*ib58tUsRL1Lg>v&DQVK(k<&xvP^*4dtuyCE`~ zok4aGD(vPx^#;DkD1L&XnuiOzKyS!E!m!NP3;h7Vz#G-(+W@<9Zv)^h;F|2E0>Gir z;sR)dRO0t23J$<8TmV-BAaNtmtNL0Dgj}T;V*9Kud_9WXZvXnkEkG#48aOzvnQ1dK z7w;u+3!jT@H*iS;lTMqt8fR`V=OL3zuxf4}!pxd_xR1Gg`+|Lh0gs|EEex<@jsu+A z=Xu$N<>15JhW}x1f81-Xxjm06S=19pCytOikym1vq(#t){)y~FW^Xh9_AB<)eiYi# z>77CMSf`be{laKJSl20h#tTcA%RE{&0WF%Ltg z!KKmJUgW54ugR!H?Q6ks@)$j~!iwIK$l6B8wGhlh0Ly47gUmSgW@;`wdA7`5!jQCm zo*&zTA>7I=zfjHc1Li4{#iC#up_b#y=oRc0Q>>xP%yzp=T3vc zdTBa#-Cx8H&KGz04~`#>|NAoW5lL^dV+Z%AD=DeN;DD!Fo?^1&R_4T;frEfjL-V3b z0_-VlDNHpaVuvZ@?(%AYfTy;pSGnCr^Bit1x%Q81VgBm-S{9~$BRWAk=Lp)=m~7sf z^YNG$!WfoG#KdEZyfKe?j7oPi3fDE^UK9ova1GLG?l2TQ1f$L6Bo>WU@)GF?j_Ncv zJ@%;jGrss|aKe{*{g=Qgjr_HA%SYL=ReLB;7(36CBP$R4y?Xsi1he*h-^ZS>s^+(s za=#ak@S_xVbT=+e)G6~J>j2%mXHg4e?GcKg*FOb7@Y{q7I$ECevp0>$I-AD1c<+@} zKVMn0#My6Fb&q4+ZyV7ps@8Dmj0cZKWF?z2z<%*L>02HdbNvmFnMi|`ro`6OKM4Shw zKF`08_FMugY)^3^+3}%4fmB`s0B9?|$=TqxQ!3(W0jt3?t{z~%5} zj|%n5n*Au$)(S`~CK57VdlSc(5N9Z%d^w~?q1+7w5sEsH5gr3059T>YubhfOdOY}2 z@mXk@ft^ePg9oF=j&LmqQU({4*fOyBIUxC;;NoWp76|_<`F}E3)%`}XT{q>D z951rJr{aa%!HqrTK)k>>TjB*n#S3L--_u3O%Q~$mub+h>^GjfvKgEw* zIVcb7yfVf_Atwnqxu&lu!R!}$hG~!1#|KL&2VpqJ_c&^3u9^e!D(@qEkjnFzOI0?^ zf$|{gkW$X>fuQd4I<&jb{fZor2;Pr)!-W`&hVsOKrFkTPp0Qhst2 zgCgV+uMqO3Pr?DD*e!a)=|~xP!w6AceHc$Gk3k9#{@@p`e3#rbshdB_&1!W+s}H<# zT+D&0stRV&uRq8{w3!T{y7(&IT2`Wk{J2BttN^zt>%TACjdZ`Q_*=yDR=mOE}y}c61-Hzi+lzIMF_?` zNb_L(5O;ia0PhzuE<|8}Lr&{75TN34vP)vnHtTtzV*rB8POzi6xEx$S2lgVvi5z)j zCLSc@x)9PfDVak%^X50o1z@!Wz$4#HNUKQaSyi~!RmgZ$6*i$T)O;Ek)2eySTVgJ- zOA+4IS+_(&Jbd!;t=&@ z@XFe#YopAGgkXzo#X->8oK&1A23VVwmiB-?JKTI8krM!uecMPt4^5!;cu)6U?gO5Z zz0AkV)Db2eyuz~AI;;O`N>z7dR9}>+K^3Wr@Rtix6rlqEO^}f4>-DP8R)nWem{f#& zQD{+??Twxl;d($>ionR_ywhQZ^8#rWSnMxf_X-2-q1g?0_SaYNEdz!aV1ovjvt;W5 z>-b~G&>n;U0DHiLIt_aCXt8l|NlmgpF>;VcpUt#O@7qLve%Zj?E&Qmn=IS})@=eTv+tRbyN>1Gdl zl9M_q=K1DO^8l1;di^J45Kmjc7bw`f0ULi)+F-SArQB2jp8Uy;Fk5poD3TxZ+LNVa zY%^PSDG0K~Y}o}^06_De)I5+)k+)`uBk>)@{>hb0u08r(==loW zTHybQp!XL@TEapLl9n)lv>HQIfIm~R9N$@Nw$S%H>1n-`fbQhYNITtnuj@H)IMrP9Y9zm z74|yw>xp;;(Q+WhA9NV9bqFU)YDl8vDBb6wR(Q!fvVM+Shox{?@z4` z0Te2va+t?Ii*43YbIWNW53Z-++2NtnW4~{L1o^;A?!lRObI-pM@9kHep2ONRRJnI` zdH?{}%S}-y8upt`g<(Gv9LW5F&rkgC>!By3uJrZL2VU)YJ+wby$;Zd1a6L2`&&%t{ zB%T+oRNENJotP&dLG@g>6H>Ab1P4Jfyk9>ZWpsJQvu;X;9?lIL6X`bi)O13Lqu`Zy%zwNCNFk%Hw0szm-F zNzkwckTP#QK@6*bG=~o(e>7eUwpIUJ)Dr(ED#knlHNkQGTW;2>8n0;1rr1bQPq-hz>E0SFA{5uQbxethRB12Qw zKMx>2Uo+kECwZV?s|%?m{Ye8rAlCx)p7}Z!bvZKtfbG9LR@DdQzY6X8G*^8jk*seR zKrj~N4Np|$y$nh$C(y~X6YeL1loSIh6|{T6A|dIjyhtlowH;8YuWfQExVVZV;!lEv zGP?WjCA~oo7g!28=O+-}E#}BmY>OR|MzvO71qN&lnP+yLjM#Yz$R{SKI%+Mj1xb~} zqlmizrpos*2Fee`_S*pSagrpottePXa=n7|sIGo|hsy1WV%l4^PCgP+vimd7_1>&~ z%6i!}Th{w}Mb?FYN|iOO*GVVJGL5x9v>URv*Q*fF_i{c_2PJ!b?&y#H%k`m`&W6fj znPk(r9@mFfY=jz-1vw9YANaA4Tk%OaBYhvc9@Ol~_C)MWuCcJ~cQx2kgpue2T3w}f z=KxFMW7=7>tXYos($?4-y4nFf8lZUR2*|>GZiP(b>{r8Lo=0;%3lLprq4Rko1&s&Y zK(1yKrTk(6pEr`-b;ZGs(j-|0Sp6Cr7f_|YLn+aI0yMR7Wc7~+R@d&IK(FTwt^>N= zKdU~p&l~gyF52K6@<=;xAjLhbB_0K0?5_b1FXC_I{PBuHYm=AjxxMrAHU^E&Pxup? zp9!)t+bcg(+yg&%gBba_`2<@wE`IW{yS;z;%y98j+-dVO3b^}_j}-U7Po~As`(xAj zG2}c(qg$U>u?p+>ARim-rqAoAQlCS>$*Q3~*QV(+6_ZLzeQrWp>C3Ia5`Er?EHku` z`rPfU5*GrfEo?nCW}o8F8*WP1WI?1FD^PWaqvlxZV_&opELW;pJuZUQQI9uJny*UV zpQ3d5rQ<1=k!6i9D}F}aa9yEReIobd_;!g=cr}1g%J`#7q zsF(6<9S!;24uk`e-)%qaL4E_D|K9RDuUO<)XlWW_`GBK;MmPPFoK*cQiynyl-ao6G z{AR=UL;vzE{WEYJ8v3_%4CJ>2KURQcv5?e1iv@ERBtiLwMnQg4fN((ayYxpr$nQmL z8hlUvI|%K<`28Q`=S4gAKYkxA>L$N~KTeUK2WPY(zezuU{7%Ks{^YkhqU0CIhy3~i z!7V?vpB-8@CY$fbTb#a;Gy>efhE$nHPXP1k{arLv4ClosDRb<4ELd@)q9QeABpl2f zyYSiLz(RO*l7*yy@bb~W)9A!=L4UGs=iv)GfzSMWnBn8?Jup5==Tjc17IRg3V?&<# z7G@aM8yjwT0z$JDcz%2pPT8sRSg?S%HuB8Bt)Q9|yFE$y-4vbmvMN5)l>4v-0 z)!cNs4N1D@)gZ{Wop&tSmgjC8yPfv>|6skO&zarVOSa(2LA0RT`LWl}Pz-H31_8nU zQT+{|nZ9201a_=@s{cZ({vy_I#m+c6VIP4$4aLca^lg6@=?w4AqVI=Xc?w*;-^qww z+!c&2!T&39xY=>|U-aPczcBxCdbYMXkFlBuKTek`U%m~6cu%Y2zwJ2T3-i%*G;=j_ z7(s;m1MTOBO@B3XDpuzSP1LHrhV^EjVdgb(H3>9My%DO9d3rrfPMudCR96RqcxWVG zXn6V|!8PP(uoB2G z9}`x{Z>}Hmn~fhOKbwW5{45sCjgSQ8S8*idcPtPNNPcI*D|U3wdPn!Ncg0n*|{WIwV$C@LKhWrl3&;InU7WGnoJ|E<_=cogeUuI(u@_QDu z>hCGPCky{q{aYJ45c!>rdeY?g9=LYt-x?ST$nVV~A-~t~vp@YSM7@;X?js<-Ujv~h z{ll8t({Ka)3mM}+#@uits?iMH*uvp992?OYHAisDh}}2KHzmq3C-p?Og#VEh{<51Z zDu)}Y!vBi>yP^wD-G?ihfWn?#(a3Z(b0Bi)ivDxBwdi3)ILZl2*2Ia~A~ zr(A=`JW_S5&Hv@Y zWyu0_e08P_ALx>Y#Zo;gC<_F=r`PhHn?`_K$RcOQo5AR*`+LXVKS%H99e>yVy)T5W zR!wB}!@Ha#%6jQV`m^*~SER@wq4q3Y*e``#*c6J;yaQ+y%4dh66`PL02>Ankk_s>J z9o~Kkaer-a!0NxVg&7E$&ZPf?q!^JajYcY5q8t~rp}=X3d*#Fh|l&C!Q5y`l-} z((u1S{MZ^^lZOvp@I{n(Ex}U1$2_(HvXImWrmRK}R$c5<$FUD0|KV-wj#~-}AyJRF z_8nn%9j?Z;b=?0yct{7Y=ZjmpZYjQi*KCo;Ot!cK0LjK8Wyd#M=9HKFFT@rUxhwp#hhV$-!u0E8JUMGk5ho$)BlA5@*oCH(!mi3~4U&`TZM_W~B@?$_M4O4-r z!-K7l{zuWB-Q&S|aEx1^wr<`mccfcQX5LH;L<|`1*>eI`F%3Fr8M%*1l5x zQnG8`K}q5{SJx&#iRDOKb?qiVrt;);u1j7LKg+fZ<9Cm$ei>1%T?8H%4J5bWE>}fm zD^-l5=-p~Qijb#qsXSp@syT%x(+dD%cMijd-<&5SzL)WHg3JE-IDU?> zhl#R(va`&6DYJPj6yx>M=qakt?YA?g4U!)N$`%0M#_04p-<_G9gSrn)UrLnj2d1Z~ z?DTc6@haOO7dpm^deOz4_z2{?5BcNRUr;m!JL=q^)ZG=4Y0wi?UZ zIY{F_{zX@p$bjuPU*r5~U#CkhklNSTS`J&0)bcs;LX_HVwEW2d#3Sb&wV!z8AFn3k z5%(_6O|^Dk%Ex?;#HfOj_!BBG{?=h73S-9soq@YfPpiYFKq$@{3 zp4M9zuNvbPwRbVhpDpThP{c2Ol*MQLTnUi+JJX6+g3&X(M=Gu;rEFF*N~s^Z|0pHI zw|7gFawAhcMk$Myh%nNll*vHAVSx*WS+fsUTy`2TD54t5kPU5w%RhBZ7# z%CPl-ifedUChF7CcCXr>CPK`G@8^A3bEJhm*o|#&1w4((V}tpo`8P{PeNg(vTYMkv zHhhob#p*wDc}@8EkY6ooxB+bZ%Pbw5)?9Zy;r8DrGKk2L^J)8k-+LigVf^5jAnPL> zc4Vad^g*r$CQT6ZaW~|_SpfBOB=_0lU;LEg(e~E1^8IBLl+R_aT#kGLiY!}IJ6P<=^p3+BbM{h4U)fOcPxi{yUh{jZv=~kzJ(|{#$*S8J}%l4&sA(K9#Rx~es@V@ZbnIC zNd_S^6Gs+>{sGA6Lt8#NC=mM7Ub0ov7|almOn_vSW`Lh1-f^wUkDv?Z!HwAd%ZR)z zA$&hPK<(votrMPGatz*I;R$A77vYVrVOf`BC}zApJ#woQ@GjK$V)`n) zRsOQdw&F_FV<;#G@d_iV850{#l;1d!A0Etz^JxZx>KpKqRgeHtpAh9+Ri~9Dwu4hF zP`FW-Y&SSlGcZ&07=2nnOrPDV4=(YO?<&+^3!3-@aEZTwA5un|Uw;hXlgErXjYw32 zzeuzRcWvP{_yq?GtMDy9Bl1^sC(dg}wol5eIh+h;7q#`xGAKCyg^aG&(n!CxS&7;F z^56EpGCi+l^u?9T5I`{hmWBmB-=0xDMM*Ei`m7L|;?upw`T8h)+S|$lIXxe@Mf%{W zp0yc`^4K(#$8gRx&%=8{iUaACrumFW5bcjn%V)wHj4mwTEH=-G<{PnR$%^_!kQ#t{ zgZh>~G$NB9#QgTqEUhTKXXLb4E>0NF0+q;6JSc%91V&_52j;6>^^Pjgy}K!m^(B*_n!mdtubY6$9vTIeM+Q^Fed9-wJy;#KNjjSclc@P zmiqI|8y3OEU1;72Vno6#aoYI^UOPl8-G&qKcDE&lnKLXfylD*ZIWj7q$Qsw0kb*5) zG6oPHsZ%w41p;-y<`NkO;OdEt#%Yy})2g7<`7Wgui-3!h~M zf<-6e4rJ&#Mr3+#~d;;Kvzm=pS=+y8?a%)R_Uz@VkrXY>mDyBtDTo8I3G%i4;|@XAPZ1Ky2N zTxRw6PSxL5w^BE}=(IdY0^OSJSLVEg!x=4UFD_(n;u=uBYS7?fq3b>Koy=sfPS&!d zSI4j*f%C@f1-n;$cCU^XH7hG9YMZQOuxHEBt@8N}YsT2JkrJLW0No?0aZDvU%4F%! zAXB)MaCm{XVn^C^E{h>o z8Ae{RomJZ2k9`JzavGacgRsbMIu~;tshB`=SrN z1vwK>AKR8r8NBn2$h%fdWQ5-d8OuMwGAahxA4?;zl}0`{BHxupZ|{V*Le^A4u9<84 zot=v}ek=h(WnK>G_Y{@7iw%*U2O)Nw3Y(%zp4a)`d2z!m#6}zoN0Q0uC5Nb1_%+D|8 zr_ljPj+kvGcG2s;ZN8ih8Q<40O}smLkT0Ehs(g7)z9;$S-!3J#e9Hg^`CfG)R;EO1>|QNS80mZ23N3-kW?0 zW&UJ-x_lpdTgi8E7UVmj?*YhHM{VudeliMm=KLm2+y|)60UTR{xWB@y8aH{dRlOf^ zo8M2|lTgd1p^CiNGl-e{;t=;PT>0mS+eC)B=`e~LDJAYXxJ^}Omf7My9nANv&V(|L zo0l%`Z}84ls&jTG#Qj2cy10AN=kE660QK3j7x!IoVD_T$YTy4a_Ts`rQ|!f8holSG zZ7<$Dzc&Gky=a@0F5tSCm4F}8AmFRA(gpl~X)h|2y_f(NH|>QU?MHzdzn^^P(q4R~ z$Xg1$h65f7yb)LaISNbzVt$#IVlRG*+cX6xx@C`-&gxCRVlNh4lrG<&y`tn>+?A`D z{WHIpd=Jn-SoZk!nFnT%cYQzk{@3>SzJpWbdm3(gm+uHL-;04@U-iAPn|$9?^8MGh zkneA_|1afh>F-T=edK}YZ~nsXWgq@){hcs8MZRwg+n0QwId`A({q^j0`5tE3hwwL$ zZ)sQBa$ZmNcfbDb0L`)G?*@S51MzpY-%s5CwZD5|D8&tLrTpDO+@`5B%4~Bny{uPp z1Ij%0f^>1;VTEr)zlONq_%>bKYQ8cPaYQYKLwK22tGQ6Z;;)0TWmw=@<}tr2!7e(M zd$3r87btyhUgXcf#6s-@oO513El~eq&9HWq!%iZQGxp!E_mm2wXlEt*bwa&4N}< zk1g>QVX2*Gmk+`Y*<`*UkQ48t{(_@G5o2sB( zPWz`h?LX&$+OON~cT;)Np;8DcPWumg)N23dZ2y-B-2TA++JE<-zHj@%{w5ACr~PL; z?Vo-??H^>f-%aI7he{!+IPL%2pRM-)hwbk?;P#)nzxKbh>if1I>~Es+bJ~xWC|dd- zJfQXuwA=5d@}xth5LBG@{{U~;5dHs*?f)XZ{YE5Ze=jyS4WNuC3?h^KM&uux3o3l@ z++e(DqYwTAKGD49&OzFR$n}OqXv+-@8CB9&6>iA%6#wo$rY=1Cz zG4?Gk9>WEH5B4_;WLLw03(H$`Imyn#A~o*v)m^n83!B*S;aw0GDZo3U91H}ptXsyr za&bhh+u@3E>?NQjVI9w1@>RS~HqkwGMK zBT_{h`&vZ4x(h_G%BQ3XapqyDh&b>1lYoE&BX-wDNn_)Kjr4^;f?|YVXB0B0Ks7Ol zowC?nI|z%+K%>Yv=r@olA8tZsS(AlZ4qOpug^gPYuvQDVs?`FkMdqI+v)&)VRRP~2 zas`D-%6KL6cMJR-B3qzrLl%pga8;!4kX1Mog{&gV&88;Ji`^xv1gusRX;p0F9sUj^ zfyF)}!JWAJtfF12NFY$O8@C;uB+3^(;#RO20NKG(Yz3tCqx3Q z0v+fDFgq}B^X~c9aCq8xJv)#k)Pkqkfy=kC+qUjN{|TcU4tMP&MC{%Il8rqz9+zNj z1sMy*?kbeKd&xsE_DdoMBXh}y-Nltw-(gz^-P47OgbnV1 z5kQ04&aJNfj^!V8AO{=R+>-WA$>UyV0TOCclnb1!#@sXmF*6oav4dML8o?VMZ#EJ= zI@fOmV`F}fG%DL=Y%$N!f81(3jWeYDTUI*ZMg86_o-NfwCXf3Z7Bv|8$jmuskQUzq zgrcaT0%6Q5jV|)z@#+t&kHdO-wsjUk4kXC_AF>$sKZ^z#5WFujs0D#4Bmib`Mcqqb zhwritnC2NJ~@|=^N_(9CM8&ew{3EsDXttvQS=qlsQ}K zM;EJCr?LLe`lhC9SHGpw!L*irVo_ zjcR{YHB4dZ^>rf15DvRG2zpysKT#6S3u1fUUG(RP!e4@2A@68FrwJ%xWjKi+i|)<9PeJF^`|<*Uyjr78U%9TFSGRet36EQ z==FaX$iy(c0Z+bT(;6R6k4-C7r&^#7*c!#&b})j?)5vAzC6T(ylE}hEMhyG^&|Gg@ zajllPCK!9nWE~sAykM7=hg)ie&qbVLgIVB4n|GtMB>LDpxWt)u$Y668E|7bEh!ud_ z>ap8crchCB6xBvi3_dErM-}*}#>>SsjM%CW`ukJ;x{OctWnrd;j1esY?{a9RDBLwl zziSbq0i-f<@>Z{JJXUT-=?&-l)Jw{RxI#M1t9vu_!PpB`Z?BJqgQu7Fk%ZS_SKfyeMThS6C=Nd6hO*64(Bi8R{=l#<%xRz8tkNozr04TZ$WM0 zFRS#15tvL;8(4L(+Ms$gB0Xxvr1xcl+a^gE*C|w=s!xmb>-wT|iqUb;NSI(m`&@v} zPs2Ot^)lLHDtw^HlY2N!TBfzDP8N5;Ntq;Sci-$oLYa@FBvTo?ydd&HMX*6d%p)94 z05F1SC`=eKg$A2y7gbD#KcZKv`~iVCva-XO0-Z));a4A#YqdXMz6d9sJi>$a)wYY) zWg^Z9Mjl!Tz>-MwP7o=HJoXAMIL5MzBw+5;nEafuUf*>nqKXgz;_o3P>W7Zl1?`mai6JTJ z*kgo&dIYGX>Z1(tnW73<+=^daO+Av=K=XteDmG$KV%P(+02*po-*Uh(fPKWdr}!rb z(&IOuN9Zt@%2;JS2uM1WKowQoA|SXQBGw0Jhuz35u+K)0#nrIhR_ku)a5j`G5&!NG z{QMb9ZZJE18ycv{OVN@Q%9!e(QlT%tmJGT^GSHL_avDmsHEC!@^ekEtrB#?j!OUdR z%rsFr>Ua`Tl#PJ!YaZe8!;leCN72YJ|3Z{afI4P)@ArX`rO>1>-gJSH5WEcGK+6EA zkBo<#&LC+(`|1El3_l1kQD*0q+c^~;!XVTPwDh|X3z4${sr*a7aame?EJ#60JCTd# z@`7Ft;ewWSCR-Yed=-D_NCEADl-MmItQ5(VCE?lozIgf3=!fg4g0+~uVchQhK&txi zc+#$ZDV^bsPsi{ATA8J%R2oSq`;cgbbOTAH@y3611eg>Pt3D|RG*cR7t9O%N$nz-( zD&r@k85aDyT>u0;FAzxx7u1lKtbyQ4qJ-@gDN1++EW-b;gtv`_5*`Xt|7Bd^V_cE$==bU2V^hDQtz1Fl zZbbytaaf&R1ef$Vq~#$< zGx}Ag+e3sq`Wh23p7n+Y(J8^m$3e^rj3A;%38c%d%7T$~t*A2?k+1cl?>Js@-j*7R zumitZ{KNzC%BeA0&$6^UvN$f~rtL^6LvJ`IIf5xYRbGT?gSW3fI3pPqIc}y+yo@8e z*Da-;49&GnWpuJ*MqMIHT1^>DdYF@_1JYVUUaQ?_FuoUEwAnG8zq}UcFqFw~VQq~M zIVxPphXn1JIIShqtC2^eDY}lUBn*WGgR4;7p~4l15fP!nI08$kkj+$&p~8b}@&4`s zV2W{%k8O+gnUC*I!_Hf=fKN5t34#P@zd=xMt$J`YnA>L%^ncZ|j^E=elPwe&{z7~( zAw!G5v5?a@Ot#bqs-ki_yd+v+IZBa}IKHdD=w*QXTtX5&raLQjfQUvRCTT@&M&urU zr|8Kl-lmTiWsf8B6$ZC0Zxd4v>~*_=Wg8QYdE2gAGlouPMW^KBupo6d4^@>!)`f6s z3pe6di~oBhf;x24UV-d$2R0vSVzO|Nd}l-oHKO;`)! zQMa`O5$|4fCf12qxjA+eZ0g!;z|HrVtEJo2o+eKz^QL}`0DXErjSwbJ8FXk3Kcg%x zH|FbY%H#xuZ4wVcc>UpxyZJJl!B0k5J(&g=bw0k)gH=eKDln{y+A7b33dtg9}CkQBh4%^7Pi0Gf-9U_Tt4uWg#y){a?2rQ}b zaQzjZWoo5dQQ=>RD-Hqr1gr)H{e3x4fOnXM1;+^;dcz+?0weqqH*y`K^IJZxHWw%p z{-rl;!mO<{R^rc&zl@Y?lJzl7~0JC@a zF=YTMXF3wCP?t(v+T_DAlo$zMwU}#wLtgHOWyQ8hnR>&IV5|6aLKaCBwrN>wv*N>{ z&1&NI!qXBn^P|zO=;O!*WChjRPS(h$2x#K%oN_y-Vs(uV#5i%=h1BMY0jcc!IY-03 z|Md!16+T25R+DN;JKEsu?^E(HqVgd|YXTC#rmrBr$%-+9$%AG{+Cl6fVpKFaDwCmj zD^NZU?*Iluzc0^*di@HH2(>c=wkLH=!`QXr0`;o0YX>FjnCfhOL-c*z#7`MP^yW!m z9@X=Lh`_?^?B}YUDiMux(EmT?&IG=y;_UwkVTo)vxJE_2YSd7*O{~_WSeul9=SqUH zZfIR%Rm5r)HBl^TFTIK8dW>SR)mqx-t@bSzZDUnLQ3whN;)b>=YOU0|oMWm|YXLX% z|Nfpi_vVI8?EC&dpEn=4XU?2io|$>(+2)y<@YwyWN*m2c^RjS;<+C_My_21~X7d}` zSR9_i(uv93RJ5A9WkEQ~BhGiSG}kx~i_{g!XD+p#EhX4rE}LM(l;OKuCnpRkBjfdFIUm22hzQJ5RICS_XMY0Pxyp~SYqQ;HSu$=8Xg&V@IjdQ|uZJb-% zMZp(RFmaka{!y4KrxO4eO)efH0Qp|pE*Wym#CEAvI#s0f?f`dA6em&8!JRb1*`rGFc;7Y{Uy6naU!YMrajzK zBnfL-o54=Bo2*Wm_vg9s^^FRppYoQxIjApurh`OkSv*rnEyC%84#>PD`(|U!BUJ*s8kEWNJytoq zB8W;=A%yaW#5`S`TqSn!alu1h}|47J+b$k(O+mH{?GLx!{2#+ShLHjDyck^zF? zHpoShz^(TpmNAWa*$L2NLd zhGxPpYz09KkHVKAyO?a_2ufE?kpeR}JmYq!t&4zpYt}d4MNMvPbbj+jP3nRkyidg&yoAlD2uqN8axMT4M?CRuDWXkUDlQBN%$Tw8gzQ*z2; zEkkVt<${8+Qy;kjL^L#`fg)&GHJ}O0r#7EewW{P*6-s|medsSME%rVmvymZ0x=0n% z#7oZ(qQn|`5({IPPkH+2bP~4vy9tGf^fT$XxEhRSRlbg$(54lTtB@33sXO^)IrgH| zY6{`$t1wCBrF`J&n{by}0?58+IokQn>p2rSu9J|hdo93Pj(03u)ou1J5PXL1o_|Dv z!=b(3(nQ+iI)$M`YdsBH<+|YD3n1b@JXMVWVn~51%yvGcVDvKF`7p`i$-=Epw+|OZ zjHCts>=Lg=s`!@g3f-{G1hNJd8VO`m2_uj}&qP82zgQ2rM)`9(56Y{2A=WHO%xjYr zPy}F-0(!m54YB6!EdC_oE0C97Y~tQ^Tu5kktoc3KUk60ubx1^S^^5>v;)%)+W6gi! zlg>ONVQ*tt2QrZ8?Sk>;kM|7ae7hxuwUy5_K07YSExS!?j`EK$%&!@HeBnn;Zzu%^ zy0`=#N{~;2*aOEG4wyocqK}(iccaNL+u+5DZ0urVn5^{Va;XCT530Y94F}h} zQDBZ8Rk2c%;w0^ zCeAi-N@9i&2fI;M1ZGZIn(>rX{z|pkC6sm71VV-lN;dCb{|>I`9F!7{E0^{zIraVE z^0P(xMwfJ@{z$cXs={GmA!kjZ1a6f0&$&477@o9@m`01x|Sy0wO$La^OxoF5Y>Nw^%bLN&Y8oUWF*M=-lj3owq%0ei};4 z{FzHEr*GuQeCZdx)Z3qOBOaHw#+7Kx;8i*Bw#$I`1110BLvp*oWA!4!q!pt8?<*Ab zxkHj&!A96bRNwrNpzt26k0=U8E&2_K#^`fx;Frg5nX%}LO? z7S?97uu8p+3zhm=STCClE0tOa5v)qIow1QQwV&Cwa#gJ5HoE6?4XggZlCGrMZo<)W z0G2$on#$<|*8-D=R%XDFN>$4Z5nd&-x%3{ypq-1!1{XvO$}E|RGG}`g>7txSqmXD9r~5}LNT+m*Ui#fE1xbX!LV zhQCCT8gn)-h8;d+NjKF5vnrslsLSk?jMoJvrLa8rnr{=IuSNkp^{-;;Ek?M$$ZN{* z%3JTi{3MwV6cb5}*C1HcMyoD1NjHV{zE|8DM5#msO+NkUP^)_i5|v%C=HreuTFB(c}tse`O)x2{qpYiazH4 zh%Kwl-&_4_vT6ZmCKccbI{ZMQmyWty8pB|)tjqPbyxWDh(=EV-x6>@3t9;7{1@}H+s-(syqe=>ThQQ9l+pBu! zTkOurqf6t+O=4J8_p>7Z+P(SVE+?x_v%oVnMFa(FvLGNdOPj9zU^KcD})p^K5N8d0f1IuYgAXUpj2x)^b6S5Wocg-IDU5}6$Mk; zwT;4-5&hQH#H3q0`Ss^13+qEFrh4p!qgnI%k_wC#30X5^Np~_I)ALp$xbWf6dO$}J zyA@=f%$EqkAxo=ycx^j&v5?WAQt{{SWvQNOr}9esr}3!vFXOQDzoGnlmCweShY!=2 zBZ~aRvy_{)g35J`Z&s(T9$oEELY}B8TJIIUDliWC&<-d z5~1f`k^x@b3Vjr(DWXCb{qHs4`GF$N8Br|*`$qCw$8(a`2Aes0 zGICDiV5a}zp53*mhBaCQ+N{yh>Gv~9Zk#e4u)7)u=?vQJ&xLEuCPhTjQe{&PrGL9=G6v3cF=((f;%t+u--0 ztY}nm&0w<15rwSHC8EjV*&;BkHx<)L}cOI{1jbVY{i?m9Xvh1p)-IornGib`sPZ z!R1jbUQ^Vs{a7oBVJD0pd|wrPmvKTdjBlK0BK;~cs!TC92q0RA%4~D?iQue>qDawF z)KAYZ$P1pmU=SJEP3l%bJioO_1*ATzx@3<8r)t1~;r}W=cxxG%!6}tk{&=;2>WxKS z?~+9NM$5q^LL;(8`xg!ZYgz<8ZgefH$v&mJyG4s8vJL-YJrT9(9-=-aL~I@l#up7N z(Xz3nPC#wg=h(J}&vohh<@%UNx9AKXiq+;6vkQTbg+>g)NAr%1nidI@|GtQpEFi7^ zl3r^0P_NQ~A8W2F;Tw%v$tNLJ0|Vr~5pav?OcPLyUubA@p(=HF%nr9AlYrL)j%lWc z@s7yXQpuAEs~v_WSC6sxg>l{;OMC1|=+F+tcHjnuk5;Spoc$MU3ZD=U9y{Q#y}gTW z1*GWq#O~lG<>+~p3D#z^XfW#=ND8MQwuZG565Kj$G!biLyOZoWN)V)Nbt-8y&7@?H z&NSImh~{L^LP9~?T{a7C7$e!Un0U#aZEl6jcNQQ2Cgt?}w6ZaWRxryaE12;FGbycB zOvzNIo?+#WXm{E?$Q%I&?c{IPWnO3WDbi^= zbto}uTeV80I@w2QtD?>qgd{8#gO=hUQIDEtSBR-!Y8z{Uy{rj>po#QfS0+?|OI&o34qMGQ$MXM+>Sbe8D@tV~t-gV-lfN+Lo^er@=#hp}d;Ac(t zTL03*#F94#)#ZQKQ@Z5ug|P>?4`X>@!k<)lbh;+w5{P93>e3e$!SmvEm2UwandyjUTcKIQYL@(7<==DCsrvIil z%byGLDQtZCyUJDV|6F}nH}=c1=FfmS%;U{SLjv#G<`;=dw4Ja4Hw@o|GcYeZ zAYAFE0T~!3+Qy@WPr!;lyu|;R=1yYl;8@GIILuv{4klB0n7tsebM#8E&~EtB+MMCNKWN&Q`bqh(e1qZn;!^%}N%@xonBz+a!pg!~D#{d!BV1L3sERqJ zrGftqADu4ts3aHKx=pNkEyPaZ!b-*~c=8ug@!etr6*6h{)ql7|lh-@~+YYTVmKe-L z2&iQP%w z_nA$vx~tjz=@5b(SFn8A?re7%LE>d|s%?+>zFG7#eBU+V(B#6&20zlb0Cjv{U1vjXA~|5D=vJQ`AX$1nNnqvr5Pt0lHOSc@ zBRvMjHI+{i^M>dLFGW^$EDGn9=_;;ro@&>MS*!&g4$3#CjSvFYP&1#u)j481B)$B{ zLYjf_kK}6V_9vIAZ|ZBuq6st&b!iID#AE_}QBmH}>CtNvZ4+=t5W|7A&;ZMM@}b^X zCSfMi(+#3Y$hMC~*-l-9_vr*Yos};)Xj)flFFHtGKtQW{X$5;X)RC>$bG8J=Ahh!q9s!{; zguBmd&>5`KXbY=m@yueC2^x_Y6yenRUqm={B;qOKTS)qh{svB|LX#z{2soVb2nE%@ zHk{Iw$>5aGPdJrYC>+U)HGhZ{0*2WXjdU`%r00WVH6WSl^8C#pS(!dK$s-)boOjy= zUqLnp!qpW1h=u)yLR&jOCTQ24;l4>Ih>5!Cw9Q=Dg9CY5l7cqd*n} zRg&RB@nAtM#O>3=G=^_dkLsgZ9Z9ZgtvcR61$N;E`m!S!T3WHG$SQRQAN7}6+9t1s zI~B>F%@OH_HWIkpDns!8Qs&hHOF+M{*Tn6$#WCJ^L%daToLgF{fkZ214eJdL^Q`sn zD(U2zF>nMs{7iEc@MOB!*(15ZmbvdPxOcHs$}RNHPwivWCw&01Iyg|PgDrnX0tn0K zAuvKBU}V_tHbmfE4pyp;`C=Hwb9OO(5G(q5sUFP?=rHE&|0e%@iP7nu!Q zldF?=P)K!vX4Bl8^;z1)aJ~um`L>crv^3IcYPz2~mZ)^C~$(*-1QF zQ?K#6Wis*@AZ9I1@zb%p^X4T{L?!Kz}00sv4%losWn0(HmA!IUshZ3a?3 zpvlX5V7lg)$eSZ4N4J>MZ&OgKa&pjXN>4J3xpNu>>CPpSs#jP zsUV{;?*(gr8Ep<~+RcGb;9A0C6{!ls-;z^G%)7s^DLjkF3{6qB&=j{r<6I1TwU|m1 zZI^Ko2)8(ChRjv9GM+@%j`cU@XAZJjXNIicnrTBs05$C@&?JpIu>0f6l8Rv1AQASg zJs`)gB2L8)KKRHIZ{16=nPm|EjzJ>D#jR9r2&)yupBw@e{_gv|y(nIVV@>~>T%p`1 z0)^vyAh2xX;X zPg(GtM#}dMS+hiNI$45!2I|lx7GAqjU*}zuu_33}so7$;vtmr$uIUCWr?;(^tD;= zA^lX?BUPmb`%uaskL{JDQ(TMQwJLUu;T2z){CFt#h$ZjD)3d7-EgOAyzeMmV8=Bx^ zW%`o3q8Py6vAoB|YuN&b530AI>6}Zao%8*RF7?X0eRE$)fJ_-qFfg&*KWo!ZCmy== zoW?7@d-gevwdF6=mUkr{`u;^{UwGyv7oA;KzB2L9nU|b%;W_7CaY1eQbG7;1i6xyQ zy!;OmC};TwW&WS1?<*U4XqCFd>RjiQzsOB1-jeq!Js+QzMB$X!gpPdqGTsfsC_Tq~1Y!*8BU*lsBKby$^II;JN zIxe?c@^>Vxf7On8Wo$v?`0;JW_D&hU_loi9XH78s)0Eg{&yjtFvOiAtrU_~ui@j*f zMLoA^R1fVN)gcdZbyrDZ-OGt3uMgy!$n8nFUIhj3o+{gZ7qltX@>Qg+2(M~ola8Eu zW6gzV0H9dkjCx=Jmc0)+Auy5tKG?rd#^~VDLxnnnd~TN3=DLjL>WrLXq+ejCUH#c{ z%GH`g{aI*xdo$c_r`xfPaI9Xb#AVRjJb-~rg z_xAR=iaGB62w!a)^mj)3(*ver_enO)+1UK#O6Fu{scYY!BP6#MCEBj83iege)!o-T zO9B&o;}UML1CTHBcH#ob>CswP6Q#2*e=AAT^V<3CPTj$;{@_(&0Q&R%aSfi&eP8M5 z&>?>fz|w&Af*CukjL2=#2{$-WzZIOu8st4gI1_9{b!%N7CrAwmmmX}4U0DS9?s(B( zti4lx2P!q5xuBi$dTL?6L6mGSk{wOQt`rzKNx!yWm6GmF($!JYlOw-;`Z#YvAwQ0$ zWc~8f^9%BlGp@*QVrSUBNtG83R4ZXOP*X@UrF-0TL@wN|OD7;5y?l@=HtS|^(g9eF z9yUiCxA!Z#P+RWdSlINMc6Q}uoVYd4J5!$9h|y0--Ga0h+^==aA;tg;8DmjDb=3|i z#%1O2VgQpLOKJFBR3F&^QK^1d6@2$=HsIHmlUf4~&BA_Y`WioSZ?jyw%{w#dKcpfn zFWf~%fgdao`>-cTUV6Z9CaVK6pOhl~bmEaBXA|Fi5d3+dGv-v;&XqMh`D=ZJ$Qgk` z%srtkvTVyGF)C^GMkTFONmZ}OD23@E%zv!67cnc6swii8fPo@iy8S{*$k72bFl()H|AsxjWW;IL;6f z&s7xCxa40+1JV<0jR%l;l^TKeus{IjDodB1y9H(Gxr z()CUqk|flXpRda)C8u|DB1HHGjixGLwxc7oNj60st$sBe!&q)Iak^ew*< z3?em}r#XZ`6Iv-lGvS~srN)?EQR~}^rk8%nzcoq8wPPPtDre2Sx!%kTaWC}*@}LY1 zGiUJ;!^8SS+ffLNGjHY9|5-7=-q@La8Nbt)acHf7P)WjXaT!ltk8!#ibZW_4L` z+dTz&i{k*dsF0svEU#kE&9ixBxicEu*!-Wjs{~2j@{?}7#u=C*c@asGYwyr)IB*rV z#pciI)}xAvIJr7~)UGkx-AiZ>eL90rducm){5p+~`E8itbbEFZYN39RvtKUhKvw7; zFC0htxT=tFk;0H{XUbl47A@Nr{@gfiLihl8Z7C@@A5z|o zbfQx!X`IVoZU8o^7|2d5fx)x>*qHDX9ejW*aq)2{#q)yEU)v6y-<^A=?|X+E0u!rML}>_?=7b(;gD z0xDKnw$am}kAy*-su$sG~P zijYMon*emX0Ew8gXpU>xv%lZGiHH4UFiG`UMi46RIa;_|IzGLjk3T+lkZv=)Hch%d z?l@kV}9_e|Ki)z#J1lQK(p<(?+p>Iz@6dHsm*qpw2e|O3=q!It6jO=?5E$MBj5F(FvptTuUuoqvWDVblFOQlOq>>-N{A! zk$$yHkK7Cu_#D~j`*(k?Y;-h9oNOe6!l`9&q(%FxFWgvb%!{be##}>fY#Hpxx+>Q| z^ga~0V)b4+;;hWmIEnP9Ia^9tuL_rC;ze9?jcm#gJQRl@W%+4s+cdVR%5FVYDXpG1 zcfOfpc4M1BRK94!7`5`S)>%PIZfCHSweed*hX%Do-5QZF<7^;s)}z5q{n|=rz-#Pt z+3+wCNN`Z8vg@fW2oO3;L}ooTM+BTanQM2 zZ|}w~u<=;SgJg&V(X98YBu^}Tl2K*%$NN=5+*v0S%+8}X2R>n2&DdY#_%l+VSsDn(-xgFCsWvjH6yh4ArD@e7aecP9>QUaE5{cL^-c|o zth%Cq0=mBo7YCcLUKVyaKlWo(WG*!%YU3yHNXyJl{jVL^7!`}j+M!$e*D&qLx|Ep#V*wB}~60N5KH zZL#ocQJkOPXYY*23rCpVcC($4yf_IvUvxO%9$ZPNdcgvIgI#^y9&jL8b+ldZ11|M& zp?Zaux&ysr}SUyWmP`{|774_SGQM)MW=6+EF6*ZG6 z2iZ<~y(IfOSg&VgU)OP?MtFSoHPGvLUN?eorQ#3XG=72NciJ?*UGbmUyrJv*+S#i3 zH;H$!ovhavvad($wLAMdR<8@PuLtS%PF^>HZAZo5v}ydO+?^3#v1$Apia&GH_$L*g zAYL+k>EfxEFnkLXcbKJRT&8Q_f1{{e3 z8D8HszE1HgEZ&&4@IdKLQ2ZY^jo(A@w^_UpdHrdm9izBwh%=X`zJ4ka;KTLty#5(h zwGns17BVc<#|rzH8N^vC=rP5|H;wldUr7Aor21}-UOzg3*SKEW^!koo?d$1!eI@(# z7`;Bpt0`1CS-DHMCoB5?O``W!^e>5an5E*stSG-<)F;;yHJzxOp|PvezblM6Lm%pu z^*%)9jU(lk7>wkJ&W-X2s*p8#)>OL^@ybTZ-c_%c@rnSjI8e+G#hjf@ zuu25^gxmyOiWx`D#vIS;x7+3)Q@natzEF~REba*r|!Ah#8 zRu%e9;$`Bt!s?^Kphi!Gi{qKRlcT(M6BFD_UZBXZQ8*|L4zSv?(BF{^oAA*)|4Xu= zzMs$cM0#mBY`9g~=P=o{Jq8HVXO*xbWCDRGf7iY`&sClCv06aH0HSAb&%mAmJv78@ z$S`2z=3nNVJFWG3;m(8vsWq)Aw`m{jkZD?R)U?&a1P@*}(jh2N(wCCF+=!gSD21o< zLr(#ArmUR=cKY82oVo9WgZ9Wm9+lkx`w=XdvOqON zKs`cK(AKI!jC#GorEcOrnJ46w`&H`}=Hr7^E{`JjBr-VBvN3x!A(|OJs7`o41I*JP zBz<@*5>z-_KTp%iL}%n~8M?m1?1_3QAfE=&BP#gxTJ@6aW?PkXVYA6f;=h>tM#E<* zp8k&-Im>|^YyOD>X4ZW0R)Q)MNjWc=OPLz3HeSLO_0pLjaCnb;?&q#AoleE38o=E| zue$pe48sC_(eQ;yaj!ZOu&gw+@I zT)APJdQ45*KW56zbfC;AGfBcunHd8NsFxbN;O>h-%2KKcp1wv?-GmP29IoPwxsuqJ zA5;iH;MG(j)EA?959W|VU6&#g3%{#a4$KleQ=hYzzz622)qGducBGNfu=JFNUDg-N z!Z(W*3km2Aw%Zk$?&Cf5RHPd3lW#sYSHIkW7WirA~GOD7J^}WDSlHwhkf4= z)zy&_t7yc4o)N)cT1MstFY=>CKp!iDubiN~LU$qKQ<_YUlxB^2vF6_ywmID>oUIon z=?i5xvTbAxz3=CnH-?4>WQtf62YF5VR$H4%Z+s!#jUIx^D)RkZ=$XphT&INR2ni6Won3w0XE; zsKYR~4lCqxfL?o>#>%vG?osLuZrKi4e=j~=3KZe@M8RYZ3AObp9Jez+qZIlLL^S-G zLT?KAPdFGSJb+gQShJ#IXNoBl`HE;~cpKzgI62YCdL%*HfGT~bY%dQn^P=uA8YsIF zsbEy$6GG5Kq6xdoJ=GOMOu!J;S(>xF>t7Z(Ufe=OY8f`h>7}l*xBZNf{yy<`r%p5n zep8TB)smeAvK1N5W9DVT6LP})<%DIY2oENc=_HgG9?U>w1$#BP(#FaaslE!o=ddT- z-q4XLU|79BjqjoPe|4|7^J*d6&tT3RMjrlKnf*l`T`lTx3$MY|KZ*Q*gS98gI7eHt>)a%HN&-uiy&CP(F-d#lVbtI04R^sQ-`9P;e z?8Pb4q9iMm5Lw*!+W!*5RyM=w!zUs^~=`Go@%f zWABEDeTbyocUZ(Gy7G*72nm8`ifQ&M;AhbJLwLhNe$@6MyIUVrCm%6?w8lLc@&(a| za0&J!o!J3-`X@plw;8ZDt;Nmz+oOb8Y|AG8FB13TU~*rZQzy8Dmq~GNb76y65Ye_k z5y5v}Rjz?0$pv5MHLr1uOWjeX{*k2Y-WOEpJ&OW|SzY3OmMdJMuVQ;nNob6To=2yE zZf9w?VA%c#>qi;V943LFANmS+u7gQwZ`hp%-o6RYR~ReUc9slLrk5;Wb0|+Msg_#j z=qY_+ls?lIQ!lbv&Wk|cv^|pqw%f^dS#p6++skhnBS(SN^i5vlo|-%gW-FAOP(`v} zUn@mDVrTTZE;TQarhPT1D)KmwneM6Rm(|cDnC*t3E2;E(;e{&ihN~QZbVq6iH;(}* zXm)a8NRs@foi-t2zs{DT6o`-ffNjFm%MS$)Php6Jed5Dggs7*BeRTGX(Vp@m4 zOSr-*cVUx>lgq*mDJJW$>`#Tmr@b4^XJOj!2d{q_pnhV+MY6#5P!mrRw&x=3sA^Cus?TD>WlVC# z&aoWJ!h@_iOT!;os%7DQ7N4bwpF_#VN5J68ZlX$Iu&-pNTSQ4l837VZOY}N`*YGol zS-74baXZFrb0!IVBZmOZxXLmovFQB3GW)NUhlQyacOGb$v3WJ6XY3 zdE7}jwDn`7RNtoZ{HFc-=H+e%UuG_5CTVbER7+P!mW z1A4pC=YXz>>N?@;R;Uvu-C$H45)q8)SL8MB7qvaPQ30*l0zSIYwS7u=)pXak!r*?> zGC0aS{bslyj4ZhE3K+(9{FuJR=!wbv;Y?Mu$qBP_tw1=V&6IV)atK)X8n&PyK>?O` zUGNx)7Oqg_p%w|gW*sLU_!bw+JET$HZ9&|xj^Iu%FlU1-rw|&dt1{Gemfo|}br`wi z4kMy$`9zR~Qn^{C^~;C_6jJLS zLA}>nvbyw!g#Uoh)T{g}=l22dUeT`EyvCi7Hp}{DKc4K>UDw2k6iBWaO^Qg>`Kl=_YK2`z z-C;-)G~O z2f0PvSW7e9Fvm~hf8T5MJD=m3@hAUtJu^B;5_zpcAPa+)lCt*^UyBy|fA#5x-kyiT z)_)U!KJgKQo_ZSZKPpn+Y(XkJk&^okdZRz3^s|g?(}!215WH)8nEL59cU;^J z_LX-HO>BP4WC(A@V`t}{1HHDZIDZE&+SPKhQRmdMxR*J#$HVi>k=rM((>&Hfb0J;} zv>=n*Z;CS?V$BaqZt<^*wBI=-5C5AeEn`z}2KOQ40k znsZ!v28TV?tgI`KP^4)iFP?Lp7f*ek7ta@R;Q1vrd=8r2mHu2bNs}ZOO+Fgc+nb#6 z)rf(LuI4rNG0-(Or1#mnKro4{y4vlY{PND$iHCSImllIYIoFwIFzv99H}r;$xROfF zn1$S<=c%T4nyKX9r+{+PiO=1$w*};Tsa2$Ryxgm6xbAI!(xXlgC)V;aK&?rCW}Z;y z1HI=CIA$ZxEDK-aQ^p56&K|;^#^ge~ufj>+Ws&q<24iwwuo4#Lk}3Ee)kSwuYy)sd zYz$n|0oQm40~NO&ivS%t-0#rmdOeVQJsi*Q=J;~XIe#}i4WFETO}Q6m7qD`gYVtsiJ1NcUzZJPAdf)6WQJcEa zR^&^p2zLxndZjmZwpd@|FF00&9*<53atDvB=HQXceji*)SHxPMQN6k6kJzF65kPKJ zv_Ja|B}y$R#`mU>qV-2moKK~(KaPcec8M1-HH8iw&|?EEW%$O+WD zVqDuSXKjBb%PcvFO1&nLe<++AuWr4@TG~F%GF$m<>NJhDqM9w&@ge-FecgD3f3(FB zt^qv8_sLl6s}%MBXMF8g!7n_%=alx1?@N_x^Jd0(+LN1%?+qH?!E%`^ZOyk^&+i!& z?(#7Oe69!5qgd6#Uzzc7Sjx6|9h~x95ndmMv#rlpuh`Hh&osqIRhU* zdRZV00G zI1lzCIYLy$i~gWK9znektdC;dagW`pQ+aoY+CV6M@7erz+mQ^GH*IHacCibMR|t^` zjR?`h`}HAe+2LxRo%xpSVSyQRKW>QXT4zKpoNR=sAEFKpFI-0fpNpuwGQ{E9ffE0^ zdd}5PLW?Ipu=O0M*J1pKFt&fKKRiNDgXeJI=_w#pKLnY1=oS#95NxJj1NEI#p*KR1 zb;&G(n8ob@*f`7h5yv)DNz?Aiy7Q*&dLeoHW6q{1e+y|enIn{+&N>Ynz);PAD(RqV zDwIexAg^Z^+SE#%lQvHyr~4q)zA$)7D+xCbVoWxi$87mXKOgdw-NCCI8afzw?fSpYX>+ka#&1DSu5OcF&_Ay}Y%EM$*zd8Qs?4t{PU~n`-w?}d!{hTozTw}fU+mT8&jn{+<-}&09;-MZD+Co2 zsik;?ULcQ9w_~C<{c-P3r!0g5^qt)r?OivIP@d9a3Ij-~O66vMqb?`tZ z69DLBojkfzOZn{_#@qtdbZWW#^rU@S$*=xs@hXB{sRn5PnT;=kv9!Nya?3uNHnEl! zq!z{d_g96gTX0Oi^=g|w>cs54(o1krmp(YRTDRjl{3`Q`woT@<{@g(bNS@KE%4r{N zpq`w)SJ#&h$--$4&6^>Rh0C+}&uuT1T+TZBYi7_8u3|-4EP2CWTn_`4?h(1HK#9sq zrH!nFHot=6+qh$5$$N2DF%Sk{QZI!Q*c4{7UH~iL33vtS6;r*Aa@Yy^odfWF)gkj< ztY(cNiB(8R!2uI=;5>+-?LwaFu9cH;2e}C!Pf+?^SIX+6o7;KYbe5F^`L?NseeU|U zv8|g6<^GA_KKh!1koY}o9(lU7&TWq5=cp(s4&T{ zr0qH1X0Af`IPh^@a7sCVYC7lOC+Bx8Owvp@Mbesqpo3y3<)Y|s&cKK##(5VYsZTcFC9*cp^rsw^R)4-3x$q-X>nnvrI-W{4E- z_mc~S2cRaKC;+f&7oo!T))XZT1oVF7|2%xjkLqv+{obG)L6!A1qs%OU%}>&$hGkgU z`Y7@fKY);>|HXpfgsipnZKyJ;)HW)yX-a^mBa=%EIseSzc|rNv(D8%xbAW#K;pa*B zSAA0TiPgs+2Z{VwBE2Ctf5J5OpH3gnEbR6jz&w=e&{QMcEy~ncp z|2i>V>Id?Axq}is|LAzFe@bcM!OU3)2@Zo?oH@dvw){13QRWB(ul#9$;suF^=sW#! z{=tgGg3RFu9ClDwzABObQEh$~Ck2e)@B)q|C`v3@5>J$`@$xw_pnFtZ{t~ZTCmrlm zSH7H+4&rs?&w4Z0+HA@H$g<^kWpb9UQD$-~7n!4+F57Zy`X8r{pb|VfS0TNQ663Yy z-Kr_QKCvXI^!!6S|J#LAs$&;+_CMpGwrv7u96Zk91dn@r>q3$pk7QfY%N$g&N(UAE zX?)9bjR)$SgO?NepCtDFQ(gMC#FDoM)}@!$jrp{C?C_GtqsF(LqLU8(G(P=u)AM9} zRvDioW7CM*{Ab(=2TO{2+D$d{(%r#~1Bc{^?dA29Rd)}Tz}HdG^R>jfS9F5HB>&1i z*RM(R4!QcM+Vl}6*-R72RNh&g9t>6wyfly7d(&65Kdg1!G%vNZQ1+G6tIv3B@q$a^ z?AL5ySAvB)2#K0?b&Z?GlGwW7SEmn`P=|>VwCZdeYY0_e+;d1!f2Jr#7gfiaFzmk_ zG_pe5vs+Hyvs_-ueWe(0GDX%B9c)kTXg-`^6XFD>gg5gar9w`2EW{J(Pq|wJe{$BM zm>;(?KN4-nmmJHDBQ+(**0o`-)An&iqgr|4y>yEXV#kvXIn;%YMyhh5ed)EuRgJXu z=`(1nh29`!OCO6%_2GG5!*dJ8{8_(pasQ>bR*g<#MkkX~EnjA9s8@F-4oCcLrtmc@Vs`6}paw#-JgSwr%}Un`D<5yjJa zd3pD8e{yece~^` z{U&9~KR{^;nkp5XYr!ukxc)f(SOWQYYVgMKI&ZMHWE%9>ORuU;f1sn`uPm8v1o#7@ zJg#W-FDZs#98*YZl!QQ;y|OsP(-?`_)8&i|x1E-#F|xZIn$1aFjH?pP?Qp81jX+&BK6@^!L` zJ6NSIy^11Y%~w*w`1FdN?Ja-wJ;6bwjps}e0UI&C?P!sxXPf@sQ$8zG{>pykqd2?r zpUWnmKV_TX>AArhvw>q?%3l#HuA|1sn-0u5FEvx&mfFJ^K@UI6DKFlbXZ`cmc>c-j zL92q;4f8-nrf!u^cJaLQsU=>P7*_7D!>sNqSxv(e={atHnR;R;y0@B4lM|$G@KTR4 zOHVDCDuh@?T0@AbS%mn}B#9Hz8AJb1DmoD&e9dUP1HNj13X-oi*6nO588)|PvAneye>Ud?nEiBd}k)>XdE5zgco=U=&B9;fhWDtmq%^mcqH zN9B4CW#k|o&Xj&Mv7k>B;w2*r)s`d3tWPYkav9#*?GPGPdHFARl2slZ;gx^jA^k{J z@sM=#pCyuGn!3F56~yo4ArVQo;k2fi|CIEjoXRHo$mMkMk#b6&B6F0}vLR3XFQkv4 zGI&<1?FQ}Bo=$th743uIJG&#P>q;uG<+)h%BdD*S$;O^C3FiFxu|dmTPP>P z-mokTeQB^e2%()mvJL)43|*|~`V!5g*qG~WcSEe`=8~kn-|W`^ion5G(b>8>_=1v# zSW#oiwAdKuOcfh*m(9)Cm^(^3EzcZ70d|s)Ylw}SSRWg8Tvcq;rDd^E=f`8C&f%y5Z;SA|y!1>) zD#=VBhuu-0D>RY9BbDKIWC%r-`s#5rF4nwfUnMSsWSHOzGGx+*pO7(JxL&G|`SdIc zZ_6pl=DUa=-7t*XP+dID1ngX!mwkm|g&F4goT)(F zyD(%;nROIbrDDSOiID+ZFMrX?*_qE-ns!25+7E-m`Ey3sxGUUV+om@JtL7t{LPpH> zzcf#$T?%n?adz1Sxi}jP&J>rNUT-cpR`N6*den$P&)%lX(=Iyk<{HaRbXQfq!O`c( z^~no(tEr_~oN3z8y&KYe`bYZfWRS-7#xaC~f1QBN_#QvV$T{+H>K|SLvYY-SHvif= z^e__e8dDr6VhR`+j}?t8j*S{eJ0~&`3J79(Ij+b{A2(SC{Wouq6zsK4Bocx2V}y` zs1tHJ_BXix$a@I9(ccdfl`qC_d9-jvV-d6(SxoM(^EyW4^_;5v%}@6Hxk93#`Ftd_ zhpE>c3nNaqH&NmaD|FQRVVv!rey69%>*Z#HLs=HY7K*U4XM($)aSUo4fz-SKgDBWI zq40+<#fB|VS+(i&r=m|!<2fC8tHes;Dsvid6~SZ{=Rig{lsPeZ28F14MV8q&gvrb~GAB-VW8uVT~<+ClEfTk&rl@u}u|a zwyYQCY+1hvj0p?qb6bdeuwCSIEd;ePL3|JNdhr6Hf_J_xeNUlILJzenS#SB;;HKk9 zwv=QjacUU1cY!f9?ihrGe1d(qUubk@p9kVpIrQM z*A=_<7PXQyht*cM-ZEFg&8@d+WwuYZ;=T#Lour)Mq~F;N9WO2OFXJd@~k!9JO+euvO4Iw)J$t6`=~D&x3G zI_Ur;6{5I1ajbW8aHE@a;jy%>BfskYf^ZRFem<6*uVH=_A+P7){;M+sHfn-aXW9kH z&;H=diGVg^YOwn^401VlPDTEmhBwB@W;E2ezNzsWIM+VYDW}fc#!gXh&?)L_ zTHi-sqFzy-rRRyjxYN+-6m`^QiOYJVVGXdlP)IU$*M3OSM_hX6Z5D$OkwB`wF>Y4PsT>GJW1qs^EGYwj6g`n#B3UUCOT@Q0n!Y3$gf*x22VfKc;BTSJ;tbv{;&2u*|;#%w)fPw zuDP`Bjo>;U(l`Yt9wv8@Y~{bDsNnndQI}v%^lE+Ny%|;2v7)1jV`H?F0EJJI>^FWp z0&nf3N@Jx1OJbuC3lT6YxU;BO1d~H8v0BE8uU|azEXY#bpQwyM; z({re&Hi-1OVC*3$8Er`p*&Es$q!A5skb7hNp6Z#hA!|1n*Z>9!nVfPF2ON}(ab=+B znI!P-sxW`HTvr&UxE52^t*TBxJFT$BpLkF$L^hHB(7%+0_e+tyXH=vwt*S{+tf@_p zL$jz)PdvU=eKDhfqsr?kBf2u6Cmy|1jiQwsSdzd(ae&jn9Z<|9I-1cL%>PMtmMHx! zQD2PBlPVuPhN30G9e#%CE6dO7X#ztr4m+R8U0vpu1KEA6w(Tq;-wwWXAvAm05nOs~ z{#(@#6oj`hP{5;gaXB3CfotY|(P`3+qeTv#05t7%uuR^68sFfOXExCFxSe9nyQY|| z)eqz=_b%j4$gkIJJ~;ByBNG1Ag*|&JnJgbUHC$#2=xDxIxEe-U4V=WqYV^9Gh#IPr zpAEovSkr2Yz2L&s99&pjuX!3yV0Kz)u|iW7_dFrysfF((ta;kqWvjf`N?3Jqo1tyr2YYlaH_al z2E9fS0^{0lIJPe{o?(+vGTLNI8#bx9l0rs}W9ps75p8S8145j|tErXA3!rg!UKjC6 zMr>Fj^$f~N5$rwi)iYjg2ugNbIy#{J|ZgCo9Si2qEj)y20dKxHKUBz#ZS?p ztwEygnEbiI{BLuHhkx|d-dhbffsfSw_oS=}Nm$Z*2QR}0%b%-DuMf_x*1jSLTy5oQnPR5Jnx7|!h6n0UTT&Vub$v;@Vn%Tvij@_uDEWgX zE{5jH$naCew?*-)E3>rKaQA_x$5c6J@jqEMH*PWY9JgVC1|8I9>S0^|3ikTjfV|-7kGPBmyFUqG z=zVu^9v_r_!k4y_K)=jIoC*KN$v}-_fAzkJ%4;vyRSXP$FVFcQJ7QLSazriz zJ_qAg$T;k5^}#j&62jeU4I-a>OKv5R%eNi*95R#U(uy1rv&tn1*cqa`16fjOou`p! zu~Abimof&IGl8F}W&&I2H-zAuSxngJHC*{l3Qqo(ix%!n%^z=F797q1_EZLA-PfM& z9nUSL0MX8my5&N%1>kFeExFL#>ttDUBDIw0h=&}+_ngLMgy*PbBkil2WF+SOBOxUB z1A2zq_LEm<{-XliOR&Jnfj|$_e*HmDj;ex~tcI9){`pe=oLq{SDf>ivVnx@uYF%tq zAal6{5b$Z@WMrF!&b42$#<1W20DeJ--2* zEmqH`*}?4m?!%vGfgWbhTAG+U4^tA-!%KiCFD3@hfu83#a4QSn_(r-AE#tHTf+-#IC%w5c4v^%Fd4_NVE0z;1Kg{eylwL| z&*(Zma=LD%bsci<*~mWDfA^3;jB?xhPx~46!>p9!RTtef<;7a^cBCZC+4b_Cn=D$u z__*@Zx3{XA^gNrUk&!q(ubs#)Gl22!-{GZ&0ydSzh#`_%4Ez?Be&~jN*2uU}v7s*g zSyyT%=}5orL*KK*000CHvO`}6o@Ix=N=OIP41IG+Jug}uZ24%UD#;mo%frws`DTY+ zSvMK_UyZh*pSmDt=^{4E^il1nN9ZCb~|K+P3qVe#=@Jb}xMp zJ1WmdCLV87L)ZC@k7i5GEb*B%sr3V6sV~_m*z_@U(T^uU>x<@4nr2h5!puv9WwH5rhE4NM?Ar_W7+RPY?jKjD+$(<)x=4?xi`J-%wxN5D zqkBH4d;TC?P0vnJ-4?rN-flMLjq`K5C)WJN{^SJc|3h6fU^}{|R&Z?&dy)|EFN!^f zTlZ`od#*Rz)u0pZ&*>hAJs0fqf3AyO8$uWTd1rOe>}l{yut$#!Z8di-X4=#Ujf_BD zOafADJAwMa-WwCB&G4p(K#9Q^fjT#)N^%I4<$*wnm2H+lZI(A}*hQtsRn|>wzoDH_o8{Q-r$cpEpy1GGq?Va z&Bsdyfo$`35^>7yq71TuXI{hz-NAmj7PF)r4bFqL40%GZjrtoVT9X@G>`P=MqNfYPp|X znYF%&B^VML5pEZXWgy`68F`|!wP7+C&b9Y zZGNT$;&ea9r4)K4ikBVs8Wbsd@Jih!A@V5UdkG(`*~H1tEQr? z#+rYNa3sA``tO9 z#+rA~uzqpgP2i3}6qBQy zS{W;vV}8f6QFBVx(9+nbn@d*P^Lo3fU8XjplcoI?*NncZ@3)fPxk-D{Zl00WpP~0a#5g~v<6USd8XM&olOQ(AHlcH;afM4hp^5}v6vidd_6$mao6rEmx6Qxi zubS#CinbW0ZPR1gFN2tMr7HM^%-$|OV4@<7L(3THkArKU;3AZ}N^T`4#qvN)8w`T| zZ)`Jre;*}o#Q2JEsfN`0hut|7x1b^c())thLB60e?DVnPHmQ<9b~d#J2fkfTw%aze1<36laBTyGfgE@XVAiIv!_Tu6L(5 zl5P|2EYjNE2%gi*4xq6PqQxtA#o+heio(2LyYXB|R!HIQLbBi0uuvqre++$tT#Uzx zDwO*^dp{btXN9!7Fm}U&62-Ys=|Tu@vEZQ;gw!}eVoEbH{T(8PuF>v=V}9DstWgQ#HTz6O_I$-vb~Sa7wuGAdx99pXt`)2&plg9IwU zc4Al+jlk1e)K}}Vu<3Xxb=Qo&1d0+FC=MnrrBg)%n*_>oLcw?k%1Xi+P*xEJ6vz7g z`!#m8>AOl=dEx|E$fK_92rR(vK4hkPRc+f{hRwPDl693E@RCLfNcbZSKQ7TR0e$Q1 zs_l$e>(2qRpZ^+UiW)R(Ok411fgVdt5vtjidY{%Dhz9z_AaCm^J;Q zN3O@)={mvpgHO|}!avRmAnuSjd2%-;I|g0h`h3-!1CWo|lRB?dO&>e2n1_!0mm_!H zky;WpY^_a~1YR%4io0|X?Uyq^tOX68`T0JF#^VlQj%#KY`Xh%NqioIijjiX@rT^VH z;Xe=%7D^7}+;=558IXJkxCRdX;xNt9{ zFo9r?DBl{wOzWz(%Q%&Qy||S9E>uACIXHtI!Ck3G30hM%kQsguHTmuzjHF$iq{#0( ztSM~T)n#yfbYE^CT}cL=Ppa8mla9Jmd+{`0sz)YI!d55Yxlz29O-uDthCJ5J*VK}I z)%_Wml)siSEMqmJf>zVZeE>-|Q$lc=%jwo|aMefw$S$(rRJ=epS5E0esyMwQ=-D6h z6L-uR7B}CbjFh%UT@guO(D}@Ii9>RUYSW;wwi%;=fb#1ZYr#h*FT{*J#bSKJpnB#6i&Q}} z%_$9^EpyY*cA_E)*-y ze1Idf@m~Az7fP3~ouKQxk{=RwM{j9=_s`!QOnTE##BR;GQ%D}{(;PW0aok2V%eC?w z)Hb7`&ojYheyRu>&{QhA>-_sNi^I{<@jojm0F@oY!lQ6=i_6cDBJxOT5x^qOEjTPw z@OudzpZLo^bL<|cj{PTn_-$Dl)rY6RQNCCo-m>eq^kKg3{!t&E^p7p{;a`8W`9AFW z(>C_u-4&nLhdwDb>BA8t`ugw`>Ix4gVk>y~zE)GY>OKbt-8>ti!%QPlw-kz-!9k>M zN6jSaGIEiqODH&{*rt_3K&K5D_SF~5PMCfVNwU$4eMH`=d!mXY{`=-B+kz{o@f z2=Lj+rkrECX?3Qjw%N{#iXE}b45}0fg>UtLLcXmTayBKLLH@&=QvK!PrvC}6YTSA2 z#B(PR&xk_yV^vS^A)HLL{-jJFh(KT;MAYBj7}wSpJRjotb>#jOGDnVo!@p2lMQpyH z8FRNQ5dY7iekcAPc`o+Bxhe`44>I->wMIdRG@xD$Lr^clN-~K46rM_0L|tJCEBf;g zpztb){FNk9;q);%lC*^8s=)-BHYc$mY(25Fge|mw%u=Mtiddm6e?V0he8kc2nR(Jz z0F`7!tkyl8h^73o=C_rR(mGThB9=rg6S3?w)-g$c60xLDn24qMkQLEdZXpXEGDK??!-!SpU z@x<$>D?E(|+0TAzbluJg15=PM?p@AkW{h#%>FcA|KnoNb$rfMNVT$Ta&qOaf0WC+> zDWi`~HVw$)$od*WL27%O@aqYa+l)MUB$YA6o&A(t{BQb@>s!|$vtUsuQ_8Woh#t!6 z?t$e55Hw1Ou1kN&;X`oF-klmR)TCO6$Rv>DWvT%#wxI}m->`9zOeNW*`r&i(3K075 z)&XH{3l$w)$)QW(93nQx&LQC+_Ms=XNhWZoYq2XjKlhaUYu<ZT5vk$Xr@dc>2Gov~$wIyGPM+E$;Ga-HAkkt zE_BoBXY*SS-4*JUf4>MTdqr+$dq=waoqxPm#rUDW~5-I z{W(fLyItkVqKGK%QA$Tt*ZHuz>m#i5j2uRUR5UVD@*DS-94VE{>G!BurXR*yULaBUL#uV6fQ$4=H>KmmOC7Vc zI9Msx4%FBX9L+{dnP4^66(mb8RAK|s!3u~1z|ne%>cK6;4aC(dBmyxY42b?hbzlOn zGR?#Ce9d00cIse(slMONhxG6ThK#V9;9IX5J_^*VVyTzl@g~g%*T^gnEe>9PI?F@1 zqEyZ~@behx4@e=SANyBYR#TrGzxTuOdzZ{jgCi5!!}lkVw)|b4S3Ya^K85icos4H?w;^RpM=}K@Wb2R1tiMI&zkG zp7;_C&{#Apy>Ew(Z@jki7Y_T%e6qD2kp=!~ayYV?64kVrzO|j@yt_?gT29eh#PKV@ z0ITwOI9Hdg6KblrlR`_9JirO)qOpC+SPolP@gcZ=s6z#%&7cBdH`N6}hSvE01$x`s znjpe!WHr0&4|Lh!Xl8kqR$u8Y>Z{R%qP{u~sFDkn!YnQo7C`M)EoO1~f4rRue3ixZ_iune zsNxN-aj8a(HMkXAgQ6y~c%wn%R&ft5h&xK6C@L3|Na8gXm9|u^jY}=98;aFP6oO*F z9e3Kg#ESAfUKd(7)W7Ea{?0tllba3D_VeZg_nGC)nKNh3oY~JTVFTJ-cIP_E}J@R z2WVeM(Ggf9b2;|GxY<32+{*TERw>-(4)f;%wQ>{J!|QilQ`*jjErSdDRVjsdErU_J zW?}h0faM;aH$B>|%N9~~*>m-!%U0KIUAFpib=jJyh!}mnJJ}@A%6$d>w^s7iuhUDP z$49-jreto_VZoQ`+c_`ECQZf`�Y5uT566IyM{ZR8(uccDvQ|)J2$R4SH&AUrqRj zDY#{jr?MniLZOD~mE7Af1bgqmNY~)N-K+-Z`s!b}q)7r0$U=&1j0*M!;<>4EV%Vq` zZWi+@^r=s+uupXxAMJvAd|Ru}pzvMVdtw2tD@QlDXHi|!#lOQn%ZSrrW@w-Cvg1)wQ(MXX#(B+uxU5x4sop8NMCmmuEH8|@AVto z!KsjZhHu^EsWunAmLBxr08=t`Il&^zK;O>9QB7irv#;akM9#!ca9Tw74HxA7B|qlv zvJr*{nkAc>J3(leMns2c6rN$3=j%bFnMsJI zF7F4Cw^iOZBJZQ}E{(i%JJWVVJ=dD*PUW%htN#weVbp-=y$6Eu5wNMY(4YHeF%A?gVT39YT2e zazo%U+eZOscVM)fwpSolA=$|6$Yw(Y9%P#XE|2eW2-tm5qiBdLa)@)kukg(mH7WdS zxqs%|&*8S)-Tn<)Sd>E2?p3PVjh`48Uq(2J+y+osk~;^lR{>_g{D<*4aP@u+hT=7+ zJMh)`8U6Xk2z{$tKV!ZjiO5{F;p zDd8T%|1yQ}w_yzC@1-9e{l>x-0K#(-34JE~0i8`D0Vg>ES^@&biGX_W7=vAz+Ndfc zwjP8K>)}_Pm*e$L1~vc-NxRz4nl_6S0-J)@+ef4wtpfvymxI^r&d^pmw83_af2Pp( z7yR#`-EY*-pIs@$xiHlqI;Xl`sg@6*2kf4~+|HoC7wDgQ2A$s-^e%y34yYq}S(y27 zhT(8R#Hffv@Ono_V1W=|yE<6v^zXH)la11WkAi&npF`ggpx;I4zvv%Q zF)ysUvOJ?gbtx(i!0WvLm_HuYJBlNecXmcOTPSajP)1-&JA*X|?DFnlpLGUn6WGxX z%rBt6{db|s|3gSdI0W_gVpR~rlG94)XSbGUw`;17*#wPHeZ8yh=#I+xhT~jV#--wz zpG_HCn5g~`1=>8w?ivT|A1-Ne^5!>WxR>J=GRC-l=CCe)KmgwYnNcRwgB$_+`E39l769$x zn4rW@|Bmq6@%!%%P|DVD%oRLMR(YycEIM8#+l=C{+~U~FEn8ZTevVQTI>9v|q1~t! zv`-qwrO9R;s$^1nlCqg(dAA1Wt8R~wT_`+9^AmAdy%lA#fwYkNFZ9P&xC@m3vYBL} z4S|S39dV!hmbmG}`M1I;_tWfn7R-U-wa3E_|1|wvLPGy4{mjr$jef4v&&7(J0rlzW zP~vAf21dthQkUd2Hpip_g$ntUK3k9zNFCCy*9mqL?XnUS(yA;&cOz~;?oy~=lW&Fi zml^Y>2MWZ`a#5VHbJ^`A9!4)CUcIGW3Y56-DhB83=dX}V_6g>Nb6~zE5Lgj<+y;1V z22n;TH!r+n6}jyMt3t+$-ur%|$zt_f@VNQv?V^`+uLO88Oh@@9=1`X|6^-e`EOk&K z72;fnVNQfW;}|d~z*{H_Pmd5_9jX|1sS_T5LGaCj?2sUTZ^r=tx9%(S8+JusK*A9H zsY1_vWQQSxs5fR?u{wwvk&$YsQfb|#Yf&1zrjodad3`>CR66TJDMZ*NSHsRps4JD~ zcLCx52)-I65}rO;kqhAjUsaMO?@=Xb2Jb5A&s&6*^!*25JsK?jFI`XV-x(4L3gvst z3>8hQi+$V_?b-zj=r-R!S~#^951>EVsT-yL?)T*IY=>Go41C&YJDU8$iV)nMmX956 zw2X4Se?QV=MjxTe0)qUHA=aB6!zRtI^>ZyhLCJd&&-;{^B@RiM7gOQq%XK6P{k5br>t8=;@Q`0+K& zqO^LYDqbV8gE?H;!%#5pOzy1mNnIpH0PvI+K!(u2IK zf56Be&EXWwzMH7d1z%WQ=@WqQvz_oGmys5~iR!h-;DsYF`E;sy=cs17365^4$AOv! z?LO)AE$fj5Uh{JZ*$a+)2~MtfhyIO#$HNA~`^NI$+u`3?ew~{IgM@7XD;EBB9sX-+ z7XB5^@1N_whWH{9I)%+1F7wU+|c{>0)nIYo`Uhj%B{lFAaUeesa1d#exGt17}>L;|@>lg&CZoK<;3 zx(dX(3XYb?uG`pfRe6>HnP-P`@^4VeFYgE8ywc!zZ0?Y@Fp z#Ar(!ZT;Dv7@98WyoNdFFbJt{1T?6;02B zg`JAg^`}p&KlePWXk!)EOi*IM4;v!blA`WlSPP%n`Pk;G;4F#kBL0mHCf>6i$VT0U zX6c^WxdIZ6ddT{sE)Q8xXqp6ubQxgt0JCthEASuz%uZj;6(NeijQzNeQ_JGa} zKu-pAJ3yBa(d6dMwzn{{uM>t<%xQY9foF--p$+#2buqS~WF{%YHWXsyf!KSHzA@cI zqi{-dEbEE>&iuI9isNqhkn(+ORrsa+0502j$09Oj+0@&74YjLvlOYIM{L!1H^3fIp zpNYHzwI9XMrhI6>lFj@6Y~FV~ztWmJ!@a)p!Pl>FlhJM9Tk?jB+qZus+{JHS7Hs5y z9)JAF#cjNovN(|{;T15uTBSzIg;|t_dR6&?&FVj3ec!0NU-RDj>N=t_ZhFN?VY`$~ zgu4xEb@bkc?hx}bAqsW_m*ch-0OV}Z@`?Geg*%FgSKO4tJaoSBj%%1$I3{%!D_pC* z*Ds_Wtbcm1tkE@Vss@e8`F>3NkwzN|chnSp1Gx}|b_ zS?ZoPYt(JoWep>fyhH5v>oDpns;ZZA+u~F259jeZO8t_Oua;z09a1{u=|-|BS^RNM zN%hLCF*zTW&RAN(hFH}zC116&{CXe5P?UubIBoXnB2$1#0;~b~d#L^wW6Ds2X#FKS z!7nuU=JE)^eFV^6ZX^H{7=92YI_=j#plJq=(@Q_)6W%d--)Tdq%n)~P+CNO01^Usb z=s`(-xxxA<$(MkF2q{SsF>IxX7-Ln4P5tJOpNWROlJ3E#+eolhO?o8&ktTI_G;K6s zBG%C9sPDmtY=jKXqM$u2)@wfG&q3N+9j~CKgNc){p=TOy(Z3{DLt&*?a6=BT)+;0$ z=BrE55}E{pjmkQ{@mzbiTi2kc%KK<_E?H01RxmH2=HPCvwmzw>;V!qmk~-jzW4Zbz zeS+YXw7KpTH3o>5Q7*uG6e_9M7#(BKP80s zOjXdO)wlAizxbojG?DWG_&H!R*SNq5cd$rlcbIOY>KtF)`~>;dEwBYAyNy^)S%O<& ztyKda9OxfRzCGRe5|@JG*Y{(DQj+ipJw{Jry8HWU6Vv3tPU7_5d+QRXBS^4TaoQb# z^%SSiM|X%*gBuX(aIP_X3A}6H>}4QapFZ;;+E9~t&0n%~L~GTCL4WS^vX2;f%vG;MgBu?wkhNgDuhW&UaD!8%hC6;^cv+$Ij-Q}{9lxq6ZntkT za;?E%R|L^+U;Ap_VP&^Z0F{hgYs})AjiV`yIx=0nCce;qA^tu%3=*SK+~5zI3RsGEzxOvx2G>H8Y%^@ zUPbHV<}c4&a`aR&2CFyHe^_{sI#$AaI5lX z{?mHDg}&*+DO#(rftB@e?y5yl!XX?{6gSi^*U=1j!jPmtAG_v^9{hdOj`{A+*VmI} zey)BrEb-@31w^!u77e&qbHX&J?}j{Z%8(5}nzYiV6W zDDUFWZ1C^*`_f2Q%ko`AwtA+Zgl)R%viu866Z9kOG2`#CFFA^&{+S_k71XeTxso9h z(4D)#LP0+322<(L=}jrA)&_521t`5Wp7iE2xXFw)qo*Ftf_}2u`dOQibo3rO6BG0* z(UP!6YW}hOc$a=UD8qW@^Uv#fN&J05npZI5 zD8p;@v^|lS?#)vagYSIYh0cBAFlS3RGpj0Yq>tp@{xd)`P+r4FL+@=EC~sey+E+6x zdiZJiZhXA7FP2wjtG~#5zEU);TF3%;?6GAOk1G*V&+m_p80~Clsymd8U#w~d24Asi zUL2QI4~yBRK(BDo$e7^k6)p^MbDdXFL%BU~-@6Ku_C2X!a!GvfAr<@_QO?hCnD8Ea z=`emS#A3$avvT>_&TnRj#WbQ{dSib3Vow{6{R+d(ZoHn$c)bm5C%P9+VNz_N*y0_M za8EP0wvNiRIrA(22C?)e>A~rEn&%YFGV4n#kRW?^9-Mu^8N%KTtaskWh(d%uLL`_Uv0IDL5TeacIu}21%5HjD>h%1w)VUZyf4D$R zSQoB}6RF)s9H?h_1XTZZ`|H%gF!Sm0QzYlB_SZSM)nw6kw%F$$HBt_(y`~R&sY+VS zN9eTTrM7iQ7z9)|>N9v0`8YG7^`pu$vOXRI+7)^n$s2hl@`V+5Y_J#kmqcSnMq~thE$FP zU00wlsh0&L>9C>e-S6i2h z>J)pUycb|Drb6>-!a$F?gSmz4`p51pDuVKp&ApJKv|k0F-&es6 zql$x?rcYLdBPNo9K(z()R@DubV^m>*`FEf_3%pYwjf;v|0#2khE%0WXt2G=Q_3Su0 z)o^xJVuTl;y*T#F4~t9c;_}oyrn#;F%{;#a-4g_rgFgvkslQ^{(d3R{V`9W8?4DcN zhEbDStGpC~3TAPo%uH`c-1F zz)({lc9zzUMJv1aP3<}cVQAUIrE2>pQeairU@Py1u5Y;KdvP&)wvOD{yTlF34QeJs ztvROVA>uj>l_Y?J59Xf5ch>1Hd=BpIEgUBDwNwe0YIINU692qF2|3lilYq6x6w|;* zx~@(k)N;Nn@NN(57&5k?wXWgR4K*gM6R0At3n@8kQXN{mi}L8CDM)RKqakH#geu5w zHH`v7(^LRRVNuc23Y_;AdIF^d;>We<5s(DlLcCm>7^YbM0{N*fQZS+>xk@;Yaz26r zdVJt)t*%fALr|g7$nwm$`?EgMsxEy~G>w8Te#_P(lmi0sa24Jg_RIRij{qY(;iPYZdlhsgv;NBd! zsN>gssz_bPLSTgpnQF5jS3hdD^3S_*Z@}(#ZzB^XoVpYytLBE7FiB~6QEc6ff6Wp3 zGz*N5fk|z-n6Ej0WW!er=%L~7HIGM~HB?4aY8b4a8hWaPt4#CNl=@2S_1pg#Ht<~r7OE$LSq}Ae8|M`K{ z^Qy6O-&3WDu?WZt>Ru_FY`3ylp+2kcyuRstIk+NYJL=d$u}$N?ygoa?L1fGDpOV!v zik_F{Z;l#4uRng`kJsz@6Y{A^wgfMu~_fWmZ-Y>nb6W-@8)_UitNw(pn zIm#q2kK+OaRk#x&dGtdBS9mi@Iot9x`BK>*oItU(${zJrVzCJAwYNGd=*3j3gZ|4> zsqOYqs_FNsRN0A;xV}Ppv1-0%$ItW*3iT2yw=#Qp2u0Wmu~*`tQK>q{F3G#nrB z)g=A@JL!XaCVeN7{)p7uZDr1) zIIcGv3jI+JrY13dVYeocUDDAcf>-x09;@-esPR$58SlNcKTymNy$=mTFmqJjCA1Gt z3?|hno72u%G6#|~_Q4hvo<;XtD7qRoA;@}HGwk$f>54=>gL)lCN*|j(+B{luH^+IQ zqdai1?Sw9KyU+*yV*>{z`$-1AMd)Z%Z3^w(#mBu$ z4&kW7fx`6Q$SHmO-G$n09YYBjH!Q@H;F=wScpX_$$5gqg)v5@kzv67SR|=s)r0#X(hV>=%JMW3{@aR8*-XeuNngWa$s<ij!}fDje_QPx<}1HEYxP(c14FOZ;Fk3xk#Zc}ORTHaY!AXX(TaGCID1DR~rR3oM( zQk$|TIyPPb}So&{we%;hy8%$t@9vbanY@*%!`Gg{iRXX*A=1tYDSGT=Q_TGS*rxP+K#*?Trn>1k-3A`qBVfbFz(M2r4k4o@!*m!?88<&{+^H0wa zXUx(Ot1vlgoeilL@Mzs6z&F?7t5z_BVQEr3KFCl@Lp)y=ycWf@fb#D*wHzbYQn}{J z^#m^eNR}g<_eFUR#tR$#Wh_qELg6a!kyBaCozBpL;qzSOPgTKxjO+f#Tfi!=Hs*3O zCJ5~D~(pr5nrA`)qClfc#iY>*f+B8qi%K-}9yIBbK_#?PtjO);`(0~%|$ z4eTh13?^mKvuTs}+r^EJO4=k~^GOc)A!^6%@F`D+s&HA&!`FKGR zdc2y~v+>lJF`d%tkCUQ}8ahKusG4x8!o2ARFcL6V6|V3_P}*F(SBat^175?OQp8ck z>sN!cYX8!Pg-PhQUSf4=eDNa^I?sDA+?=C+ISDneE|=;nox!y;)#BIQrN4m~_m*nB z_5om&!^Y&`-+{+2ulEHM;nFN6J07Ph{K!xTxM8y|Vz2{%I=IRP` z*GL{H+u3V!VG&<{^9#qE&h**dG@^X7cg4$JHf-QgylKO{ z!UOx;>6rA9!_g$^!yv2G7Pm}CT>i=ifwoL?1t)zHdfFw{V11aEK0tGM@y(#ifF``i z+kqiS`qjFWVpzlX_+*SV$U<8?t?5_wbFbI-T2R($39s~FnvX^?%Z1{h*6MoF!ni3i zlFNM0381&fifnSS$b=r3YB;)B({gcJD_@QF4R&vtzzt3$_QiMHm<0zE>>07 z&$m%@!+i5eE~QVd-M>#vLxz6wnupO{WeulKG98l3FIh-SPL;l#gk}^;$z~DJ&(09G z;0n9bWw>20=J^tPvxDJ%{2pAv=CAS(R*edAvuaeD>ZeVN<>*rYlB6!JKZJdpQIlD> z7|@}w5+mGm5j8p@pJ3_JEq00@WvL2^aAy-vP|VZEIDb=%ob|Ka>Ro-H!tDWZz?Tyl zXn8tgh>1;1#4lK^pJfx{=PjnN)=2^?DPcmtTA!u1a)nFIHGGs3r+smDeX4`;7_W7l zv_yN-xO8GEN7ok&U@?(b)7>iK(8Z-Ao{!J`l$uCnag>WA7XRYTefwtB z1v(ADU5fV*2IWbKR~XitL=5Rw@z{6BvyXK~rB9$IVq5S(dY{;=Hh)7fWLN@cIzZj` zjCzJMT5_!!PMvZHo zP{FuMR3@r_JgifvWBo?Z^90lX#@s#0nAIIe0c)ROH`3ARyi}A= zrFHaJ|5d*;QiONucM5M)zXQpm>%Ho>zPdSE!&P8dI$u&5mQ(WR%K7GpY7o;{r?nO& zW*0C{n4493Cd#?LKan-Vj5a{S8#NhA{L_1C1@n{H)M8Ek^Hi=>LMzi7oQ~cZ@z3V!JYW(XCp)faLn+j?YykWeu0p zVV}nTa|VQG$FdpZv@d5ei%s&cDmN@m9g9|2J%$65wNP!tfr+@n9?^yaXAWEc;lSVjzK-F*q=t;) zKqG5*DtljY@Nd#-qd;#23Zu8Sxx-3LMWh~?u7`3Ruld0+G}&+r|FI{ETb3vVC0YO#Yw0uIjr3#GR{e79kn5)XovsyZF&Yy}!Lt zmVF|dfo|jIT4GFBND0c(gRa;q7_v?p9>C=CHQ>BZv8>ESz-$PJHwyqep(H2;6s`bPIae#!6E`XIS}arJwBtG}T`*cU}r)-aVe zQo;X8>#D+c-|JF^{=Yd(yr}S2)^#=^#|1^V<;T3z7Y4=B#fkdX$E2`IY`9P7Nyq1H z%aPE|{iXjQ)x78+s%_!9!Y~z=HvkN*3~k|;ax#knoMzioz2SE<2HnqvbW;wayOQSZ zL5ROWFW{SX1Me$vouG;GTYLxkJ!?mp0ty~b$PbVSOf;}A140e*;$3Nw2jTIiJex7F zK5RIH+G*aYE-cbeBe!-MYQy_Ld4W63CCLTnga=fd%<|i|0P~; zK$w^HMBewefo^l9--w?y7sxvZeVVgUBJ`PEAhZdO_v|y&lq+yAJ^ClSTdXx7O)Kgs zxc3$d1{rO(=CAH}mh^|e5AIIqU34ney%)@(r-2L(Td3XEQM{Q_TZ4t7cJG~^BM(|; z*ETp^UZS1fL3xL+Y1iqXMv&tDrqp?7$vf1YhmqPXU&tcLcHZST^k)Pe49p9IRE5F7 zoMT1HsZ%>^WM5}TmC?ssyh^W~)p8w3su1pE06dGY+R9|D!Z+f9*x@0uTW1n`Za`f? zY*~-QK3sWEYUX2=ezp9hj~SlX1-bUUwIDx8-(vBYc?|rHeKiHe_{lCw zC6L=mg6iNLN4O^IK`Gq~*167+_N^({m9KVsRCPGbJtuTC(P~r}Q*seyhnCtmJ9o>C zVx%x3r+RQ!5UIpoL5_#Eg?}2d=XEJ(0MqbPhvi zwBqNpN>gKVGTv9=z;5M7LQ_{|Be6sl6ZHoV&#C&LtbR%^v!}e)QF)j@mn;6rD2%aA z$pyN0Ind)$``CeA@?()fV?|2irjHAYYEWbs?3QJeVPm|yOo#U>867aczb2bzke8*V zkVy6A{1operDhn}?0|EY*rC!>*>->+Y5safiK*-p_6$12S}rohQo9{3e=2*IC|DQp z@Qv`sKs7B39iSnw zZTK@2>v{HzT1ce?iswIg;*X{b8t+$lC5CGhoNMOjbyQwb7P2I)Xm1(MENVAVl_e3D zL~yu;i3)47q(-O-37exm08;%;-zr&cT*Bf~B;`o+JmIfDtQ;1OSGfEfv#IcBWh-N2 zq`K*1*8gTGn}&d=C?gML#A3r#pKIzY2)MHqz$Sn#QgPf_93YFY6y&koaRe)@yH(^p zQmqdQdg2s7c?RSxH*%n#Kz}BCwE?FA7ps9=23*Rf|0!2Fi`(+47ynX6MGH`(xR4a) zZb%uQ5Ck2btFT;Lkb5zaDrzK+-xu1b5K$9VU-dVv0%+I3xcj^cY3C+AoRqfdguh zB%bRMTl)+S%Kc4=0}T;cLXtd$mXK6-X9+3x7aG(jn1S&hLP{3hQ_YZJJ7O0s$K};D z6Y+aRG~TdJY@vRkxccNCUG+Jz#;%c3v#xgyFD*Q}}?7M0h4 zZ{=dbN`-IIRd~O|>s-&tWgzbfM5nJ7HU1fp|E%J{Q7)wi-uLBI2e`-+eGd!x8>G{D zYvuh&-o_ck{#M?9%DY^-&6M}~D0aNOPeie$^4^bkVcYcl*n)hDAj4uYukEOu9$QcM z1`~`<8)jP@T+~RW3wHsOeiz4q5d57Xv%`aL$1BjOu zg!S``pxYGG*Mg2=5mlg`K<`#~T7ty{HY5B3g}>SCx=^Wk=_?uE?VcI(%vFfkH^OlaI6-`B06LGHz1sx( zqQj`pAcUL5o7_oOV`c9AXzFlPbm9+LN=#xG@ z6JYPn0hr|d-2sFpwj0uh;7kzc9y$7Oa_&B8OT%{NyWY7Z$t=n(kF(J;0r2<+ETNVMN|jX(@jO%OV)PuAC`c4Z1#+gw7ESp` zC9pu%$R_}5QHb;;*P3z0f@#Lf!O|+rR`U$PR#O7~McgtAG(8unxK?+_&JmJWl(yTBN6bjA-+r@Qb(K`=_NEue4J zF1#J8vQe1#7W|&*;v}yu*1WCWgLRMNG5dsSR>2vk*g?G<+&ZYoKCvAf6UX9@VBV8& zYIecRd{`}Q11kRL?1J0yPQqeKg4FUl&O*4c|S!8SA!Gpyc@wZ*xMwiknnHvoaDf-GJ7 zbTJ*z8QAw7!^A$Ta_I0+^gfN$Z=cEwxs*9_NBPRKK3llDbZ6|do|_XpgQ6y~l;-@= zXKo`I8-V;W^9F6*m@yaxW;}MIuuKg47RU1&2=PW-l^q*X z^GUo`4@DH$VQp=6-5CV~nbkBAU42y^7AO8h6uSW!qYZWgMjt$YTQ~QbzAQ`KWt=Xl z{+>CsY`KlD|DgJVzD>C}+Y3JN=;oSGJu%vEzd^jNg_C*PT!qAQ`)gn$wrV`2ua`K8 z%3wm1;HZN>uRgD_ga9%-sX^Nk5smcQ8<^5Il*(f3{j9n5gjQxrM;%8psmCn=h z&%AvIVTD&YB01I&c&Nz#l76qOzD)zY>NOk0YtCWR$6CcSefT7{hb6RwkxlM#MQL521TW{EtJY1zYagLFUwZo!{G!UZSz z<@lWr!nm?ViKFtA+>)``&W#6lW?V8xn5@+X25jp`CEVb3Il~{!`BSVclvo>IwJdf( zvf{a=xo8Omv7xh?PcUqx@zj~mhLo)~q9m0C5;u!DCI)KNOKnJv16oZDhI($PRc}8< zEVWUm!EmLXuR@>D&+rzMm!x4hEbJoDzr@d@hS%fNRg`64&D5mI<=sE(*{q2pQf&4N z*L-LM2bWxUm*OL@iboz)rUnLJ+Oy!;tW*7gT|6sK*@%xytvrwJVC6vrG=fr#&b)SI z?X|T2HMiuy@;Gkw5roA_TK2*{wDQOL#j8r!5J+IXYa1HYu7R@hv-YqdZVNDC zi^5g7yqbJ-FUP%Y5Z=ajp92U7mo-Chc|n|{L4QgwmWSyZafj)}SN#b_%>CWIE{`VM zg$lQN8Z8%?#ZWaowa{?(>}^%6WkOfPXq~>etijgkStYzU(ni#87j2{(Uw|p2%yr&X z-dsWu_%?D=e^&ZsR?O|0xxM@0Ia&%^D+fS@|S}xBFKd-Hhls4YS<}et0!n{uS zQ|=|^lnJS8H?-Q;#Mke{lP75+WdcZs9JXE^uaW&w71*(KwpEMHfW%aASe3(9f1wuA z9d5zWKkNP)Bg|6njN4x_fyPu-NCBuCGzclj-H03K__7gSR&I;`VfkwcbgE1W>n^-; zX2i3Fw!ysxW%YXrj%-ql`1_%Az_v9 zbS(X!tFb_XE&J1`CkKrh<9jwnpkez%ES;L)(teWJ)63OLr?K#pnl{Nb-AnqpraM-{ zrOs1_({rP#gPjk>z8Y9GGtk9Lzdwys!&f_LUZe-6`lf$QA>uW!*yicuMy|=a-%N;m z9;mPmT&&OtzMuc-_e|rPX5`1b)_a%--opLcMXEX(>Zsd@ka}Iq6$hCL`Fr8vtNZLG zAvGAqHsO}f+mr#M*)#Tcba4K^d6WqFsI1rab!9z4y680`z0^ZC-Rd?TYg*P>1AgY+ zO^E+8`2=$^wI_^1*HW*erC_ZlX;BzZi$F&Xa2?9fOCCnnQ9)317)QbdQ*;m~Q{4j}K#2jJFf{iOBtAwQg}4F9-|UY?v@-WO|S_21desc+8| zNmyl~u4Gt>Q&3BCxDMT3kr%k0vVABAF+dQ|qB?82m#O_VJ>j3!w`yo|dIh=Yov`Yq z`QB`DVdcHZa^bD);_kU5>YoZB&_-7ktHdlQoSMyb zQBU`YJ@x$a$%A5*1IaPRzY#f3P4DNw(!OB^15|!WUVTuXs!bBrPie^_pv0dbeL#kP z`B)k*&uO^Xq|SiR7#VIv(N!+m8zT(~OYXY|VyE2S!E(F*&+gYnDCO+<%wmao{dcT| z=CINR+wEQoOR);Cerl3gVo2H+AL~(?H79Lv9?vu8$p;XR=F7=uwP`%2>9JKtn78X0 zs!g{bp@Hd51SVX2fuDYjrMrz^(n&feR!^IXvq4}D)(pJk!J3|)Y`%^#cPz|?JFr`) ztd+<$rI(-5u+Hut*#0N$dG1b`JVf?N5$X@85?59q{)uRKLz*DsngD z^>~+}Fi5dR6_E;#W)Frf6(q9@`u-s9=eVo-Qb=seh9#{m?I>mX0B`lZ>}-w&B0XF` zItrLc+rsZ1ZP$}iC)(boOG)T#;A>*S5N|Gcgdk4{rUi5+gVg1jbZ!{X>764hHi*I< ze?b%`k={F(l>w$fmOrW7>B9M>2hSxjTJR>&)5?P1yVP1IvUY-vuiD5l0cz=n{U z_}AoW%I|#H{`j2!YRdK(v{!FaKci8$f7hu|YM5sA6SUbj7wyd>TwKbdP~JO#wMq!_ zJ)DW}fzJ4*cEL9*z*iCATlQ!0UEc*?g=tZ=lGCF3-SrzJBGm>VEt(%_(aVLc*kQw7 zh|^DA!M<>$VOmad|5#;i$ePW(ljHqk>4({Y9_cYe$=%^DzmnKq&tg(Xr6%ktFmC(@Ae=MtCodBXV ztCf-P_PRVWtyr+tOII(*wF>*n+i4LqmKjeq;*HpIQi)w+IN9HMqMAu-N4%Fuh&a*q zrwwANkK`grQs1frlhcd(Ruv@|%{A{YlZ%A0Z`ChcCs*M;aEf(uQzZn0OH&JzM0b}1 z*UuTy&jO&JtGkd4y}jplXp85chwG~osdz$@75&i$pXIEP9j&1aKHFaKLXmnB+Ek*R zkwpD_3yat>(IAeEoIIR*;Ck#qgJQ=&weZ4fVpzae*m(ct1mlQ|bi)*D%a%>KIF)WA zOP2{$(E(H(0Qm3+UmvsVY6b7zv0gwzZ{Mi7ky=TaqxSBeZ=Myi? zEp30Aii>Yo9K%|2R^_H;4S#L~Luva9-nrFkt5NQd6eV&@1<&kxypQosNg=ZS70O zjrg!~$YH6Gt9bLdz4B9NJtC)SRfkPxuL%Tc9*cC=idndrHW}=Foe98Oh>SXS9r3U5 zreZz_EtE*4_7p`jEadu;u%1pSIn_U1=`#9BJGYcRNP6uuHQx-z?Hm?$I}oS0=@J_; zB1_qJFk;Vcj95)8>OJ|BeMsKGb>g8%sosL&$|hE#yNP3$?3}x7^Z+LkK?fO{ZT$_X zrDCqUy-R-^=zqkei3&oGlw)_PYEm!?tQwM>HmM&IiiT;Ey$5eL-R~3$#H&W7NK#Ys z!`yrKFxO|GA1yrD|th?CU7{}2RsQB4h@h@dzKESU+&26M1 zTyUrBZ-enpa#4OC>B_1^{ddVldFEE_kN5tukFgJ$TPlYmZh0k-Yk*NYbV)isaTfMw zb4uHnU}Wk@WRj=|N5(iN5D68D_cR3kUpJpNc`-O79#H z2jiIVqxpcl-N$L7nROHtmC!#v^FcTQYfuUEPzel=^J#+l>$*vF+kNXeI=tJ2=;&~j z9ZY^6p)X6FUf9b8slv<)Qp4Iv9M1AjZfHT&(U;9f-?d6)Eo-= zPan&<6D>IO`+j8BrMe`#T3kj(G<{iv+f83K7PjalbR`qof z?%G-E9Tg(Dc6Q0X-8|xwgoZ=wckS#S?__Xw&>z>u)eQzXuJ+~IiK~6kG3$Hd>=ITv z+%O(7>*>Z>HYb}pVZV#kg;H}jv9_SW40By+o)&4PkB?@!NV5w4YF55xrF_#zr7Pt9 zoAXAK<-}@N<%vV6a?K;X(my%{iPY@Ca$Nd+Z(kSEiIzOk(lD*iYd@6sdV;r!gGq0x zrrhIQB%l-Cd!xwakILp>w^=s+B1e#~(JN^?Wip>8De(7o~P^WHu$*+dI>R1XIXBa1Qv)3C;my!LRvdfr_@JSJWA^ zHJ>d-nXbG|rm2LaadgAgiT7-OH*VkK7PRh~KQQ0?oS#g6b2RG@d!S}=;xmuj7!;;v zJdHf8D~Q+Zuh6hNa1-q>=3`Oj5tM)RngQ{dn*)Gq8djUHLtP#`pjV35e#LTCvbhZ} zr&I=H3(5QzJT$g=&DRV96PQ%T?hkwXo8$Q)* zIK1}uK$lm|0XVdpt;1=oIw%{l{W?}DoI%2P&2*xI9O((N-FRac3gVwhj0iWZeX;mM z>XL;;{A!Iv+nD~I&=XL%VSMI}0d?1iy6W;EU2Qf6#{aw}Z{*i#9L}KG`0)j6ki0ny zG$mPOo?*_zd!fWgLlN@=9#o6i=zV;nI`ME7BVO~M;yTuA?!YUmET7+6hJ7nf6CbLX z+@v?_sG=$O;pb$kh(4^ys^C<@sMq53_KAjRQ%e?BD94+}a{D&5mxfyLngf71G~b^(-W0;!&~-6oC7T$GDOuP8KL2-wP#SB`2ZGywk^s`r zBaN!G=4%9_DG6xpGuTrh(r?U2vVoHP+LGAg<;KWAkc4ct#BC*iBb0)=KnhOVypt46 ztd|rFP){Jk(~>!c>3x|76gw%{k%A$dD-@w}4;PaY(ZCuI4 zZPZ?=xRkAiirNeCLIGOSQBdyuTMFD3VUI!^kn=op4rI7Mnj@(A%STZ_Rw9KX(sUbw zBhYkJ+jnR=n>{&c3ujNw_iHSy;)Wb~2UdVf6>l7AasC%02ov#_LNR%O=tzm&VV+?m zg_XZCPoPBV@IbODkw0JGS&5vdxDF+9GF}J}kBxwXoIg`wk<8kM?efPs}YuhGv)LxyqO%(<~;r`YBUuRz@WB+1C8bhIB=7B0uEe* zC*;7N8ai`87O^rope-vhoQpO!4jkZ;wonD$%{ywZ=PyKs6~>``LDwPm2CXN}@UKxK z>qS3A{1G4zCAd~uc;Mbltz+ZQHnMRV=SCN~ngCQ%m%(Y3iCV$HbF2(iCkGN$bxg9^cv*E=&>dAB9P)6&b(uV@+_{5)>21N>6jV>m z-NvaTzv_oxBRJ|#mf|VRdWYSc9RESwB%2G#QeC_9HEvGCk+iq8?Inmgc-?#T<8gU! zrHly4Dw1UL&Plj!Uh9ml!7Hs8c2)2)ks65*ppnQP)t&nw zL)6x>6y@FSkgagY;x%=2E)=BA0K*)w0LZ__r^c03HN6%-9$)V3QLMtyrcolg(3|N4$a^MSQ%9YmN8C3R0DQtejKL3H;Kl zZ{tnc8%ZF!nvqb1vC2Hc(Jx**2@e>B#oNeX6b8dsrZ}Er2rwRC>2wIkL}3lVP86Dy z_+<``(D}8v#3l;MTte!s&O)6iSp8{%$wXnlzep6eBc9arCuP7*mOFym*x+PV3-EmR z*oKy{d9|ygD3an($epjfR-Z<|;=^)LK1|(!_l2?UyW6>WE_(5)`pr zr{R*#A_!g{iwBMk!{@zKXN49ojbkGemojdu4tBj9L&)1%R zvUv{RwiBwZjYoM;Fe21k zwUisL{Rj7CL8<_+o)fA5GXz9DQ%@Gj$z|p#=9iM4$A@$(w72*gLn_W1H_hSR`Vu!w z9H=qjnjL^~vkF^E)*7*7)*A$+wnl7Vr*;9;f`@^9h@G8I1={;~_MHw0#%Wc1CGCYV z<5(`)x|e*!W^WruWWFQPI97-o0->jaAJ1}}E9A#zpTUpEbiONSFk&~7^lJ!?R1ED8 z&s4=!T}H|xT;2n<#u4#K)uTlqaY}W4EHDc9rVTMxhzMha$|#T5$CWV$x2v=x#~Zd- z0O_c)D-sIwUV(Mpv~AE&wB98Rz%oTNhVVI@mNaVmid`bb={P_fyA0_kHI}D{2n9?G zb?jOWtP`JGbkxmlwR?v`hkvc1A8%MeFHtb`Lgdg3jd#66ubK(b=i_$h+amNM9eM?L zY1rcLvVPS6a{Z`(TL(7->aP=e9qe2W<}9yXFXmj8fqplkKY#tuU$lPcx645P;>V!h z$k0DdW%sSpu8hQ${b|aWnqOg@{;Kj=L~#;sr(OTdFg~qu)?9)5+espOQN&jON=p%* zNL=Odj{eA+q$=2n>m76(K*j>duHw1_q=w=e&zRzGO$M#if0w8>HS&W!+P)fI$Yyun zU>V@++xzg|*=6p1yrh7F0css?SESbfX&rSL|Mv_IWT1`35?<&;jiX|9ibDgwnuqXf zr1%J5%B{73@WpHHHh;7B1su*KIPKyl4V^%1IFrq>3xic0PO^vL@*bXHr7yxAN_H`B zC)pZNxP}u9^cCO@#=MlTVJIChekj#Dyy!INsW;Df=eYt8^(9)_n6|9)ag$ZN#_E{m zX8dI5AL&3Xi;Y%t;P4rk6lJlMVV&f#4l<7rq1sh(WFa)(he^vqC9^D6isz|jl}=f_ zZWsg7YRpqkRNpFX5#|cPpBw_wD|YaZjq#Pl>Ei-gq=u}hRdCaARjHp-5^thQ9u(1O zZNf>OZ2ks1-Lsi1a5>rg#nCd#Wic5e;PT7DQG=TotAOE%!MpR1CcjM)j(;6xWu8Ys zBaXZwP5My-NTdBULzwC#99HDB5<6in5L6QccHpMb2}(d9?OH&FVf4oLz&@+i<#-G6t9` z<_an%2e&F_GD7WA*OE1hG|nSxN!_N@FJ5J-J=`W2Cn*lAo%kge;~eO6f!_3<6i{;u zZdXTFA4!+3-p-;QW@#(g{4BAtc+D3gF!QyWUjggCV`V6IRA^aP4U`as?g6{pq7f-tWCO^iYIq8yPRdopD{@7 zQ>_UgwNE8o>ZI`;pdcuh01@Iz{SM%E>YC$jH;dZpWc#B#J=Wx`Sm~3|MO#TWC^(e89 z+POU549x$uR_}*X^r{7i8BD_MGB{s}UE#eM825!Ug+#g_N_hEI2Ezs`qngMPW9(G`B1hyywi#j2WCMZ)$fg1CTc)d9h zScL5+2Nq(h5!gi$m{Nz0y4YdTpaqxfpr>hm%bqR)-ed&AKS$IIC%ylWIQxGT)nA26 zoIN(=Y$%RZI|kB+7?}KF?|7dKVXHjMKhCkPLuR-7eI&CTsVbkPq;o;<#O|v(on$s% zJ6Kp6Z2sXr(*~I_0z^_f(xLB2N1A_G@O>ose$Llu@CQpq5-u4e2I?tZ^P)J=q0@Qb zlk#63R$2t6y|xT6vBdjX1eWL69IsJw!15id{dvOn{tUSJ3oXsreyKXTuuA6OrgDSX zY`k_WT`mo_`z7e@jZ}~6W~n{l9SdO z$u=2CP85<2gk&2b*xZ+4(guKX)iqjSqM?z0=6yUwA zdY>UAHwsBZgk)Vj8J9uHbwV;yNX7|CB0^$IN*Z2nC+LpF`&_|p-yO`}f#?A9Q9jPKm(8XVYqZ5J|ua1F+9&8{WPVSa}F`7|8(}AApS%w%iEJX@5$(%3)KDst7Ca zdj3^N{)5sZ`f*hrCD_6>l`sM48Q5APfdh*;_-lt(l`OnT;l06u`CFo({l5|8iz*WO zQiFWME$J=QE>oQs&%8Oak%4wnSx#Zk$9gM40kBg;7Ygu=2ym+6gFZNk+W{R45F%PZ zfOr4Skn$(FKD#n3NRg$2LC?DK7UNeznpNIq5tu5=YK0|RQ6csVObXh&-GTX65vWpr z;=ZV{@nN#d)d_X1?VXF)JBMWMoE~p3a#SN@bh>h^-d7C9qt6LR=6JM~SmUd)G8*hG z6I|x;PH)^zQq=CfUd<_=c3QH{0K)-KAwaF;#y3O&uOa|ev|gt3_i+maE~#>&!H?Bc%|8@jOO`IbSI2;EBgyt&SA#EU|)m<@bwd-UiB>umEgPFm^67(v+_iQ2P z`>CO6bnpLDKX2&gW&J$Qk5z#2IAqo&M>WhURNmn*SniJX{~N?C+cE+!Cj-tjL`LYw$Xcl$1gvcW=ptH03d5;)qp;Vy$hs7}>GYK1AsEbm;vNPL~9e z5-^nu(}JBS_WrONOzA!JqkAq0nTi?-nLOThE4m2T1*6<-G!rr=$S?mc$nedG%sq}^ z&b{*2;+Cy&`d7Nl$x{7?WvL^#@_6^Y$>c0JavQ})>&n*?OKFz_=_KK8?2!21x^kxX zqa4B1MoYOOtn<+PREP*ln=uXeJvgA<>2`N5App! zi@8lx!$zg&9LcfEtmn2HIYGrbR7Z(P+}S~7SOg=)j?D7%r! zbkZ9O9=|{IswQ<=DR^F0dz{OR1L4W(35Kn?i9pA^#uBT|c?3lDE|0g9)qA*tqC>6W zVo6mI?#V*SNV(K4g=AHpkgg)Pgo2~V>E{hbyVLJqRW1Xd0su$*8!j?HRQV{8Q=`bo zhzu~BQSmyLo$YYXilA-+s`Da?zoU}_|L1``1Y#sPh{|WudWeZpD6Lg!CtJ^?XpN55 zRlE5ykU*AX(9t}^GVB5vuUR4LoUsQ7_w99%&*Epi_9>$5POx|TB_!7< zN}6B?FrD9}4m$z$_<2&yM=dSJR=x{viJwua4oFuLrZGYxeSbS}{08nzC1 zufB-G-HZvS{HkX&Bi?iooU5x)JJv1PNlsW^xK=3kWX|-p_aIQ={Vh&h=CLnZc_u61 zm4j4iJ4l#D^TUz7BW>?i1|kG=ahjdU_srzm2#xjp8z%iYsFY3@OzpEG5 z%2gnDb4@n^a=l^8rE>PSYb8G?TdtLCZWj9N3}0|H!9Rh-f!nSr1gC)KKyh!>V|5Jb z2aEbK-s=}5Ps{m9?~~rk+MjW?a+iQ+ZhbyPY(@<0aaI~`bj%53dMwwXI#;f=U7g@C z@m0IKYXiT%&?Ku%d5d47BtVT1pe6(5?L!XX;a$FVe>gROLEuKN%eJAXAyE<43sF*Dy- zxY<^Oq~=S)C2#6Ht=EmZvjUI;;5mTk&Ck{NttDsN5b@Vs11vKtb@L;iWk=^Unr*Uq zG{c^l?FVZl>)o-XvNR}3EC)U5aZGCCwZn1Rg(&OG*xDzlwY;P`v{YS;%lmYq_260| z4`sI;w_0A9Ke_n-BI9Ip6S<-iJ~Pie=TQuxlSR<&4%t-PAdAyegVPviVq?ZdqP6>;^f_MOv1(m@>Djt$S$)m$AkLjIO3_%8k_8319zTnH~TW~ z^HGf&4Gg7i1||XB8T+!e`w@xiY1j|o6+0gE;+?ReT)j$U*h*;c!B#@MH-x+yYm23! zMry+CG*U|tx^bkI6yojv46jOSCb1wXK8087-3_RhlXh`DvahgXV3wiXdz2U(1EddC z3)oOCKyO+7(w(zu6zZGe2=y-BA?Gj}IhY^UN_wH=Zg|m&4(}MU5GO~T#h9TF>4Pyt z@BAF{QV;w*9})S9{Cs8lkLTw*OS_aKLo4|+KnNFl;OAMy^u*71Wn+wM&En@M&dkEk zuP4FJ|M0U`e*UT}9bP}O5I;XY6MjBK`gQX2p{IM`=l7ft_=)_y8e71~XHg)D+66Dh z?c~$u<|x??`BaE^eJlJ-;_690hl8+Zer`cbPy95SZNc%l&)IT;pMO3Je%`^4<7Y2) z^zTZC_wbdDpSPX?KTjk5I{A6^^F8qMKJ0A$M1Jl81wWRb2U4fK^7FkbdgJF(VtV4| zB0Y`~@Dt+z;^%P_;pb8Otd*aSEa^grcLrHVKFdyrpBs}tWqM`D<`xt$urGJaOix)$DsPRtm zj~4w#H8Ym6ctp*@)1ap2%!ry`zLKyjYSfR;@J=8>wP>yrZ!;L_|wwggoA}FW61sWnsioSn`l3Jre4@^9H4N-qs(F2Q+ion)Crle6)BJ`OkPEmV8l_Cy=c55pby zF>24&hTY{eta*IBV)7>BdT&`YIMnq$2-M7mw-hwdeO1 z16BQ0am0#zw)+s<@ZRlON}2JZZ0Cah;j)f`4)zW`-P%D2d0^VEHC?2ieEm$-PX#|PCG+k0w=gr- zg>|KtO()jf-4e0R`-qa5oeGj=is99QNp%v#_GhgUoEYkYuf)(hn=IAXjy#pdw#8}a zkB#{W+yDP&ex5xwl=6=Cf#JQ(&;Nd@qi69c|GV{pT5xt5maJ%sW<7*4; z7%wQqJ7uBz6%__^Dh~ z+a2|4bX)^3I*nVry~slR+~!31`LC1LgP(n#>VcoT{d9glH08(3=fdVLa*@f;2_WoQ zJ`W+LCw{)`ZrzxC?!YV#e!h7U{CtIKH@&fJIH&-RuK?F(<>e%)9q=vJc2^sK|@#khHjH zj}F*qSaTdSEIh$z2-a&@i(q}d#WphXOr?&>mw!teGRbmie$?7e@dr@6pa;>~ntJuj zM(TjQ_aIwEu2*(Pxa`9HqO#P!>$3Ip(3$J7;Zm}tn3VApOIx!fW>ii@v&?S>bow_v z*@@<~JE4=2`i{)h8jL8lcM{1|h$X+G5Z4}0<=65PR30DOFGy5>412!wwqr4gMVj1_ zL7<6jFXef1LOvud%V%_QKo%S+>($Ogs_|D@h)OYgBD zG?R-rgGV&Jax5jD13*V%gYv3>ij37w&()IDE||;CNpB$gRZH?@{BSERYpl`4>yuK< z___i7uP>mTy&V{?%kOk{AgU?1)^sM28ErSTjtRem@y{14sm>n8KXg!?#y<~BMtZRq zxttq18Dbm_e4BJTiNd|7Y|d`TV`@Fg7ozz_7#$aB8v-!>%E$+J}mZ7Ak7p9`UX zFHP;EvZ-J65_MC=|NBlU&AAzkg$BR>3?~$Q|e@>k0_Shq7WLqCID3+;T z%Tfn**Q^;@b@GiJTJ^4@)~!_=5f!IZe=ApyTJ^fW8L?fp>X{^9^X0OmgMmOs5l$e5 zig05&MHml2Cwc2`?=$Rr_b+*Z8jJD3OJeEM3`5(;3~x`fHuLlvtbv*hKA8gD?9f!d z{jG!h;LwJV`+K`Si1_^@5Wnqu(i4H%*GACf>4E5X?Ek$``JDD2jE+xaHS|yOAme@S?4!CA*ZRjE`iniJ6gP-( zhe=cRFV~?D$3u$rVbsK&Y0XHaT$iy2P~DrD>BD28ATi_PeE6HF|6E;H!=pB+yMA%M z7>|@5RoZaLFiAq*f*fGlH+$nwByZ_hZJ))e3C^mTj;Z#9`sQ4ov>IC!AKI@#rizCq zmNIW)sjskK0k0(G$WA?{5U_eYV~Mhhp7_8zwBC+euHk`n>oJpmvoiVDh{rp;r8EEX7fd$( z{q~Md{LBAI{8M)S1O9D=b>r^*n|);O{PWIS2mc-|3;CCy<@lHHje6Vh?-t^`2}ktA zzuZjz+4|{5i#qc!Z^0UBxP7x<-QJ0RKTZCW-T#1p|2U&3{vCsa^d^6ENwHS>yY#S- ze|Z7_^1SM|9RE%v&fEU*p7=M6b(g69+9dZyUi<3Ye)E87-)!^7{{jD$-T#1pH=o`U z|29QJdgI?DQmmDK`ySezfA4?f__sB2-g{*s|E#}}@)Kh;N4e$o>{$KNUpV|e79;9Iqw+{mt31!W)?0aQI4Yw&QumbS``@_od`YUXJVViZdXdSR3#L9@dH((T zA5or1CiGUGTZvJ5YGA1MWK=EP%M;emcdzzVp2bIGlqaa4-GcJ$m{Fdyk%aE`v;B`L z&xaMgmFIb4RGxv6g8DgmwyU3GNfp+Q@5%VNWCL(4L7;+)RHPHk8T*xSR#ZO?PtdC zenff3LUqsWXV;)So2ooV9ol>SObyyk>gBLJo0~ph^}!TE1H%gM@WV5zNIgD9TEHk< z67UcS!y;YsjulBbGm3QoZ+}FQrkv7Sk&Y)u8J3KpNYhI@7b(&QVf{2O56jb4zs<;O zKSBL`a)T?(2c!xM^NlM^m->0{H$S2RZygjGm3Q0KYOa5jebm#UOlO|B0WZoigf!ZiuCRwor~n=Z!+Q#Oq{FxdjPxOi`ggp)X#o|Q2En}=&W4)BEc}1?kmId2q*P|) zVIzE@AEwUdRM^Rbo2kPJ^;lxDwUC;Egnefhl=J1yJ83HZF>`#_+)DTh5~d4>w+w$K z!MpWL*m*))PkpNx!yIss#s3}lgH9QE{d9VL#uBl`TFg`3hoXrk_goJp_+4jcDVTJy8O7{0LER>!!8c_)AKbA{*scjfXxj(Mx&j)e1 zk{w`Id3kmDKUy5(iSFXC3rE--#v(8V;&3|M@SQo+g3Uc})kAR}=&=7vxlE`-Sv zhl2@OZ*drKd~f3L$#^FYuOEasY!cx9a8@V|S%mZ?4!?jniNoVS_8<<=jzS#99W2cd z%0s9RuHdAftFG}sK>#io(_H{|=B%5;IJH9nHew_mV1>opkhXQZ`Y?T0%5VGC^(EqsJ1mNReIRSX>00dy;0QU#i zhXN2Iq$dH`F%W=eAbSviXG#!&vf>PVkRS91S8!m#)z+M!Q2#F;+(Z3yrp;k&%BX)f z2Ce=Px6JxKdBs}mpHg)w04Z`Q0CfO*KwI*F0?>L19S>i+=M|HzE`?`1r2KHIIX^72^k z{ISEs_Jg{M!`2*2a2Sig7>oz{Yv&KHe~R>Fio=U6;`Kf}EJoTo)WMG!4-6pT`iaBa zlt6@iz~0i@#{=_$jKpDdeJBp6!eoiV9)zs7IDB2+n>f5pjOclKU&NtrfcuTQP#pff zf6wBuImAgE?gg?3aacey?|}U>#{;20IFEt5tFG}sK>)TL*^e5r^3BX$iIssTYa9#S~As{0G7&S8#fKyn#9Z9p0M&yhV%zV9DMHK%W5j>(_(=uzEz#0M>VHqwe}Mb-nyCKwT}S-`*;DO1fMG503$O;*|a zcnSpqq6rFG9n^?bTR|+yXe+2K>l;Y5Dk^SRm2q%Glt!v31k(aBcEoYRWfZp&w-H4V zsY2Ot$DI+Ex^iO>QAepF^#45PzVDkiY0?J9`TqWVKBVt`@44rmbMCq4p1YlQ6CCw< z?jX*+U~M{SEowR1HeNW-TXjgFZhu=F@<} z#i}LnuJG`waI`0iSW7-1d?@Q9J`kZtUrO-%ur0x7GtIE?vS!%Nje-QD>1Nn>BZm^a zp+6+pK%SldtoabDra!a^C-E}yUy_dhX(s<#Y!?6WHo^ZHY57MHi~pnFOUM5WJH!9T zjQk@<`0q#l|D1t;x=_MD9Q6$R4|MQvIog*`HTl{3I1pDuyl*|M-hwv(_a_< zNra>Qr|%5^{*3%1NBGBnl4=-`fq$>XKaSRA;NRK)oP*HOy!?8Te=RnPe|ekW|BST! zqlm@-47kDcK9l(m?F|1$M*fi_{2xjFkIKNm-TrXYv*6!u|LaWtwb(5F<*kGNC)2e* zidg)2d?j7`Bl3W0L9^)pBQo-j9O1t&`R|{Bf4lu($jJXO4*j>=e~QV!7MsPtyiM>w z^YL{2qlm@-p}PO4wExtd;eU8W{*fd6A3^^6W#B(#=|4PkNBeulVsrUdE&sEF|GAd_ zUu*KO#b)s@Z?U8-1Ay#g)I63(1Rj*KM6h6$r~v6mn1D^!+ahRtk@cBj5JB2S);p0y z5lrg?5xiXF6oF;`ZT_Fn$p3(J{9j}8uf=BZFK?6hADxzel(P80a78-)uiF{^hi2p- zIl_N$@_%F!|EJ65w7D8|BDe=Zr^@PlO+NKeE5LK|Op8|!F<3r$fM;#ETY#l@@fHA& zc{p~i2zd)2S?gUm&KW;|PtBU&J@E`{mj~2n>R931!nv80&Fuf+tWNwMwPzBkGHl~~ z9G0(BX0Hg@0RFbAn=z|!kk2vQBA?GB>i2%xlK&1MN%TiNLNDZ(CXvr50VIDvgf#&- zW>U!ivnK!4zBmOT^fo~-ByjVBBm!Ly`SO_ro}IOP`2lU`OzdLQFO z(CI79q|p1-H9~K@O!SgB%J*-WRyY(OoqV_T&sG861|${W-?n^DNTSyiXw1L7g?tBS zdQa)ohI~JLCW+p3@*P!_ExiW;lJpkZ^1WF%Uy6KxUD86nHPs^D2YY9rH$#6rFq!;x z{q3f{*^++&AW8luxWug0d7W-elYFbcbm znJt0K07(L0`Pm}y$Rq+Sd-kFx&}q-|HGzXcpmXwpXW4HqlLM0BP1yF_W|Vy3sbTO- zf8+yyWNUmM9_LP+=PobV>Zxgm?DFVg`cUfc%~jv>AR|60KNMVJKXQX-RzG%#IwNO` z-}6k@{9ue(r9pBEi)CU{A#El;{5lNXG9t!9{#K+}6OnV_YO#HZYN_n}Y#vmU2 zk+0%=^FX6}WTcP6q1Zs=vV1SHtIqOAk0dchcsoAOZbXN>$Ne~}cGE#fcEvj!rY)dhnvoXxflbmAf;&T2;5OZ_5lJX z9no4d#LZ&HnjzTZB=zfY47I>MIfmmzU?p$MJRd-~tNq*IGDhVs{h`0lwK(rFoaXFU zh)^&6$-f2W7O==S4xrBqc6TjhO-p?EQFq+X6(`6rMl+bj zEq5O7?8vun_3EKq8-PXIsQ4*OD$}NeF(f~W_oiOZAK_`)@Fs*_?G%Vs<4EfmY{2st z%DQK9%?LrbN{nS+<_7BW&o=7dWB4QAIP@bB8I+HvC|aC%KlqJ&7Kr?!il6C6_HXuj0{yH)>M z(9=f!iTf>o#c|!Qst}s-GtqA@YAL9tfBKraXa#%taIk{fT_!#FslLOWd7Eq3pL~(^IBf zB?Eog-S@d4sI$B86U;8bNap$uDY~+ z-|2o}jemlR1++rEz>@evFI|@qD>cJY@Rp8GERniczm`CPd|j+xpQ2wI)>WJe{d%B& zU1_~G12yL3HE!sHprg2ii_Rp@RToS>Dh2v^bM~twav*=irOk;Ei{=5()<1 z9I}kv1yD!YR((;h#Q0-%f&cD4M9&cD%H}>qdk0neibU)8A>KVk--oC_fM;*px({(X z!t3BZ#F+=#hSfB3r*epGaWU&^AU8Fkx*I=DW$MD&v2&1fwnJoAe=s8N$`w4A=xN?S zVUtm^eDcBk4rw3y*=!9@Os;Bo}JOMV$ocGcbu zfEc5N`oo{^(B;-(b_%a&zu89fa-jE)s_VHg?o{sZcbw*@_7ZV9-wS<0S zNG&kUho@#bNq{D-86iGHv?E-euDBCp)WIzo*6+JObdq~iwCiRg{3{|Y-azPRj_1Hq z@vlzz%sK_F0nz1bflt#d_$^PJd85;L5f9^j=OCuV-veX5+8sfG;4$S71bWjAARJ}g{hM;*>*-KQM`0fdLYLrz^ zISH=1M2HOmROsznJvBk=W=-p3Hm!31#H%huP@aL8<#!DhlMY-95>n=BQton)G7_Z3 zXF2Xuf`nK#&&lEHZy*v26n;J`+8xz&U(1}a%z@wKwLGgl%K`H`e5=|6;eZ|5Hr%;@ z^X!IjyB)AH7>Dn(8s0&0PqdsVQ`+@8`!Pt|5ckNs0V)vrEl~Jvc_D9WDP!3e?VEet zGI4j81Nss`CpuiRz8I0Jd|x0cK8U9#N_nEYno0vT5hnKAj4H}%VH>6h2iFSkR#4%y$* zuh!wV_Z0o2Vu5P8k&I@JA18|T9p@law(q0`D&zq!E(ucmqTm*Cjv zuaNj~&%&O|%EH^+lfM||dFZ1_AD7pSahUrL08$=Vo-p_Rl66Vu{$2pY=Hn;T+}E?_ z_)&qn0b;WKTR#m%k3TUo=xB%k0%E);)eYF!A6_kkfj_*Xxe5k-LQ{CVd-8sshvJiZ zz(ji%_GS7xrk|$CUXz4%YSW34>yB>HP*;Bxzp1=%eR*Vs82o)rgYTZaf7v2ZROWeT z3*uQdFHe|yUK(+X0r9Wx4sDLtoKL~{V={#}#xj`-KcXj7gD{zDpFEjz&bQ6^Oy1(^ z#C%3QB=Z?%&1ae(ZgW0k)lXZZ>u-$B%iv$C%*!SAgsgvsMz z@Y@0W-jg(ev;9%2U(c-;k4don^Mha+=VQ^?f*)%J+NGr;McxU1_X0Ti#g`k*Nvk=Z z!+f=Q&Eh$Ux+1I#^EwR1ob}!f?lDs4rOw=R6KAaNAr!OZi&>#rrzKzC;->q2*8Dh+ z6^2(fTJ2fTN{vb5!x-abtPS$tv_N!%w>+}hkNf9=2nHH8&~tl(zhtxL&SmapReRtr zF=noujGuQEDvSJ%$iAMM_n^&2bgWw)eMCD~nOkb&-yY|=eYwBn`%=%H zt4rMM9Hd!7!p%xYeDYrR*gx4K3jh z=imc0d7hdxq~2vvEskUrfhdY=D2!dDRfiaLQ<{yEZH8y?HrV~#Nm!`<$cSvl-Rf~K z5?SmYq!X(_c`?qCjOI0w-@;$CH#|c>FbY2;aN%#Tt=p03GIBP<5GJiR4EA`3u5#fw zu*y5w(=B%yegez9@KJLEC2N9>fx29ggg-~YDE}%ICH3!;)m3{1qI=M&1|l9tBQu&` z4Jv${Hs1>&K{o#8SMeHhg)d;#ou0!O14g805k|lw3`pk`c_G3g2=g6J?UguvAK#OH zOo0%Lha%mgm*p3ibG?jGD)2{g5f2f0eh3=%HbTM2I99CS&-f#6$wJr;b;Lw-p-Ef? zHcc^mMuDp2XA`l8G_PA?K#~5ympHfMv`oXdlspH!FoyHVGDoxQ#oNNT?>MtC{e@0B2i;uA0pfM}<|7jLpf zyCS9kqSqSiu8mkv8&GO2dR+f&XOyhE8l4t*>%V8GeS89q$uH~?6`mRej_5C`X@wBa z%WPj+P-VC6iB}X4+=rFyPf!qEpkdElK|zJrDa={CBL55IvvUi{|v;S!%eysF43`J`$>dCBIgi~V(zq2br% z`_!3eMTY2)EHf6PO8yHO{oV#u(iVotzqUF5jl3IuE@P3-Mn1JFK7$B~F(XwyfFo7~ zMWHH_L0LQX@=2_O^mQXL9_kD?(1>7Q#SF-Z7+3>N(quSJy5k@^M|XCr0+~>%+ycxZ z+A|kdkIX1L6F2EAwCne9=riNZm>(Y)z!e}k8t(X>cKaiVx#nwCxXXXFguB`7j~=h9 zc;GNpVZ|S^rtplf0W?@d`laeHAa>K5IQWa`Qc}(-4!6G5qQeZW7rLJpCHt8 ztNM0#IFKy0^|N@F*}D8&RbN|WF_HRAtwuPW_*d#iZ|ZV}j>lulr#QWQe3Va5r+g&P z1pB4B{!k#^;9$_?4_*>{g+W9pVK5T%Ze9~8*;dsHlSEAXG27UzXB!(GK70X@exNyZ z^tb7osBY{-r9-1vyQ9OqLg~7em8|xJkK}$$bT|}<#*MLC`7dNdJMv9MS@UWb%dU|X zTQ>yi#^sL*)Lqljs4L51rV&5b*?xoTa*t|m7#jJZd0AQHO`JLM)VzcCfhnaLR;aE$ zIls6JIPg;$DB13*<%hTvJ;7hHs%kMI#v64*^T&IH6H>c3_u`KfIi~(6licyw^FZ6aVdJzuCLiqeTELK%J1q4 zPsOvW4KcR}Y{w6!b~^Mk4S#;pkB&P=b9nflT5!07_1S%$94<=b5a;Ltq?x>j1T#rK z_52RE=M0eO4eCfz=5CD-Fs#|Dp6|uw&T-%fQZ8at9DFFKJklrEAGs`71VB6pfH5@J zixny(B2XAmHRCsQgQ=15s{xdU1=^}69e@>&NZ<0v1Wc`@Ay^zL5-s)mBf~Kq^N!yd zU?^uOzp&)jxNIjkaf-XajViEShp_5jm_!+L;=(SdQR!F`uEQ0?YMW}8fPNWuvy?WT>w>74NOJ9 z6jG;ocr**701Ig_P0+z6{!8)Fo-HNqM^4|=M3%Tpxx@c59{CS_@t|gFP$!=5;D2WGq`q$vV22igVF3pC& z(rmG>pveKKMm2Fvryepi`)&n|bZiP~RSeKG}d= z-6x|+N}s$J$Ys3Av(>x6MAr>{yqf{t)fGa$3S``4OOhVxwRtFyaTS&ybZKqIXbnn2 zgsOv+u1A8Gi;<3(n*NMGa!%hSR=5stJ*cn|f1${^eeo0M3k|Eu--1_g1pE3ha4_;* z9z6RZBYKnWd(Z~R`nmiNptQ`_b~j}Xd3$Q+uyk~oPecw6Vi?eS%VDD|ktce-QL>`y zGF!H+Hd(ffd;^Y1tH>6SYkZ)y9G*!xgsvHg`Ix7+5PelfSknp=5gJrtG~1z`ME_!E z^TyiIdq6v4-i;Q8Ouf_xH!yV!z&=uuAvJ=FXaeWw6f+k@Z9q;#L>~W9Fv5>8&6aE@ywQ-B*r}!hoBl(Lgvo#Ff zR1KXsBU%nY{o4NO@t^_nKq^{}w^u?QCqo_|P!OKMJN%I?{=z0dM0)iZ$c5bVkH-uS zRG*wD#wN%RaW0oE6qM=Ni)Cnr>_;OAXDoIN3{7f-47)=&NEah=Wou&I9mAJX%(PcV zWC-YlG|b~BF!)2x@b&TdIn;-X(tW#G9W@Ch+;5-R>^9%~T) zlS}+Q>P3OPf*0nCY>lAtma87SYw3%y#IAd~fqS03DR#JBPI+Kg74pzivyLPOve@jh z8BfPQyk~tLYOIXi8P7wV!0f0;A3^#R=b@7Kzi=LE0w5gw7e=IOel)QK1_^9b7a&rQ zdTQUKu5u!h(p64Ic{uZ#4@f-#5&0uu#}7&AAEHP@Bl+{NSHYRHoR^yHBo^nTauWM_ zY^0Apv+iIUB=0Zg4UIl98?Q0n>Kv2}mOS;ZN;U&mm3Wfs*3`~|)e9`OsXW+{n0#o7 z{Y9&HZoaAA;63FqRT~Bd`q27esu$aH52cO6RJQ@h(VhI~qB}t)(0#B=g}J%(9(SVm zyayhrF)!`tVs#bKm?ZmM&B^7M)X8OxZEsF4D_Tr0$EQp#3yivp?a5_jHuEpeAIpRf!^DkMJ+5iH1ovU(kt>{-M*#6; zANj=3P|UI;>E?wGX-}mR1gq=Lvgd_gd1~$=50P&~F6fY|OAjq6Bp zk7TG?fPeb82Cg@OF&{j}#3{!m7f`(DAop0vT9FaJsx+7;*7*Xt*u?qaL-}$)WY#>Nz-Anm%&dw_F zo(+2B9*_y%GwqLz@DYcU0gej1gWjCPsSQ4^!AaJdPN)%!2_wwK1bsFnRt_FGEyGl{ zMxqIMy4B?KbBav+NCMJLsG4bXBT4i0I@9aOlvhvtJl@-6uIKUIo9`01d-K;5uG?+- zYvu1v`HSQ)gu}l($+E>NMKISa?_}3gh$$uCLv$hh4McR4u*KLIGRwsK#dDBo?r}1L zK&pH9gk2)AwoAt$DR!wGuV6u%R|FzOxU4DrCUuykCW`Ng;ciaa$pBj46J z*a}nU+Q;!a`egoGVa(JvFWSPu)R>DC5Jrf3(NZ4;#-Y_|?N;e^exuH6!_rEl?j{M& z=IK^eiFLsW{H?&>Qv5B26%y3m3ZKV2rpVLnO#DCD=jrD6az!6X$O<^!p2$^z5EE#I zMi5U*MCU<;%aUIp5)afpDa>;eha3nRh#pdp7=~rd?->!znkgpTfLL>nZa!KogvpaNe_8gu4;#no ztj-((2jnl}+_4Ppf(hbv`I%;jF|IX;dFG^SXmkJ~S~p;VH7rjpgLQOF3ooFtq|4C} zB`_@85xsFAg{y z)On|HinSs$-uOW>gtu%LXjLaf7ZTq#!_;sqc>>&LKUr#I4Zq3jRsTQmZv(sSntwYQ zEIRz#pLa8r?f=TZy{!xB{$KjH&!S(7a{X8S?R6dgcmAzUaA$Bbcf!BD_oUYR+rv3H zh|5~an~_j!_YYb4w|kku8@6cRRR8u}iWkW0&HPB~{_SlVOcU|~qKdHWG`zHXRyuo) zosQJ?zuRd)qhn#e^!gtyq(rl9UYl6x!?t(rD^=Iy6SeC%d^ED_sd{%z3HOZ2ty5oc{EY8)w;;G>=L80GTtUDR+-|^INB*KXpEXiT6 z*4eR!=b7;mv$$;MS(v{!&*PcPcHZD^+IW*Keb!ytf#&QzXP!`!pqb%6&CkGM4<5ikNkTkDhjlRSR}XIi!y0Q&0M9M?Ro3~Yxe zBk!w6P>I7g7>=Z<=EV?orggAk(FyKhy(e__gz4n_qkYSCgt{Go6vD+G|VXx#(T~?-Vlo$?`tS>%BC zJ+#RbFcxH6P$K;Sg_DLBBk~qz55M^%>&$JG$+(YNkthCc{27cv*a|w<+6GF~Hls7N z&4;)_ZnupbRLslVHn9r!nq6$3?Xb34H&5&vOjJ|bWZ-1oCJ!mJ$;ENDiSr*%YlSzB zfvTrzn#0pH4cm)*R;H}Y_BuSZy}p{#qP^tc+gN;P#!=k%0$OdVg(*#CcOEtndlUN& zIuHBJsB6G4q>Y1tTz)IWLOxtKgG;d9K*^TizRaY7!7&H@O&s)}*g4WhGNB*M+*9pb zZUaO{`C?peh2T=`LmHuFr_U>|Z6Tkep0)Er`Y-f(AB6Du-{`Y*Q>!0Le)hWjZ5my^ zqDt%XhhIaN|Dm$6FYPDqovNDtYdY~VyX-`pR;Lv;#6FN|Fszc?N-DY%w|VTcnVe6o13*C<@Zt$xppH!y4( zFI&!oKYF4&(i7j^Y`_sfILJ6nI-X~y8M**BJkRDqXrARP;>oEoiTzKUT^g~4+c{(8 z^!w&OKx+Ol##n;yPukgz84);qA@}=I_#X0%aYR#`$Ou(TyY%0b&YrAQUIZ5&wBl68Xl>ph5zLc-p#EhXMp!A%leBwY3t?&x3x(ZG+-dHz#8D0;1XZ6ovNpyj|V{Iheo z*b1jh@A*ryzp~wWt)Qn=VIcEmPn2O9ng20=tD^xPPOutw;guYJpt>FhfTw;8e4Rp~Dp< zw%*S~yWx6qHIK|6i|^-6#JQ2U$2#B0?+1P(=fO8-IuD))1o01WzkWO`*wX+CIf2ea z4Yh46^>|37u-MtCn^LLPp8$%&D-0ug6brzkF+ZScwG)oe$5ybM*_1p|ALnE^egc24 z5zR^n4p+{!;HCj_9HB&@cZpnE5a+YngdmP;A&3f8nYnl`7O$H!UR^wl4PtV{kKk0Q zj;t8*UmAJ$3$;%&$QXl5m{BBt{)HB0tNP><$6TEn!}|(GWE<3lIstvIz-g)A_)z_P zB-;mjg{F+p4faGO6IHhlJFs2}2*Iz(hX5g;lE%cwtj)Z9F%z||4$Cq7`2MDp(e6o7 z9veF!P+G$BolyDUd3N{@OW-F{ZZM_Z{7gE6rT?L&K5X^04+gcQh6<3`9~T+M)VJBwe1`P92D3 zK?4#{2T#pbtS&%HXhURdh<%P1CQ8_(72Pz-n}{-srAZe@`Pz43s!&Bw{K4ebQ}an@ zU02O{gmU1{RKHBT(GwH z)O?51WlM_j%k|LB_!~P4^qACj^~^lPq%KP8!raRjhC6^^q+gffbMY%Q_QSV5B>O)Y z)x3BR04q-dA!SoyUa9w zo|@wTF*17HQEq7>_2!QdRw3S@N!DZk6ipJu>T9?=2-ic&GVqFO7NMH5B@MtAyOUow zsjHtu+?$WXi{*HM^7B!KOun}p^`Fj9} zb>&-=m4ivw);)v{7Srtyx?+2QDiFv0a(TH$^g8@8fXbH470?czn%P1!Xdh(KUi$&y zLiN-oaQKQOOjY64*HAsVMb6VmfQTj_QungmnAsAwqb>8U~I5OlXe5W#1= zOU3K(LMr|a4W}!PZNVdGTFVa2rhG@IV*oX!)3BWxGr0~5O_~Eu3e{I?nik-lEuw!) z!q7Q)ApvU1xtfJ9pP|oq@hsF{&%9_o`69IwkOT!T{1FPMRY>nkaB+uD=^{0cPv~$y z-dGKP_&_kY1E1?a8Qaoz1rF2FaWT=da^lUEe5t)SqNERb98DBwj8j;JGmoOsdA_)R0V<7;} z0@F@~1p!Z41oTC=-3YkdlAs1hz>qNYv=b5_K=kyNH6b7sA%U}zM1}KUO+^B-Go=R+HL{lr z4fYtatOh$mL(hWN3$#b4n}}0J(QlysP~Ev0yIR$SY2P`mPE|Kh)QD=d#koLdYLb7E zOv+Mc4%3-bcd=Jhs1c>9@){r?0I{*U8=9IGyriW}e|8HG!E;S{21keLMV7%)p?Z;H zaIhuAes4In2!RxA`QfPN!tf%qd20SCk_zFM4LyoBrlMBQv^SwgWB6Np$8V zP-Fm*2iD65oR4SS1P>sSo(Nvh6KRJqxXv+15H%*IZt6;nY`sS2shNer1qd4j@SAqB z9H0UKicOFlF*0RK8o`Lgv}tPe9YEy+tSS1cy<`+m2qYJI7p)0D1LP3Ko=}5OeFzDd zkskOHs;|}w$_nBr#vfILFD=51l=2muY!hpa)*DFEu6}}KsD2hwK!QEa1je8wh$Gii zJ01yOBo_54KF0=(#2^?0%!|qxNQ}oxITs9xs6rD_2dN5+Soi^5xIq^dRalE>tqLT= zl8Ut7vTsbOborL5a3Jzg)q?R3xQTqW;l79wZhyk94*T>U#zh5N2k=i-A2cq_D;xJ` z#NgF#rYN6uTHD2(BbcPn>M-`)A@B!aPRf?Bv@NkK@X8kZ1(F~^kmYGefaxNn)RV7> z#3)OVSPAo@B27x{a3rDC70BjLRx=L{iFint$^($C$3v+8J*YhrXi#FFN6cUR$ZeDb z)q+{;atO~_m)}>S%awRRcCSW=WXr3bNgTQtitwOH@DZh!IRHm3)fg;8^|N*2QY26% zDO8`~Yiwx#F?becaIS->SPPjcMUuWhXcb2hA1r{Qh)g<)&+LY3R^rDVik=W@8pubT z_esKq1XS)8Bv7XtDRrr?(~D=+S#=HS%fmD3i(ifgorq@$a6SGYw*(d`I4o4Z4oOkL zwemm}oP{TKfJQbO&qPLRM4o}nntoyTuvyK-{c>c{9g-8L>Vvz5@wIrt38bg?qu(HW zb3x@ygrJJOf)}>TIFi|Va*ZTP@e9r_!yl9*)9My{_z=>p;45}dd5DVHq%_Mks0iU` zA7J#XLME_Wv!TwaPcXR4nvH;YQoy)WAz%vumc&p8Fcd$|^wWX^LQ<K|s83pb z?g2K?!53J+fVgfH^kW1o&{GuzJrQa2M5D%P^lTXmy${bCeWQ(jkVelJsvb=r>zy6- z&G@_;nzb$JKiQg~{v4uz9WSyF&fM(KPj#T*jz*1Lo*nwK?9dfqif z>Uz~3t*Yx!eG=;GaZK^!Ur<&5O;ueq7eBZVh48id2vB=-8DI@yLQ}4BRbiD&Ld;su z&ny(sEImv#L$1O9qs+q$p?c1^&~M?2)5P+|0v)~@1Thy+5nneT-&~6WK2Oa*C0);T zI*qdeIAgQ%7Q-Z7O2?Tf5AYKU@Srst<^uA@hut8jVmw=#U5aO|+4LxM$1xp!zEGb- zf-$kv5JBL8vZvvIdnZrsC3g z>=g*fu3|sII$mSlT@pkD)9%vc$d_7(j~Id*awb)LB@I(g?pVe9g3%k3rbns zboLF6%Cxoxf@%S+pQV_Uc-Bg^o6el*$gH+AH-84juKx{bt=qF4Q0&GU#ackE4hz)k zaD?*ANf@>dW+1rqS@-!i(KE~Gx!KDjel=G7+XUs}>;A?*1 zj`Rq94>AwaMx;p}PujuG6NwCh@&N5)zBvfum0F~+P%f7CdGQPkz)k8!Kl~Oe`$9G2 z15M#^3h5KPblOB{7i)B;(8L8Hfk3x9ECLACzlOBd>G62d^6GU9by{+u(-nA6*Dmlv zl1`7o>x53<{|VLU4M9dpOIJMhFf#qRyyQ|*qjV}gX;pl-Z){ge@mB2AJV1}ZM0B&|U~(;B(2i7VyPq?mPR?(K z!pGu~^s)zA6^zHTuHZNp*37Gu$A|?fK&Ec7i8oXG7I+;c^X!uCQ8H9tg0!m&hX7=q zit^j-xg`0ySU72^_|*;MNeV(rCzCfzF5SOJS!@6v8*9cW6+0Ny*VqgE;Y=px$08zf zV?BYAn?7)iTGeRG3Sb$*9aUTnIRvBAD|n%DSDCwbiGKAA0Tcb|L4tj<(gJhoYCJVh z=*c3hW%s)mNwv@hGp)O)rV~g8Hq*k#nh18Y4Q3BQ4`A{IFlqs@{T)d)-UhR=-KxPX zY&8Tcv%y%}>eQtg69nVJlOCX_kYsq+c%e$65V1>0O%BS(o~2}e2dlA-c%o!avm|S& zWAG4D`=AD*f3?2^k9H_q)u`ART677W{r2Cs&L&D#y$Vj}0likc)qruJ@zi!BmO5E9 zQFmcYH0Ht!lGF_C;NL--wAeM~--YI1>^`}KhFCZ1h@p!Cw`ra{HE&V^37fuD_+MeQ ztqsP#HU}6*qCQ$~f#qp2dumu5U~C;W+I(VL0I=AhT$&TDj9uU0}!sa^zF z>>1h-{%F0i3+$u2idDePt}@HUYfJEEjn|T3hhKe1dyB48&AzlmT*pS_96*aYN%M$(jLbe z-;Xl@@GcZUSj#Y-zaCY?KC*Fa=SNyWau7O0E>yG3d?Ez+I z$y@DE&gQedr0o$#+g|$Kh>(@ZOW*MWRNYHfwWW?~sTQbqb=bKy?y2#xPnx@r*X$3a z+rjo8sZk`m**IQ8e9&viN;_^Z)PmPT@D`$rac@qPB!=lf-7NKII$2m++x5b zc2cIZg)XQUQMKi~hENh*&~sO}VXhV%hDtQC98kmt_M;#ZJMF!QzP&~t!zX^UJY-S= zOq`UcOR%6B8wha&Q@lTahHIQ;)mAbl)c0@;fSkN(!5?3vXQNI?7a>O_^}2HCHDRPm9)V**U56^IGi-J)=SGq{Rui-ikeZ;U!q9}@G@tQf z!G}4u;ZiOMOLonV1Q8~;GHPfX7Xt@cP+HBjj!pyKsWG;Gyc094{xOZA^R(?nGD0y3-Z%m^|~%t20T zXPGECt(|Q{T?nY;MV1(5K$Jpke^VdKla$m0n?KRkeKdcjwgzFHWIYpg&DEj~9ueb= z0u@s2G|fN0!3t9VJvB0P!1uS|UIiQ%KRvbl7(@)`;4uEZAZn3u2k;KTeE>jRabHRs zk|KMn@NxmvdxS>=9I)s{)Esi?sqKY#mag?O!8^&AO3HBS>Iwza62Nu!|$ z*kjxbOC}+C(c;_J**qzW7PUC}l-;7m6H>gbMT=TMfe$f#cfBJk2$>fo#sE0Of<(N# z`uTbI$y@LPrp$91iH5G~2|*;%h$1Eg8{9UnW6T>zyC z)enW4cFFz~M_%<{cUCD-JV=d$X+R0BI|*us9Z8o2*p|MBtwmP(#Vqc)*Q2ip*ignWOB{5$om;=y>Bxo7GT8@PwJd0YdW*&|e zBMpSH7o^-eU2e7{8gwEo2|*vc7TAbEP14v{nxtL8mc}zM#ZM2_ug9aTK?*)D8ZuL_ zLC(gL8la2M!L!BLTs(^t5w66OZGo6jx9`;s9G-?py^L6dCp{W%z_;mFhb0H!=cCf| zT>D^rq|b+E9&N|x`4ab0aMrlZ^X9@BUDP0= z6f17>TohoZu zuN6c)J05l`^@2Uzhl;8yo$nb0#z0I2Kr975oxE%z2O~8PpV829 zBY^^jrt>WJUH|mebaq(%F%xoemn%14Y!FVIY*g=~>ja{g7MF!yUPO@u-DRt5`ILi7 zi_7btZ!n7v`VK|wUJfCtCO*aI+PQf4hrbK)Iv0>3LYG86lbc`avK}-fj6HP$o{}rA zWTjXf9J2{w`lb}{>kJ*#kmlXw<-s_M7`qdw;YNUr=;IsjA!fnKB>!u(MZv_?t#HLyfX2IMmI)5(k7l3 zzmQ4Z=)qsR?MH0aVml0Ll(Bm$VdF_{W<`U1dqMaU)Byc1S(mz#q`E1^Y6H$X#?MwB z4HVxO_#OJd6IZ4_0D6o%!i}09WKEwwAvML8Yno!u=)cLe{A+iuv3l`b3&2zR2tZ9C zsB^kw0?G|rRi_bJg1el}G6Ch|7pkjtmTtR|dxEP!tFiiB95GHH5L1ti{#^@XZ?2O< zU(|N=iuk^&UoviKls$nPFoyC2#%`Ui7GW#)>L7i;_dHx~`r&c-z?<-+@AL4cV%>RO zTZ)S9_c$vixZvxN%g;~5nI`+zQ!kW<<7v~5U<1ychpRD>k zhDJOLKk>owQeD=fd;lb1QjYs!?E#aV-`$b#R$tCD^V9O!#p00{>eg_wv349sv1Zly z2cN^VDjt#Sk@ z`RUQbwKg3;LM|-g!SqDhZNbbiqv1coO=u@ zmRE@T1BW8=nQr7)p>r5{z9K^OpvmXKE|>D6N}Ufi$h}Cl8sx!Btp$u=;K~vc>Uycl z-Vc-67Y9N0AFP<71Qp68WBLjv;xn~EnFk$tOrjdnl*tzdMLk8K2~@Y>RuoW_;#sua zuy1pYZYFo6`>PBcgM60_o8(^Z^igj(g8gE05SECsjzBx>2dYVL0D1QV~7wmamQ%^T)@ZYW`H>2SRa*?j)2+5#3AJgiR6M zz9dPDPT}6COD-h?#;Ni@w-ZcGmA^`3(kjnkhAOW<#x)*xw3QE_quuy0EL1Iiw6Duw zb3UL({{TO&Zi+iJ&{c(y0Qz2R5A~1En8aW`M5jBb%X2_(c#79mwGSx5EyM;{Eh#mP zMRO&-J)=K%MiJ~r5rBxp*ql-dsC6ksb49PKK*Xo5s(`d@en`k-Y**Ze4HdhHSXaAO zY;TZZr8>lvtAk5ErskmkVW=){*lKt0=Kt_RFV?5qV&fr1P-16K)Y+;6?^*x6xu}1F zuHTeLAbLz&ZrVFIAl9mzcK!u)ecMZ?kkD{0ZKvGwW-qi5-xF5-YsrbuTpFnb^K*q`SK`grwT<0Y1;1i)VlM`;a-Skf7{{rL29Xy*pc;Z&yB< zOn1}l!RO?K`*vax=z*GFu+v31U~s|i)b|faZzdhom`7lM;aC0JeCw3rVssDE_~U)x zco6^+%u*lB_y~TuQ24l>`N8(8-k3JI`4KuoKKSXs@GNta&M`` zmS$u+RKn^`>+uavyAU-&M7A8zl*>o|fL!LzHRa-vhZ2hzy^q6Ec~rbNe!%q@u36#J zgEe@KCgyt8#;RT;ql3Q86pvvR4!^`d@JAO~)4!hf!jVnA7SmWjCX30U2kL0ZwQjK= z=DFk}39hH}66T>a;n{W9Srzm=xIQ~Zk7C=Oml6^fg0Cm)*WchZmdIv-p#U}|@Q0k9 zTwZsPFTOXwuwj3%82V5|efTr=p^?}Y33ANqEcD%O3~*d9r}#Ve!W$7 zfJJ7N=(98k`Vh|dJqJSn?MGaF@WzJH_vTX?>Ult=r2*bwC3-#>?8gbl1f(mFrZ+ec z-r!hxgBWMTFF9pW1zf^X;V(9h2+_bg>zGM@MwV{nm>*d{L%)M)dIAjwlgU;aPSb4| z>jkhC#`HC8#Mqx-mgr*kc$I~H?*CXD_IcSk3H$7^|(( z3SjZ^u6wmrb=uEsQGzTydly)!27qn5_|P(5j`gw9fn_hF#a#ZvRmPfCxIfY?ANItj z=9&;qM`BnolunP4(cFPz&AuL4H)x;={02fkGS%RSBq$cR?$vmCj5K5s%j&8ubo>!Py^En zljYCj2(cdB3ln~C*)J<|;Gu$A=D!%a%O?ab-43s!hy8lI`MMfc>&E$;J&4`OM&P0u zU6iG3F(Xv>L?u|YNtJpXN2dwfuOarjj=-ly_#EEH^HsrJ66Rg7!Hqfb4js7N6o>j7 z4_@Q_(RiQETL2P?Tl+OSRJex@addW4FJREA7wSl*O9m&tqxYpZRwC zH~(t2zr42Ee@vqN*$64^AF^{R95jp=mlKNRoT{&yy~|7~{rQyl65KuP=Kz54x* zr1p1tA$xovj6D_RASF4gt3x{+{>vf|g%tSZ zMnL-@f1w}6z(xB|ioceA@SUw6-$5R>eW)1f)DMk|`r#9bdV!)W^+T!^{m?}>ZglF0 zl`HyDeGv3Rv%CyYE$jpHZT(ozw)CT*)V2?^`lRZ|l$n-(uwFF?T`8S@_e)RpjtsfMJ+F|O)-gvJ*zAZ^V6c@f)u@5)4%dY*$Lu1hX-|R&DZ^Xw?#XiU; zG1_1LqWxzB7u$ah{#xzNcZv1~zlruA>}-FHi|t=66!ii{S+>7aEA6j~Zv5KW{#LHE ze+V6Vv1WN0pjxy)^X>MZX1Bk*w%Xso;eWB{(^s+)lI_EkTC4q8uX^dr^zHvJ-n0F0 zO>Y0$cKcHtYAT>;ANIz3_3_`){w@8nHsTlVcE!%cFXXKV%PrBa7v}z(~*RBL=uE09u7dB$Z#ainkWU04HknaezXU8vW`X2t4 z9l!AL6fiq};oAhW;}?cgz__G4m(@HDFf6c!@XRR^PdISO0cX=ZDR< z_ysIphxmn$jbOW(9O?Ll!&$Lgb(xKR%2m-8@eBV9)SQ&;UuSK^n>u5zr$Ak(6L5bs z$1gk?C#+F#7V!($JR*kzfY8-S{K5wSr6s(x@eBW&z)z-(o6r&VxLG=arT>}Z7k+fK zh|fn~e`n$sez6HMZiH;xh+p{X!xmfG&1Hj_OGwQ_A&>%f;oqd0T8m#;3nXOi@+f9s zZO1PhPTIawU4YnO3;1aHzu`@JXk+Pka@yh_Y#8xOY|lOjY>0(q zX7ZfHd^_`YWXf(4v(;a*04b*#VC8!Y6P0@5eQz*9)BnqHTzI>%G=o%2ol?E_Rfklc zy0I;(KJlZL>O=UOB-IDMLrdbs0raG}Ej`)$P9SMbPaYWwI-G4b6xd;0^oGkm=rBcS zL0AX*-UgSqfBH!lYpt{#uV4eBd&N(Y&7j!xI%)4is13Tw*A7CH&!J#rH);b3ty%E{ z`r_s4L;WU+mPP1I1~)#Zl>+80wLrsITWgjM@N9*t1AsQv`4|CX_p_QCbb%Pp4uHNG zue#%JQYELd5-4eJl(HE2)IJ1AlX;Z`j$?l(zW&KXUP=|%i(USFwU5qXKllN9hl3Rz zOltMP3R7`D`A93y%LvW~VoTM-CjfX~wH~vtRLWkA3;V@t3%ZI$8g^oJo2W~E)a&5y z%z)LMgYxQD{8(m(_9kt-R0C$lIsum^Ug~Z4r-_$38)dNJsvrZbWd0%XQfJR5%3Y6_ z+NYY=pLxR|L%h`2?!y`KU5%GI`(|Od0@g$r{^R4N-ZYhi_#YQ9b)7V8Yw=R|L+`T# z+#QEWxFeX#egA;4vWb^k3Bja^m%4I59VhIVjO2)ub}{#Wr*JL-BGY3*1~EAdh{(5n7{ z@ls2nNuiyKmpW#ONX2VOWf$Y6dJ{VAjFx$WGcJWfrzMH;w43e~> zEd1}|rH;VSYo`(UKaZEX`kG`t#fSxh@yj(D?;0MOoSf1RmG)~;^C zIqjh{>Bh>?)*@c&e{eMU5000bQ|;8E|3~psubV7HR0`wS$4mYC4)(goPzt?{Qp*@G zwF$i*lZXaDs`HM5cw38?`Zu5jz&zay(tz{vtQ+u3WFint176Spe1{7~jxmU3l5Vq= zX=Lj)vJCN3djcric&S@%&m1rHJ>=o281~@sFUxqTuB%1%r9vP&(Iyl{FE)^7Fa88c zJE~)L@lyX46pX|mv*Xj-9}Y75T)33T=7?lm#>CwARrAHC`|spfTyYkh>f&^|~sNSh0|eHu&S>rCx+sR!kPlhLOMQBhFf+zt=KmsI>Oftm=^Xr*@lrQmB@E2g z3}lR#dd5dI6OLF4{~RXeI2v%BGdW&rA%??UiI;l5CZ@uYraUC#h+tEXhRuyXYR18A zv&40FJ6`Hj|HdqpYs3O}UJ96fuYCrw{n$6X4ZFi4jdzj(ap7{Xi z`{0Eg%oM&B=bnJZVpc>FV|3y=T}}=$#4eMne8>?eM%oxljYy-qqgK;-${e zRTNoOd?gKIhpKxYNi)W&r?y5CJj?BfmpV)%AiWgF&c;jan8c!va;@1*A1`(F@#*5F zZW(8J4dNuNr3~qAxk0fS5*7VjgqPaf-T)lX^!a#UYdRCEvuL^%?L$x*8kM<0*>odO zSs_5gD`%T%uY7~foX8U94nnn^xdfSQ$4i|9sN_%{yB;s~$xC!E#kM;eW+&sNPSB+l zRv$$5&LLNc*m~tmn(-EI{hS8K5s|9baTu~W+O0!rH2}vg?D$mJs3DqJ$k1)^3&MTv zO1#uJFBa~$SoA%p5jP>tu5qiVD$kg;8ZUL0#v%v8%)Z=Oywun`u%@lVOD)mpOrd2R zFZIWP>EfmKydX)Z$B~erbxH|6(go`Y*@Ye{lHzTJ9_a!oN4(TaD@l;O)X9Tg z$913;>N-8~;+Ls|v(z`R*HYLQK6fbqd z*d+P60FZR?LEVjlslk-2{{KIWm%7(Fj7}0S^}Q?1Qv*+5i)}C)Te^6u-E6S7254uzR4)`l$4h;C!v8K_>f#z(XQ4cE+5S+w z54Bywod+MB=6PCz2y2rE5 z;-%K~Z!KQxMaa!6Ug~#K#o1Xe#Ak|^x)wk?9WV7uM6zr(Ug~lJv=uM4TdYeWdI&J{FiuVJ{6 zP+QJx1xi}Z>p1M~Wg9Q`-M4DnKr-5;0+LfjBu8}U+?u1Ha`J&x3~QHb82bGwjG zx37|Zq%iQ&!thYAj1Bgo;F>9vR@?DX1E|tEa!U+$HB6|!nxJ)f))UX`acwyJc&W|T z0=bS3>zD?V@al1VRw@kEfxc)#iGS&2y>a;qQw*`-qxbUX@Ig!U*Vgw zG@f}uq5!}d79Ttop^(JPXrF|Ggyp{FY+v-ONOVpT~z}R`2&|AHX!OpbQ-^X!dC16%+2fk z(aCN$KsSH%3`Wh+MPHbdi2DVrqCvWvAnGpUlIZDYQJ>BDBDk!OF8*%=k3fNi9$so> zYw>@96aY$e434@Ew3G;Ety@&z9M2=H8SeC@S2M={^{~qSGXC$WGJj_##{VTs86eZg|LukSCdB{M7*pf_(mq)6e{pX(J6U_K zuw>n8{ND+wvZnP~ahlw$llu>8?dK`{NbIiJ&&jCK4(rsyex8Y3Qcy+;9QXM!_A~xV zcJYV11IfL@kmfyo4 zeTR1*o^buD2$2-sxA>^sbMZ!92h3Q_U4&=b!ZM+bdX58NxWSphgnE35++Qn$cGmr|MDMOuesYzNV?#jKEw zUO}isGUnk~mnuRj(N@->PI*m2GQLeDK(>y5coy+24$jHJ7Pr12640)xzC%3jWlC|# z7+WY~)G~>%v!c`%MWeZB(n?HTbF!WilCcq_Xp*nLB*ADmb@*s8!Z2nnsD2ouYTA&D zEj43b(wR;(X6snemS)%?8To>`v1K8qd)#t|x7k`qMrWMLmrw?Ba*D1{s!0;v42j(% zqEnB96DuU6Qw=X5OtKn&Rxgd912^)58r4wwQ6)QDzY27=t*5~I{t-Xs1+~of`HOA4 zY@a`berLANFCv%pJaCff-=_Dkf86!@&uF#&60`n;r2f-St$?{vEANBoTE@@Y{e|45 zc$A;~3t)eAJjyvIqG86KENzlL9_5UMY*;fWW^4?INR3C?{btAA-eznaqvfp`+j@9$ zP*M9HXrso^R!KsJnfi@Vn6dnhDF1WT86Y%_vo zi};s|l4y>%jDM;7S8DuA6eAN~1;E7PC!sSvf*-RpQGSm2Y&#MEvX0k~&G?rm^0|%p zmkS{aiPYAWPiZ5ywG$iCGX5oQ1vCETiQ0cniGOLnbxLvZeBE7t90iUS0U*Jw$#2={ zQxTAMSK?oe!vK_B{7XPOrl^+o+xn`yZ$NXl?7!s;lKb!ePf$lP#lL(qStYFam*dmN zzXUWj;iHj|%iMBPE^L2O9x4Pq_5Ts^FE50cvWtHS$Ye2D^uWfYiGNA(4Dl~@Rs~%> zXZ*_xq=Xea(T;zK*MCU-OW?5rOQyuXL{3}rFNL-&;$ITZ5y>PQecp-qm*<1fw&Py{ zDlH9I=c$A@2J6`m4%|+}za+v8@h_1Dv@a?a0EKpz>zx{|8iEssxs1ETUNDUzGYPx@+qxVeeww*)@Qpn z+6>pC0OMc!%~b)%D0D4KkcDT5gN14UBQj;i~JGJ{Ifo7k$;#o|J#pSHZ)^pE_kMgAIR{%=Y2$DY`pET4hR z$?5vvlhY~kiw)e7oFD%!IsL@8=`N!_bF)f=`g4h$gC#R#Glhae$r=)jFPM_T& zIX$XVa=Ldie@Wx<2|1LI6?oPw&|}QEmWy5|pTkyT zAIfzt2_bJWeHYuq*V_U)K!|CCUDY9WRU6Mjhvc41d?bIm;s?|hsrwP<6$>-6yztOZ z;H0;jJQObTRrn!H)cV}BJykI2_yDp~<+;d~XG05l@{QVqd~m*!PM*)4nMs~^A}5_ZulQQzIhUwU{ZZt3*bvCG z7k;!nGte>PffPE_08~MF_AG@wzZjf_JioX3mt?!sT`Jmmf~6Kr=_(C z{p1_9WNwOHI1GI3d?17r(&*<1zc>{j5JTuVo4OU;0=uo$z3hL)|$3dQh zQNB%iUVv{nw6LGweYVT;+!GY+tbQIKd_Ysv$#dChndJE>a?z=UVe53w(S89JBjVjpR2Ngq} z?NHv7C&K;91T$J)YUFHXoV^jpkR32%e*8%L;t`$;dNG zUcI_65^m4J?p=)LWysE(b!tw(hFR^;Ua@52Ek4&`oal8eJp@1MWgODS{$->hZ;|(2 zA3We8ZUmwRpeerB?fUUKgR6QN;f5Vf3c|m(n{-er&WnMQh%Q=$GY%2pGQ!JHDwRkh z@}}V#{G$>1&?wxBPvPWD-p!^XzEl`^p?iOnZAT6+ik#Z6UxT2tNRz(~`f?`kol455 zuYf(^a8PXvsb&3p+w~`tPg!On#ZiB*$mjQD`Q)~gj~_&_0*J@uGUbC(ZONy73;9Gv zJh>E4kWJ1{$s20tnUIwPT-~wK-V2{ zjNNsmeXaRU%KAxm-)rV}D|Nklcl|nb zz5AC@Xre#hdr$uYp7ip#4LNPBcV7t*950!}nL1YKdt$(vi)Yy=cL*rvCtRlW?nM7E zrf(`h5A;XgqwHP=CjJXq#`dHnV++fQ)1@VEUwtAiuV-P`ZbtKRnv2k{jEX=5&0`xg zBS4XAgw9+ABXnTu+aY`l%WGJc_fmWSX$a0t_Vz~yV5I|R7JHGrD841FS)9I-^xB^s zJ~vi55{%XjYfob`Ym}pC@Ris%AOv>Lv_{a0GO%zmSXf7c>lxhSk2LrToBW`9GN>ra ziy@>XPVbbtqq)UKcsZ=f$$91Ya+^OIz)DNxru=!pSRTb!amumcf~-Kkugv2enqN>J zy(}La??dykv5aFf5Jc`(*nMQ(e5YlTJL%$736!m*9UPkPhI!yJPY=yz^d+e(5ZR%o z`Pt$_^Q*xjzGOJb7l>Slp$y@Ua~ScmGAyP_TE1}s^a?p-z5Qppm#ygXsIr`YNA#XwVG6_ zSxMloY&5M@v8`?T7AbxE3n2j%g~d%Yw`*G4+Sa!Iz>2MHZA;&^2uMQ!Nzhis-&m{S zPwu+@K&^(TC{&F?^A8Vmo!UltkHdXisW~bs&{wn zdP69Jv%7gq0x-L6T5LGf`cy;QFf~ao-Aih@uM9%!_a^rzb)!#aP7L>pP+{u^4VB{L z8L`>TagXNWPA<{Rb7w$xk?Sk{$#Kg%k3}Qd+k{7C^XNhIHLAKMFZychOAxa!5yaWq z*hh4#Pg(Z@^{29z0P@-&ga9wU*VB{YZmDqdxvH1pwuqW5ePyhX+e7nx$&`>bY;-Fp zONckcX4x5T6cJjVK0*MGc@|ZxwUnx4E9el`irUx#ZMCss1w4M`03Ii$&)*=fjTx#7 zyGL~{389o;|Jb~vr-$NEW@NWt<{HYJWiyyZ-0T<0mZe-vq{R;-9F^2rhZ{emG4Shh!`Z0Z}ApS)R%!UK3*42Kt zh6`%!^qN?TkX|mhl6u3e3UrTRPY5*6on*K<_r*OGSG=AZXF#%cZTibqzw9u$2HZ71-^!5B=dK6isBtJH8}e*&FKq0Ec)W2yJ{9y8Z~Q!; z1OP-=fOd`7IKVWz^9o_uf$~{TS_QjB&0yqyDFBi(@wvPJ6eUq6a?I{F_^Oq62dS?l zA4oE}YYi!rk8mITP!}5)YKCVZ>n5W^t((UXI=Q5d88$w-b~x#rQ5vs$w7D!Lw@-`BcK?Tl)etB)`m`lURKIDp zV5|h+-KHc4FW*uW8doc)o^h8i9L4utz7}|wxdB9l74zzOr-5GYwl19mJO{P_H z@xGoiY$lz%jkwVBM!x%00wcT1f0swwyzJnTk@l-l+590xvP6~K3flVWkDBoUZ=zk& z9~aF(y1%k;*(xau8*+9sv&NHMnej0VStYq?$@a+~s*X{~KKgrsR{Aj7_^yQWNTU3M zMEZlG`QMQWbgx(?;k?0Vd1T2H!1GHA7~Z|$6si6+6xDKfvXoPgqcm`{lFql$l&3_K zVmarVD9MW%jEPXPy52AG?diSJ99TFU2;laRnMiFT(1(9=e z1-}G*-Dy36H|w6-*nTse)+*k!f5js*;cOJ!H;A}gg5!1Z+<^oKA5zX{yH~s}3LA== zV#3AQRhkB9P!zzq0N^`yUd&uoCzYuz)YLmH(gB)cWv&h?^T*AJu@Ht{NrIsNtE-o| zjew|ijSzU3^&JgkCr`*qD+GZ_CIX6c|M2AJf0XChs0bo6Us-G=V=JJI$;DiPSrD|742=)5Lgb z?uY%%6>1)A7fkS2%s9iF0iV>r0Dt?l3h*|nmMMdCR%xxXaD1(EezexP5GK8_EX%Qy z{-g~g8A@_FTqE1bQwe7?<9m0)`Jldhosrf|+AjCz%DLYFSTZ>?p2@CfK5^EiU-(e- zaI0mWk&kCnrd`F>)w4_n>zNS~lG!hrIgJdiC{0vjmHD9FI&D+Ev%bFkfkb*&(fnaa z=d{w?&A^mQ$xH-6H?sPQ()0%}_y$zOK=uCa^tOSMN{<{FG)P%pdG?FEd4KD5=dHtwjikuHlU7 zjpnjdZZS(&QfR|X)yRyo%8p&%`RG?z=k%fvL};>CEFbf?Af_26MHk3kO3?xob^+jN z6_R?IiU=&xJ`b&A8slK~+s%g<5n-=;C2AL4Bmup>`DojDgv;Q87?q8JG2uLwSoc;` zBM)NkBFs+CD~WY)M6*Sr1ZW%WbuZARH8otft->Dhuw7)vGWzpb^o+R?avg=)t$**Z zorM+II^>~eB4_^uhSWCXM?YCY*I|9?a=Sf_Segu*%N9r2qfHmsJr6))g2eR^8nZN6 z-93-}@K=p6L*U_2=E6e3!g7DP32 z4?A8|W+X;a&tx>?L1!Bh6!xR1U8$*5)GnmWYs%QPm$M0Cw9tejf zD?(I%Y+We+g(lkoo1LuNTY>Fsggv;cR?y8)sv}a6f>%?UuQainZgAAuVyNebl!5mY|vlPW|f`qv~wuo_-!6rvtz z>!pepI6Wxor0EKTgS1q0A$^n!Zi5K{B8vB=Y9p<20f$~csf;jnP-jvjZ{jCs(hT0j zVa}vk78>|hXF8KEk`-$Iwn>*{_f_d+f-=p~t1|n|(E!utO-+!t7r-a&v4sGbkvuCo z#1rL9+(;0;=kE2!F*FWZ_7mg$4ds30tIhnnP`Lg_>_ry{X`#JnngZaunmyZ#jG#x- zmAa#_(unp7k+s82gEBXHb`tDGohICyT#6+&^KHvs^n?U}KPOB&{}+2vz7U?h=xSVN z#b^JUk{Ejt%efHXZf|zVbjP#*AP0PVQG!z+RYKdyYJfe_f+oyd?WS0pLY!shE_Fd@ zR-{flU1p-C=0jruv*iVRXg-xMxO>nsqMmP!g^J!Jve!oBO(fxZRm_mmvsciMjg4r4 zOsN00g!qQsRMC2qXdT#yFkt-W%|xdh4ZBh!)y#e5`MjB^<`d0CV&j65^wXJ%=Kcz4 zH-RzY)0>G-V1PkhcxIwrqGylxIM0OSiEfstf~mWag~41ONz~6w6z?yJpS;5(`+2=& zFR&4zg3gek2)&+G$a=FKxeR?OThT;K7mU45+BAX=qqZa*mZBX^`x@~qOOeyVpR3@H(eB(7mBBfRs56r{B=q{v{B zbS{pnh>f11#8_PFD7mp$$V6fm%IeCTn`OM=>jbB@n75g=&Rfk9$Metz$_hImkG}>rOq*P zFP`7utd-h!>pPa&9_9FZ=;J@ z8JRN;iPe7oFj{sr8h=x49J*vQF`~;_agpXGFLLfzZ<6c`KM9rfV$aYBT!p*KA0bcw zzV_e0^sBftdn)3$IIor_(OqDJLE<&mW=rXLcdrlzgML;(qd}NUZ8b{tyI1=%0@Ld?MSGy3pJ4D$qJ? zNZBVRykn1eAim^PzIy6MbR|YSnRI5CI18AvM6;)XH<+OH(H~0bTZ1|yozUMTw}4s2 z2lLRdj7hHA?&+51&U`JAH@zkMH_RhTJ>QOj9!K5;O1T$^{a{X~Dcv)BvYqswCu5ky zf8*8xQ)Jmq=@aq`l5J`l6S2TADBjWV-9A34<&+bCW|6wyVan9aY|qyy&o{F^sWaC@ zXlanyQy}o33fI@FUo?M|3Kw6ij-I>CD`MWX)9sBWYCz^RS|L^UX)sGm=EE3p?lyXp zdk$Kw#tZ}wnyB4gZ+v{B8bQ#Py=C4+_1~@5QH-QgGg6??(+Fm!rAzr1>g^^xSPJuP zL=Engg9`CWoiXCNEP3)WGcB-MHyKXx=|ERCR;dP~-hk2_79fx)H`2h?TU2skw%!U* z{n$sfRb|SfayNX|FGC(hO&-Opekj-~YpS!QFN#!O6v!#0se}1GTh|l`M7E~(%W#y^h%y^TDOR})YInz@ zW|oKf?gA!zqm6TgadYtq>9*$M>+Dub zz9^)*UgtLRE!QCMRY@taj8Yqf8O?V8>?bsM3=h@_BTBpHG}hMx&@(Q4>|RAGReiR48n!jB z3%S>@$yKFJK@2U(9oXj_WIN;e4!EZ(wX;2YH%IGeHaTV{IW8(_##7kDVLGy^WcmqJ zH~l1-F)@qo?RCFWc7{H*lhOStgHcoY?j%wjaFc*~8R6v39;bzxPcfVnw|;zILG*Y( zI^1+{5WTS=`sPP`K5MQkC?aG~?(R1qGrrY9!&w>Wp5S7`V$B3`ZbOkU07G+{I?!9;N>DYBRCLfX>UHs;0(z0Br?ejBV7PNnU& z^5smm^+H>FZZ=y;%sYKqi;KRGO(QRGP~N`YESw881}IvkAz4)K zDf2#3uS?DARDXELyYiF~<@vv8yl~PoEQk*l&2-G^v(ifNefhb9c^%f4{)PWKv@I>m zL~YycH=D=rZsC!A+;@Qq=>I&elQ%f9W4TumZZx!aI}XY#!pzqT0jM}#%)Pk~z%B%U z8nRSg833q%T;TUc&p|^TvgZ+Lp?P*@2SIjf!|lwZ7s6fPpC0hq}f3? zDHRgZh5U3uFH8CO+~U0Y?XMpi{kz6_!gkod!TuD+zj+b6db`zfyBG*VeofoaC)qu$ ziqF9-ab2SPZLOAB*Qf%{sFQq+30LAOyL`K}F6)}7h>B;Xlsd)vXgkBY(K@^QZ7Idp zHCqjC>0FD)I}w z)H>^)#V5}6uy}9Ye-IEA^s1RBZ=_vG9IS?`%yv@32K7LE~nRKzbycCs%W(UC4RRPt@I;=qwUB z*?I>}nl$qwCf%Zv>^=qQOsd`_QIZ(wMI|PSj~NVuEc$`IcYqJ-6-LW>dw~2~0O=Ru zjFN25hla4Bet2&VpwIA%@XtMi&Iv%hB0Rb0BG>_BZxJ5cGxUK0v|ogdJ%hf5ieAtp zEA|YzF@W@u{ti$xP<0fRecL_qg*!!r5Uv6Y*C%#m;=A#CD#wdp6qL>ow)E zt-2?4%5(MldHZtuXv8jmN4>Usy>)FJG)-g{M{MUGcKI&qTeP^Oa!1d&CphCWf%{P+ zBPX|`IV757)$h$4o^UP&7=`B&@^I1Ii}RUG;#3EdiB*t+G-%s-jS%uK;^b)Oec^95 z_%HSFJ2Ohd$@U9}DwBjVsV9@9^Jcv=(Quv2L@|5+`^>uO0m*@xm5`ZGsxom#uu>;k zI+P4Y43^=i%7`o92FvKyuk_7mJQvBU{dBhmiNVRrS?&4(n? z_mu?*lFqB{3lj|b=ELmFC=4eDu5U68*Oj_BtQ7)|uFg4jthf zZO5retlKuE@(t@?inEVDe$M+0y!*LAoOXI+vHYr^$sJt@pF6|+U{$RwsK}au6=^K2$l-ga$l0pM^vXA8>hBoq;1=+h+?x)hEYze8 zI(k$_RH+^>Q4g_Ezk00Nx1b*P6=wbSBCowf?@kgH(A(5fH*Jan5cU4I<^O=mV7?vtl>buY`PX3dHzlPe_mNFuO$ajP60DPy z*k7(&_W~OZMa;VpVed(RvhyYq&!Pd8?n%Yb<5~&S8nBG{F zP^dN$@B5@4ADEY7VD3BNVKz7)v75MZ6PJX>r2C}YgYIO z5>$UV@wP`2R?p`}5Q3f!Mmm*|gT^{)N0y((ANBz7&j4W69suqQ0JL~KSQ&mE0E`iU`ar*GULF8^b`Jp41Ay6k$l{~` zK+ac#WwBoXFhT$&1IzH0;{%?!n{`m|_Mqivi?jn3$-vktCh2Hjp0u0_i%uI_H$ zw-zJ25^Rg+#`*FvUcIyFSQGxRJ>h+O1a|CA+imMlSClqQ=|#>g5d6*m1H(tYhWFR2 zT2d~KuWI;NG{hY-h_L(Jr$19nC*SS9HhDPD=h@lPdJZMY{mojjjwv0LC}t6Wj&0W_aTX&5N)|mnVXoibcnpuD*IXja5J;x0NQRXTCxAf~Q9-d^k ze?1m4lqYw}Go*DSI^GE}Jitn|GZ5AF)zzEGMpNxq7I9*+rg5uXKjblm5VLzRPc$#N zxse0<)b?b?O0*}SHELJ-byjXzzUkOP)mQH=PI-m5_{yPb6sLREN_~C#zlY9xjh9(B z^5eSPDhkSqb3tg_1mEe{PI&hED@TUTvNH$kDwlD}yC+p}&fSoeMImTS#jpe71iRSV zFOz+3Z_drk)4f5yaNfyR|syN6XA&|C(g0)h`;o6un$W9 z(}=J{^+WTy{q4*WFWubgnzj?d*`h<$EKyFb>sjZ_t;o|~`JE+aPfg!EOUxM&JN?2|ySgoedeC%q-|^heq)G@@ zKW;gL_DVRz-o4(3ZGKS&w5z+VmRD#1>zvM<_3rfwOPqX))uN%x&RiQ&a%=V0sFjv# zM@XsEkdr4ztZU8g#>}<(9EO-2CNo}LtHRjbCN-%TH!M4|!~~{0qqbw>D?8QoS1EbZ zH8w^-rAeT;Po%ePr7I*^kv{4Ns$%mPZ)yZX<&P;< zyS96zTKC$}^s5Kk)$i0;Ki!xR`DGvt6qH`qTGJ zW1Wk8D4Zo&X4$ltDX!O8-!%|8X?9r$*Mult=9)p_3?`tO|A~ys*C&y=MlF)w*<;<% zS<|x7YB`XG!>BJ#8OaJ8U)$5kSSO4)3FYn@6>od}h+ipH&0oU(sbRIgsVUu0_*tuJ z8_sa8sexGc`!8}9r#`$N=~DEkOx$MpU~yB!$H`Mlo12rFqimkX`H;EC^)Je|@dKSL&C)l%3v0zc0#`0IeFhnqP#W>~y!cy5#_#ydUZzQ;k2_2KvG@m@qn+?fp1`8QcDQm|93 zC!LAnec>z=Z^XwWySq4cC(LelBZLkCLNAdZq%;VLUN0Eug|*Xpc6dzOiGQ}*-?vIGnPA$R-JHIsRN@mu8)&2IX zBatAcQ;V8MClEp8xuKB68&I$%1Ah0~h(e9Icl_(mk4Fu{k8{`(S;$ysbH^ZDy5p)r z8hkJ=E$DBbj!AzrD3dM{lTM(9M%0N(|Ane!nDiIDOnOiOlg=64+dXW!_U(aOTRB)I z3Q0PfJhF%Xueg@Oy=ieWl%es{GVT0NX4Cdzr#_coh|GdlicE-AU&I zyL=tPRCxZu_1X|%_sS3U<{)H@ccDf;i49H;xTk3-s?x?G33YwRy>GgYpv&d?X&E1e zpMFUi=5@WUiQviB2*(~IopCiugf|)iH3}P59dm*ngcM?o{?AMc zIrS9&vRZTpFtTbbcT1Z>FY(1w6&V{jRTIc5JCIY;C7&e18YQEQ zP~&M{1`%pOR9W&UFIB}+0ye5dL~n@P22Jd7@YY;_N_U&+E-UkTVMKY#1PU*7n9 z3FGreI?S-2YBTzB{P#YOTF$6_2|fC79nFOTD$kW_OdIPNhS&r6uwDL?IZp9&37oCG zap+Tw;O3k!jmD!9xv(Wz#g-E#=}w~jdCuHRmC^KZK8=feUVZs{b8GvT^@0VI^=o_L zxdFt@UWCZOE14nvlY~@7@5nl!MumcM%11bB9Pr6fY~SjCE5)`q{%54v%47OVv6)YP zq7?f^e<}92ycB!=xjyXnr}!Z3W`F3hTg6KwLVfsa0Zy0rEXql`Gimr`vr$_f@%$@T z0i+k7!Isw(Mkm@Ea9%i@?Vn9-D6ZZ-Zy{SVzaB0o-0bU1zqB~DdvWuT{=PlqiNE2n zH+nvE$H};8PccHYfOnkX=Jv4r78GLiENErDGj7i)P%GX#d0!J zPWM+6LZLg^^VrjLob8-b(l-zMa3Y%Au-zQVZurc71Q|G_3k-ftR(3K%c>eT7^UhAlE}N)+ za$ZtzL-odPw?%TsPaXmDOp6U8jD+|@zmK4rl)CbWq2cDq2rQ0eOCYWHN>qPL{Kxgd z^rvY4oTM`^@1oypu(2KHEPWP{6J|Vs7-;R_E5Dc4SsXuf{Qe1O1>%QPV)g}%?=7-* z?KQv`W{`A3xnE=Ii*aWU%@ofRTj|an@yw|GB~DRN_xWqj;+~%Pp+}!;cKtGiVp6W9 zbQtN4?GTtlKR6(QRanR=>$suTR`Tvjgu4^vUG>#()?1U_OK3{4m=Sk)TT!;1Qs7H& z3BNEdVL4+)$ok&T316~16#7oc`u?-Lw`W43U-YCu_}u)lHg^`S-O+O@&1T*HfOYlx zut9sKr{||cms(frm>qrI$md?xwOl9`T0MWbj9b8-#8;LhlWB1|4?E9$>uNpYK0F@Y zg()I9zC(ig@T-QQ@Ln%XBAYApRVE*Z?E8MnibIPJP(B~_EcxIC!mMkrXVUnqI%hYtfvB+{OC%n2&wuOw#K|ybhUD zmHUc5uIFRKoTK#meO`;_L~~!%$8~%Z&DmG4-!-o#OLm7tO`+z46Fr+?5obEy{LJHK zMVNy-v&Pr9+0pF9EUg%V);SNe+XGSX`>$f?8Js`rlDdY#d?BJ~!M<(|Y@RgE1CxOx$9uRUan8kK5gyVC+d) zlURh_M_b0NdW>Vq@=eL|`}v%I4yIzJiaXgzG4J3+5f(1zJ*-l46I|ajZvAoEruQbE z8nSrR6OFX$8JDSK96os_?k)AsOieUP0*iXyxX|As{$3J;rorky`>v`jq`i61Z^_*@ zn101E1uT_!wZuki6~b;`6RW^R=>B)fP_Bn=iG9RJIE=~AZuifcYQNh+NGOimYiI~} zN-ZQ0v09Fz<7f$aJD>8RP3g(EqOFMMOJGGjCv_`wQ*5ik%fHTXIOWq~jat{`H~>k1 z%3!l_W0O+}g<35|y=UBl3i=>TV-}@r+yl-o4($Ls-1HSC*sfmNH^CGVB)T`&Al+xM zq3|%WLtW3!kT#E5Cv3HBAO!o4)v66nYnT2y%6L&UJd|x60wh`4NtkMOAGB1vXWSdd zs?qK?nQ8;WPG!!fO5-QleuD{LwFS=djDrX5=Mh$faBo{gw@xWRCfK(J$xP|Jglqpw z!j8`XyQ=CYtzij~dnCG1_6@)~wkM7xv*+CfnPH(B@vb^MJR_dEYBIIZh^LUrVF)uj zymAZQYmH;2Rku?ISuAj0qLrPEap%by@f~$l;igeD>M~bNA88Ty)zHho`O$`}R8>Ri&izq@yw z`y-j(1|dV;XR3-rm2U{T#=VvPlkYd63+coO!V2^+8>SFh)-Jf2wnegpR!ui;dp+Oo z8IPl`j$L~rAsuPxy}D7MWf-C?42v7G#)yu7;#bH0#+58?%yo}r(l50|eZt)pA?!Qu zL0(wyD<;D0NA5SMZLXe>+)VwP=_iW1&7+7o(gzg}xDdI`Ds%AF7x^MO0bFprp3|7?)p1})*_sPKhKDbr(`A<;GFJi86tN7_dU~j!;w>#rGiIpN#UKG_l z0h7wiBe)6}fT$hZ3gU#mROp|3%3#i~S7(OnxT+#dSgceT1m1GA-9DY&B(wQ%9G=J& z2Y0Z&Kgb_9r5>uaC(G#NN>qT;2A*`_ul(+*U%=I2S)& zI2nNwLH(OvDN?IN)oM5=EG+XY-P6eWjJMWfs_#MQTIVuuhEnYh1f{!`LB`P4%pki< zWNinH#}@l$hfP$Id0#`bTaF)a|1>?gD$grb?tY&)O{~pp1w1s}{rChEKC5r|EcaC} zd_mvv1@1#8JlzHb71ev|i9+1vUhItnVin^4(2Kp(j~#D{x1YUag9!!2FuQV};RgZ_sM1j;n@Izzw67OFph~+To}JlKm7eut_fVy^UTjdM zaXz=_tK{ASfZBBOqqOO$Cuq}vKZ+ZQL#dNP&5_C;`&zgI2{F`t>vHJIHG`>z6`?|r zyZ;yZirj7ZuOhr^3i{RENPLmyv-+99&j92<^pID$ztJqfOYL4oG8OQSM=0QhjDCaj z+fS-Rq=4UMk$vD{6V&Iv*91{y#%?woBUs@NwnTXn;D~~fo^Egrlni4`rFy#t0^yIo zR2{C;J@}ZqL|^@%;i-g*HsK}Y7tZ~iX=jAp)eJ~%A}>R*R@j*fE0UQDtFUO7BziU$ z`s-rKY(gnTEz4X5Q8z{sJrB|obIdCPlnW|UH#T^gMmk-E8XT|unT2ocVEBTweWReN z;H1Q2PX_s-%)6>2`?)L}&?m@~l3wO}xet~g!HdNDY3~yE59uA*pR0fU{?U=*02P$| zhuZj60QLkBxp}VR!4%fN=fNhfwmgpk-XnqTr*odoZFA2HVEg(v1J7}B1L1?}jZS1v z&DYL7&-M7L?qOPRBp3sJc^NG!KZ-toNS{Gg$G}qdd~~N5?KWsK0JH9V2xJ|P7ztUx z55}K~6J;};Fx!41?R=kUj}K`NR$_4#y^7XR`~KauFP@<=>5is@^QFx*X)v?P-m-0w z=IHL@@7?ov(6?WVo!iR-+#H~h+ZLc7U5MVT2cgD|&#MZ%H$x9|KRs@Nf5xvN=q_e7 z{Gnt=W^RczhI7=TaOJ4DUiQ%R{l#)^IisTaZHTg&DGI+luDDlGP}c?K3kK!{VB9p(xg*_kC?joQw1z&#dzX0A z&w-WkPYv@;)FbyWQuL|>rha%Isutfu1yUsn>Gz+j&!fnXyyD~6XCG4^L(V@Ftuo&G zcgncr;h>BGKhF3%)j_S2G@&neU4NW=Gtz{u%6U<6@zD|md$_N@<`|JAFTrxbef4)D ziSmh1UN%HT;4wg}Ku4-T+aK}^6qKjw6=n2kyPSF8fE!SbZ%vN&)>-M zDwAc9-wkcBA0QvT{Au&OdJp-YJ}}>Hj54{1JCYnFlgMTqh8mURb1KQZ4+gE#t3ORU zg!RW>rC=x|^poyFwkhd550G?aK~lqXd418@ZLOFxg6V5hmFBsvT!76c+Vm1wl|gE# zb?p@d^u#tcFsG++7Kl@<)(bQTXkWM>dk!zDg{2{@m22n#Scn@C6Py-qCkO$0Ca~4K zc5DHk=eRfLB_#1-N@gzDEwWl)CN6bvC%=3=Wj-p1=i>qMQRaR8l@Gi9UL1B0Q8{7#Y%RW+!*OqfvHYgM?aywUo@lSzfA0(F!y1vQBqG(GMkn7sSd^bvlg5eZ-NN{e9 z`x#KW`{`%2hg`K2>z=eJKWk9`(_~aj1)c|(T>6-PBj?|L`Z5~M7dFhGjNI_yvS}pK z-2Dt=uG>1qY?_8iLT+xW8X@XtJ~NVMg`4IHlCnJg%iQT^Hn0$Fi1xkKaC392g8|u} z7I`Jf-UcS77bYx_QxZTsAg5m7l=RF1Z zFp4}lf=7T50;fL$_a0(YwOhLoDHq%i!LUjv9n9kE6VClf9Op3=A1{+Ol6&;(1;${c z-=ylZ5rKZP4B;m9;t{sUoy7MNp z8b97r9Cajz8M3q1@C#;ekH zvhEwrhAKPOV`F^*bU@c;?wk&AUF#c7@tN1hQymf+wBfJ$jrUw5aU%Mq-%N=lAC97w zXa-Y!#LjwmM3cc8?|HC!ohi?PYJ54_Z;^hDB+A~MXAvSv-whiyy1xb>dln*p=Jh7Q z6uu=?Ux&p8-ps8hwE|I-#3CXb*oa>Y6cWw=yC5P#=WH5v|&N}EqQ$wbdp(glW5|6 zXm@WgChTP9Xk)@ogrA*Zt(XMAhntSVXxY4%XSu%d^_+y1yJt7+aNl>F zH)nKB!b+T4C?oMfjEXjg`D_OJjGDH&ljEt0u~1)IaROU$iF?oPqLA~%j2)AVowzo$ zaN>;G%-ovX=r~JyyJE&vT+6lsjLF@=2%j@);tc1)8nfvGrZ8d8G1ll799sy-W~`KoFI9YGh*laJ*{eg>GKc@@)R%et8~#bQFN;NiO19q>ODPo$ z&*{J31wXi8*9svQM!`!^*WEtCEP^Nn8+<| z1*AqRAQf5x!33@qDAp1*#B;QrwmHZa@BXYi6q?8?%NNP#PL5&SW#XTAmprDiTb)qJi!7cYeyebA#4iI6&b%RBe5hXN-n3CuMLYyNIycP<^2&X~{oMu=XDV)a7606! zCB66kq=euX6eV{YR{#_sIW&*t0Cy%xa=4IeV7G*4(vP@DyiW0hx;&s0OQG?cPNYT^ z(C+d41T&rj`H_AdLlw9Co(VntX=(LK9CMB`K5pMiePK`Px-O6e9oY@KN0 z*z?`6WwHCklM*54lYX9J+GCB&5DaLSF5PYE$~JCSmzzVrUtTi-+c zu>T^=><4_?KL05>gE!V`d30OH>|aMib(Nj&ZT~flC7%BLVD=~4Mp0t30(-!(;AnO_ zm~L`_0om7x)orHT19NMSBaSOmFo|?Fon`zSrl3w?_Fv%dlz7;>M$;Yw%t`%LqGz4I zBVw3!?IU!Dp4dkXw?uKw90nMFDZAZfn}qJ#D9Y7#%v%~QynXuA2Hdt$#Mfm@?A7@c z>Gh=8w@up&*4yh|t7<#TV&g;^8z=U5rgE~l_8y>;d;`nf0)LOj>O@CAxw@wNV@_t0 z42x>`Eep=xN6$vZg)^#y`7C!yyzdz4sL zpXr6tA^q(e#xNBk1$V7wOXRdSdP#ZrA&dTG4hZ5_@ zWUZ?<3R==!pTWtf3rn)|i76NNmtFZVY`UsgWVP&v@fvHB_{eZ-R`qdK%S6MXr*lX|r4EVEXn1!A3$`<>CTmte{4VG}&r%2fI z_kv0VIl6l+s%fom_kL0ZRpUrRHPwuNm*&R<(>zNW*`K&2EE8uO4O@`}Ju8x_p-WBU z+$VgLYUJ%WU21Wo92TV~GZmE?hp(vj#aXX>XvP&n1)Zio>2K2LY{B-CzHe5c&eGsJ zwD_JZ6^$qi5t7DNuDmr$wYuH!o*_?`K)?j>nbF?a6M&}d$|pIZ+c>}=RG#EunofjD zAK#bh*_Y1IWXAJ$v6qsI6o~lB1%56ulM7N3ndSjSdx1i{swh3|W<8fZrM*D2t_G8& zS$t)g5A=@#Ks(99&u)vK-CqU(ZMqmB5j4KC!N+v{0HE2uWeUi1p#ciW6Rd~#yX7st zvqXbXC!_CVPY?75p~L$RFgH!^y*8{-n% z%a_-i-*LXA^O*A;fL(- zW_#Vbz3s}k?RD!T_PVa9UAf*4Zz6EC9e&cTL@!-G&aQmNUe_5-R(9E+?*W+-Diw+S zgd|d05|T)1{e+}a;{OD^UnoX|x@{y6&GI&01DdR)^d zaA(*y4kqiWFaJ1x@+I4wzFgNnw`XSEgy-s-7gyA^bY6a8 zJhheWA7^Y&On8J7woYqHmPFpQE}g zV0HhEV13aJKb#k=A9#YbyN_UfDv*x|VIx?(1Ht-mUa)!zC0I!-!TQty!HNX`55Rwt zV8u9c_Wzq;?ZdC{KYwQX#Kn@Yr=5IJ)#j#i>e?4dv_4~2PU2Im_F{JIOXjO1%i zGTd!Xc&d+lJ!=p0Rs5O^qtV(7>{HR%YPMJr+vT)4Hi8v#>fJE@&)}W#(YA|AOB92{ z&a77ZBn+#N#+IXTlZ_qGB*v18f<&^}qw_^P?myF$)>TGY`+}Omr)%itE{u=(J|lv( z-h{M1BVxb*yxl%(F_&l*I~SE~*6d`Ij<_2S80sNdOCCpUEO{B|X&i)N46BqPWoE3h z_Y_(@?e?>y%uW0asXgw~3yhYW{X%b7*(t)A8fA|&vlMQAKhbV4X0;AZ$GWwTPBrpY z=nvdL5ccLFzcuzm){E&N{q!YL)Y-a^pjTVMl6G97y(O;&&8yVRn9FDOGXB(dXDkOwVrDm6-Df)SA_%A1ae3-t+G1-_p{^q%za2Oincs7JUYI0viZ<0#~qPBvBc;6H)o(Z}W8(K|TDl zikiz)iyO&BD-7xGsQYqb5oXWHRRQzV49tbH1`wD`7uAr9`0BU6CYRYkE~&+1i<>z* zZ$93R-mz*?!-m-(b%x~hnL0Jp#EF~TCD}Qw9%L35XAjxkd-}R>@BRuFZzg7R-rdRe zds5Ib*}isZSdSSjrT-OiuD=xid1mR34dd^)kNz2QvI4iYpK^am%QD`Pb?(?s z4Aw0B-g_r#3dYZ5<{q8jRB(XSYirHOgu_|$i*~Q)2$w(vZZwc4nqQ&7N{i2A;BnJb z0H!8r{}seJ>o>hk;QLDrwtwJT8l@oU0o!L4NWN#FObV&uK{ugisZ~r5l-A!B(^6*I}8f##uL+Wll>--CG729zvMy zaRFM+FCX`tkEj>3#(Zc6mY6^CVYlDAg@=37H;e<)b_Hn}^GAB|oNBa?*}`Y)-dp%3 zoy79Y^uh(awhOHN-V_h_T(IUAr|!Lu56|`Jdd2##M@r-gws?ma;@-^!u-Nau_zGk* zUQnI`(E~g8GT}$kyj_!Khtem@O9uL0j%5OuqZ%c;`Bl++x|iZcKgCWpL}pT>NYl)5 z0UH`g<~coH#Wi7`lVIRkJS2H}FeZ;*2{?Bl!K_jlEoe z@8G`p81MVw3;FmOeSB5I_wlm6_`YUF38b#KUnDwEe#1g=i-FK65%ouj*KPybau1s~ zJ|H068{|zt(4Y0e5qCe{aF{tG#Dfj-!jvD-aQRyiOjF6 zJkfl4{Pj=D)O%FtLSMBxb+tOcTn4Qj+UB>ghH3K_U|fD#V-Q{KT8QX;gz4|Qr^Av)4URH zA%GHY<)IRuTvz#WZfv1HG+yi6_}g^I)Xc%V=u}qY z^Ime4qp%AGV$(>A6 z%snl2)z5fn;D=X`QTBoX8T*~s??3U5P6TAK=p+%&-pckjp4aol4=k$pChvXh+7NJd z(aAm^W=Bbz@_AAyeSCPB@a^3b9X_G`0AzQq0g za3Zi!m$vz2MUyA0E1Up(J~+B*UXGtmlnscR=Mv#QIBg@B)9kV?R7m9 zTxX+L=qoc@-)KHYy{|xDQ<^$ixZK2&`*i!Dwqz_})Z`%0m)?JZdC^At6F({u5HI(`ZGVAEOExSuRP=SP{GN{2 zzHX#*Z@jyO5D{VNO(V?yl+;>D{vs~KT3l7sT$NgTr};cKwN@C5nh*Ds?nd|0uNb9! zf#d-jFbvoEoKm3OdwRD4+RF#>RqtcT(0%Wg-q9WVo$b7W?)-AfUh;ZM`a%1enE0gw zr|gh>%D0O{Zi3nsoQwJz>&X0_q0(Qu>r{(>t^p<2<$Aefu;qPB+p;1WGzFJWyYCf6;{xYr2b0O2UubzkdlK5-db` z&Ph7Uv@6HrW*5Duc|Vot@I%e!-;?xy;CV%%+~=e`MY(DM`S+aOV+ws-;s%iS5ApU2 z>pk~%PguVDGb**}Ce*{b`N^wDfqwY!>-XiK^sC?KLF;$##y<6Xz2Vc;Z?aclQ@<}z zV6T2PhxOL4R-r-t_AjX4NWXsjs(w%Zg8Dtq&;Ox*zx-Lh`c=jUYrkji>r=l`pQ?T{ zC-k=8SJB+O`ZdOS>o-H8LH$nhz>UN`iU5vt!=Kc#*LsD5J$>&K|F zT?YcJrmyLb#n1=jVPQmsWj}z2#ipfEhOln1p?7dvK*cgv8tL4uG)8#U!sg+X=Cpu& z6f>F_!lq~c^aVM|^`={(SRHR1Upd`R_hyB+AleIbXD?8j4|Kl={IGDEeDQ_9R>qZMW#hl9PpWqUl+R`*Z2X$2DO=8LLTgK?jm z`tkaBn|zn}Y`qQie+uWKU@dM&8@VzTl?rnA9Yq9l&dKoXAAzX6zr8NJ+OHAoy01;( z==So>O(&ZAr1SOpNuT<>b+d~yDIpEV&;W;o;h0mHQVEgl{ z@b)sV3RcS-0B{!QO27OYad({1UR+bYv1uCHovqdtUXf@I++zybUs83B_{r~cYK=6-l47p-)685?yx zwFs}5)-T~1GJ~rE_?PE5`%4neK2~JtW#e}A7>$ey@Hxl-T*{|3Kk2yIe!@)6Oeq>V z(8dpTpJ5}cb_b}BS!KbIK;EG_Ryn&t;AV@h2vSOgeK}85JL!>1ueFl~t(`O~GUWqH zDO4NK)jiddgOW_y|1fm$vj1glpR%v;KbM*^_b>aJm^5Xt_~SpR_@k%An&kd7L+eD- zbRw1#n*AVpQec_nRJ%r=+Ay(HPs%)7;ZVg?2&$+;miA1TCwnGLMLlg-=|cw34X}Xl z-4u)Z=>w`&_}`oTbTxdFU5fgV+t(G^OUMYjPOQ;4#F7dgeO+v#dA7uk<|(yWO~tEu zzcF}kUlUuZuy*fotkqKfd&d3s<&kQwGQibZyf*Tx#O^!Ha@KC)t)oPrKjPC&D^O}= z%@QJIv|1oWIll~CtOUW9;oOMI&g_ef#JY}Sa!J8_5A$A6Q&x!DP7t@lo@VcQN%Jc> zWU}paVQJT-(ok-Hy}|5k-Jcr)x^*4U^_dfc>zA2QP#_^#V~WvH^(*>Z2j@o{9l6_m zY=5J&up;`t+l>+q*06dEGkUyJ7jXFA5>s$|4!hEN1=ZAunP2;xS^=BQk$AuTSZajM zBHOG+`P}XL&J10c4}MT>chAr!0%khty9`#`TV9Adu03Lt^E;I@+5TrunY+^Zz_w7EvqjpXsorigw6k1j@%dd|3Bn3^boR_!J{*3S~vS+kx3r zB|ZyC5;V12dYTY>8+*jW;tAX`@kJdCQN{L42?_dVylWW8k$zCrJbZakHWDEs;B)%J za^cq{$-7lNMxeG6s7?5WqwcVyk`` zrLv+`#-ri7tx?FA-7Mo`d%DWh7Y{yC=$-w^ZC=9VpiN}P#N2T{DtP6Tue+usG-iBo9PJmQ$n9h4|&!{ED5LFa!^KB};7nJ#tptVP5XcIA{+Ucdz7x``$_zeQrCeG~3A{pK|6)=Z7AgT4R+kdAnMe0&W zLY}6BWzt)f`WjLPU3~kUMAKtcn9wfvR`@+~?c2wpfrfrVe^_)qXVYn6Ztc6vqW;ZM zrFRf9?ph+wRm9RCoEYlRkNc%@WH27n%i1=D>BntX*ujLkf98Z_1`mFPH%w^b{7i?0l+j@C6~^Db>_8hq_073@M~ zEnn$^u#*&Kc0L$(5O=KID&SKT@jqgUei1_z@v}UZodO=Mu-3j|&t?d_jIe~W(RhgS zloafmG-3!-2lube2dw!K?_SaNMf%CjT%y8ND-fKK{3LR(zAH7Eo z{Dm(T{X`FU2CH}3Wge_KdKEN*U~=at1h~eGlI~YeC!-E8qdY{N0)Hb!uTle3Xs^Jd zC~)pL0^+PZH_w%He|idf*>?!aaj{fyCNHuglRbnIxVL*K;$6ds*~;3QYee!W!vcH0Q7PVP}8u+g3)?&KHAh#~W= z248O3&X3xtU7=v>GIC8pp4`zPiq4O`cTeDS8-YV(3aC>L$*V5&>fKUfZc8&l)OOO# z4aARD8h9g-Y$szxkz+)WFSNRh%`IrauwCh>9){nkzETD4%zRY4K5X}unj(4h+!gy7vGLSLj7@V! zD9twaK%x+yQc7f3Em)8@BNgMBXk@Lp&Im&Gh5npR^w_N=uPU? zrv2P|_9;doA09UQ8Sw7B7Lk38Yb*cjna>mDKnfh8g>TDE02 z^V^kvgx?SvZPZCW%A0jhZ7jy%t`&FaCdfqheP*|~nWbr!v+2mnH{zPT>7>)9IR*3P zZQi`O;v_R~u8rv+QESCTvDz7R)`}}*b+yjUn$$<(=Dq7$Fuz|poQkzi>6sC4tBuvM zf`o3Qt)u3YSkcC#_YZiwA0>)HbuBMjt@3^6uFqI)+m$is@Mm#JdQmCpzDNvLn6kj& zX;$uteb^+PS!T$b%&akFj;B9lroldeP@VHpJpD@1$_Ve=srtrr#NSF|Wl2pOzPERK z7b{X&Iud1}iGR?Liamti> z8rvM;{OeUbl(p?9d+2WA(V6XrrbhMcO5emspwy<*hs=pN5rxLpT?=135X6`nenS@i9D)QeRb@K=(3HIU=qSh}!0nIQx@(sPU z2LZ07l*d45xBFzJVGUEDdP)0k`1Wx|4eJDkPxG$+Uiz!3dEd~xPu1Ia%Fw`sh4n5zc%ROzSUu_7h)`BuWrjZdq0i5r5@~?FLY=p@P52;|STgXDYMz&D zZ-nJ$@ju&VcB^G96CK0w*}cr$VB-aX$cz`Qo0xnt0&icpP;mKWuQ zEgzcOcX_cH*|O05S#^7qL);cH^LU@LF^p=S zy$epvcJPV*oxP3^p84{=wb`rsnUptsDUt4WZWT7ZX8i{H&tecS6g+RaBMGT@J~Gp% z{wXA?azE~yVw?LkA=yJ=2Edcmo+PwdxU}AMUUeb&?58P+`T`(9k9Ok<%+Y!TW?%B3 z&zR>%`9f`!N^q03Rb+s=gZupBq&Th@jlq5T76K)wL61Ku?qR67m}O9M!kowBH<~g1e!&mzPWEa zs`ufXD9!~W?x~MawsCF|dAc88WeO-7PCr!|zfqfpBr{F1DvZMwMM_fAdt57er0x`A+|%^)Mg3IqlV7{-XW!>O%l!J;z{xW;`@I+smTwaT6uxIs1Tn^@A_N&Z@|{K0Co z*m7=xOz-K;om&8LsRwb=>Kkv5hO%owB=n^P5PJi`A?LkFCz>Qyi*kh=`xIz=Hb;CM zsd+~sg1@iARBYg2z$hv$TZo~bZd9gb`?zZ+QpW)+J~Bf*`UR7+AHlB^{7N#{pA=T* z+OaxC1=cq3(@{aVyW&b6Z)9stc1P2(M)#oSXx;E=rfs>;5@T~d+c-al(;41$$0!C{ zwz+0tANNpGF#JL0v(EmfD*`s`v%YjAl(rqNc!%1zBWu|!Z|)_j)j}r=nC|y9V6ZJf zo37}83XHm0WZ7C3(_0AmE}ycoOD|@k#k_VHXn9O7(G!m&_U=z+FXZUSQF*GB;axV& z`rZ=aZ0<5b6T65l*clf3*vb{LBbpGI6Sisu-6&rnKn){Rbj(7Dc1vFQSf$e9*+)HQ z&6wgo@4gMY)jLPjJM+2lkO;*rdV`!!yQ!nORo%J zB7R?0;dYt-BfbT~7ak0sxBq5Odv9<~+O6#}oQIPcvF9x_`{&us-+!|we4NhFi|-S+ z^xP-n@n`&(w10#<<84RxHd`wukHt8?;FnPb39aR@#yK_8Jt<d&$Eo(^rZ2j; zw8M?+B^nnm<3oehQRY-Hxn}(6QRA&vC@!$LvkY?wNmhF4&ZmBwgP%`HbWG9I3cjoO zuAz=LaNs__p|X=Bud8(4b@_cw^QljTsn2Wfc&|Qlg8KY_?7aziRn_(PpPK{-7`Q=E zBVq{}H4)ULMN1SlR|1@?H;9TBXH=wURS*)up%A>G0NGLwm|CwoH&%&v8z! zzZx8~Id?#0?L+j@**XaNf7lgSWe;Q)fhjx2DrBf4{+Op<$5QU((Ye#Fk!iP%rU+wQ z_u7n=0=WVYH)A4+uXGH6F>2y{Vfq-WSxoroWoX$o3%a*u?9e znWvJEsK91TMdapO2)LWkM+moZR+n4`>WAV9MVAno zH#-XY8bYrS=Lj?7HEN|H&OB?X$v!*NTfRL+$FC6J-BXy+E}Z6x73ym9_wVB4?y3JJ ze3b5mk9;Yc_fNmC;Bc&sY^uaJSoP>|xi>bD>QZiOG@4Bpsq^d;A37fuK5DNAA7|X~ zU&F`WCVKdQfcK^k$zZUKZ$~0QbI+xZv4I?na|B_(0_6KaLez%GJgIQdU+DA`%U!nGvfaV5wYrD*te>gF~ul<3kV}t}*Nv&j9g} z4*5Sx(n2?eO^vzdBQ{c3>!D#na`I0wlG7YU^1)7|=I_}DU(Xg~WO>qlfc#~!`c!dZ zv=>ucW#qFsYL})s=Zfb+KkA9POj~-feNC|&?VZe-Q}rqSO&snrHw?9GMA$JN()wHVCsXAlgK_TTTnvySY$W+7@``TO zNclIvvUqz{3A27T?hxd}dvX7&#oWIdz`2)K-l@skSG`r{J2DBTx-hj+rpw@+@;<&b zy}Xq5Ao|B*<~AponO%L zJ|cvwWz9q+-d?(`X_@(r5&~-*Mnef7MP74JiAZLk_Bd_B7^wsLi{K zg+yyd{;i9W{)duGE7ME*MT2&(oW`_d=i?pphsHbT5AkX`DJMnDboja~`{yUd$tBBC zFv>|0I5h~Kox?!|!AZ3G=l@o^O7e%?3AP?sHHa-6P~e}xQ*b@#vQBVUx^PYd{PRx+ zBo^eyoygrsl0L>7;uv1&5XQwK40cOotKQa#L57=gO|bs@oJprgEEwm8S9mG#F};?6a8b?2tDS@OBNn7a&6`de^-tMai60XM@pJ#R9! zOMw=Q$@VN4Q^>#d783KU=1pv3F4VM~Wliv{3pXFF5y(<&0YVkb3VTn{p);(+nh=Y( z0b@5Zo}YUEE!@n4q^TrS)>3uysQPi4c@@elYYeaXm66wirMoNVy;|uHzQx)4hWl78 zVgGQg0E-M@cDy;MGnsgk@_+aC~;Y;SBRjmB+2q_s1hmH)mV zBfjOi@jNVTIlRY!vA11pX05%7xqYuWtJKVHQTG+1r;;c#|;- z$WpatPF_a!P*tDxwXCk5pSKMa%vIgN01n}p9hTcCpwum6E0`70*ochHX(`Y1(bXou z-zW3))}u@*vPr=#G$OIUsv7Dw){*o#+Or=`xwU@vv%OUH6qwi^>R_2g*|)T${o`9w z@!l!72}H84-)rI3VUOyZ%pOXJWQze;I+mqx&UY*=tXO0!X-}kPivQ{gCjVtuCFCl# zpQYvA{xx6w)Y&;yqBoD^P7?aX;}NYUC+G)qJki;3Gm=Q2e_)O1Q6HFAuj&t1+#z(`{E5LUo7Elm zoI>_cH>3~{Manx`iu|OseYIp$!DnsLVbbRKM@sx%)ndn$o!jT$&y4JFG!;5K`@D=3 zhMD~TA&0m|V3Zb3*UmmS-S`c(xq`^9HwFHub29rrLR90L3EU6%>>2zMyA}s&!ej># zv?g~b;_QPb_dhx}?O*U?+P!lfQ~Dqlo3*c|y+Ta-e#c)4QPX~VnY-W7wSA4BuhJOl zVMwW4Y%({vyjdqjet-q(`due~jE62)QhXAgBbBVK{U)Z+i}9bxao9KcW3(HbEFFK0 zvQ)Z{e2xFV|HvQXuV%s!(&eROI5LA%rO*R=_X)=r|0REneW?Ck-SMCJWBe<#wW0ruX~K^#OTov-(AeJg zQ=%*2cnOzQ-Rw)2iWK)@Kcz%;n&ia^`ziM^5)z3L_ER!}7B>5BJm{PNMyd=xn!J$P8IL%UEvAt)@}3QH%5(xTT;pBNY)AUB zD)vhy^wf3QpHQj}dx7>A)75o0Jf~jT%QapL!P41DERZy}@73D&X`Ng99wD*YseHV^ zup+M?s?JRILHsm(8saYT@h-jSoo;Ho#eN^E-K&j1mU5ERDxMaHJK8RCbK2XB-tNbp zMt9*4(B=TlG@4TzM_e&p^wtrK7roanLJn%x&x`y}O(8-9W$Sq6Eb*^@%YWX8m04Z- z&->#Iti|!4cP91a7|kBRlTIo!bD#Vd7TNhNqUnF?KkssK64t|x|Gd)=cDUt9s&?Yf zkzd&l^8DZRB~jP@@5oLojb5x|lE#1tapcm^r<&5@-{Aia2xYK_9fPzC>}QD)Mj!kE ztmmo=Q$?~QKj#Rf$ZQdCC=1z+F2dR*$9<#N0w}j|iPl}$`s+s*ga+AGv|o8BTDY!! z5tnS+%l!+7uB)DfM*HXzw&=cFx~BXYbkEuY{)M@P)zeBpQKc&SJKS%;2T8HLfUuFJ z+v0jCL#8m3P`SVc@}PV+a#UFx5IK%Z|5>@mt?$f|H<~& zgK!@=1MCq}y3IbPA8zI_uDpuc7)1bK;8z^&Qb!}LK70teGqs;Ey;8qgH$v}qL}>g@ zJs)(PctI+J*M%++y#p$u_38a42XDv|J=lWk#XLST;7+6_$5lq9we+ zAolxez|4c0^^J*^AGeuMV*+EYLOl~0;~a44aHDMzAz~Ukj`kje9e=woKhBW*3K@2}oVw)bI$dhM-p zz)gE66QTA_JxAmJJlb2z&%fW^#piYE-)EUj_toCPv(wvK|H`*(?_b_dw)gi4Wez<* z;gGGN=cg3vwYSy*H|?E8gxXtkHtiiXj`jxlaoX$559WXmrp!L$7dS)6$*3MF>3`Me z9M~SEj!988yk#&W))l#?;8@krO8cR*kOk)fml3E=i$kwb5R7 z0PKmIX3j}>ANzEAF&LgrU5}G4n<`4x@_5gqD6`o(P!Z-MoMH#Pu~n5CL8TgP-Wqa& zSh7Q5Po62YK6*~&o#TuU&iFUl=Tmn4I3i4oJ4WTihw@=+V-(K%*iQ@jxwd_dM4VMY zK*TZojMZ+K(awEsJBTE!-3}pc(tF4LBzn{S3yGZG=(PUA7NGj#Z2ao5n`*H>->XM% zQMTIsa(aZjK6K*<_P~c123>nE+(Em_(gm=p@9~?`FXa{V%M-LdrC(eVFjr-mei=!> zD7opEk)~fp(k~Tt6AQc3FNp7_N$GKB-Pawu;rW%@Io<8wf-ozLAYA=j)SO%@;-Jk_ z`{FqN2t}xKI0#8!p*tP)n-P0=P@glL4r)<5jjLx<=wOKu-R%gAo8l#Z-vt_Rs{ zu1>4DcQ>JQD`Yr_+7e4TgTD2V!>P_b6XYI@pCXSp>1pI2ri-~BtC@@xe8imG-9Oh{ z$I#3G7C~C?eyfEvoSunp6G+Qf3kn{}`<~NW2V*qXYxiWY-LpJIap3P@S1F6g%cLyv z5)AValzUN@hp4fg5he3A9+ryiNBVbT5vaWKHA;VcCPPsR*Osdn!MGC zG)5SsEAl5iA#v^;R&FLA3I=$Y6A-VVGNNE9NvKZ_2=6J6+CwNhlz22PK zxi`J*doI~q_N)1HDE(Vt=Yx<0t*hzKx)kM{*j<=+7Y?UcplcX2ekytIP2WMI|4Sw{ zp|TVG^UQf{3Y`yG`F}W_KaVSJL+5BM{+rZ2p6*BC6Q*@n%6grX)hXy7e^NCCZVn5=5ZYx@Y$W^}?IX^p@ z^(PBq3H1CLCOlFjnvtG^(yjvx#|~{^*KlwoXQsn`lK3FXSRa8f z$z>ZcnyxbDj|6v>B(W`i(h!KJ2(mWUee$NWF+Ruf*ASa{sc{$alC*P;9qWV4CUdnv zx$_h&cVSX91ot`aRvV3v^=9~aM@J{?;eV9H@J_H?O_vN~;!ls}<-qXeR=L_)fl9QxID%DZ-5#rFSepYm> zuif%Lb#_j547EH^mcLvxLQcC8ewZj6D@SbPq?kDR<>)jDbj!mIL5D65_{h2Hz*&cR zdH1dU)XSO<{5FN;{{eaQ#6%&|E|~iTK9;Bw zy^QAtKbd%9!jrSL3R~tRV^w9IM#xaZHTyZnoz!?c`~Vi0AJTGn;nf&VV!4YDzQsl{ z(K!ii5R_*V-oE%kXKT44;Ou&%4zn+IPzop_NvC)T878+_-!9|x67gFvAblEtz|D}< zm$m?6MWoq=zNHM9|AK(v(yd08moT4AR8hh*dDHgRVDvhq-xdCNZXi0Uqhb)dlCM-v zn#2u;Ax6C+NzeG}Gv>^jf^%19=sYL9GVc^)&HTgdt$|3(=K=rH7A`|t*vm9_%j>JU ztq+xLuKJx+10D|fYh0G3AbTtbr978OENwYt6l>dfd0XIsj0@? z_ikivSB*@v*Dl-Jkk($uetl}26XxstO#0unUmtjw7C-nex48cgy6DzKipd&BnKmAS1x4q-QqPt{Z zl1&Meign+HS?%J&JhOD=SSY4rW@Z-|iDv)uqYgD)UXRaZ4t>KK)PnQ2>{2`p;Lfw1 zeTr$Wv%1irH*1EMW%wiWD6=wR2aDT-k)6Tft(B$Cm4ns=!#nf*w<->IU)J_FP-hML zpZo$psq)uW2Ik5_(X-lttmCVGztig~dg5|!2W;hjljt)$e+R0zSAxO7bEaL9cASh> zI{r^s(=we()U z5-{WVg2fdqo?yTGd4+%JYeC;Xf`eYDl*0bz>`L}ji?@$F*S8rjfqYPt{Bcgm?I7cDFi4=RMVN zdR=Z_U8p1v1&jRp)7!23b9OizC(dswe`fp+)A%(PhQTuPc}Q}eZ>|5FSb+%R3GNVXt{mQml{!we`HvjZMWOcX=ak7d3JG0GwSTyTx zZlFD{d7i%-?faB0Y5L-r3`4Mi#Z%usCc}Q1Q;67OSsDl`@s#RmTAEl(?kWu4secOI z{=S6Ybur7g4l~`EaySTHwy#6*hK@U|*FLcpyX?eom93nK;Jq?wPn#8#`Y;r|N+Nru z?@RxkP4JA*f@LrJ?`_U$uG-&Rm9@X0WfpX?L#d3sJ|YeyCc@+FQ_ewr(je0|VcXf% zRpM6|cE`SJrEhyEdL0C5I|%y_QeKIInGp5~>z#%UlaN~iEw{sIw3$<>h;wD8WkPgu6`+!4ZD2Zc^F^$)kSIY0FpXq)h3Y$Eijiu4@_!&NDiWs zb+@>55?KOCjIq!RD6UmA(&xrSAosSL9WezH2ovFW`CwUk3*Hq5uQb zw^9(x3xab$Hwf{4u2dv;Qz{v$U0^aW@Fou>qon@~KAE>_CL}1=($7PsAB0NZ2}a(j z92Eb21VeD31|xngFBTivTIqYQa?qzEYKDJ5L5Nao8vIdG3}v2u@Q9x zz8|Q&7{Bn_Ukx(EgWCiQuM|SXBDf(Z8k<%sYOr~9^iSfO zB>?rHB2B79d;BMsb6Zo}TFLRmWsZV)iOI>m?ER7bn+!w5@e8cTTb3@eXBV2Z$z-8o z?5C84B3DD&S3~0gwj;Jx6Np`5`&S0Y_)l`=5M(7Fo;=$&X zNHuQ9g;ev7k!n5y2&v}vVDmD#&OaQfCazQ@c2hc1&1;oD103?b zW8h65N=8Zl89X&}^H$Bkg(KC(5otoD=*hfYIp`los_ExSH8->TTNCoF3k}*Ds2QHi z0u_T786%@(J4Oy#W;udQC>mhp*&e7HkUOI8;%o$)b!SDhgF)>VNj`P(Z-kp3r(;v1 zM;^c9dK6%sXUsOa zXZq4LW_@d{Or%LY`SHO?smH>q*yGzBuEaGqq@I&Irx3X!Oc%(!PGnFhas#5z*$gR1 z^f`)Mvl(VHEZoGlU>mXz>a@r{z1bvkrPWnprDe->{pUhkJ z(UMLDzG0P8((1$+i;FMT#L?mBSj}5lqrkcOhZUOy&O#j8r{L^`B+f#m&Gl8Mwtf@R zXyX4xNQ?dP&Q$m3oOhkZam^p-VQeHG|8TDiy=MF8t#|~N2$%gb4OTRo2LH2%67YqB zZ@mAT;UD~U0zUge;HTWz6?|;HJH(D^I38832yI-N`9ltb>Upyet=r0zSucz)aj~i!&q7O@-BNY9^uTA_P zWPMwv0~qolc0M@$DOmqM1q6*_hT^Mahxx)Lq`u0XuUiT&eT~(Zb^^xhYl8E|VTrz` z=KoP~oS%5wHBP_-#tEjUS)(v3@_?fNgBH$1)Ml7T__V8BHF^b{P*}kuZD+qH}2>WSkJC}Z9MGKPMme#)mAqtoNo~El~8-I}mbo-axzlPl^ zw;Q>~u79yJfED?NVF^0rT^0NF&pO8^iT(5>F}?{M$EF!#Ovc}tj6YhHImc8+_cv078C0IYZeD6|N5qc0PD$XujHCjeE_F61?+>mdB%FM@94femvUV=-Te}ry_x-H=|y};dH=mAr3HAs zz^I9i!vBm!S3f5^_U9W@`@k(!oM^d44Qz~TkbGgZJgHD(I^UK*nr1@MsEBQl#5HMK?@XymtFsd^-CcUnj z=iQ58Z$M);&oAVcD`RWSM*;DC=t!#O`F!W&Nj|tgrcq?)z9(vM98O5Cy-RV9-CO!2 zR%_CUnUION%%t$mvv`dPEc$#65Bo-PjnAoh{x&|ct2re8i@1`uR^*~viJarNr%us8 zd|m@t$`I#pJEH!1jaZ#vb+b>JI8sk`oCP0a|Ooaq>=!BUa#d6g?sZ-eXcPKq2i zg+&TbGr`bCU(hmv9xxlgu}{M0d=*1n@xu*Odo8UBCR-Ul#cn-{&G}J4#7p&asQN6W zZoi)C)a^Y+aa!Fr=tz>f*X9 zNWmh#J%S%^nn*fzcdf9+t{I-Hvf=9cjfIJL+C%@rz2`pUozx^s(6Ld1i)}sG?E3Dd z2*>?@V$zb?D+y75J#l#IWh@%?jdtwdNd3)0*#V*+X}dU<=VCL+j-y&eX)dy|hZ{Y+ zzE3^sr>Hk4?o;RAn!Hc#@sqz@kuqo-tJ4PU4zrj{4%&yDXj^Mt_0;-7^wh5lO(%Kz zRUyPDn81|u{Ith!=)t|;JJ!u_ftz2Q@*C4BKMf)8;;XL3<=I-YCs-hd7zt)H zZa(nlaN4y?;KCganF-GR9su!v_Ld_IffCAuxzYX=JWNgMrYgKhoZFsn;qU#s$3yx? zHOk*?@RIFqW43@YK{AJtoh0>z%t3 z6$Lb)7Y(qx@sp$w!%x|oEwGqG20}b&GI5;P*=xM;k>WXi)aBe=a6QN0G)V9BA7X$9 z!=Ke?!5=>=_ZU0li(TH@DI0p5w28m(suj=VVH)GYL*6LHs-RS%;_f z%XyGS{1Cg$4Nb*jfAUe6oimUY=L3*zEN>n?4qY$gbDHSR@&zt#_nPGmgl72ycb4Dv z9rA4&v8C9tR@b|B7o7qLyKeI_5mBePb)SA9oH8HY1X?Er0ejOdw_Im z=qTJK+T^y!8_cH9?T8r&UDMH-4w_|w)RhGsxCF%<>Sc!F6+o+BZ#s;6m3#Ht z2mVLN%x-)?^b5l)N~At=g4lAK*rq?oR*&sWxu>28(ROK%u#lMevXrh#nj=iK!0DP@ zC+wqZOdq-ZgT&HPs&jd$x>XM`?CQH5Kg7H1N_^E3U0k_7_ZH{MwTmnileih9dHpqT zc~(yKODQ+yXHtdu^9&j9YV!F5%$<=gvi<62CtG2%1SoskchY(|l^=xaPurUlq;P@q zOOjlm>ac*XpPxWFX6b;$)TuIZ8soIrwjjvb`3o%!A|q)=y=*)8TX6!|}r@}_;nYwrry)@@3-J|Bd^q8FLiePjGtevgoUG|iM zEIgc)zRG24|H1>fn^C)_sxQjG*kD6mo0m<$w8eYWHu0!BI+cCV3g=GrhPSda;!p6& zh3LSWyyMhD?N+i4*Z7p z{JHj9w5NAUdv16m*`BNPzIS{6l<&2tLI5AzlMn6Gp0xcBnHa}Ll7-)+`T6l6TFli- ztf)(JtvW5TOgG8;)r~9cQx_`q`xk`@59ug;c>>Ef=XzNEQd5Zio7LT@qm#O2l!b

Y7}?*umRphR=8Bi&#=#W9oy?2_G8ymcP-v3Ku%7JHlH z8ac1`a`)4?HY%C~_0xgISP5avMPYzGG2l#mPY5 z4A8rt5M?1{S!E$**{OPx|3dS;&G@mlq%zC55Zua>I)8DUTjvK4NU8I2>2>yhQ=K28 zGwdkW;J>NP6IF|3omG)0(s6xmwkoYWROy90*}Xptul0RLU#bjE^+7_DG5`sxw!i2B z2MIJULn*;-o_XF~SYVzH6qe{o`gXwsSMGj$o}NekzZQjE$CpdTL+75Mhm;_1y;6a-_#__0PMB zlIjo3*LQul_OKT`lVDs?#|W6@_Li&$Hg76G6{P2CYPy)5$XP0|@|$K<6r1ITy4G=& z39_{V0(+*{AL7k%MJ@6P_@9m5PROJ{q0=YEdG%Ek5PQ;uK2X@?X1AJW42R5sKHzLS zlcY_7BiO-H#mh~DR~EVTS??w^Fim_2W|#wGxiGd1)6Ua)-AQp8J>ZwrVj8ixYDYX+CDdxC%lbs z(y3`Q+;w5=ZLbrriW9G9nRGk!jN%@T0Q}YX`(kY~kVhb~wS@(Q0OieAK#1DA*VbaPod6dd}hm? zt-u(q_h_FLnlpJs?s?T|m#TPT+Sx~cUl55XjS~)CHU8@=Kpo6 z#>$Mv$~0qT+wIb$L2^DtBreYkBt%TalnbFW5or(;`xJ{PfoJeThyurF_UP8kjM!uF z2WfqqEidNLE?nLYBNRT-4?HK>uQ+|sn~x+dFhk|Kt!P{a#Um^TMva|7BMrgwElQfo zw?~AoSKDo}$7#nWdx*z?z*|jVg;sQ)2RyH~!xMFBQ#q8Ua=fWQ%v0rv4>a-YbpJ-+ zCK=VsLz?y%AuXBY@LpAuT=ibyfFt{h_VA=7p;xTV z6?oMn_wfm+q%zY(5AlTAis|Z4APe;*rNZ=Whzpn|zO@{Y>?VTOpLejS@aOeY+SCdE zR`K$xA6WJHb{BZ$Q!9G6$K1QS^whItQRh3*!D){F+Rfn<(%@8r4Y}XFr!w7@Ja(F@3ajM|9i0>w) z^X6ct2d6lPp9p@v;%RLgPyH#(=1C(H_Wx<0zjh)6Ms0L5Fl}rF&ThmSq}qt7VYiLd z+`@F{DcaX&GJOH%mPGr$nrYf6Ze^;=hS>hfTD{=xi5+u9q6>ZUtSf3p=*yaq&?nLN zHDyZwnQ;0qgTmDc$z+~y;&Li%&_uY!d%i?e-pBI(9i``e0`H!0Vv`4XO(sln4o`O8 z#VNh?1u5x`@ayJPLb&Ifco^?R3OD^$p*M0KPpIgBtXktr>-J@=*5#X6O-cAB#&l5h zQuyV!@k_jCP-m9;F(HOUs<3tnw|^RBd@e1_p$un;-f*#os2h7N3;7!7Jwq2rS(}r{ zjMt$8(wBYjRCZOlfR_?^a3b=;$ypgG^a7AjpB(Y}vX8vROxp{{Eh7y7U}(RpyE0Mn zl40*7KP}fMv?HnzPDBufdGT~dG)#*d7wi2sA0lfl>}Dk_3vk`TUwbR%NJvs&if)XI z4%ZV;SD)td)SoJDSTVgISlls>-p-8E$=G3P?@Kqp!s%3rPiy(}iMsX`@n|%!uwm?eUzdKvab4>5P2&s@><+})cpjA{M~T`HT&o^^l@;_md_4$jZO@nT*@VYa_- zCd8xeh@3$;INfJO&Y&AyREoQ=KL*dS%Az4OCO{&2L!INCk{DPcba!%y<;99bx#|L#+NLT3;0 zWXTaXI}vdSE@3X7lRCpO=c8@S6vZMBz0Ng!XWj1H#COE!l*{;iaSlKHlu#?m@#xCWoDi;@;nV64ABR`LpdsnTR@&Pz7?9@{@)lT}A#^l;-76!0Y2$r*KY}vi=Q!`% zv!o5uXsIf3y`SW~cj*1N#t91lTV#D4TW*w>X#A_a;!*gsR? z7$-2TV4XD_o>s7`lBa?%bqiiV!EsXs>?UNyenWoLhpD_3B%%RyDxrLpQ#fBG&et&K z>u|mj^Y{O-a?xlJaTozBTd@qAd;+9n^o6Q=7N|;t@*|X|LUoYJE(VHPBshkK>-Fkx zveR&lPZG`!mrx&aDvX;a$CF7AHz2yiIQWoMe5=`q5E3hLz-f_Y9TZBjF-o=xDbiot z-2|jcl5P1U{LJkjGHREcA*&u#BHml|gk9v?Z!HG_u25j#_7*U^oHVh1z{ckA5&N|p zB6ThjQVo$ah<$@nC&5ncb3WPfGkHD4r=9UGc|Ajjlfp8{zq={+gqztf-RENf$JRJ- zv3bt3KCz-&c8<5A%GgAHR}pVF`&>LHx~*zbN@v6`upe|FV$Q{jRk04I;$}!YWOJZX zdV)gFd57Ga0gHX=!iJI%JJg=?jV#ifZKX^l(^|nk`ArijIx~TW)%}FP*wX~r2U8Dw zf490Gl7G-h^mcN$cVw7`#6EISv4v;6KlqBRPZll)VSlfI6WA=%X-my6zui~4Je349 z((Y}vLUfuz;gW9r^Sbe-+A75U)n!>3vCmcS*-ptKOd=e~_y=dFNXB>4+L%^6_PKx> z%4Jbnl!4`U%CzX90-cBZYqgU@QL-T4gV&UE@yiYZo1c@t8l>GFJ!O90ZH8&s+oHIi zsdDj-UW(B^d1h>>n=I~vCrP~u%S@?czVkqECd{~EawgPi1Z}Pf&~Ag4-*O~Nv5_`&k}!A1-D%pCZ!OjK+qV>oFsZGc$F9e|O8_;Y1c2 zH_(_H?MIkd?O*egistDOU&BgW>%=5RZM8wuLy8)+-k?ci8*f*RSe=xSYXoxgMMg%x z!vR@p&LHj0uTyYu`xq5`q?0|gf@Z~mR((aGqkZBU65M?u={cU!&moy+o5Pcj7dDC! zNrD*#E>!+~;9sqOh^JBi>9BWmqsne(Vzig)=UILd$~e5FoY&&Am5m1u)}>lC@gDNl z^7(x#u6-ZQU);O)yj7rI&QG~i$1MO@KtbwKpeot>5S9&?pmQ!7qOwJy=)}TdT5|UB z4=m4^h?#Ter1eO4POFBxyQU(wv;T<6&44*dO|BOWyfKfe6V-q@Qf1*_&Sp_il$Yo= zKkUFds)H#`;XkwM8ZwO~+v;AL9{S&%nGvruc-ElIm!y|f{!AuYfnmq5sb^R$vfRmp z)q`By2gnAUj_R+VK-mHmPTUNX@0~kA^mrmu(fiU^SO0&Bu*6@DuBpsh*qDJDqSDaJ@+1O0V4pZ_-pP_Gq7c4(x=cP_a`XE zrN>&D-B?0u=V0?lJ`H)UFkBMHgksmMbjrn@okNRqvrB2Qq_rnKBSUT2T|(Cn+e93s z-Tp@s^4i^h`@_7+pzCDO?^Jc==qjPuqj|-#*;&QbCvk(_xDt(rVR**EJZ(+@6SblG z0ypciCd0?gL=k!12ufOWV$X^_R7tdLs$%hNhSi25k2+J$Z}MoN*p<`55qz2!I`csb zE!3aaLbyzMj{o)#X|3E~Lq4fR+-7*MifST_8sOXjadN0A9G_#dswkXbLZXg5!i?E5 z(C)QN+s{O4k+*<&Wjxm3*WEOL%Pb}^7#THLYg|=WC+_0AZ2FEF&(A2UGBShKdQDbP zz9Ne-=R6GGmF0}vsVYn`w}^4okzA{Al_&73VB{w?yayw`MqlQ)XkDMHOmCAyKeF=F; zgNoZJ6rHk&bk=<(ZF3iT;3fNQX6dRRJ^=tpC|~(b>E; zv+oI(&7Z*gtlO-)%~I3|Moe6Tc17%o$ZN5i2<>z}psvax+t`i7nK>pDDH3~3p%r)b z!G3g3wV9i8?AK`zxO(f$4i+yCPG6GH8NCKqF6) zN&U;-jJwKE{Y2$+E%}grxy;j~B*)!q_4PEvT&P`4x9E?pSpu+w1yT8HONDX9=JxeB z;7{Xkm6|WERUD?>BOBw>Qasg$n|G_CAUG%1LPnzIu__i)_(aw;BQM3zb^{&9@!8ru|>#$pMc$Z zHO%k^RT=pTnKM+@R!w8E0K3QTy+30tT2Z*mD$6dcE((TMVAtyiRAj49h>uWHX~=XM zCae7C(lE@%oLLYrHo7y+zDNXT=3~4O2qmg=jISEGahtt~NzpM0W8C4mcB1zJ(`mDM z;y0hEO`iU7Nig!JQAnkO?JWWkH3-|(;^M^7DMr~C;nGF@%X~E!rX(Hj-VWZ#^!WPMe|)+w^8(NOy)Tu2B>Rtct&_GcBRogzfIN*T@rIm+g_;F3 zXY@kZRv5@b&Gt}and-wE+lXm+0>CB1o&sjiKQyy>o4!?jxF_whI)nXx#k1-WJ(#}p zl{2U@9n_bQ_!EeId);utzZi6v4*dZkV!khaB6@Z&bBr;P+;)2rf%Yx!OgP*ZjZMx? zx~v@w#|YK?gV7+vFt-r8&Iv`~C=Cl}-xA0_GxMs%Wz>6r$X@GjF4KHB7EDVz&zQTXhTrK2m7~m&?T`;sT(&*9 zTL!{x3#-OTF3GT>j4*#*mMHl0?prY7=_ z=8tj#M^c(zQ1e1t-8jHQh22QfeMuIjIZ4(yN!~xL=7pN(PxmjcS=(+Z0eCmSjiU;) zf^fj^H{c$LIz(eAB-S>)SJFS|V)EBtjc$}ht?pLYT7T_N2uM3PuvVi~;H$!e?V9Rq zr6}&vPW7dhp%xjDpMd5F>=6y3efm26l1ioZKbJrlhleDts5#{C+?ZGmaLPB=P}uhM zMs5%m1^3-KT)MN7r@TMsKDy-~Kxx zs_RQ1CF`m_gP%A{Iwm~&CHq7UZn_1GRhf`~M7vf01L%HBV6g^W;5q$@nk~q z$z!uKLBVmq=ZtMk!)q24@5{5BtxoIZZ(ANsqdfhpJTAX{yYkN7t33BU0kbWZ%9)bR zjP~XgO3fVSN-s(P9B%lF!OBBKEz|C4J& z@)1-6s_i}kBRr!gu;DlhqGu-yTFa>!?cyNIFJ0|eihI3ZoWpA{yh{Knx%=@ zFzU1$RgOG2?p#cjMqbyA5nnS#1vP`H_8fn2h5|a(ervGo6;u0~oxW^WuOjCWTxNn-=GkDUR3iu-VBY`WE{Zx;HuUG~%vN zhd-(nlXsNlIBDNvkKGIQR6-nVer6wzl%e~#r{eU2(Nvz_@C1{I*QUO{?8|sT>0d5CGyYb?AD1&1%GY5+7~mye<3k|@Jk856-X_qM zT6M^-5^*I9{#;-t7i7X!_KnP7wVVszp#(;zhE;IS2-yj`40gPPpLQJ--AO#=43BE` z-#(vL`*P%Wqv9bG{Mi!bwSPI6D3BZP9{8)Of;5U!14e2)4%~Foek@gvu8d4UB>y2E zx86y}gOY*lbq@;3`a!#DOr{oxO3u@%J@I!O!IxNYItFMc3P*n~cZvbptp zrZhWLyyML1(Bqjg@}?hM`l=@6z7@lU9z_3jpyAb8jqtdvwCOQlby@5yveteu?e3=q z`lB1Tp|81v*h6FQ5o`Dp+GDlr_(DD>P#O8EvUmk{#X={8JHy}n^SG7L zab|S*5JNqo$g++DA1QN83+71m098bU@T_3*ilC2`&dKPM#O@(`d~j{X3~I6g{+R=u z1{`e~aAaBo;)hmnMT1Iz_O4s$INkx`-P{^i9g$MWvQ=p{#MeaG*VFHgXIqgU6|{`N zj<75;Uzrp1yCX!|yRJ{Z{c? zuzM!LnH*Z2mE+2zW#x54eX)l~YPPro1_v;O$d?Q$xv9G7epGHgh4JA53tIFNPFofE zM~x9F1CjPXv+aqkeF8PBn=0zExi#hU#m@}Xw4FvsO(3#0&>ZuG)dK=GYuYO6a(xwb z6+S^`#s>wEX$ekBs6&Yj`3y)VAXz~l^_i)8%P?~@XQjwz^3BK0(nB|-p#!UI*-Wgh z&&~w=v+$d!kJ5fqonW{X|FOC)=-1Sm)FH2WX5%%Lo}#Txp0YstuRyAQy|$SK=L?)7O0 zD7oN_V{KRB>uYUB@Jr_(!N^zK1kP`6%d+b0@}GuD*VmNj0q17@2N$qdjGH%S4Y=^_ z!3^6ILm)~lK4*zM5s|&*oUN>4{^Ap79|CDrvZImXC{jm=XYz zXpwdY3MMmB_ej<=wFRRi872t!kv0|W6xdFIOMW_{fb|hf2N0D0I)P-o1IU0A0GacR zAk$6(ahhG@oV-S|M~#p&)9eTvlkG5%)aBBM;D~sH*#pf(1zW{ z3b(eYdQhP5-LsG$fqL_!7e>MSgQ#q?wVzNfjFr z1z}g*7TTT5fh_riKWe6%6m@y#90p z87j2SjOO~JIvO^jG24yh+N3JdTs=&CvSufwc(?X@^1c00{Jr!F`X6~|`l!k>EINK& z=^q_GBbwVwJB|Y@s8`vl>1PI`L&~hOFa6=G5O%HT6dz)9ng!dVCTMVsLZZ9`poEnVhfLJ;WAdWBf#Y`tcgaP zG+=OL^g3VFyO`b#M%KjtAT(%Wl_f&l>#txq?(^R&9&Qj62U{TM5)K1iK4}0)6~T@w zEPL;aT@7BU=g`>dLDFciSAvu+40eJdQa_GeNe1})@z=iUuX};o3wS)hW?r1TtA?Oy z12`07s@-L#T0c)VV2m>%98It^YWCM=3okb;m z9p6XDZUc^~^gr_M^m6E>GV-!}zd0BkFxV$8CElG5sEoWqAM~hPv_A4ic=JHy#BqLKAk56Yt8H44&kBEL zp!xmofpFVtBYU>i>}sEOkzlgIn|m~G-apXX)*axAp38dvL$chL2(R%oBa+xx5fK5Z_W+$Y_EtcQ)ar+ zL&u6LuzJo>f~0BY*WwpuT#1R$K21NqG_ZKJ!5GrHeaBxlX_`rNn-$)bIrEI_F$rs` zHS9BGRZZo$Th-b8c6Zhzi>FSjo*4LEcdnX^$)3A)>hz3^p3T)ap*|45xcWE2=uo^< z?aG|7sAhI%REoe-^y=*OaLS?*Fvth-4d1Tn$Tld;{DY5EBhyk#$T1Ty1_4bw5 zU7a6qt@OPdD*F^4Y@aSEHwgL6ehT4nNs+1NEB2#&z;r@oYk^to!n|Tf_YyEu0%T4P?WeA#~C&Q6_=_o{OH zZ}?FQm}Q@ls&(t^27(NDB_J58V67YC0uY{94m^Jd+LAb0n0^FnHOUvwzLL9abYQ*< zOl-I?9R9jsx)yav(y2@*+|*_bvbm4!pK|Ph`EnUE<%He`ndd229U_l36&V>=vz?Ni zt6xmp0?|6j|JCa}-{QG}C(c#g-i+%Gp6_ho`!&Ab;G5?=Z{m!mjsNRp61Py9%o&%9 zk(cHIH14Z^tF>h9FR2rbYxApS=wfw}BZixHP&qO@td~=@BVRq(RPER$`cBMOWI8)L z7dV{deDxyFb(8$>{f!Fn+(<>^tyn#IqaRjwnsZd@EAgXsf|^JVv(C+qp50iptH1xw zWlisQ%XuMC*DqWC>&jMEZ_6jG4sXY@F8SxK{DYh{1_F%g2 zA)#I~Uq|7W7EAm|bIYb)>z@}fJ+ce-GXqi=3Dou>v42rc>?Q*0OB<(GO}naekN?>q z4CC_aU>IBd^Uh7Ak_MwmwVnfdrP7o`)>Ecc`D?!hY;M{0msd^l*VdVE-mml5p2uOu z+_LJa*H87=F3iz;)s0iH^3T&M8U{pV7IQ{nvYqQ@yOaPbbI$oAf>dVFjoIPt6+O56 zYoDPA!l%u+@@j<#VMh~H!>1Bi-A!R8s}oIDC9(Sm@IPBRciZ% zWg@21OeX>cM#PpxM5h$L@8+f$8&rxQEU#ix&#l#LGpiNzbxbOhKHpo>B{5D)RNKoZ zPMlV{r#_g~IPI$G(@S?!;aUkP-22)OH^^p`9ZwRiP6{-<9doE9<<4aaX@Bs~uo@lb z?-196k>vA!m>XWi``SYYCkv#zT651?KrXH{cm{$_0V?%y zg`4UBD!q|&0imMAffg)G+1oR)XA_&KE;MKmM=)r3njoR!6a|>51zyxI+^D+~Q5SoZ zHQPkx#3m?!U8cwz_Pm>nnnwT^)Bbsv5^s)MLnjX}l#RwM_Phw7i>0+7E{x7SK}xrdsQ~s7yENbpoL7@Xo>h+E2+Lyz^Lp?T5USZmZcj zxZHm?hwX1##oG~I7;_z2{_p{&`pDmxagOI-R2*K}8veScfBr&Keh1WHnTUWd+|(N0 zLCnvIDfcgW*|#Q|8_8H5Ss6RZK$L{{Q0gp|x`$GysMIy(H3Z(>%#3Vp=e(1$UqRHO z=x+Y-dj_c#-IMf|?+qYIn@T@Hj`M|=wT5?5)-hz_`y_hp6B)kO#as|Ge9Njg#NN`_ zSmc!0-7E2HsP-F5?CB3L^h%Wdgsw|mOeWD=p2&y}xhYxTd$BrGpo3U6=^Vt~rULhc z*xS6aa7UPm*dLIH_Ji1SOhgi~rx25l*pie|2YRI*^i8E|VQtBoV19b3n|gYs`Z|@m zikS3LH^ME{TTYL>Dg`S{oVWUGPbDH^mp|L9eA^a(jkFFTD-jd>dX#aC3h7u@p0RTJ zOR*{XaI)xdv)JLUEihS3TGA_H()RcLHD`EvlzDj!GkL6<u3Gep$;xZdQozz%^gkvOw?)6&S1x}_ z%Vox1xlByWIY7vMT*as4326iql`=r0Y z9wj^m%2NjRn;L9}{_ZdlN&5RMG3k^r#Xva2>_KA9!2UTe-#pB=(KCh!&mn!+!|ZG_ z>0+22VG4Abd7KIq|2k3y?rWI6>Xnsak|y|9J7n%ObF1Nr$!5MmOnNg#1znQIl(dfh z6$#VHqh5u01V39JdlCHECW{2IUf|}@iC9lJ89BsyqTahAR$Yio4nMz}Q*!uyEo^(W zY1fCLrSEyPw824c?E5LSw1zN)WDIBQ8_CajNUos@DYR5?3K1{6+C(Igd;>A*NFHq< z99lY8rD~EmL#6I}l7MB`ctsyW`mSlI8<})LOS{>X=n{{AB_fH(RpguAtIwz;508%} zi%nr;51K3zy&87&=+vv%nv9%YoxnTFscd59rOf|x4VG3m%M;$}%$V*e?FBRepym%z zpj;WdB|Y9hPn)+AB!&YM+sTOEEA`=NMeG-wn4X0rhkOl|=`FV&S+Uaq^0>|Kc{ddD zYo*-RFicR${f4*_!|-YnIm0k)B9atx7BT4*a=C$UD5O-Sib8b5>|0VuK*;D)jQD_< zE+|ABj9pU5n_x0YA-@GIokH$XLXSdzqL01C{UVb^fdv)KH zb5eUIC-&Q}`uJ3UtmY33tnkadV&l7l7?74tZtPNkybf;R-E^={Zuil_(<=-=?_rW9 zI@gFeW-5^+?q8Jb+-U%&ckWt^8a@KAMmOuKV+`7miMworDZ30?$fI+cR$M1+nSJ3FKnU2l4z2#PfLZUU1I=N0Z$#)Lm;>K(lw6 zb5llra@}iANzK{%N@I+L&28rlx@9A~z)zVl)cK@uDrd2UpZn)X<%7+qVKhH+NPfxk zkvfm$-)6h5PzT;A8v!VZu&yphoN~J*Or!+w1nY4}L8y6imO0?GE#l($cFMz?V^zN% zyM-l6F!FKyXGSa9&6xx4MBRHSb&q&v9DaoAk#qiaK&K);e2?N$zkGRRy82V<`GWk7 zvP$E=_@CJX0^uM69bnLz&rWrTcB`!j$1uPQup*n;Vf>6MjqEQM0GkgeM|LJr8qABp zR8ZS*1p1u;n)uB?a}7{c;ebH%r&$$|?Q^$uz@p}MY+(5M!yiCVC>x;ox>1e-rQGI;eX zeCFWVbkL913=b5)f?l)#$<=%x`J?9H#ju&M%Ex=PY#MT-1|+@k7YfWSY~In^x-ZbY zrF)>~XTj!=2L|WDti@mZ9*{qJaU$b2aP=$7 z-v8`d&GG#rZ=1Z~Yjyp6q=MHgl~TM;3g0`?e!mP9y&0%^rKF;6xGxx9nXP*nd2tj) zD+((NdW`B<>m4UZ7}Tk6euIYAlEv3)fR5JruYcZ3GIQH)hsuT&a=Ih=RP$6zw(nTy zaG8?D*MvNWv4J{=F)boF+rAIp!!Qi^HWFR~4+!}0T9IhrJ>*vr+130}_dv}{po^R< z>I&5+2NThowzb(Z@E!iciWOh1I z?^4Q)_X4e-25L4Bq=IXs{UXr;cluszj^}hnZMP(9Rica9Hv)871qwBIG>6&}CD)~t zJdU^?CN5$J8dI5Z;76|vFMj!X@oJdxdK~=@R&}k4=)#N>uUc_R#tZkKOgr1d8#*e; zduYw>EB*7!w8pDvhAM04xnB}(r6k^qBBRy0DaD`AsrcUM z#SbI;>X-LT{#=Ff$p1vIu=1kU%WGa{SaGf$UgDCbFmtMb`5AhW}p%n$;Pr;NSGT_PR#!nSDYly6*X8VQ#xg;r$3glI@LgA+`gJWv;Y@)2=Ek$$tTb zy)Dm`@X)E3?)trLpZFvz9UO)JP|0 z%pN*-CzEJ~|7U7;^p1>-Uv`9d9qXUp$Y)34>vbz3jWKT`0Pe5mW8G%Rg}pMACOc!! zU_G-k{I~a_59c;_bbQr;b&RP?NmBU|Nd~w{c3#kntUEe(k#&LpC%2iBIy!dpd7yv( zVI-!c^(#nby-qS=NhK{KnM$}JV@|c6Q>f)?H|@_!o9mx{o|86jHEAz;kFfXzC!hsZljG ze+|hRHj&J0Y9E#RR7c02j_{uS{qwH^dI<-rl=0_%glk}?&2;wGX! z`p7k9`sg)(?Fz*DxjQrUKCgf=+;E2=y|%s2`K4+Eifdb4NZ#iasYZuTTEp+$8Z9=E znX3D|a>c6s4IjC&_q+LIsuYg$8jck4c__Mt*oKcj$bn>|7LQlR28A5# zhKy23K@A}VZpcuD1eDLAZph&Z$xO{TPa*vkat%smD=_ig&eVgR9=0qSIEQ^;K9?6ovgA(YX(yjB)1#|3rQi*U>R;@zr zP%HYoA=4BxUZm{7Oi)N&YP-fLWS3yPz8J2M_Dc!LbMrYyAwN=`zvG7FD`ceF-q#K3 zPKfzvxW}c^FUA2Ad>y=Y)-{wXPqs1*as!UkqxgQ%#~52S@Rf>6a|7qOyj*hHCbw^CaxT3fN& z)~c=A4+w}M8z2cN7(fw4C7{9#D-cjg_>g^nzdJLV*??bd|L^lYPkA&ubLM`Yd+xdC zo_p>&wK8#NV)X+;Ds}*3(&`36`mlBrV>N^v<0zZu{0Weim$4W1#w_?X)BKjbINNCR zLP8di8=Dk9hmZqovq@u92zi&Yz#KszAoRe;ija@26!iijUs~I|gpdbGQ6_#K zBIGPhGWg2tcDI+A4v(hYQ5+PqeJWJ5?C_)CXU*@dLBSdBkO+24V$Og919Is45 zX0wI;ZTcKMHUW?)NY7?nDj_wbF%zYyUeTJvr`!jFOiU()uGn zOgj7pA!iWtX6^FB0dX0*?joenDkI%Wh|AjMafHleU1seCgp|Gyh{?4s zB;-nReiMhi0nz2LIR-~cVVdhmhvur+>I38-932y59}zObIxpTN#K)4&8Ml&v=+6Cw|D<$>)DV$eq^NT}8-D_SB@Yaza|IV=belJo#k9+wD1d@&DBm|U1q;_6Y>??%);1Oe5DX2`PIE5Ob&&5K_Q$%-VlKNMDv?rn!ZX z3J#u$EH5FONVsOMABZ%Z>L!D@fRGxZ*lgjMgj`JGHX(LGmRfTi#BJHy&8*!dr`MtG0AwphlMjEp{_Yl&b%YfOh+X;D* z_~~Kbu#}L?n8qB7;e^yMjfv-6LO!wLryn6z*4onv8MGC-%;o=ccrvLi;pmtQYZoDv zgqU@`MaUT(h29q+)p0?rO&|r=R%lH(K+Cgkj zZ=>X`gt*?floKW7IcqOoCS-uMuHO+dletVv2ov&4&OsA$A0a_2#_k}*IUQ-t*?j{c z*KyoU)-#%r2U(Yi!+b*Ku+1i(2NKdk$N-}kJqX#!Hk-71d<-CI98;4HHA2R7UYLD< zmymobp4Sm_f+d@|{z1s?)?CjJGKUmy&Zb8QImR}dyyXEx-e4LNGK-L9Ok?KyAtCp& z@1~$UmXHi$)ufFp3F%2%HG6tKAr}#1;<**@u;-R}3kNaFR?6!ZuH;n7W3FD*} zSHisLJ-DUMqe;^Md`LGvkeRAixE9c=kj(O)Fd#AOho=G4mDPXX4(eRg(xDcHp4L*O zX2-|VyMx-hqEj~Y9YCm)e|>4Py4{RNZ$?bV@$XJGCzBpyM>~Y;&NC7JoKU^yDVnfE z7CPv!iQj%FPMmp5?>bbaWLIzLZ4W}eBswvA$=LgdUf2#Zp8fCjVnl0TcExGhXMkF=K_cU=+}V>41jRDsBK#ok0;zO#^wR%v73na@MygQ z;&6MEVa+5!dSs4wG$0}rw~mq&id%}h0$ znHcEAfN{By4)&0iP7QLUO??)jEQrPjhI!t*{&z6YI$Q=k2IPloPz=no=%!B;$%!XN zh8F8&JVs8MK?6VGrr66# zasL5O3Fgb*4k}S={)zT%lf(ZIhm9zWbjQ*JT{=*w`WTW3BBMWJ5ZO7kyySPfg<+OR zsh`ndp-3zY#sG@(GyH40WN^U9KZ2;h2X4X&VR(i~2p_12)p{@%@9Us8{tNP8-2o%A z`NQaM-;wZ_M3jqjRo(Te`q@87NA#`AG9DyzGIBofHhT3uDoHvY^@W!+FiWiqe{{6J zAWCQhRs*{+M&uJ5qi)De{J_1wK*WVQA_msl(8QHNv{7ewu7ugJHWej-+jT(TX|W-8 zHp7o_^uMm;#00UHte&YiOFfS8r)m_g@^yp?|EOSxk^2kOyZ{A+RCFkTKRB6t?j`fRf6oU)0aH{kqQG{#q3gie_zmQS1U)PlSA`d z|HubjYyk7v`mV&W^?Dv#ODJbG>x+!SIWEjlzT<)OTAV^!Bn#daQC|T}n}vhsr1SGF z{@Y|bJfLdV;*0gf8|+@3x>pt8L#)5`)A{D7b3`6E)7q+*|0E4q+KvPHz`)p@uyatS z0ur0La*jCk6lo^tX-vr}FxrQRVZQLZ&Q3t%j2PC*V`p4#eZ|@*j@(CpfC4)?+dfU! zf1Q%`S!M-e4nOWdvrj!r4<+TG`MFcQ8?YEm3fHiA3vnrj1&l)hs`E*MVE;d)ANTMC z{mgy;RQlQeAJI?M%T`?L-Jb*4{~i5YKC3hRxBy9}pPqV}f0KS*`J1&*q@Ujd@}1}> za7xx`%!=V3|Jdp2XLM2y9f6ktmY||5`~`UJ-0 zE8HbjJ%y5B7#SS3Xb8l&wYtyt++8vwvp@6-KDxu#Bp1MPv2Td_%v8(R7)}!;9e}z9 zC+aEt-vp!{r*9M2{y9sTUllPQy)&?dHmYMfNth zam2zYBm+w?d0%DKcnYP+tut9+e|H6$lE^?7)+s|689H#HWq(uJ+l{pFv4k45bIr8L zMRFm&Qlv!Z^^|7`wg{$T@G$ENe$h)h;hga+t~z3%g}h!JA(l5sWVb2(pD#^$ehNvxVlOHy*`Ryl6%mQI%6#ctWav9G^?VcV)V{ z(gjPpKj>(Hod-$Wh0UfuTr%9_zb@WF?V!npVr>o3Tcz0=TW}4i9=C^yK1BaZy61so+HSiiser{CNI)HS(w+EzB~fa7*8r1F7fB>=LTfZh)I7 z686_5JT}%$_?DTlb76?Pt!_;u%l)QgFC~)w(M)EUtqkA|i{(7EI+5%JBqJ$k^&Z{f zFXE~ue=jo!J^w6=315%BUsx#mR zqiGF3l;qb1k6r9$oKvO2m)qd8!$(oQ+=dtdCo?KaP>NLbb50?9GaQ}*o_|DyI8XTB z!R3jxAGqN&!3~!j_dXLz3%Vm|#d5p>-nG5<*1*o#bs}#Au3Vxr_Xf7@j82R#d|fB^<}-;U~SPBSN?kAHLW>+OHnsC z|B3E)$d&b?e=vj8(+d5S`gjR0@F_x?C%d!6bh%Ewe=I#bUGJ1D*SIi2yy0K)-YOi5 zJ$RwF@S&-Ao_9_njDr46*(pd?U3?>gu;7-!P9w;Sa}0ybxWl(T9uj**3h)Tr zg4w@UJr|XUl}YR_gxF~LYGYF%5)?$hVNX6HIIKk;to&>VM?(1={8fa3$y?Ec>7<*Q z^IArZI_0Or-(eoOEqxM-fb#V3H-l6=PY&xIvwV>Wn9Wt$K@{f;|2lgSes$M}XaFYN z{OrlP$H1r*8VbCVa3_*efP_7q{+|o~z`ooyWs9x;4r92-|>>6MVF5qR)i=T2mBxSau0$f#k$gemuzo?|2m_3_&dby z#7_PWwWR&2x9|-qM9myL{s|9$y!wL%6nYEmq|iLPKvEgfZPc(KDgLc;Dx?6fViqqg zyc!gyU5hH9b%N4aAQl0amqURE$An1s<#4%od8{umAS*|K zGTfwr3rA$8{A4&me50a;E=-Om<_{bvUW$HKT!4pj+co?-KQV9Ocxzeh~Ev`IjpRDF_+val_19z50_iNe1SvGi&Ryt`MfCB-H-{I`MQ z^e(8{GOq`c`DY-xwh!Ok3YbTWa4lGna4m?NO3Qo&hHJrHa4onQt_7uqPY6^@Do90+ zu5d002ZOtG2ZI~nV-Up#{t}bubP&D>;U$oOC4wKCt``x^7DlB>t`|jA0Xg&@Xz!?h z5RrLSu*gyOKwo%SOd8gSKj~%*?86OEr14(?UgdyW!jz&G`V>;$f(znkOJ+$%)T3+= zXcz$O#1=wN0=rTYsQu)tDT0c26JfZm9vDE!zFE?;)KEJd7QF#*s2!dL>hXYJ)W)}x z{PjiT&{3a=ZVy`XYv8cAvf3f4N7gD|5GfECnw>8E&Nxz9T#Q zee?p%8?P^O+v_SeX{oFwzm5(-bG*6m)ODDuP5b9`=^yB4_Vz;nMQ`86Lo5|wuyJ^3 zs`ut@mhD@SIKASEQuuY8k-x>VUP#M^o*8Or#_A+J{3LSP>(CiH^f~q3!p(tQv7-DV zWvjb^4V(TiF;qEaZSWE_8>xYeD?)}xr(5xkb*c=@%lq0jc*(Cri+h*33!CP4&0nt- z0aS(w^_!@c&!qOFFyBW6f~J*A#7uvSikI0xqtpa~Xvdd!<4c2j1HdbTNQR&gOjg48 z8G1Ig057urEjVZuN%;MO#CLEFhuRmfhC-=>|4)=(!!X;rVSx+QKFLRaZ)y2MoMC0D z54Z4V_}HuNy((DyTRhtX8Nt-aWYRNut^wGz}vIo8;fzlBD?@MzZ%p#VEkW{0w-SUpm0KLl(`cTop~~Dt}eJr z9dG^iBEIFo(Iuskr@>|*x40l#*aK%s%esQ-{XZ*J+Cc^Wg|RMx;3Yxr6by1V`0Q^P zWDi$L6<2}U{qtlyg$YsxctmDDcPI+}aTN403=@u|9Z7SO9#EZqb6`izt7kyTZegDR z`GG>m27jKLUYi&>fZkIjcW6zs$G#nsggbN`#l-|wN2|8@-_myC8B2R%um;$YsyE?P z4&R4m^`1GZawHz7o7dL}jH)hoq1dHL)$~v5Q;yODIL{a-V$%Q**j$3J2spjUMs)(R zmWBhxrQx68oNK>-1f3{GH5AcPdJN9_1s_3l!nhYM(kd?ThQ5NMv}^IMas1@aeKH#3 z=6eM1^ocsuNL;>vHDR~m&n{N?e#sKPO0DR|B%G~O#~C$EaCB641cc720-2(!hxgz; zb|p)~2>Y`qtH0ArN-NJ|j~h8JM32X0O4Tcv826?G-p6mQyf<46&CCV6b|5ho4VS)Ge5*{6 z{CmZ>dJoO{;Tk;{!FPyn^@2!lw%_m{!4cDJ8J74~mRME)!2$n>Cp(Rb$)0Ir;KIk# zAMkhSoK5}W34N3JL9pYjf_=dHjy3j2UTI}ZLHUo|U^xCel}*u;-6~JgQ9;GrqzRi- zqHJ_W_d7hw!Q#4j*AnHRJ1_3eiMxaGesiZGWGzS@lc?D758wm8&hB{E*5QwIQynw| zYmkKh8jCaeW4@L(7H8m^aIu6B%ppFQMSZYPFDi|2H}50a>=l9aqPU7VHCv0WNLiIxvT%$~GL?68oQuV!9o!m3mmV&I)_soGu2(@eOIurnn z#yv(6J&^?7h-;s*_TudZ(F>{iDtr|-3u>OUtd&(48u_+i9T2zqYyV))`J|ci1itGz zbBvtv9BdGjw}E2B`AT5Mr%ZKdyO21!oa@YT{+TGpWt6iV<*@UU*aGadTyiSZT>Rto z*;{10ij7GMlyd3fHvBwbu=ZJN6Wi7qo%kBYhqxhG^{<5mK1g;E@wE5vuWC{pvyIgoKd=-Pw z$WZUXcgf9i9A|q|^awH5Q$=NSR2!%?w{4f?dQYTxDMpdrnQl+TPCbUr(u$!1@T?|< zs_`UGYm#SfrgINDy3b{==N37t4vZd4_t@(_v+9d{(~fy(zH27%*pIoD%?OaAr`RxS z3w$xbPs{NX>9KlGZj|~xcNJWAaAyE;IwZal_-1{q-mw9#*oQ`N$A)n(kvtH=cW5Cb z6skIp^sH79fP@h}SDv<6p1H-W)7~7aJ6EZX?i(0wPq#PwrnP%#HtHYYD8k;}@o82a zTGNPXQz3mB)z*t@tyL;bv0iRr&ftE6e+|z$!-SQJKLm@cROeV8W%w$=w&bt4=h_CAY)!MdS6=C|@DbAsN=r2NMkl@12!AYJ;3NF<^unP8yxdH|w8hCuIZD@lLz1#k zY%|(t^xE!2F+LQ-=A1xtMk9j4c?Q zPK%{CbS&K?urxqmNt=jL1*b~V@gs;6907c!E(JS8@Hj7Gv})uP9VtBuqOzKbS8y~Q z(@`A336)2A!vmqBxB6q`_CW30+pWCk0ozLRK%oQACQOSF4d3Y076RAbUg(DBS|gS*(X>-bL|1ozTWP>aa#!y)%ln$HPH<}T zzZ3pG1oqTilx7yx(N$oKy`AFJxD0$F)_lq~(LQzOCG2Ms>Os0J$VarfzrCZINTEOpNmxaC!#6p#@~_K+ImY&>g=QAaG^1I!AdkNOij6Y%)GNTk_%A5uMeNiKvGODZYjMwH}Clytg03`3TjCl7f(IF_irQ)^$jtyB7FHqyWJwdtEX z_s)F|($6>3pCZ3ZqzM}0ovvKTU1I~cIR6LnPJbS@ZdiFN`BOknAMbSPDQPDFV#YhY zyqr5#UH%gGEP3bvlyL*3W%VJPYhD6D661)l>3RTK?OGQ+A$|#M!xDJeD8l*u7K|&@ zNg5B*Yk2Oc?`frl@aJiRk{Gss6wi~+laxb{);B;0cgf5sH^7Wem|Isevx)BbAYq;9 zo)v}Tyt)!;d7T^?dt$7#{O1|%dtJ6NY(|UH@LFXvUOh!vw;L-@##_EjS2o@I$I#Jf zb1#yXZ;tLunYl%H_uJQN*5T>UkS~XnZFXZlXOo17A)@Ik?skXc2f&_Eml*+z>821|$ef zh>eOg(1sZAh-GZ;fAfFX|6`*68~&aCSIp|@d#qeJ1Pn?KuY~*{^s&mRSaXZMcyk+J zC7gy(F5n3}5s_JKfLS=AH3JoH>9Gc%RMHM;>;@tkCCfsEUn5x%t=AdG}_4lDW9#AvQ({N7T&~HV8ezDVP((c7;(o8&#mb(Q+pNfl5oqvbixzUoDoAvp(5A&}c^Dm0|x855m zW`loyhL~_;lu2op?u@}qI_XvFzW@B|Xn)0Qo&MPNScO|@OrBkHXn@Yy#l=Y{g_0_$ zRCXfd8;G~`G`n~F|%oxBZ)!McaQ)dNhUzi3LM3O5^`a_269&3S5MM-9D4yJ z3LQ2g@F6m_RI)iXLD2*u-_EH~#d4FT#%YWC2a5s?L#t3PR?`?loqo=<5!ilE%_Z#S zK(8Vod>*KEm`SY*(Wv4o*q7kQs3EfG2)dL06h?MX(+Da6p`82jHT=Q@1$dFR*hszL z^r_45$lrn3EYqchA|Xr63`WwLqH5->rs>5wn~-gjg*|3xU>3kk{2pd1pDPOemJInj zkp3pKQ3(c#c(3YTX@bs~3@m6IMrf;*1EM{lIT#f^DlXo;RScp()lrN5Lmjb8UgHP~ z=ry{RRsR4->}IwlF@LZ_$k1tGTx94_@*;2O2y7D%tA$3L#Js>$Y&2ri=I_9_Sm7yU zh!hzA0fL={KF5CQef0=!)Rp)1caZ!ZTLU6!*3J5`8cw;*%5swQ7n9w}TS72BZWiljm<$ z=}3c>A3M9Iy7sQ_yr??|8kJ>-w9oKCoY2v$zZVJ$5%`kmsoD$({nla{lvI5pRVge3 zTWV1WJ-(KSWNB!SJMzepcselHp8iz4D<)A??KLz7EdOB!S$H)iC#vm4??n2aqF9e| zGTJn%{0Mzk_T zo_R#*IAO;SJ&2?ST+x$V?I%6$1UEA)K~u={^^3$>7#bcyYUm zM+8fh9@+t}CP#v;1cdWeqL-X@>L6Ihix+JX8Z8j}GvE(R&H?ILwFl67fdxOH9_3`^ z9-(~4lD=|phS(p3HV=m*7L_ZCI$F6)6tzVZ zRm(1gwhhmZBV_8B!^P6$jk$+ru4jRjQBk7SBQo?pYFGXM7`iM*RYjScy`s0T)PM?o z;hH-BFdXtRbrh`M@vD7l*8Nvh(^iku44mP%;@KUIcN4~?JcZGXIs~m}DbXYEk<^zR zlDw_jT-1pKfqQ_MJbl*C;O3P~p;Q6slF*t$M>C}=a$|Q;%>*#;EFo@VKcylnra&G zQo9y^@Yd=Mwr9%Hs6!$qCW{*h`*rc6F`g9WoEL{SFLXsLM;K7iQlc5`Cx?jr7wRz) z`wr^I>}cEWmgL3}(qMdfQ`M|z_tE`VCl{d(TtFGeeo1U&-f zU{v0TjX`y4Pq-S4U8&E#HJp-PH}@WT9CMU=2L@$PZ^8}&@Vd9x4RWX)n_nwc;?sk9ux~rHR6JKsl zLzpJHZ4cVqeP+GBQ*8PMN&7qO6lM6-#8we3{N87^W28>8B>uV6$hlx(qcpjLpV&Pq zOC2$nE!HFP+6S*(Y`f{2>FL?sgrbZ@yXFN$-K6~!nCi@(Um-IFzao=HYVxZ`kpaJA z_5200Xw)x@FvX-B>`fWHNq3b#Kh2?y#2ZG)qo`t$T<6YNhxziQF-Yn^VK_qMD$Rni zk3eb`Zm-vVhhkq%k(Nb^QiK*(8r`ICZ$B0CW1<5oXpd-&9eJTm4zy?&fit|Cq8;P} zQQkS-sBfgDsA;jKGL|l4$VR1v@-OaBEf0Vm5^+iV=Jt}1-hsO z5$F=ry?n@bpX#y9j^VE8o*3#_Ulx(f8HiR95<||dH}~FX1N0etZJ0&<5xqQKos&%1?Jm_+(FfGLMS+X{!^T_F!(Z zNb7ksKaO$W<9d8_&#V)t&rKtE_$)1a9UVpj4~**m0RE}{5ous{3XVE$?j<}lOu;^P z=6azm(t6E0G(GpQw0uiq&xaN%fWx9mLRW+<^~-;*?~F~Il3Q@FQ}O%! zp9Fr%Uxk9Ck!W@wX#`h2N3;iXr7=~kS2*%acE#Sgx5;PRQb-sFf8C+FgeceOZ^yWG z&P{8!r19yTz=s4LB^uQr>mD*k_|zkD7;NhmnS*({BxmbM66fU&8=ISo&XPi(!$=R^ zL^I8^at`SyLxiWNT{_Fp+<8VvsKuvNHZ z>A6Ff$Sb$LGH%D!7f5r(+Oiwc5rXVooWCPB#rs-C|EttPUo3eH7d*UeALDj~{Mwd8 z>Qg{a%d~A%N;K51+N_nFQ5Lb%?YyE#c^vjr-f z&AQ5FVkec21PzX%`=rXI7kg$dgwcDKLcZZlzzCl*6IzqylioPetB1y_30bf@U4a&7 z<}LE{K0}U!8MnibSTy{XqY_YW|$UC(9fu_&0(cDB#dM+q(e8tZug zuNof5RD3=ID$=yM>2&Te>eY0i9zTkg4)u7)_;kn=(9@}Zd&XEKxor|wrYFij)D@J5 ze)SnN@SF6j%E4R+&X%#Qo1Tlc5o0TKs}^Nynssb(GSHz}eewIB3{>>7XvPN!_20d< zu|3IpKe04?ol5*4OGVfH2&qzUsIhyRYV2dYWPEx>_UZ7SgY8j~!^D5a_rU+9dLyLj z|2_O)@$`QU|Igz#Qc+hE|Bmm0|G)kIf0zD$_wVChoZl#4LV*k=qJIE)lBcS{%hRxM zpWmSfPi$lgSu<8@aJlM5U@x#YnqH2O=qMyfk-ZV1jfuq(rml8KXv(@6t~p~Dz--+r zx-l9NF5MT!`mq2DFV42>`yptbi@c#WXr6^Ez3M5w+a1bhhu6N7%I9Oc205Ym*QJ)z z&G&*d&|A7mZ(Y6zy{=YciN5eiIL;m03w>7X-EwY>V$8He&l->&Nlm4gXi`jrd>0|L7(EHT>7aZMLEm6aT5-hyEY`-=+WG{MYbb za1!|MV&cE+_rU+vdL#ZP>Ho2RAO9Wl26j6uPl#Z7RW#kn-;uOgc`j+QBKGHtX^xxR82*U$m$z<+VgeAq-?N>zdr2UE^v~>Nojyqh}F;2{foJOwN^(&+ja#f&* z_6fGD-zeA^N*O(#m9#7)x+_%<|FVt>^zf^#{DHdlLAY_TYHx6h1ozjL+}5Gfp+3j( z!Lzsax5&0K1B0O6a173wVDIY)7G>iGt{h3b4PfCY4@P(JWg?_O8X4a*ou*0g*jTFH zpk8a+KBtII0)(Y7j^f+Y^@lTT-qj+k8H(@@!XfTKT(iV|`|2Hjy&xoGSrW>^Nf}gh z@Tmv;jWsX_he_n_)e0I`OOL`Ua`5D?c^-e&O8DEAx>G&WxtzvnR0zh^m&YYv76U30 zeSMI9g^Jat&OFM#!mK$|lx+_n;AI;8?CE{A`YkF)p=GZ*2MZOV>y|ZqCiZbBA}BQY zL<!i-Vw}~vKgO92 zRj24TjW&)1_L{HBjzru-G4EahwKCMl zht#Wx8epIIvT()-cTX_JxB~Uz4$2hV;f8SrN64wV|J;e74SnRqQl5Okh~)VANN>r| zm;s}MnxV~t_DNb?*I|O|%RTDFIs470fhA4eJ{y7r6fmgi;AU^me9}hV2 z_ZS;k{Ub4h0~f{4;$>f#`WygacAr$e#E#bcM!s%Aa6iYd>86g_nn1It~l#aXr62f4vt0!+=WZ(I}k} zz$n;je~m4NuIWA8>Oi9H*wh(FmX-I^55Yz(i1jLC;6LQt(;!y;qmEcu*|zG2$h&Ii zaEjoh0TXT_9>Gx5$gT|BHMNX6`N`y~x+b{HL~(%_Y16V{V2+{w3-YG~dh#bN&{O^S z3KpQgQ!9S%igqdv_c_~YU7w*|ZV|Ny_jDR=e8+tkTv5IkMAE1o_}eMp(VpiKhQMqh z+t;+bBNg9kYLefx{+0aRgeXSV{M#+*O?pEk64#b9t>Y?3Cc~Q}y*f^X{WxxBVb7Ef zN;!>3$2Rrc+pX5d(CAr8((L%i13h7}52EWKOyc1B7GoAp-~8ty)?&M_@TC6$ zCkXDZKVUejy#+PL-V+|TywOim$47=v7amF3&XH_Yc-lNTIr9hLVmFA&C>WkfG)^~pA`b^~ACT#z-C{iYaK)CvPhs(|2ODW~J zHF(??S>VKTpd0b`6%J`(NQkE^{tE14`k}XH!qae;V1!~-(q^DweSH$HUX4_^mtmw* z$07myf0?J#XqfdY$JJ>k(YkP`iMU`>egGG_&3H*Pr99D;=V5_hR6@7L^fI8c<(;>R zGN{xSWfY+d8jB~&xHM75^o}z6q6~U=vh?UTDCpE4jj<+F%aMkix_Pw2X6<)!lYDGa z<(hVO3kvE8ddW-|Ad?z{8+-6O5~BJAKGf#16@q`6ls`r5jsn22lfJ1(ZqbYRXjEr} zUeCh%eT9pauhpT>TeOPbbWCPUVpP^@^0ON96`h|g!6W(E>mPJtK!U%3I>Prl$zUQc zB$f8&o8d0QAASWDNx!KRY>=xRQhvO$0VS@WJi%^n+YBC#->Wx@+Y-)O5-d{=i|ifm zN_*m&Jf~y6%9WqB13&68^nJAp1=kW&>W-U%U|Iy6)0K6t;n|n?7o@SxROAp=H#5wK zIb3=hsDR z>EFZ;x+!Yq{g*znmj%pr@!9EFHK)>~_S7k4a&o+gv#~{pn+#vIjRk3jB;dEb{6soyuv5VdiAFdaIVoDHoPj^g-^clbJ;og1&_b) zOx;f;y#Oxz9b80q18)39>Tf2)G@!%xCFA>E0T9=|&EC)nhx990&eZ#Ik3q6^Nx!PE z+8pQw7e$|-VFDEzO(K!dRgspzK6XF6inaI#?SeBW(8PuZzKG+u$941ZyZCdrba(H5 z{CjIZC&0VQB!3HjWB66^`$d_w^KhB8V^^6J+k^La@V*uA8s7JTw6dM}Gu!FJQJ_nP z$EBCOg>On#U!ozfR?70<02v&$x1)AsPM;9e>n>y6Vn2$SAMD)^-`+=s+wuD`DnKK4 zyoU-tD3i7gV9^d1{kACjNfZrq2@8ikss5bRmjHk_!@m=*E~oW_q2Vx(V zj~w3=*sJ@MJ#p`CE0`g%9z*^g+7Fi7!z9n4;zdK9c=z|SCjfq@T|iPSkQ4z)wLntQ z#58Z=+ksbo%5&MRqCr*J=C<``CV&muJA}_Xj`YNwJjMOYgUNB)^DqpFp!02=Re)-Pc$g)}XA<3Hu4Y!yH1b;!HA2~Rqo{~XTg z1fO4mtYmIvd@K1K>r%YW+lx_(zE?_>8%H}PVxnXJfw3B$)r@D3na=5PsW*>rI+tgI z)W&9^f~lS$kVnXu7wM?T@kYj^%7qO97x!Cvmc6i4MM~yYtU!ARPw>}wl^n;khEt06 zk@BD>|4hgrc7H!gB7u8Ec3Bo z%a;@#j$PkL*o{ev@ygQ&eN}R?Aq?YA?oz z6*+iv*DM9X)XT3z#P<>OE9oR!zCLvgQ>QVtq*uW~QGKXF>P|PY*7E0x^0N*g$CfJ@ zc4I99MkM#|EVF;w=O_m$tQ0&cLBXG22g$SqpJT=RgYfHXHCkWscd3z43~skCuvb5* z&WdD!bAyd*k66DJeNNJ*dZrW2{|e<>X+AHR=KZXGfSOYzI-##0t%m^{toAlwm@uc# zh$7?@&EP`AS)ksD7Er)G{3XWKg|?Xzpz35=EFJ9y5Eg5Pi%pnC9>Se7xca$8clC3t zaP?E>RyMhnH{F$==%)12%3T>miY@fcaOk7lg`Y`dRJZi_IyXE5xhqf3#)A34Epj7F zwlTzwV-0KOvBH=+mM5J2bd7;)abdMJj?LsxEX#N=Ya9#ZSi@Mj`58+|4@5#;6;2!z z?&b{tK2nGrKzJF2?GoMmz&xZV+Z}mGTz9Zq3|}D6tm7pI7=WkX>ce1|2j_0HZ;E8* zRYrM>0nXxPMlbL_iV#k!D>u4Xv(uI+lD3fz$ZcwCPNbA0*V^;zLPxv6X1(6Hv@jKv zr<*tbnnWE5PA0&(v_J`U_5#6X5LKoHU&OAP;2U%>9fd#x*VvUJgshBpXc=*&@4#Pb zD~f9z>+FH=+J4CN?%dDZGe09|tz0MW8tm^ebDj0}f;)FD)+1aG->J^oMLTrrd@Oa` zTMF&SkJP+7lWDnjLe=F3UDLs5W__`e3i`yEH zXB|Yt#BB}X6E^a&lK@M{E6mc)LTR;06-_ojA&xzCnmg%^=bxYGPV$6LUu9czhQVeA z-LD=sSh!wbcz5|(3pX^d@%F>rbfTj^K}$+pr#QgU1G zaA?j%TUB5ZZTO}RcOoVE*sPRC@4nlDF ztH?eDwAhjghg8MlhVP_oSCYPkoE)mOk5IguKFQXWC~v8Q&3g1Is##EIO_ncJ)VfYB zfm2AO#iM9GT;Xs9UV}T2F)(kuv5Oqt?UFNKK`k1*O})D5lm=H_BMPUQT!Bus0+o+< z!fP>g9ICb|&waDGb778$&>W$BAYOIf$#0 zcyI{_7NVsD!0SnY`q@C(PGXl91cV!%=f$tSCFKgJkHJeq6g*NTGTLPY-IJ=^7&H2* z29K=Du0uY`3^TZEqCnuoawrx72%7Eu7=Fr-tVd(cVtJdGE@9pd~oAD znV2T_%w99~!fa5Pww65?{}Sy-W3-(}Y}Vg_kH?Xi{=qT1Zq1&@88#<&_F}Z3rbR?3 z{J_JaS+s=~{Adez8$N-xXvH>o3|5XV_C|WA5l4gZkSQ1LlR}?>k09;PE?l2+RO22t z6gG>S{qMy70{p-&SyxQ;8l(La$3=?ZURxhrpR#MQ9MbIN7s-VOrBEFTl9pkE*yJA8 zyFiXCi2HX51ZYqR#Z7;~jc{8>G3uCnF+@=|-08!G4xAuhp_qE_G@tTwp_-u(m?L9G z7x?g@czmR&TfEPMRhSLfT`fU#e5tMK66m(v zexTG2Tk3bggiDpT;(ZqsIv!d5J()s{*<33v|J;oJu2@xf{04E{Px** zA(~sER?#z9B-K68&8xhr{T0(IaKx*82DrZms8rJ3eB&F?D>#R=oU7OCaK9@xw5w}$mq7NOkr~@E4pkl{BBc-q zE%u0&pGnpCqav@e9}S?QUvR@rd)4~;QZb%hWnHOq5bUgjpch$b_Qe_+G z4b(fBZ>7qc@vWuGu2TC^9a+j}7NkklThM*&bNor-cX0onaa3bMFIRWG4^JxODrvx z5<@{a5kAchcJpX748q=ui!6r(o%H#yKiWy3Z#^F<{s{zcV3`^Ly}|15)^O|4*St;Hy)f);l}p z`RFF(xzNmGm6t-FA>I*;fKRB6Q0-I70ADV~VTLDrq6|p{sG%+ol2oy+4W%l3sof~3 zrB`V+Z6R7g0)TI5N1z)?#ic%t;JI>mKsFao9HC5tutxZb9*11ODGf{DJWTcCJ`z;| z;OGcNBS#RIV?|$)0y7cS97J3nH5-Y%;SynSG75U7z)$h!kVnMhm<10D!C4uiha+q` zg2tKhUK!d9$#QpXF-oK|Vf-JVq`29dnNpej&6)cdnR_zxImwApwhQCHvJXDT?b2E* zuWl0TGoe%|7R#D?wVQLr55y*^2?rD0*=Xeq0C^&td_V29#qKROiiK$bN)G%f_Ug)s zXfozk4t`b#D?xc~bW<%IqT9$ATBGaO+Qg`N^-L`_r5EX{9WDc%`!Uz7Fu5PM z6O4F=*qk7~)?kOeZH3Z~(|Z&?5`GcjVyh(n==Ki6B|i@CCfrEEO9R>ORnNE<&%op~ zl3fm^l{_!}3<5G6;}382=nq^OCTO4)@0=D$YEBs8`5csxg-2Y~RYDKFTwaNBIs6 z9dwW6i)k#)h}Pp2MeS6dzX1BQyK*||(W%A^!)cD;bn@oND2B9sS)a#=Hn@N_1GNdV&a8bx3e?uyY{M z7tZPESzEI=@)IWlWJ$QY5E&Eq3_{fDxBO+qz>rS+3!Dg<=vZgN(g^zr10A2XHM^At zoFA>iJ?!n!tQWJVu=!0Vm_eY$O`4&Crcg&s z^VgszT67xJT#uN%!37Rm0Gf{UJD$NI!sZqbVxV_^-NOjulHyOfWeo@v=jh$jZR)xH zbU3&PeB3ZP%^v%Z6F6c25{jpk=LWzV+iDAdK3$1xj1BCYw9%+tX$`fYP9V7 z=i>jeZ?}*+F&z3A&Sz6g9DDNgHZfZ}Csd<=P|^IC^DGRg_(+3Y^nDhhU>kk!iN3=` zFGZ?)5a*d|gh@em1v%5ss=8YOyBfx#_d9eR)}img^7wyYPtzT({yKY_gTuIT>h?5u z81^*2@QaIp9@_2<6Sh0a_B7vWzw=v^`E~Uzz&9gub@Ht188F4D1U-ONGcsUkSBqS@ zh_37X=ZSb&;UMELgT$n&hp@iON|(Xlwy#O!|T_r+%~KKt~~UZu{O;>K@HF%+(;M4V}82?VwBrY^K;g@xFi-&6;29IFgg z#3cD2$Pkz#8vN&&D5&1#}o(ZK6NY+-9@#-ErAk%$u5kg5-0+ovtTALF1C3Dkyp=ET(5m2NKyb+%#8 z^m=ut?;Ya_d!r?2BDiv%Z}^{yTj}B3IHMv@*Wkra7PLyQKEhY2dI@!Z;q>!=Yw}U4 z`Xzu6xoX)Xlqld@t@?EUXa_)1Xu7OCCG>Q@@LjMF&~-I(_^x8AQ;X&B*f|u4u(Y=@bANcQsG2}p}T=-7;euVcK2nqCnJH8DI*+-Ob zQCyH*QIG&7J)_hWK|XgBJVr10%np5pS^m6lDF0S!Tj4_5Sly(mk5MWVdDCryvrNZy z6eD_ceG<5-j!M-UbeC{V7+xh1U@SHp06aCs9MxRKu;Z&^OT(iJI4OY=8Ns`xP#Pwa zF0^|ZF$T*+FCvw+>{nFvM|V4Q&HE%@1Un8&v?GxSWw-UL^4y{Jl5YUe6v!A@Whj#vxktWH1Z&#J(c1AyRdMV5W76I-%Hb0 z#D~-m?Qej(Z?9T1)Vgd7drCk=-vpwhs;#766@R`@Qx4$7km4E6B~lTv3T+ZwO>GX! zDOF(jJUUPG^;LWkLoSDZn8OONMVL>(WEtwu#rP^Mhjug3?_KD3Q8#zI(WH&Ud==Oh z=Oc%aeZJ37&Ef<^weMkLxXHjlOaMl}pv=%(HSlKaN-7f}|EFb3y|@S9ke1^9D#t}M zy{be^dW0>+oe`em?84-&op%^o0Wv?Ph2=x@j|`N-9+KUvRwz)S88SMG7^Tqaf+nC0 z0ttj@U`_e$N^X{?vRyJ~-3)F;X0R#Ti8z)Xx=be^Zjq}|pE|re!xo$JoznlL57KvM z`b)o4`ukY^j(cDi0d%;eT(kkr%44&zPPOpY#a89Cqz*x=aFkTLZLA9nBd$L774tevLNF>nO+CZ*yPhs(s(+_wSf`+-Yk*A*36j9{T2*e`(ZwEy^+}=bGaJ zSCczB{Cm;iUuOsT8~SNhN=*y$;Ud8(7fkd4lS;-35*FL*&`)K1U}Sg{Ppm*qma)_O zAfOyu3}?YBzq-;G&fksDkoBmUnZ_}lnneQ?{VpjWa{sjjSUHuY@$VS1tadlqwz2p`@D$_6{W=mLm&ALz6~ zL|`liWj7*e8ym43EW$%zDmI>dla|vOrmT(z7MOe0J0MSr8$!llzja&;HVS2UZoN?d zi}vGY$)O zHij>`fQ2Z4tI(ZiTDH$`(%yY43_iP-NpqS!WzxYOcV0)^*g4Gy@Y1LBTD~msWkX%G z05e7yh34T)op>rHsZT^xz-z}~UAz&vzm;=hCj@1+4vQcRJtZ7G__HNJoTR9~08Da) zzGQEK+QxvjD`84!^g@89w@)b{~=ONN`;6gVAoh&I=H}2&PMrD>m z%F$n?UZb7bb0|fmn!!{wh{hYlQYrW6!qy&dI3vg3TeIOb*oiYn{GFXGOSvxzvs5X! zHx>>|87X%Xj*f!w*!upB~gwpjX*Azp!86KPE%Ww9DZ+B8%VSf*eg$tReH@c>WH~$UHL--Jn zx_tRfrS|s##N>~b3V0u%f;{<6UVMg{1?arS;mhAFD-v$)GJY9Oo#oK(cJ#I4PMMb! z@jZMyEFNy6@?78lj|&gz;)S~!*ph(Tpn7k9J!*04Rl_cAv(LUApL%)oHvkS+6?J*@ z*U0%mT%7|&m%ol?pzfP6q}Mp0uR-kKwDLZq!o9l)jKaivz1>r|zT6qh!Ij}H=6l6i z2uk0@BQ5XkFfd6JWo#iPJ%vpbXL{{*uv8eTBU9eGN6t7b6MF({hBl$o{Uk0b;^OU_ zFmRNGLm|>&mU`iN>EI?1oye&nJI$xm|B*UyeH!=4c{ZMVKu{Fs;5aF5#WEF~2a~sI z1dFg~ywOx+Yqi>ZVBD#Q?JWioa#9?N3lFEm zgyS$4JCY1JJkhC6xxgxEF_BXp2beg-JfPm44K!f69wv^&VEc!lC++GAY*zKf3gzfm z6u8Wt!F=XIoiHe_b$$-!(-Uol$>k$Y!{TTKp7}56ReJJ1uUS;!U$HvTOs?pbmiEwJ z(ArmE6lKw+i`G5`SPY0m7A~JjEehfrC4d>-J0yT4e)&9_0ed@0+vJ**f%q@T@ph^U zVIJiJYXoj*!|X>HPz^Wp$5 zl^nN#9JiQz-s(qC4NnLiRD0{p%Ru>?=L3s^D8AuRNuIbJ1=#~Ku29P!QawLQvxU%X zWABXiPID;O4#MbK8QmMLC4M;aQq^xzxe!jcy}K3lX`I^d$cs+hkBsn!DekYI&&JI* z#26fEA5bqt;@Hh7s5en0t9L^KBsuk~a#$X~mUTNoJWnQ#%lg`YB>|sclqU7MMV5M9 zUjWXXgEYbd1K5NarOD*UwK*!uTw6xZ95(-8v(=(6h@MG)-U)v{KabSAQ}t))V{RGm z&}Z`~qe6mnpavTscvC_=WC=)k47!fJjO6ShIVWI^qK?H}nOsEoMD_Sg8V*o?gL{MO z@en(t987a5$4DzU!yFcaMa`FuwPZHg2n@iyg$Q`CpELu(T_y${u|9|-XfL&&ppp@K zK_sY00$i#JAa22td4s(1b@~PB|ZmH zX+^f#kl1*nNu{Y*6xSE5Y05ufS-@_E!@UZau_2@+3%A?cxY@+AKQKHxBCE zaTwY`5f=S61B&h@ktm0y+6nRM_45YEk@9%tzP3<2y}TthTO4R7=u2Am)04%)c-;dR zK++oZ6>cilJ#aoUoWSe26BK#eFky3tT1J*+AOb4BoDA(92t7ii{3}2uH|7Ei_dFSm zwAF*@<59gPX<<2rIds$|Rn5eMZtqrpjq(=m3xwhW7xaTvdRZvmH&BF6eZeGtjgV%{ z5l4iH!ARLtB3E!*gN9SOBZF52Q3iR33 z1$d>Rwd!%aiE|=q2f*i$f*8Z{FSs9GK}k6-#57hq(&=ztI7y!ag0V zv(WND(gwkT-+^)Ce<5;9&h+Qr`63P$4oy({U-ZXfkoH8ZB2ZD&(~2GmN6kExWJTq>L5kq2H4D-KrCYa+_8LH>>;3b z*e-enwrCNfz<4K0&M_0YKdHlaJcAMA`m%V|`MUE)n9EMV&f}@ItqthM`4yR7W%K&ZEHtyERXE}`c_hEU$|L9NZcJJtQK z2#MHb^WVacIUV_M2@^M?z%|6hRO6!KfwNFLGGfu6pFNd|=^4U!nG6(kBaES7KzU4k ztPYYQB+qlTGf=f&bf>cZfU@Yz#@zcs)H|X^1P}p#7}{L)OH{}E-sSkDjR2UX%}caw zj?U30;cIx6FdSD~CxP%HtMmc;EtWG&uR?XH+!%n5r^bHBQNbwlHH^8%WsCeBH$sGH zgV_Kc59jTttMKFg9ThIHRtW1)kUa$$;D&xXP-Gv5J zhPND>|I9?!A-xXGR_CHJnx^aQJAsnh0gmB*2E?c%IQIEaJjMNetOPNfY0wR!CY__w zFFz+`Z!Gib`zfZH^z{3y=g|RK$;=iqHm=Mamm_zf!3W`3Tdnwv`fD7!gN$ra)jbdw zC>J?P!$Y!#%NT4m5agy1W=wZM`8Kugur#O6CbV|m@Pp6^K%Dg=94(?{mq~NC_`*F3 z;p#nqi+51l=c94Eegx9qy#|-uqh%iH-BuCF{$NOJVkH1F_RFKG!3^4a&pugrG%$cC*1O!D3F&9FL$ znuSdGXUI)+t1{1^RtQt10#tmrQ89QxF;6fH^wzU-QWGz4pz^!*$^(^9H`qy7S$_Dm zd3Oz`1WeN41M8?f=n#5`Yy5-;X1fKeLey^fx57lq^4j0^h8l4mRPPkWlyVqB7tsVK z_FQ1-CAe1FtBV}Y1lhVlu_f)26L*qIRI&$9EY2aZDmS1Du;(%q?Rot$gShR4fa&Q0 z^)akNM3It0v6Ssc&T%M>vamBn7oAasD4ItsVXyc&4-UyA*R-MsC5t>GZ1~f|NtXy< zXt)nqCf(IkCN=b!GyIEqN||&#icjKde%nr1oh_i%nGm^wCDenzld|V9$)xmF{`k^c z&^1qbbBAFF_SL!;nFMK>QN|H5>=yS4p-cS;8yYQum8ipb4%lvIe@ECfutrK@`drWJ zD4vH>;CB7UQ*hOuoWMlcS1^3>hT#hBh`%SvR%bSQ0p%om>qLj+DPsm1_DIlDgVXoM znGu;KcPhna<9r1~kITGR&-J$!a)TTK@|HTU0MEjlSp8?5S*msFoi?wo z`!RLe)EiKFR7JUzwLp=h#Y?~TTv2MCMmhN4dK@f256PswnoH_n#+ zd@@;JH0`hcul=8)ZmcI3|7QT8^;~eh#?t}Zf_MP(Z46P5m|CO3@eM~Jv0+@42P6Kpnj%`rRgF%r^VKb9iZ1x`brr;D zXAA+s^sH2nGIAt$6eMpEI#Rty&k%Tvw-o7HA@&sPABFgsW%1Ycx5-%T{#*XqF2VZx zo&2>Gpw^E4g>X|v2UNxcX*dIY4Od{5B_8MWs(=u2ze`M>TeQF6W5OX($NqjIEJJ;8 zPC%L9P9KW$(o%OS9ECYcl~28GA9}$*8rR`e3n3104{KnMSTD`})Eh~=jD}|MbvQgf zM&o9^PW%S@OXzjNNe!qIMJHa29JZk!+rLHFxA0z#rXKF*lHPOP868wASJpF zo=JAK%ek9Tk^|S+o8*fj3gCh$1Y(QTuSKTE-U^z8BmT?b^bQK0F$m-K@>mp@nF2Cm z7z>?@aEm_F&uCj&_s3e)1mYA6g= z|8_YXNhk+#fYmk zB@Xl3L-^LJf2+Yat%A&#>z6oef{C@TCnj2i$rVrr4N3=Z=dJuC`(mverL3{;A3~qa zfbRuy|C~y7>^`N1T`6sH$9t2*7b&-cLm);Y^izlQaXpGF`5e~`9PQ2ffoKN4*wrb6OJQgX>@Dse%gFgHBih6UqSv5Rnt7Y9VXGsChkGO z)SA}>UPKB6`fOvu8q6mC8z}4`qxa61=_Pd~<3aL284ecPc9YsRYqFhzCk4?+udi?0 zEbEsV<*f(gc*6>8GSMx}rCoENfNqe*Y6n;l0vQB?Mz8&#^k|(NiXJpslfNexy%Xwf zbzN=R6s(F|dYp*AgjK+aj8q-=!iyliZP4xDrkOa8*2Ra&WLK&EOY9hG#p$H7FWx8B z2TcVe1g9@D4vSwi`j5%78Wp zOu~i%AE%-**ihX^%YUircC-ZJ4x;QTq&|1sHk@!ZbD4DUu8Hy$i%6nh2!nB=Z_p<9 zB2OP1{#@xaHFXV3~kPf`$y-*`fC4n5h?@pIyPyXyC2pB zwNmowt0OL7w=k3#UubgJZEMztz3&-YNM~&$tkh??a=TsJ)|7joG(X@P229vd>hv*j z(ldcwbj#?uD49|Ur90g$cS*FEx4P4d7d!iBqKP8^AtG;b54h?k!#y`*W4r}sb>NRU zxr6r(-q~C@I(YBoy_5G&-aC0`p?;&myTQA`dpGY?=$3BYyLmstJFU3o2=6@iQ7R?J zDj7?(t<=`y8rJrCG0nB9=6VB}!WGEKa0ocCSt?Xo9u&<~YdK7?gxt(r{qGs z#m>Q*`K_geU#P=hZAm<7Uaz9jXX?0CpWC@ZRCaf8$S*D^ulAhF+?ppoa6Am>z1%-vj|9L!U^?258N7_ygtZOOZ1 zM)hm`lEBxkD-=&ykwLj!(E|k@q5&@W=SEoAp-fO0QTMsBPoe%3bZ=)ja|=v27!7J} zvtnZ7Q-EmV3ihtMFE)3rU1LhTgTeEZQcP{V^NdYgb|$-qpLMf#H}~Ut#@C!Pl)xGS zjcY$oTwJrjimb2WR2YKEs{@j?QG7mQfWC;4JOOWGt_vIm5Q{Yo_Qx4AJ5^=^30>7L z)AHM_K+;0&wH#EjjO)@vsbx`=!rho}8{aZ=tE%iK}Js zcYH1E!%9HeF=L>z&-BjM@DL&s)qP#DZB}fFG==jBEWKJQufdlm%Tq9}3U;Hd{XO$- zYqWp;KQfY8g0V2fVypW|8=i!I3yCTJd9YlE9?G{JUO;jt&Ko7{=yD7G{fCSUVD1dO~8}Z-5~AKYVH)_A}bsJ=rj}~zCb7s zJ5W3So)P`Jqiv7lP$O`10;3j@*SG?>Z5v$Nyj*i0!KJ%#kVvLTOa{f`#XlaBTG|9?z({LlU5wcWBQws&nmx^67_2 zAD;56#t<*sc@;0--tn{xs*4kCH{@6ojQCUF&tO-5^!>Fsk>p?>1a-J@)7&#XV>8z* zJl(PKzF1e)wxuUk?USXOtu53T)t<%sCrmMKig(v70Jk7qIUCP)kw+=npds8KV^4@) znJvf-W4F(hE2XDqM}Zs00w?eittZr(9S0}SIU&6*y~TUv?y8}|CB)0|{R6C6kKC=* zczE}AZud5<@g6z5qN)^i1qDAmFn^zQrn%R5=U>(Qx<;*u%6t$QVl@M0ol= z7J~4!id3p^fffi4{j7+?xpk9r+`chxe2Qc@il#IxcoUfjV88}nn^ekkoj+x4J|kgA zgdf%Es$G=Cn1T`E!-2a0AzSEPYyakZA9D@UtjmTiXM%8FK5q^s7TnW3{* zKXw_HpNeFXXDD_z&rW|av)BQLTza_ZdIG#Vw|g7cs3d1=i#SCXF10-YOlZ>UT0pokI%NS3H^x_9d6ths> zw>~^{q?AkD2dcVjPtT`Op}tzpY<^uFTv_=-v?;(?0wZJm3OoSi+^eLNQnc(hy0L00 z`4>EyJjR|=05_mWk$X3NsEd!s%r6|%6s7UTPeh`>l)V&&aQj|2(T+HZvy6A$XQ3YX zp382KcQ7hj_?7>n+We12eGQOigM^Af)BMI$FudwqV7qlhu8yZi^*X6a+>9*xcKp*! zBw*tf<$mwXp5pe;OcrY{{%6|=NhZ5_aGMg+? z|3X#Z>k5?EGhv)oEBD7+GuuL$+4cJka` zmD;1!9?Z_pSCSSyg9K7-(FU_C7f@hXCrFL{qXbakk20lMCYNb7k6?f|s;G!{zqOPF zLmQ__-Jr>OBwp|iX6Y%END*&j8~#zulM-k~W&>wcvM2!%Y9K#wT^Zvq*zI?@wlKzMbKr z#Q;_ct!2!JF=UGH->qUGnI`+^`_vFHe)pvi*K$LMjffJ(D2#~cXplaMjs|fQb<1dY zVt|C293sof2*NG*H*-_56fa5R$BE=~!ZY`e#(*+PnqDjY!=gKFU*6kjFQxY#a3)6BT+?>C|!ln2}gJUgfG$`z)F(? z+6R<3t@#bjDcSNUz-&o;%IYvOpD`g{hCX+GrYqb8qF>EZBn$p4RrBrPG%T?TOq`(O zofXbfuxtsLt6+iv0>Y8ucz1<^pd9bceu15*2~5*x6Vks--&}oMTzIsaiO|>OZAxJe zePs}=KY0;Xp!8!3!Esn{IAMXE8R=VmUzYl$2DP02i1V+&<)RXmNvHS7SnWxJ%IT|~ zm!>2oWdg1i(7f;QsC<5~d%Fu!E^0NR851!AASAAU0s%cM%Ai_=I?Ct4tlA`7}yh?rbKi?$Dt01m5 z9xMN%NNbi7pjy)hVtJ2eYc&F?cnI#YRpxk)U#Qiz^^=G@wc1;dzpvOVX3KAQ)rM9q zCHMs2`AZIakDRYP`5Y<0a=aCD(6UIv;LrHJ`uMBVw?d-nyGM{;4u!nOAJ=MsCP~qJ z6-mu>YK9j0BsFtO&5#EtsoBTxe}kH}SVGIHnG%0d$rU!vqI%Ij5M9&0-~ej)ZTVd9 z%^7lHT9G`$8F>UK&UluGZ=3xI!{~7{+-_0cSW-QuIj!! zt1{zQH`wp*AsJ31XQ5cMNmme{DE7QG>3<_50Kf9qh`0{k&Jai@vTvSB5G7 z=A2&Sd8e~z@z|KRVrW>AXE%Y4V6-#Y68XVZg2FFI*W+gPUm1A0JTmh9t# zb@~8Npo9fCo4d!DOD(PT7;Bf{QU*h>w!m+S>bLK-x+Z~}rvGEwl4S`t<-2%_3jbOR z9x_G}Dm?ffRN-YdM14x6+H+YupQ73aJ5N^ajsF<#j?g(lGQGhV6O$gJ-GWr>wQMxkFOxY-@)UTJAlb zUYX@RZm&Gudz_;KtoN}@GX8?Q`4i>k8d(g&+$uq6a6FsW)Dy)@wQo(s{8ZMuq3=gj zR&yYU> zTIjh3=93g>S}-jjOXIu#e6IUHPRw<7Bv<7;X>JApZw(LK40fc_8FNyYu4YTk*o9=XIlHR3 zM;yBBMlR{Z0n0Ai8(ETRgKO00Nod0+KeGS7TK4~z+C-8WOC+&OW+T4mxdC= z!;6)6s$^mM;mSr)s%`u?t2C+46kTD766C?*Do$N+tI6C?cT3GI6#;cc6&}$YNU6MJ z36T*H^R>*Uth%GHQR)OL#xjvX#KU|Za;&PNG#~_}PDxgpBw9A<60?&45iDI3};2 zj-qBazbqdrmsIj?6V`!(>W-TZUd%K#@-eoS`!~mQjiP3c*?-VCE|zb7Z<a#l$TM3Hkt++(T4yS*5>tAFA7H59O5Rido5U^DJDizxFI}aN^C+GTeMSdjL(D^6)Xe9nY;3`II3dc zkRd1ng=)uitk!6{o$q9%6t~Mri5nl@y*ef+m!dXhG8QLin*OM4Gk9Xf=k}N7DCH?5 zBXpj^%fs_!SWuVSgJm0;gaJ&ey^uM_Rd*R@OEO(`*JtU48!B#5IHhP9b4-?JJ60gy z5Nwx_A}k}ana?qPb4hBFt9eqU#L9$GpqLm37p$_VUo(^$nnSoPu!o$wZqadrsokg5 zipYwO{Ut)`Ne1b+-`n*MDJ;%I$`^MTa2Mx0(Oe-X~wqUipCu(JO?7=AuvxRq12 zeWYx_qwto+QBj$qan6$?lwl)nPfvocY?pB;$f^r9L3oL7+l-%=HV==-25xK1-NYqv z@#p!(A*g@lwPJ|p3bq4y_vg3D!eg>JZCbWu4ca=S#D3{gJpcE#GNm$3N#yUOJuyW9_a6`dxU{{l+&p5Zk0I-UwS4M8=OGaI038;56vHe z&Ca%+9?8@>)2%u#fb&}bqcjHTNtrV8?WDj09^(>l-B`8;k5bKePA4fc2}m1N?YWzU zozT5PP&lb0_%IYVhcGsAiDA+eUuO;}>$wN@K7t_48C&Cl#&kJ>os(2KWM$5mc2VEE zHRloYQ*3wUmqjLb$|sq|p40j!;ctf-QunUYW5W}RL*tz9yZt{@{`Js=6P6D{lOqz& z(T+QXP9nX8CQ3BevqgGguzM6XrujDfaD9^7D_5FcjP{G&y&269vD$x&u9`Ol*qNcu$AF?F#C!|41>ByXe+ z5g8p>4O-&)HI-<)@thi_uVwjYV&BH$zy2vDg8zD6DuUre{MQ8h+>x<7PQcIo z4p|x7&P_$P9gm+In;)jo3;z%9V}A2fIQSIzG5?Xc2!8C}>ptc?qUHUi`#y}c6}4-q0G>b4DWBTB|UJTVz><&)hfU0R0h zk;SC(>^(9$pY%TIEHXav_GNMBx9+1nyi-a(Y;13hE7=r8X8FFajQ?cT(ChxpebS9o zz^qDItSX6@H$P1|gxQnNa3#~@=r%|WA zPx|W}RO!U~q&K%9j{ogVnY<4w>Rb4xALsRw(6RBxe&uBZ3eIYIx_O85+%pqkJZm4v zt`i)XChG(Cz7d$x7t}|070J?#_3z}_vho0;j}w=@U`mgi#{s&1p`r2X5rw~8xVQ3o z@I)^Muk>AoS9&=t5sz0&z8b+JLb)R@_->-pQS}BfOb5Dw1%DFTn#3}hu z-naRpm4&ok$0;-gGP;UdseM`ySX49d%l65YJ*~K zp2K7M3?)^~21D$U0kDRhstTZ3wz{-;giX45q~~$GgG!~d-TueZ>N^%us_bS&5FWc$ z$Y_?tzREK zN4*lEPQOpPjVb4$&;gn08-Jw$PtTUGMt_U1Zj`bZOwUx|0{(O})QS z(dAar-y^dKTV4UHOSTcXR2sdM3XADo%?1iCb)|gx=ipLH1THngl$|oC*o853%!WiF zM3@lT3p7=l7r2Y&4NpKljnQD_Fq2|0lE|!f)k0Cwn)N#gVCqsKy&|6grb_-lh<)nB zUpfsxha$Fwa(G9gi&ME4hO-{#+jDnPnX@Br|0QpDzngI#DSf353}kn21ng8i9~A<2 z5A+ki|HrcDTkzL1Kg3~ZKQ9D65xht~Fb@BB3dB!cIX*fu)!d82l(BGdYSL)2SGnWo zrkWX+GZk8BXih)67t1kUY5bZ7T4*A;F6GIwvPA~#)vx2V)=mYC$6ro~t5mHxtGfJm zfq1Quuj8+)IQcQ((hqtqFO4yT1c#H4u_;qF16u8u=rJ5k=2U76vfoo%d9~%vivxyz zD%&F@!3$GX1|~f0pH$cyg%DdHHGhEnsX&Nb$}D0DP|3EqMaWGg~{Q z+A{vLgMC6NktZAl2pdllm#|1Sst7@=XncQ-xma5tI!)!vOfFlq9D^f93MtmDy4ZN$ zgo!;Gz)kiG{zzgq?F)XaWHf|~j1P(FwV#e#uW{2BmZ?+0&&zZKPrStC(~-qW13~%w zUA(uyw5~ zDZPSv8wI2L77cJx-53i=1Fj%MPGZ-DUKDld@R!t>{`8t?|J4*R6pY^vOy!c`BF~p{ zsc57lYp#}2B2!Dz;`^C+7|LlU4CQXfZ`{99c%A~-X~tDO_!7k#H;}imMHa&`3fen> z7i<5~3&h^Dxpx~LBt)U*6{ez-o7#ZQj^ zE8fzgl#%aOn;x7X0CxjEY>c7EH4b-U~y?)O4tZA`4@p17r4<^J{@ftcmF8;a1?{AXiNb&+%?k$5& zWo?C_6`&3QSIQ9xqNNg?Yx*rm{K*ATPlkb*D@6)una?Q`oQBDDrGyWDN;&LmgP&7I zewjk;q?2L{;v-F1EoDOL@X$LnKp}E0KXlOjXGRUCyxbu#4Juz}_I2{&k(V5+QaM&7 zb6zytF!;{wG1}m%*_UX8-Pz~JT>*gA<0DT65c@ClBmXf~{7xQe{yeI6E~J;%V|A^` z9%#MXDlf-LB{90Z2vDB902Wx2{jv3uBQI}TFSzyAWXt&lla{>vo)=>S7gfeF+)Q4D z;g~;7YjTY7&~cY?OQWdZs@Dleu;u^0g)pu7t6)e1f3@vruv`=!CjogqGy3|fyrvmV zubD#$5zz+3jc}i_5`+vHT_!sjY1RO1Bi#52>Eq@Q@X$Dt_5-;@sG#Bp4$6OT*X76yJ95GfPx#Ea)AeRy8K&T(w9gqv z{AS|Gm=s*kAB7HT(AAK zQJWOVUGFUaOspV|>UDQtz)xWBK!<F%Q9!4K(Y(!E>yL*P#LUv#o`WoMD@RnpbpcIJvrR>_y1EG1$#DJTn8AR$v- z<%iba{#bu<9Vux!2fe9PTOlsU3ws%mxciTA=NqEJn5`G5;3td6NnH%n& zNy4jUZhX6~)pPW0GoR;15Pdq)zA?LQBDzpAzx-^Iqh80yL*Pkln*;Y}XJnSJ0vf<> zB?HHVSEQ=dpLzJ9<1)AbXG9V&&U9ntr*x6xVl-Oa(c$#k)fOB4o=jPyaIR{*anU)# zNLv`IiHtNmE%*Y-5*g{?NDecJl0tofhNJ!RT5?(}cIvRIol3mh_NDI6xR{gu$%;jN zdRpkB`p@FICpVJcIi#0n3M>2W1NKN+kb`Fs9F>q!dleE!pheS?<_y!dmwGPMSG~LJ z+O6Y9Xmd@V3&w>ju=f%)q@lZ9tLL0`m2u#U7oJDFx`52^ZF1GON0So-N>3XHWcie6 zmyg4;*eQ7?e4V(5*jh^muXA~~VE_A|bntuXN&DRw<6VLMRTAGdInU5N$;R;0a$()>b@~o_WNcREE4Aqw!jkWW74a3>FxL>Z9S#FH@11 z^OmCHm_GMXUjS?nIJdl2@(ctA&pa?Ax10Q;-};=V4+bj?yB01U9A)$lr_LF9i=C&R zhW(49{qA&tH!mSj_dhy>p!z&o7#=z*4V$R;(ymJ}d+IC4{&?D_w{pCUd&^6;Nna}} zxT?b@6~5qudPRj*5h|1|QRs;~658+dg>&C`mN%QtH)wv_jNJFN6?k6VERBz~_B&r| zD_)Rk|xp%+LI3<`a>_qe_@szUrNQ9(AO5D?^}KQCpGoS z&u?D^X8;w!fnlcB4#A&^8CK))gv{l^R56q0u_9-6d#<&*y_A8@H{f!b08zpJI2V2P zm$E)Vbu_k*_Jn8<@Sq9G-g2e*8JKGhZPBa3zY?%o#AkxP0%!r+A2$F!b7^_NWZrH^ zZbJg|24LO>lX)j6GVj=wgzg;6k;i7xR_H+A#(BT;9-Th-Vr|8yz@FstcEz`Q2G2Y= zBliG|9328acS>Ke$NDyTkHWQC)YQ|Ox7eN14|QSiTwY&E$q8^I80hldrkg-Q{p+7S z8n@Q?_bV*nID-#CVyWs>bnxw|K5p{xF^Hfjp(YZ!-(6-CfF)w>Z~GhDe@wN1!(Y?> zIWuEz4^?nT`6yhsT3A((lzk^s&7s=j%54TB0I-UtG^gfe&nqE#r7ugnk6?7Dm3tWMr*& z5uH#}bEqtYw@mcv*~oslX8HpP_HnF?UJ5@Z_m0?#1szkjRVxWr~e#IfNabwUR*gkEp+K?(a;+t6j1AP(?YjP zUE-umcDhOKYyG1~OW(S@hd{DAXso*2ER*$1qX`;0(Pi7loesW(p~4gLP$^)Ka}|4d zKkoxZg)vvM@O=o>BsQ1l*P=#lGaVUB)ZgfAZTXXlG|Hg|&x!P)+M24xyFk?ie~KhR zSSew2#~lbGoA$&4dQw=>x7`#))&NYV<@GU9v;^pwUh>EIGvjYkqWl@1IGv1U25G83 zuEyWn-+cTb#G~?O4z)JNAoE8{a2~G-lJqNj)1g94QM%+r`FX&R8z?E?WX^tjnEe`& zp8@1&tIJ;`6@KnCHRDb4O-+ew&LkvZ4|l$Pd-)lw|D5|{bq~#P_?i=?qvuk^I9ly0 zX@%)DJ0WF;dmpsm{T4Y1m#(DlBc5=4T{9;`V*w4F4owWCz!D~0Pt_bR>ww$I6y?4z96 z3m@)QhwmK|g(Gs07kLb0p}3BvWtwkuU>`dU1G|x2*HK{Y#kJ)J!`WXZ9k#>1;oxjq zR06Wn^9`N@HhaLyt)eyWvk`V;jmL=2>X}vC{nkK%Q~L4`3> zVff5xq6G^Z^|x>@X@j=-O03t8L+d!VFo~!7B_ii8Qeimy)yyM*_6YOOa{3TsnSAg< zLkZM-A&?f(YL-hn6NUT7k-1N_6u-Pg5r}JP+4~2_^)u^Tb1|8r_S9-RIvni-dCEF@h_dk6ooC^Jpq`nyLhs+NcgGVPL zF`g{vqgRr10zqk^O8+3)I(J*MdKw!iunR+>h#V>k@>O zhARr(PpH$^Q@u;+MVQT3?@pJ|o8;Xzrf{P+sU>$~d6TF_Qbi#WFb0-4B&ar;g2N+O z3BV-8tlpurYFAm+tE{$+$qxe;6VTAhvC4QX9=UZsz*D> zQzjbK(q(Nl%w4y#Lw*F2^;j?%Df9Q_f4EW3gln}yo*jX3|KI_6Q0(@vJSiT}@&yik zAS}N8fadBB&Y~<5R6PVi^2~7}*Kse)D3O}<DMdaN zJe_sn7GONJCqGS7=8>1_Ca13vQJyp!5^sx z!mDNFHeTvK;ty}#4$qMcTxt)PXU134?xdhtof%}HpcsQDNiQEm5}P}u9I5|G5=AJv znSvP#hdUhL$d1!wxB2ud#Ji?9yURO;Zv~YtU`%iYz8>MQt#iDwv}#n6^3J6xunOI< zIW&plj0zo@c%?beeoqxnInbVv^Y*e&Xc7tV8dW48$n~C(!wn7tH5X`uDp(VGn4J1( zT5vY+(YiX`$b4uNJ|bVMN-vm6g_YNXsa-_zMBaRj8tMR!@A6=m*6B!06Y%&s84hB2 zMg_$1hzLz%>-Ts?D^Vog$vPXa6s;yiX38lfm`-hEU@UHj)WTVUit#!>qDQs_X@ICQ zhd0cU@C+Vt@@aOKA6X)gfv!x)%y(wwwj^$yvj?biNx{Qp0zpl_ULp)_j^KK@ff3v( z0d=#x6Nj*odl9kXkK?48>|BG*%xFT7@)lF@2yPvM=jaIAftjro?(nU19RA3u>78bG za>^8O9efiS3D`cG;SPI=``F_8)zUk|rx z(qBFdzg^WCoB-Fok{nFo$K+z^WBNY&O$*=93dLjXxLLwu3MvY~Xt{Yw@QH)(^0nFR zA6`qwAnf_xS8L(e!Y9*fQT;q9)oHlu4f3)Ng`y7}EN`A*HJMrz7Z$*4crYZL)EBCD5OXxWra8;g}ibov5>$U-C=GH;w(_<5w}*l zM_EttKQy|*xS^d;m34bC1YgMXe^MGoH(k;ND=)NY*u*D_hHAK1jQZw7J(Lk+fH?!A zogX?wvWVY<4N#PJtU>lA#qF~#zPik;NmUUW;*kFBzCAchwL&)MxIvk67EHA?xiFee zZSKQ}fvVzOerueO#GJt*%5oux3r-5^AWv~&5-RWRh{{{y9%t>LE(PYZ1l_qrP8&$1 z#)oE}5e>LRm9Tsae!<8zqar$diTVws2!3EjB^UxE($7>Ie4R)~d4pv|P*#D*iFEp! zj0Z4B1z#jyDZq}2YID;`RGSC2746ZD68j{jA~HYeKWC_CL*C-4NC?c1|Y!b$%&P`>_5GsD9uTsYywHYlPt zJ0_=JPp&vq^jG>8b)6;D?~kaJWuvGr^S34t@1+Fdsr%D<>r=it{o-};iJFveOusly zghfBmqMVX`DtQ9^;8~fj-xqxnw8NZiX}Ctk6oS!d@fD?YY9wLRz#wNk!W?B2E!Z(r zXkuAb_b9|Evy?tk9hg9$rRXaTLFdZK=|nYTMN0nG(D0L#TNo`@t6fYFfa*1);u4if zg68pUg5HkTJla@RfUcQgZWj2g|D66{!JrfzH8ymnWDq~|*vzF4+P|?b?_p+oMVi;o zF-a3s{&9KipK12V#`DU_jOV_Q@!aoQjOX!Y>Hm!5dE(iB{djhm_MC`3Env$vHaSB7 zKHq}=^=GL{{4>&jZPwq7{wtl(zh8v@Y2SkW7fgiyeIoQX&3oT$ zJyCzgKQI5Ir}}Hx6TRfmN(b~$i_ky)+wi|xiGND|M}P8nqJKdV^iPSH;-Yl>?qu;P2!@%pRRY{LCZxx_oJ40{0_ZYu6aUxJUPu& zH&0gD=1`t;itWdtp=Q$I6+2mZ#R95gzLzxvX`R$G8MoNU=po2KJbMycP%VF0&D%k= znD@}Gy(@09Lv-KRY={2|Wq*n&cJZ6pGeR$K5UUeP`ebZTBT?h#Zn16jXXI4}#H_^4 zA?1M)a@!MDv)sU@piO+a{3&ls1#(*sw?$Lx{u@Dl^d9YtL7~yIBHbqnP-R7WjwYjn zo+bfxdCGnyJM7=#$SOOaGwTgvlmSA5pErXm!3P?P$8A5^{&UAcT99i?(8fpUH{dwg zHBZh&6O}Eos4D ziH<@!0`HMJslFn)&8(AFEB+@Xi@S>b&c~B5grHjtzvDfUp*{IMG+BCJH|DdS+P|h^ zs^ODW!=KEOfVhVL&mhu@YT;~ht4}ECg-BFbRb;!kuU4WT5&vL;hQT2)@q>FKA8eEl zFg~QwSrPZ%4V+4FDfHzLal~}{W~BvRM;U7>Qrc)Jij?!cXjamoX|&N9k*w#$WgYeZ zC2QrZ3>ATCi&2p(WU21DT}nvE@HM(hwfn-j4DDEOq({zIb$yTQ66<3w^#j@!2|E%+l8(n|4Ol()VpXFYr3FQr|R_(FQ`8FEw( z&Omp&`+zMC7*(n5xXZTwT7L>ostv%cK}8rH9vA&-P&C~2A_i7>&}`%Dx~Qhh)C-vV zVXnkB z?sfAJ2Z-(6ydN?TR@-#(9nfkVN;R*pOtTRBkvE(xf8B&|uQRU=aP#pImD!8x1c`1z z^6O|hL_po@&TWv>BBF_K`JLG?l$;r6HXzZE}-bbL(qNz#}O9aL#ou|L8NpveLYLlwqwxj#`16RCLW)++Pn? zZY|B-?Xn%_hKdWYt!x)BBCA4_Uf~a3O34xbTd;8w`~h8sJ#+3rp6J}&mQa7uNJ;&@8$QWrUaCihJM%syvJeghY8EOGgV zr0CFSBo7&S;U3NVDSS*?RGQ2WpwT$48I4YHQ|0E+ub~faFr}tuPn$R04X(foidr1I)cY_7+(Z;z=O5cYJhc8pL2NSl%%W^n`zm8O_y$7EDpKyZUL3rRO2$JhVQm7FYok#)LZ}Ohj{>)o9-I~we_V%> zw2s3K;$%>DwPZ5fRk(LfR{vaq;ez|J$0-`EM3Z|;(XlF$}Z&OD`5mh}$ zyDKgs$UU-;x3gcM^E9pk;F_HDP3dMfXNMjLboNc}R(TE#O$&5pq_@dS)lG_s{of9`3+HI5ZHHcW-pjlw zAVfYdWqjwy-9IXQb&ilbjSjOnJU%pd89B%73BWk=PAaWN?gdc;Y$BtLftws@E5xb=p2FQ_M90$XY{|B;!1 zN!YH}nb3D!%%VU-A(w0i)cu?yl0o7pXy0gB890j=U(Q_Fxx5s}h zTdTkD@h`29$IHiHxW$)5-u7W;-WL!}|4SWjQQ{}srA2C5Fvh+xy)V*cBUqU#u=s6a`2RBnQ0=dX|-c+q`<^>+%3ViTLnaXw^6*HpSkU@ z+EYxVgkMZ}%m!xOA6{U3#TwWDUKlS0?%i#i2K0nba=LJ0j?DIXuDZSwa=&u=dzo%i zpr7MRa1~k6igO4_1)^FQK*59XkVTY&SFtN!55)^IvSyvlioBLMho}BG{3L_p#1B!z zmpjB6@F=d0iA>Km>O+gR1}}Mdh~8p4DkRs+YSHd--0vPTiKK*QH2qX&mH-qM0hI z?Z(TGaZdQbg=*&!8~;;4E!1jy)JS?)fLeWF6B$>nzx?;I?8(j!UC&jpnWc62+TFRG zdf{3V#mdDk;%))5#J!#iCv{*UUAB)(efQdVch_ZS$L3Ex_g$B53ru2qaFQDrDNe9e z^}|)Hh{o_^=LbeHb2CD?y1Z>c5X z!Vk44?2?ZuP1^KfhQ5l3B(<^u?yH7-JHtU?T5-LM#12>A5(~s@IQTETc^(mfSPxHZ z@^L28>wbiE{9z1g1%ViD>jhFG_%u78O+;ttGTI1<>q7b=DBdU1Au+N%ikOtGEU=K_ z;3(>t-;UT=5*GGtL-;7LO$(lI)ypdQeZ&)uHySF$v1;u}>T>f5b#Y2vVDwRs#E<@X zd|;FRR>bpP3Iu=Xu}-HPJ{X8}r$xp$sUCaLQ7PQz}~(0&c>3C$apBnpiH+plN|0SBK7z=f_xl z`|FCaf3A4wJ;ev_YToY)m%J@+zBYG+OQJkfBC$W|6&vNDk;H}`6$YxR`j*V|s~`7f zo@WV(qkr9~Y~@E9tADX-pH?f!%oRGVfF<|l7{y4T-Mtv+$=Ro3obyho#{fcvaXz1? z7>AQTS=#bsUjwS!;q+V<9LcI%tN9h%>H6D}h9v<=5B0q3vVu!l%8{gj?o&ygmn8f6 zU^NeBlE+D+;@a6%)&G}#j)$5V_k&1WtHceJxafB!#G$4Cu1#BhZL+q!xR0Z}U3v{~ zRi{7YnaTbXkHgl616)6cx3jN$^=&H23E0~GL!K$|wK;OyRIzP*!;F9#g+h5yYG8g- z&bi||1^o6a7<0uKZoHkLc}Jp~D3RkHTTmv86Y2o9whLZP_}^ZYO4m23#&qq8b19DP zf4hJ5GyWk51A8)*_gkbg8N{9y*P`oPcyAo$h z=$PL{;#?ByAL9ZO6__KsUg*|uj zMI3vU68zT`{L61vFvmwFSnk+$m6X-Zvf;tlN8YV%PC8Qc8K~oa) z`ik9Oy^&C&AwfS($ZN9%9ZX2oC_&2-QvFea&Q2)tMG0D$kjf`P*$JuU5_AeKkBBYB z<#VPBkDZV3S3DD%{|!Du)ZN7grxKZF@26N@(jm(qWP1k5>C0z|{X-h#WUTand@x8Q zPk}L0ACQifPg0C!?2%>SZ?0j{sl5z2PMv&PIh=}B>61rl}(Vb+$K{WL0|uM8)wqSt*# z_UBmg@ZS&YN->ep)RO+L;Qu_yy2^ZBD_~M)T5i3GOKbcqiP*jyb03VX+9UYdZvR3# zP-=XHe#wIIK9g@bziO4Eyj_E(WT2j;3@e?K5ld%WY?X1EDkHWZl{4NTr_dN}MPHV2 zX|`c3iqFjkuo{!bT(+a^Lz+a@S0H9fIq;;^Kx~lpW*ef7)D8^HGNQZ-GBHXR5>_`? zUHw4i+l{ALABy^e{3;cEE3m+#Qk7zY0qcSCP|cD1@73pbLCQ|La1<6Q^oLWq*(PCq zkAjPx$~Llh2!_?V65l(9EX-9o>iAe~tz_g~o8`t@kqHcv0kmDLLH4 zmgy?oR<$p}m5QUm2kfW)q#>%Z6j$_2-S-KoYr~RO$#PjX2Xntd`^fLML;QNzW!@1@ zukd{=cMm(fB<+x^Zi>PEPjg}0=TH)K3Y{LYH^HXBxNf_8CTY{fqK3*e>K_nw93i`n`Gm-*?EDdWoc|)+8vF7y#ptj2fgTyy zup5hdks3D5w+7o;Y0@9c-Q0(Qr$?{rCkMwaxd9mV4RfXpHG)>B~x%>+t`iI7@-=`)? zfFR;I?v8d2_5F+W86eBaZ&jaGa2fwXeSUJv`XtC7hLrd~(611M?pi2PM9#&*NUql< z3|fcX{&{wnZ+GZwwPo*2RQuGvPpUZkl4#_VRYo5J4|rD)+cYuDCZe=@U@45|rVrXf69fnJAVM}FQ=q9BUxIy<9 zvzJCO>PD%AVu^c)OpQ7h51~}j>ny-ez3wK&YnSmf;14m-QZZX(8jlhd6wo=@?xUf6 z*YJ(&13~0mSRBCU+SMJ@H}nzup%bz#I7znIgvlwCwZh<6s~oo*;d^25^*@Sd@PA=+R3pPPSsV*f1p|Gs~^7M|EYTM0|-pWv8p**`CwB-n&y9B8Pbhu;$?T z8+)0z-qPzP1Pfxz9aDZ-m>Q;a0GzVzq9A3SXYLv-mxK|b1W&MjL2NnF97&R4B{7x~ zD+6)yJ(1OpDW4oNe?%sZN$$FPfxcOn6&fh_lkt=Zuv6vbr7R(gQVjdu5i=Eo>abMA z98_CeYET_EuA!7rOHA%74XT;uv`CsWNP~-uleHCjXO*&^N8~=1eZ&QFwIQ11Qr{P$ zPh@)7I)gs=k9#A1@I6`ly)VX2WM(oK2YJ`prTIbc%c(L?sQ5EkYxa&GZpN$ma_aY{ zcot?QRb?9cP#aJ|H0Ib`dR^nhkPpAI71O%W+9)2!~lmA+9J+wuK#a-{bEe6&}4jUN*d`n_7W z_v)6gQFTJ<>4Zo>U-v@`oR)?d+o-7oUPYksH5Txr+j)QkDEMmE5yqf~VEv6LqA3 zINFlt*gYFM7f&U*J3Ez6`kD@^>JvGieA`;{BK5$2Za?41?dMd2dEtM1bZ3v6&{6jQ_$aq9Q+yNMoes~96t}SUW*D>^whkN~8fV=z@ zxF5&stbURz`>&K0k*u3lLJ}^FJ z$1S(D3T`ROJ}%+o-}&aC6633kRoN>VEpM1JQ*1pl1!6Kg8NcDaby=t*f7$6yjB&+T zvO9wsf;wgKhhvfU>v$#xrG&x`MA>ES(ugkDm&4f-9Z3p%8*8jygqWd2L>Zn!MTnG3x*`INS?Vt%-^zEUHRy>vd!sua1WwxW+O)^UXixSWyRvdZZF|)m?sA#lV%1NeAp-lU-?5RlgXQf@VA(X-JF%q!-G&->09mh|eCYt@IXCNzq8&PvMad}$tAVZvIc>-OUr@8GPfhx( zP}AGcS6k6i-l|9$%v8WLn+(w_Cz~z#|8f1_`X=?CVqA=})z=nTRf;=Qz_@6f7zwl| zFQRMoRV%LbRrD>n3=h(7q#Zq;88-@2&0d3-0_GrSGI{C92wOLB3Bu)W|0KAai$YyZ zi~|6@Ear*e>Ws7cmB(=8-Aezv%GX^OD95ubM?o#LvW^^8B;U|Mq6! z6W-`MvyfsgFW>meHOZX9@V4{;t>*_@#mnj)n8S`}D{p%pA3*q#(Yu;-36NwarD^b4~u$ z?=VZ6Ir!aIjMXN-6X@(8*p;3R-eVxWyVACH%9*2LnhNdJ2&l_**G@0$(gi8J_{Hr`s(Ugca@I4=Ja+@7VVL3yy;pbyYfW>m+Bab3@YuMqRxX$7EYAj0f zcTxX#I+<=~55A4XJ z)XnGzbM*8LJibK`s=`eyw=)P)la#jn`az4Y8>FqcKBLTcU52`@H08vd`kGzzFJ?x1 zI_*k&`h)L9HWLUnjwJcs=gfrzn{~j*B+Cq^R)76K{@gsMU{lq_j)J3ABT5PytL)CY zzD|Il1stzasG!%~oZ?FZjKjUI9TJpIP-{uK8brmeH`Hp0)=f>&XKf<{Ev-UkS!lL{NG(y#@pPB zNxInK36OWYw8V4t%mt3ny%f?u|J=B+OGDpt^r*HT;=j?5WElLP?1`KgY;o5_yquY`YI6aI0$CW>#^cB^C9oB3NE-mh$B)$cxF zD{~Zf+_B&+_3l{pY!7Y!AW0}&VrvNpLgR#r3$G5hI;sOB?|i!05ojgbqmr#-RV-hI z&w7f;6aH($t5(Ln>qa#Xen@Y>uL=2buZ|_rD z+g_@amrk z>0155L3-{nIlH3OAJTIV=rdc#BA7GfxRh<9zS8r`qI1T7!se1$z}6O<^<%ZaC9Upi z%wrBl_}{Vq3TV-3+vv14Ic?kY>4$)iH0!@bTXBojANyb$KQ|0==WaCX-!8D;s{UtkfPfFXm3x7w8+#S%ojJz?V^d?3p*h)q6&2-|3wL(<=c$h zclfq&u>t+|zF^rE6+Dcx%g3(*p^;WL9eVSK)%%v6G=BsB;C^tmIQ8$;X})u#$=I( zfk!zlXUS$TO|C*W9-fCDkVe?4N{;uj>@2+Jj*GlI+5BeBZHRCGOEbov`cT}%cs~3@GYWac?+=^I}-ghXuCV+x?3l)b-^0(H4fA`#4hyP`@h*4Qh z^iR!V6|M1-I2alThZuD@6c-g#CNpv;W?%x@E)^Om5sBlo6b2hS(8Pl<8VuL zqewm`o|P1;Wz&Q0RC>H-ByJYm9w3$P7{3-z#oKHQ02u`r<0uxaHc@*Kp4{95A% zQ`#g}&jwIp4JMSBF*3ikI=u7=FjkA3wPyoZ&HYORV%NV+0qkz^FUk6PU{Y##2WY!( z`Q6~{+FE)V)-F?fDVmdGs>B$5j67t8GO&q;%)V@s+}T)}owY`tIq*ysH^PHT<811S z_pdlXUu?y52#w1}Hl7eK_DRe6e8+v5?Fyi{X|`L$t8C)0cGX>>W0`*pRJ_d5k z+;sZt3%_S48ooSa2UYl1FH) z?rp|%DN@M?#`UGjgovRm{^K_3s=D!}xn1h9e+s8W{;*luXU!I_&2I=DRQ&rtwjxhB zxndLprI|ZatA?3s&_6A*o7dzTbB|-fP|9K15_CM&9|(LQG<>M6Qo4xYl&ZAq2{Wo5 z_+jPE`fHF<{_}`>s=s;oB2Y$$D*b9llQiHyW((h8Bae6AdgEurtx2-OM@WVw;~FVe{0C}y1K&%!g}&kBj9`z` z=OI zZ(^>tqIg7^Z{no{j$AzPa?<3GhU+tnF*Hv^)yxr1A=rI)a3Psgt6mB;l7AazOlv$_ z_ajU*TXYxdFj_QkZy&Ke8*6Y)iEG(3URBFHWGF53?T~im{iSxfeHA&hNsX7kLz|{C zUJ_b0DmL82{~&VFIgTXDC#S*lnR0%l=0nJkzf}R13Qj|=c}7)!r8&YVn%i%lz+7!7 zL`G2kMa0mTwO{k`3D?=>a==u}m4i}zY!^W_Wpxg$wn|iv#%Zi;v>ZmQmcwAxa^%pm zB-YH&re@EsOTCKA+a!Cp%3dN#J5AEgmV5EIyN)G?I2vRb-}4MY?aXF3-)L zDg21Sp2u5bkJHp6-z>ilerHuDt1w@mrip1b^te@n^>F{H^MuNo#=kK%LW65tt8T3? z>JWX&cBA8%Y4D8Po_p6?t_<`@F>Z5GA-6Rve|%Nas=TX)aS&}OfAbF+)t99t1)mU? zt4z|?3vG=jUP?<^(}i$0J+QJ!X#`7U+G$38VcbQU#08|VSkvS*0OYGOWMT?)u>J^~ z9+@wZ792F}r!7xwLORiwVQcbOEY-`O)$+&Ky8tPTkp%U&#)!>YyXICY)r&`$Ooyxz zWKKlZXSV$q$uG;&HTUEpDOXCe`>9-fjs9|ZkDa`{)4y4HU$X{@FK@~W&)5+wA)>A7 z>=}Ap$_PkFB|Xas61#9Xsq&)R*2cxGlo;bC(_&fm(VE%Pib-JfYXcRd~%s70vY53i3oJVn?8?~I2Y#I4vB%%T-fi&UFsC2eHPNb}n3gEGY znW8{MOPsiHXt^v_a%HiSdoyQu7ZmBu4dSli>SLzIEGIDHaPo)7Pub#gM%=^eN$t{* zN*qFV8w>76%0RNRNfE0Or^`|^*QUq#yDrrh_bT>!-5U;9_SM5Tq@h<-!)mn*uwXu! zMeR{sU7WrS4u>?~{j~^_s#$^n0j7RcA7>rsNgYS9@3_1MI)-N&U4;!5Wi0Efe!!Yc zmSkFPKP~r$%;w2P1w*L`ntoK1ElzAp?{dOw6YkPrtkpJ4P+ z#Z~^88PB+kkE2UCb*&ZtC>vI_!B&iTG=Iihy|baKDpO zZ~c*ZYp3)oFHdi=6 z^j^ZQxiH9O0YQo8(TwE2JjvptvJ%2RFr(F@&CNX%-asF|{hFLFJPP6spURW1_7LAJ zygxfre$LG<(-uCK&8=;xr?NvQvw>ZUJ`a=OEGhUfrOi4j3EkOCcz>6FZ%V4q`RvZ@ zPI>%95^t7->m}j+*&g#}DM@BzH}LoV>^8ppSdxU~i*5Yr*&u%cg!S|gSxNRhenD#U zv1a24-*3h6;h_uyLSK@;t5c$+>m)b+exag1BkEL*Cw)*#8uweX4+@gH_^=>pH-Ec6 zlk5!sL_)Vq=*N=2D=t*N=-MZt`>jyvyW{}BMPA$|e zf$O4y@DqVD22W_V6uN^B^!LY`fj4tw!m|iV8NgHJR(1gTx zSS%3N4y*s;+Y#yggmy$aU$ukIe^xsGS?SJ0>hGuOZ~OHGH>q9@tB#kEOxJx$IN}09 zGaD{J0?40zieI)ChBs=p&!L#4QL`>RXMvJwJ;IGW>-m<>i3*)Bql7?QbgJ++`Re}c zhR{rT7`RushKEo10~0Ql=g-Y&5h-tyA>%^CBW$gPf$+9UGHbgemdO3`@RfwCe(aE^ zqw+yOazeg>EX6u7pd>Xl6hU##g+`M43ECvlEc@sD?a!Az?|-f>{B9=Mvg{?Qr(I&c zYbW%FdGc6XB&puv{n{z8Wg`#8(|Fj%!|k*Av)aS7DC9US$zNR}Zz36JkV?I1sS4>C zl}+N`EaOEMBTKZwiy91CgkLB$=DLWGbXuW_tO%i-4|O1W=_|=r#$Z89gF9Rnvts z77?QK;Uih2&=ahJAcfY|NFJ(z6htp?k$g?+h#>r2O@tz2Ey_q>w+d{MdYME~qVTYq z2NkJIdZ^GZRp|bRglkX|F0B3{?dVdGgEORKX3vnRQC{f4*@r|}&ORuAPavdBeeJ>< z?eNO15&a*5oY3VhTC+joHbvqJl3>xUJrdStg$cnvCDX2*FxdNXfx;GDOroN z^sJ$!51Wk@1{c;LJSdG9K2#$~mIt&%M7LTLsFt{erpzGn&511$#*eUo)e@`k<62^M ze0)nH-JZ~rNUy7wFj!?;Y*15SSpD560n+QU-r<4SkVoll8T3-M*<0jU4OO8R(~LG7 zaUi_%wqhG|QDsh&zpy6BD-X?8;;Lthu(k}No+k3@=?N8+#W+Ja1Qv!HRL(rIwcrt| z$f88aH6&R?dJ*3&>EDq*|ChXXkB_pt7Qbhb00{)2M1u`hWu#+G>ZPQjWhCkhOyn7v zfmp4VdP5N;RUw9nf(lHSr0{f{)>?XMPwgpfPtVU@PK&)zNG)VSCJA^;@B%`WfEQ*Q zA%IFQO6L8p{me`zNYC$_^Pcm^`+5DyWIy}9*Is+=wbovH?OoY>o3;vWwPiO%R*Hw^s0x|hIhJTyn#De^k$FjUqv)?n}`-eZ}WM#jR5Bg1nbn^ zcdb)$sx7aYq*qAz+B^baZtXRN9=yv$Yt(+tQ*L?+U8^fB)+*N zRqlO>{dH#ZW9<#8ay^nxIram|k>32K4R3x(m`Wep@WFcWA|k){CnX|ljmyVS7ER&W z?+_s2#dLyvD}h#P`h}VFhjfyB|H{ISqcv?ZlYW>^l5b^Sf;T#Xz-$u#ZW7?#YYQPv zpGw$d;HOJM$Dw-crI1!7jJ_)b@BQ}mS3dlL8Qv*aFPf1pNf3I1}lA*o62L$YF4 z5k>#NTxnnSAsVDtz0Z@K9jNYAp@m8uc!9*;ekpv=jL(q2Pw8y0a6w25BqLi$F_KL} z_<Nc#NcLyPP9fFRcO-YIRQC}!KUzYNL1?AfPARD$=QF>;?E)Lc z$w+=ALWzD=qD8t_otEf6iT;%63|L^Iv>|r%RT5y|VEjX5X9qJOp~lUR5C++6O~42t zMZVM$FHo0ReHI~=2FxC25mM=+IeHbzrmRMz>Q&;a zQYi^Csi9|(sgoEbb4v`0itM3hVbbu>voL8l^N-{TDh#E!Xu%{w3x!D_ks#Dmg++qv zX|4@4uRS0L2P-G&A;CT+y)KlEnVt8JC2Hp#+9iOM?Gy=spFX!%1`T9)X1JGmmYUl$ zgig^m;t~X*b%Z{l8o-aBYEr>nz=o0XBlEQ6^^v>t0R3Q*QtlujllC8sL9>Mbk)W+w zmD-lICC@2R4SbcP$yk;=o}%JIZ?Ii{gO$S;D)Oc&ma;X|^`vZ#k5rQuAw|ihPia{BL{n;?+ITZtGo3Pv^_a!jLn!u# zBYdGAU(X+P)X1er6#mA?vE;GQ7IE;%oy|S68yj_Ed@-Cet{&=4=kCtRZEn$xx1W@M zv9y%V|FaSKW#4YpPs;yRoc7ZB9~_aNGbgR_(v$N44!_k(ZJqf+zP>rSe2EqvV7n)9 zldWz3@-w@Ydb!QDd}WuYm+|u3_ICN?7F5GANuS(e&1jw3&D*w>PmU;+a@)-1laHn~ z%2Fhvw8?F6FQ2?0ZL-$5l3~!wIe)(Y!(?>%syF$!kAJt>pWt^p4K9hx&j4SXe9)=Z z=m1E%Uj4SHU#I%*A_sgPzpqPyZUP*<@H^E`I;@!b-S9;8yrKQkAN9T-{e(R?I#_$` z+33JfJBg?-q658==uya0bfE4?VRRtzMznb7&9;c6cN^JTBzw=Z(Km+B{;C4&qu=Xo z$ttis5szAjUT%vNP>(9`h?Lq)ffiMuC)&{48I9Lkx6bx-|JK(VFZaYw6>51;|{U~~L=v}hj zLt_VOB>ooa*x!2~8llqwM1kc;y~Ne+oJh})jfut+d+Br<22VtbdwXcH?$wEHk%@I5 zjo~-(TGYd+dfHsYz3%~y;WXF8M0>Phs7+N25PP>ryX(3q3N*$bd^HFxpHkV9^f>(5N?{O-6(E$w5;E+jvKdF6R8a+fFKo@1qIviKvy#qU>byY3?TG5fte5ua|p{t3?v2)jMPdyKitht+(OhjvrOuPB2_ik zMeC3pX}3j!aTQ!oMNBpn2pXfBWeu+ClMFosRL}X9FspCL2dSM=s9sNs>fHj>qvXA| z=-{feqR)bvgR8EkJ43AmX4qI(?Gl(0?MGkQ6YVda;grQ3k;rPMR~8+?d0-#7L8w;c z43JYvrGo8}dA00&Du0W7$wn15hB_oHTVC{$RsY-~f1jnsCnQ#OJe9vozIx=Vo3st` zCA%G`lBi*CMiOOYb8XP?GdtN5dTh~wmD`nClpSH)gX{>R7H!+MeDZEaeq{7Z^=k}Q2_^qish+Fav@nAi!uAGEnH z>+NiFt&;WbTB&|lL2x7t+4;c`RgD@Nh(@6lC(tlPU*wQ3`eFjy9Ys_)6BSMzr{bRI zl|$`qGtRLbYnw5_^1ifixNXLj@_CtMhqU!ly3V82*%A#?NmE_dL@GZrCfbx};p_E@ z(u#c1W^Idu9~Q!i+To2`x?8qsQr zv|5;MH8nPAH9ZgoAafuBB^g7yA^{1VRWL|*KTP+5NUHneRrilT2k7+oGyOM5aftQ3 zf}=WF)c0ZT!94Ba-&@fYs|c?;&YEO;6BCFV_2VWr!780nOM0?6&bGG&wZO*75m{HW zY!tlgoA-bLk%?+4 zMDhzGztsI5t!UKi3qDM0#bZdk9)}_ROEEbW^QF1ydN8=K8{1;!qE5@3sKvu3rt4=l_l=B*_4dt4wSSZzsdCssEXnwP@+kFPBL&!_1 z^i^!6LUS?l^4PGjNbVnL&->E1PHq6F63U~5)^y-U`RJ_hDxoz!{B*u0e)>AeJDh&{ zk2C52=O?7^{DGv4HDC*+#J(Ssn$qUAjBfKN8FR%S^DUuqnAETR37>|%u_QUfUbAG& zQ}<(DBzAnRP5KoW8QFiIk6_W;f{4>--$1+ytWO67HB?N%47ink%B}QM*y)huwmUIR zq6vfyb-)(8=j-{(`0q=w?o_>fq2|X_ZlSg-@~jo%qVeZcRnZbZ%parkd`x*(1^YFO zVYVcfTP&{}b~YaK->HX6qCNBvQ~pq1bP*x3opXxKm>Bq$>EYYV5tVJRkk~w)%3Paz z9FlKeZ0_%v7>4WIGDQ-_yOL{Dk*Z{0{5#NLs&Hn2;@mP_a$&xnsv>?LSxlg?5i>|X zV)CwTb;X-Iy3>eI5ZKkV$wna%aWqn3X98WL0FpAbnKDyU2CZ=lRVwg^Ysn5G7itfR zI%n_rop&R~s)F|*o9`X98ae=6v7FlIwOd0a_Gvq`Sv$B7m&bz^_8jN5quMnuNif$8 zPV3gL*}{!*Q5B|MSk#Wt83!*&UNCIj!XlV>IN)8EQ`fuphWW#$^% zS^&_ks9OAu_5eYk-?hm}0MFh{_|Z+lYe`!0PR&nsD#tpNgR<+1P-W+-z>-cW|BzW; z(DLyV#_x)Nmp_PXswG?eM$*mowSiBJ;zCz9C6_IQ7NDCV=|I2?oN|4r zRl@lF_9^BHnejDqg*4Oq==*-^b1}G+htjT#eN+rFrQDn$U}pw{ zi>NY#^(=;ejP>&}Wu~YyTH{y$A=dx>&XHLE_+9^B!+Ld-YD(m7i5=`XXutwTC(av^{vvM1Kxl$8W56*6UEemEQR1AsUK?`jj? zO;4mT{|S{!*?B5pVt!pV=C3z%WMlr<6y}>M74v=^7JXt9>J43ae;8+EVgUINUgxyN zW=bpP_u|&;FjWBp#^%HKZD!#VW4NuF9^JpanK8qZjITL0zvOxoC5%_W7{CG+LJ z%9X)%hDXil#6sye?*1o|(;RV07JsgihJcFOz%zw%zkaCJ9BBz7t-DZ0xo6nlyNtK~ z%-F-~f>$%cPR4Heybzvc3vrwAg(dlB^`?KOtzW)wxc)q|{xf2aoK%0J zj;HIOImW1ac<{{x%+3WSV44nsKFVn+4TH))Pv}5c}{M5wH>WY?z4!N?X1>Tfl&hOJ} zUQ+G{jFj(-xGgfE;r^mqUFdrqr#gd^0Kh`7p+f;>OGdHQ)w>PznO*O%IoFE=EgAobzJ+Qz>~0(rP<$Ki8e54YF?a8xohA34wKXnzKK|Tc{!Vj)j z^Udv$H4=jBJ%dHy&#Blerobs}?l!G#)Vy0igegAmzX*%t{NtmoddFz;Tl{D1!FH$` zw-MCouvT7ZPfnP*7%OzK<1WToDE>~_#mwa7gff!agVL6D%Md_jNz4<1~<#J&INN@KTkt%ItF*eT2#(2UH zS`!aG!9Dokfk|8{y~P@Q`)V$-?|Wz}d2Y#xygk|_F$H^xJW_Wt`SVD)E;o2!Oyt1n zT-zl5z|~a+dt3!O6J;dl@VFRX#?Hi9eC0+C6uJstsY279E#D(Ac+26bc5s>B_HbF1 z(e2ZI(YbUIewsYSQQa}5HQmCRf#~gw%M&l+wXhw-auOQKIOclB3&GrERnzum zXL`doC0)S*+e3FHRt(c0F#FCSJV&&wIG4}~2}~mAr`pCPp9bF@6M1(ugDglSiisRz zz>`$yMDT4b3jiv(pRv9n4Lp2qm9bs*dICOey^h!6wdk@g!|LR|mR^2Lw+<$H)dDvC zZ`>egyFt1y*AKwl@`_~gOty#Apt$=GoW?nSP_lH4rZ#aH=Lxpu^E}%0Yw{mdmuE_2 z=S~D4z|7L-r^qQ+5+;Q1E3ml4nH4*++?$YXSzS^CzYFDh7Z(xVi;d#OfG0T`b`=_w z>n{_YwMZOHn73F{43$fn&~rD-HiIQ+9S7+<;v#hKRe4fcQ1$FH(>DoB`XuKOp)t6T zh))U^`YxnbMr+?5P49vg&e!L+;s!;$h=}hYYpc;sw#eWp>yG<&RF-!d9g*ZDV<5P{ z(z;8Zze}$fG_&^Fth-!BKmIEwMUtc3)(-c59hL6#R&|lLf0B?a%DAlEE^EKMty}13 z&_&h=LF6-T+xYJu=1z*fEthUcmng2W!6cgZZ~%ownGa;8qZC`CORj2@t;yVoENz}9 zKzSO`RjJzkTP+NW)^JHuoiAOT2~CmzkLV#S;IP)8U#%x2x*^Vf_iuS-HR7yL1J|Za zl#`igMTCH2cBNB@i_gK&SGuOu{DiI^7O^!WBVzjr#`mp0IeW&Rqj~>!=%JG{z$r-w zGyS47$`Oid)7n(OzNGqsAo8 zRs1w~%G-TLpC^*M+7r(EoIYy$z}SH4Sxput-dXFu8Nx`^YaMK8CCy^&irvDYom_)) zH5`;0s;qrRuG@Gt&$ut&yqh8qLAmaPFtGgcW#K7Q1Y41ncq4P`ZpOXk9J;xA5h2&6 zetu)~Ph<5J%_QU?l!1V$uQ8`UYU;?dSCh$$oKv)=mXJ~rY+eUexHg&FM@Q^olpiSt zjyZkW#)8QHTs`!?044O$v(LyM@aMFRC(n=g?|kOm;SR975BKoTGt-1MfXnC>&LH?3LHuA#QNzJ8WN{aCG#roytUHWpMs*(UvbRN&Lanc?80%(&M?f!Z9|$lCbIc%OVHIyMSa>d8exYTGSE08!Rz9lQZ0zrDH@B zf(kI%q0dixYdTEFClM^F@R1^pPdck=TBKE%F;G<=slx3|q@SMjm_6yFCjrGm9URZ- zgD)4w2U9Z4|H^z+{a@ze&jQ-)`2f!8DRCQ?>^b?anv+cj&$I+^P@{Ol*BGSC$}V5c zP7@HX;F1DB3<8KfRi*)bvZAJcgLNK^u}6 zxUDbOC}vo($^&lWWp=HGgVGz4w2fP(GcK50Fu)b;EQ%k?5-;UGUHq9Flq*-YhUL2D zJlf(?Y}Td9KnrEKx;B&*w@KpSg}geDS^NaleMbDf8vUpA@fyApq3>b--J9(}RJpa4 ztC%pC<1-#!@46t{HKFKL;5XzxA;c=~Ch^q1E5CGdu~;cF;@Qx0+L(-g&A`>8c@pn` z#>wWUFa8G|{V|EB?r6iw#bQf{k&fOpKEuTP55lwfVvZ)<;(0{sk{MqFGjGm#KPaBLDBebov?BABd2vsmI1-M4OaQHA z#w09|T|eHOUsxFvJd)5!LQjb#JZHY;9bTspdT5>f8TpGe zViRYwkB7xG$e+w&LXMPw4#D=Flfin?6Y`crJvPd|NS@3k@Y}ZuLj6zRnbIMOAQ~^`$2>!nF2?Mr4V4S@ zllGHjtoXc>!Jf2nJAT2bbH7d6h)GHyT5Jlk>>Oa()>h{5o1YC z^(T8mR*@>_WcQBA(0fxJPdNnG&48e3Q^hHz=rTFfiG?mi)-~E(;x5g^bYq>pi;Q@k zU*-yZCqPh18h=vDAoh9k2P*9r+(+QlhIc?3f5(iN&v=qGAedjhI&Sp$m21Nqe6tm zCrwP6aFQgt_1}V5p76KUs$N1TT%m70L6~avE5(Ui{n@5>&3c>E%8x~#&e3LlaeO=3 z%rx{FLJy_msakKut-L36xpWhs_bc-=il^Aw^c2VZycc68*)n>onAJ?0l1`d7T9=S5Jbd=e4Hw1elMhOq^PnGHMjt@_6|M5k5Ga zd>}9|N^4xrw6fN#!`BT326#hqr+UL&o4G?yIyDmU6(&xrg>Y$2HpzX1eO~yxtB_P0 z29h|m#jSPt59)JBKAqZ=?M~ZEn*}X!V#+p@AY?4dQxz+xR>rRQtHdd!5JEF8_SlhacvRkEZ0R$trvKpl-6)s9r8ew$=;^!)hI>**Q0QBB}fm z4w;N@KO&qky62;4sX6{^?9SF?U+{hcZ+(x`sg+uY%0du@&2u$%0Wi#mI+#$r{X}UpPH$ zS}i*_l`w0#rqLY;@fQg%{LNJSJi+`T6B)|I6V`#PEvwM#+o)=DH7gAz3BNI0GT)N; ziqxd`H;@MPE_-dYh~3qnDYIV6d@v+W`6z;dS^-R{qEf*W|McNmP*@Z@?`)I06yyq< zhTnLQBlhV>>h+(NQ4o9L@WJsuF+zk6hqPzVq&3ZO1UEp7S_dN^z zp62=mOKTTAuw<#e^{%=Fix=Fx{C>~o2bSEk_^!Go_qdE#P+g+?>ykH)f<68I+3EM1 zt_>Al?y2bXS#ii28Sk}r_$s9F}Kx;zy- zc;6|XSCs1hhWpSwZM861*MurBS4sso=IvIu;|*=~I-=vh5)g3!(**>Z@xW<`UA8e7 z9sqi%bTCb_c48G@6lG1Waecl!Exl+>W5IqOn9G~M{9A?8V!D1wxm(Hd?jrt7es|VM zn?~$uVzBC!bA+mjWV&BV&$>2TcsYJf@myILr9&3aEARLU4(h?q9Jgcl(la=vnxSo+ zdO1&naV`6m_dErCc>bH_Eg1Avbp6+XwNr2COVSD@0kJ?j4Q5~rr~$LUSU_!p84xQ- z|G&$3 znXFmthHvFsP;})toKU;QZQjsD_Sh1hf#>M@mngy|;)-7|jjPDYiSjJV}{whleiH`;Wvr}Se>!bJw0{5(1uC3ygC0y*JUGVMSa*P=lw-%z)zGJ1P4|X-%+eQyD!I9r3?BCF;}c)~=G`VgkfV5LvZ;TcXEG^i|o>Hlh<3 zWXIej88yi`Av@Y4peQEVwaG#bX?yZ#+FmPVWw&!}T9nFk;)f@9FeaI#C$3GMsZ6`g zOeoI`Q&AjaDpJN>Po?twN##lDhtu-pQ&c0ao`$^(LZgean6XP>m*Copto4c+gR6Qg ziy5<-%$VcMp(L-)CC-zb1ZQCENkZDnh?6%d;KuOhTZKA#TWrpGig|>0WR=MR^U8IT z!PuGdERVFE`W`Ka2mcdL9TfgY$%2acQL9j2_)Us%|^k&cL*}H<^<&;=Eak9poVs6s3M8wcX_+f{K zYy+d%z)jeGqIEK6=C$YYCTH8tS(r%8$#Tow6JB-#S8aLP8j+l|jShEs zZWj*l$JW_Uu)6~L_u-I!D-mba;g>LZvA-agyijY}11fPS?y**duOs{5*t+wSm-_=` zZzcQSS#?D`zH_mEEN9*1|FxO_x}2);H^~2q%KwTh@HY9kk^d8we^BKgB>yAi_i)Bs zUs16gZnR=A9-x&FW7OugJM%4TtBcz$McXzXoCTe~l%8*qQ2c9VGq>cr!nbxwE7+>+ zr4ibYCQipfVQ=sg8N??vGQn&luf8DFNTME_g}m^6UCzJ>dT6}q47|I~8Hn;K#)-4) zinWc2;0Y;wg2Ezk(8E!@MkGB_E738*yF(V9(VBT?L&~=Kn_gn`9BW=4}D0l51XECUOnz zs;HaP(^h(R9wem z{#<;5`iN`pI)dyk;I6ae~K>d5c^_F=H$tfqfTj3H?A)l z?gWh|ri<<(ckS$P;y&EUiy{Tk#5`duP!-QCTFX;cvkT)*GDaDVXhrGtzL*1AgSD+) z_Hd<5%UAR)Rxy4ksi#Nlckly&}UEc6KHl0NI@Lp~Ut|c`%FBbX5@O5&$CmFAsp6or zTZ%n*zR>3T?H5Cca_cWvT!rl9=(0>@1amnPwLN~K)lLtn0)ja|qmRSy52NimM;r?K zF^)lJsGMX!toGFx6x-yFRVB(f$)EO6&6ps<1SWp9;6|SN@Crc-&BuzU9>4 z=Te@DhnIA03Q1~3UnZR?Guc&?Xi7g7=d}GK#Ib;&r$U_mu?le(#eP@?;t1d3Qo5S0 zHiG8;l_*(MQ^I3NQ=;=z`nt#M>j}y^!Y}2op@XB<6P#-oox@8t%g$B$CE+%het2jJ zEmH?mWLAqNr85Uc5+gjafJP2I&dCg^%rvkU;NqDy&+c5ygi$?E7J*pyS5X-)Qr6@i z@n^d)_R1(CPsZ(SS&H&cX5)$&@`Vg=Ja(851O)x$7kl3g1n(?Y`A<^p5<@% zhCDp1ev6Yw+Y-bv@f<0;$IfAUI`8!B`yZR&osR}(rxv&s#2^bVsy<);t_Q)K z$HINq=Y7+!Ke7T*ne)R(Dz?Y}9Uugj*XP!YSfDk%$!D{Uz*v#Qi}SB>o39ej@`Psg z>kcThm=`oZkrH9QO}fYw!HBLF)l0EA%9%gtWw3vY)+i@6n2<0?tx3c@Szv5wv+@%w zU_7|EA=Zc4_RGdAdUpct(C0nIOY%VaTt`WTN1OY+UcSd;JkKU)eRwYc8HoZr=@b3q zw5MCq`0Cbf>=CWq{x9oEOcEnYm*QwA&l7SN^)xR_4eHNF5i^7k)9?0Nt1N#^!|6JOW+Cc{8S0qCmi95&tj@}Bky0JAicm*e z62EGmrz&|_UVC|fdPb-dN6JS)OoSZX{|=2cIwSq#d0-R=xI7(nflDo7S9!!!6A?Wy zmQWWYTii9Brd`AHghWy74c!QWTmyoDl-O8ljp%gEZT{b(^X||iXm9So&~LA|=0nq% z<0DVx1B^L_c=_kOn!QS&{K>FB*=^nK#+Dcrv-J(P^=L+??5#N}I%PJ-s?bR2Pk5|{e2#Zr+S4sg?Wa+9S=2unPB7{cw4LU2yr(^W zh$?-K!>hg>pGbAeKAlhPacN32G%Xg%7vz8l&Zr&nPp&G_m@T%2rGlhaHLAXfKV@UIrf-u|Fpt#@`n6lYJ!gKq^PEv} z5t~ohh%r&MA$+ftEE7!xp6zEBVJfYjHaFK?xH^xkpCxX`^DCV26QxESBNm0D@s-eZ z`8+75hnO*bY1b%qL&y`J;rdi`>V1wxMd-nNRh$B2VOmNJopOQ)sq$_k-?+IbQD6?j zc}||$1!cEzn=AE7XY-Nah2lP(Z)x7mx1u?h%U3>Phx#hxE3=43@W0OpSVf<44K1rZ zd$gP%06QLjAmV1NC`Wb@T@Sfb1d1GM`ZOOsOp(rERFS+p;h)0-f?~QLWqnMcPxt-=+8MGnZ~+qQXb8x@Zno_nu@c z4y8SiFaHI)gMBBi`x7kG;BCgvhPm5pio9i&uno-ZzC~A0&RW zC^fd)Nc04+vS@3c=d&s_Cm%C6rO4OT3Nj-Ta!&OyAzye7ue!E+`u4c~%BLl9j_Qwx z{>%+mp5;k)c#_+=c>*W)W0HN2ZA;(w8ap0=keiZdQ$MTT>R{5;& zddp9EH0PnJkfSP8bA*>=s~o*#YI8NTNsg-W-YU)c>59)wigCi#_hwe2t8bqq>J2B7 zal44`k0HWJ`->>5#;{>rdN#y)f%0^g@b@RPq?rI&>m3|_k~0T zo>TlsuGV;tfX;fr8~SFy$MLZiyi~I79iBQ#H$K)Q@8)?NC6{c=~;s2g8Ts4mYH zSdj-xZ6TAh@woqDwEd&>>2;&(zo2dgZ5Wp*V&zX{HJr@`bcWguSTyWPsJoD1SRq9u zo?*-^Fs{c6iK`pN?9vg;w5+cwBFz+MPM}5ga+d{8izIzG$z<1(v1?LE^M;dzaTb~D zLP=8hOoTcNi#6NmJ-6kVG*RrXCk@8Fc9@l&IWNO*7SF`-KMR{}-zkA9V$4H`LrJad zHV(IoZ=Hf64`f5p*u)df(|}%LT=O#!Fpu#uNG0bPwej>(r3g;EKQ3a&zStx0rFlIe zYGOZz5EdNN9=<>b$>qEqU9o+bp9@r;X3^HQ_zQH$4n6F#)*s$h%_Ge}*az1IqLKs; zlMe%vGQ!THkLs;0#2WQ%`sf8`)`IgSVN( zvZ2o@+AM%}HC%PWH)YvWA-EEKq}0;Oa&?6kmy)T6Ot#@n1k;&zkf|!P@@z8w-4|ZSIoKD?n(ijJFjdnp zRi?!@GVLZ)*>EO;=}ZAKxea`8irlihDzw-REq;|DTqK(7BWfHnPpubujT?(xp*zZ| znhxxgYSM1EMt9(7uH0hb ze?+5jFfH2i#@;#Miz>V_6t8iKnUAL*Ze(HKX6J6xUOjyFtrBkWlyd?tTt5XnrJ&HU z7BAXx&Tvmi4Y5oOJeOzI(5Xr_nWc7X&%2C$fn!$T?!zTNPy~STox)AUyw*etY(6Vz z1UD9W!{5x4ZF9Fz`+cvkJYMJ0UNjEP30Gbyu|3SN*{L;86x?fEKR^P;vMk2T>H zWMUG`+I-~$ODDIFL3J}LKkmV}VY8g;xt?39W}%dDyo}h{;k@a(tO@~`IShy%6FNrF zT{q@(s`N0tp&Ny~F$=)tsCE6OW14tMdWdb>L=G=4^G>dT=k$F4sp9psJ;v?GxepY13?E$00!AD|xR?HCQFtAL zQR%fsYrL30uJ)?@JWoee(KHWaxudG|5|R>J*@0nI+@T)&lf7T{v(avm{=+iPlifiy zdOFr+yHklpsqfCzx7YwmW}9TTr4nT#oA_m^coPj8?Sa&HSE>?oQcaUl$-h38-oxLxRecCl z{(l0HlC(hT{jY55@}K4n{j1VH`i%Ev$~=z0 z^PZ-8tV~}6$OWHf=Ie~%Gsy+h(QeM5gEDDzV>6C3U#33LWGnk(`#w(1m)F>zm@4~J zkr0twAtHqylZc2B#W45kF{&)_g{T^p*;NIin3}kZx|8F9Wfb7hJN2IWuVwWqy3)5_ z?|xqo9vJe5?O*c*KOMbvx(uv^+#?3&o&G0TYnO8s z*+>b$^Ujuz};q}s-1qjbk}%4SykmLQPspp3S91Dv7O_&O0B z8V{<1p(&^g*#D%Cm%Q}6Q&Pi))3|(hHJU2sH&8jv;zz-_o!2A0j?VhSaWOeVx8^PH z)E)iW>IGCQHmo*n%{K`8IP2=$?a^j#XG@nw^6LZU4$?!hN=y`Qq>p;I(f$tKS`nJy zDh74GeVKRq{q{xmyj=B|eNpU}Wn^M#?1*vEA!$Wbp{!{{_@kF6Y!l(BrGIFMK5E0k#Y;=avr@ddRl6mUy9-0reNXQT^n2 z4Q-@W_&cY}BkRg3z%(zgQWQAhpS>ebYrGE}lDmHeLVj%iv4my8_a#P4ps!Cae_fP? zSitmY-`cLK}XgY2po$y)mUqEXVVa+tttsfn@8X*NSIw@&B$3EEB79UwElCJzC(i`ZE`)K`BuE5n+vUDWAbG+5+KPxjM z|CXAOuaYzVdqyX)m6=iM7L7^C@D2=1Hmz9h3rIlhfHBEM?j!tV|L@@s;_BICk=iwn zu>z){zBGOdF=9lHK#3M^=o4+tX&{=SktX~yh~QsBIs{Xk#z0H*|0+lT*-uR8G*HTy zB56Z6P0Fc*Z>9alMWrdKRxSE=>{WE@QQk+>xqZIoIuOH)Ud3a)94Z&e=B)p-ps_Qy z_i%*G@L#NXw6m4V1n(|(fVXl?`Fq$(L_ok~?W;WEBnDp~ zCl6O_7Zl3T)MV9lz!;p zKbd92&<^^ihaXq{^M=XHw`esUMU4?(fz9;Rqnx^Lkrms#2vms8*uz%zwu~k{sv?v9 z*NWEJMFB2~)fZ*d<&T@A|I6d{)6}0WEqexF>13-!dS(jZnDLezKC)8P3rV=vyJ{$fHTnP*sT(ObynvC()p%0h%MjT zlgU^b`-)^d^RpG4MZ7jHQJol_$V)tw@T+6P6zZRyM&Ww3fH{^qUO!KiK25K3S~wEp zS0Bp4`0m8`R6S||v`XHr1#n|3uT<#&eI~E^T(8!`@JjlULsQ1i|C^h-z zdI&XtxbRGX!6HAqs-gv^u8_qZX~z)hc-?7g6K}1LCyFa}CdPZqTRDki|KG(k?4sK@ zmgVc#YHXCzOvf79g#yb70#vC~F4tJ=OWJesJ%C>?V>bM&+*Fh&rMZdyIi8-h)=$

nQ{Jju+qp@IhHTW*uSl=I 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


RYsHSDH#Y5KpYp&Ot*zbrfR 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∼uKa-gb6^)XXF7%-?%W&Y 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

o!L0 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¥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 a{NH&ocKsK>XRd$wZ~vP6ss7!){{H~_eVK^> literal 0 HcmV?d00001 diff --git a/proxy/src/insecure.rs b/proxy/src/insecure.rs index 4a32adf..1451a64 100644 --- a/proxy/src/insecure.rs +++ b/proxy/src/insecure.rs @@ -1,5 +1,3 @@ -use std::process::abort; - use proxy::edge_node_dc_callback; use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; use rnex_core::common::setup; diff --git a/prudpv0/src/crypto/friends_insecure.rs b/prudpv0/src/crypto/friends_insecure.rs index 9fbfe95..1f05681 100644 --- a/prudpv0/src/crypto/friends_insecure.rs +++ b/prudpv0/src/crypto/friends_insecure.rs @@ -65,11 +65,14 @@ impl Crypto for Insecure { packet_data: &[u8], self_signat: [u8; 4], remote_signat: [u8; 4], - ) -> Self::Instance { - InsecureInstance { - pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)), - self_signat, - remote_signat, - } + ) -> Option<(Self::Instance, Vec)> { + Some(( + InsecureInstance { + pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)), + self_signat, + remote_signat, + }, + vec![], + )) } } diff --git a/prudpv0/src/crypto/friends_secure.rs b/prudpv0/src/crypto/friends_secure.rs index 206efec..acfa3bc 100644 --- a/prudpv0/src/crypto/friends_secure.rs +++ b/prudpv0/src/crypto/friends_secure.rs @@ -1,10 +1,18 @@ use hmac::Mac; -use rc4::{Rc4, StreamCipher}; -use rnex_core::prudp::{ - encryption::EncryptionPair, - types_flags::{TypesFlags, types::DATA}, +use md5::{Digest, Md5}; +use rc4::{KeyInit, Rc4, StreamCipher}; +use rnex_core::{ + executables::common::SECURE_SERVER_ACCOUNT, + nex::account::Account, + prudp::{ + encryption::EncryptionPair, + ticket::read_secure_connection_data, + types_flags::{TypesFlags, types::DATA}, + }, + rmc::structures::RmcSerialize, }; -use typenum::U32; +use std::io::Write; +use typenum::U16; use crate::crypto::{ Crypto, CryptoInstance, @@ -13,7 +21,7 @@ use crate::crypto::{ }; pub struct SecureInstance { - pair: EncryptionPair>, + pair: EncryptionPair>, uid: u32, self_signat: [u8; 4], remote_signat: [u8; 4], @@ -34,7 +42,9 @@ impl CryptoInstance for SecureInstance { if data.len() == 0 { [0x78, 0x56, 0x34, 0x12] } else { - let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) + let mut hash = Md5::new(); + hash.write(ACCESS_KEY.as_bytes()).unwrap(); + let mut hmac = ::new_from_slice(&hash.finalize().as_slice()) .expect("unable to create hmac md5"); hmac.update(data); hmac.finalize().into_bytes()[0..4].try_into().unwrap() @@ -45,12 +55,12 @@ impl CryptoInstance for SecureInstance { } } -pub struct Secure(); +pub struct Secure(&'static Account); impl Crypto for Secure { type Instance = SecureInstance; fn new() -> Self { - Self() + Self(&SECURE_SERVER_ACCOUNT) } fn calculate_checksum(&self, data: &[u8]) -> u8 { common_checksum(ACCESS_KEY, data) @@ -60,7 +70,27 @@ impl Crypto for Secure { data: &[u8], self_signat: [u8; 4], remote_signat: [u8; 4], - ) -> Self::Instance { - todo!() + ) -> Option<(Self::Instance, Vec)> { + let (session_key, pid, check_value) = read_secure_connection_data(data, &self.0)?; + + let check_value_response = check_value + 1; + + let data = bytemuck::bytes_of(&check_value_response); + + let mut response = Vec::new(); + + data.serialize(&mut response).ok()?; + + Some(( + SecureInstance { + pair: EncryptionPair::init_both(|| { + Rc4::new_from_slice(&session_key).expect("unable to initialize rc4 stream") + }), + self_signat, + remote_signat, + uid: pid, + }, + response, + )) } } diff --git a/prudpv0/src/crypto/mod.rs b/prudpv0/src/crypto/mod.rs index 5fd0d3f..f4806f6 100644 --- a/prudpv0/src/crypto/mod.rs +++ b/prudpv0/src/crypto/mod.rs @@ -19,7 +19,7 @@ pub trait Crypto: Send + Sync + 'static { data: &[u8], self_signat: [u8; 4], remote_signat: [u8; 4], - ) -> Self::Instance; + ) -> Option<(Self::Instance, Vec)>; } cfg_if! { diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index aa68194..e94ab46 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -1,7 +1,7 @@ use std::mem::transmute; use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut}; -use log::{error, info}; +use log::{error, info, warn}; use rnex_core::prudp::{ types_flags::{ self, TypesFlags, @@ -146,6 +146,15 @@ impl> PRUDPV0Packet { let Some(checksum) = self.checksum() else { return false; }; + + if checksum != crypto.calculate_checksum(data) { + warn!( + "checksum doesnt match expected checksum: {} != {}", + checksum, + crypto.calculate_checksum(data) + ) + } + checksum == crypto.calculate_checksum(data) } @@ -230,7 +239,7 @@ pub fn new_connect_packet( ) -> Vec { let type_flags = TypesFlags::default().types(CONNECT).flags(flags); - let vec = vec![0; precalc_size(type_flags, 0)]; + let vec = vec![0; precalc_size(type_flags, data.len())]; let mut packet = PRUDPV0Packet::new(vec); let header = packet.header_mut().expect("packet malformed in creation"); @@ -245,6 +254,12 @@ pub fn new_connect_packet( *packet .connection_signature_mut() .expect("packet malformed in creation") = remote_signat; + + packet + .payload_mut() + .expect("packet malformed in creation") + .copy_from_slice(data); + if let Some(size) = packet.size_mut() { size.copy_from_slice(&(data.len() as u16).to_le_bytes()); } @@ -281,6 +296,8 @@ pub fn new_data_packet( .expect("packet malformed in creation") .copy_from_slice(data); + crypto_instance.encrypt_outgoing(packet.payload_mut().expect("packet malformed in creation")); + if let Some(size) = packet.size_mut() { size.copy_from_slice(&(data.len() as u16).to_le_bytes()); } diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 55b508e..aa603f7 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -3,7 +3,7 @@ use std::{ hash::Hash, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, sync::{ - Arc, LazyLock, + Arc, LazyLock, Weak, atomic::{AtomicBool, AtomicU32}, }, thread::sleep, @@ -123,13 +123,14 @@ impl Server { let packet = Arc::new(packet); let packet_ref = Arc::downgrade(&packet); - let conn = Arc::downgrade(&conn); - let this = Arc::downgrade(&self); inner.unacknowledged_packets.insert(seq, packet); drop(inner); + let conn = Arc::downgrade(&conn); + let this = Arc::downgrade(&self); + spawn(async move { for n in 0..5 { let Some(data) = packet_ref.upgrade() else { @@ -153,10 +154,11 @@ impl Server { } async fn connection_thread( self: Arc, - conn: Arc>, + conn: Weak>, mut recv: SplittableBufferConnection, ) { while let Some(data) = recv.recv().await { + let Some(conn) = conn.upgrade() else { break }; if &data[..] == &[0, 0, 0, 0, 0] { info!("got keepalive"); continue; @@ -168,8 +170,8 @@ impl Server { async fn timeout_thread(self: Arc, conn: Arc>) { loop { sleep(Duration::from_secs(3)); - info!("running another loop"); let mut inner = conn.inner.lock().await; + if (Instant::now() - inner.last_action).as_secs() > 5 { warn!("connection exceeded silence limit, sending ping"); let packet = new_ping_packet( @@ -187,11 +189,11 @@ impl Server { .await; } - if (Instant::now() - conn.inner.lock().await.last_action).as_secs() > 15 { + if (Instant::now() - inner.last_action).as_secs() > 15 { warn!("client timed out..."); let packet = new_disconnect_packet( - 0, + NEED_ACK, self.param.virtual_port, conn.addr.virtual_port, 0, @@ -209,9 +211,12 @@ impl Server { self.socket .send_to(&packet, conn.addr.regular_socket_addr) .await; + drop(inner); + let mut conns = self.connections.write().await; conns.remove(&conn.addr); drop(conns); + break; } drop(inner); @@ -247,7 +252,10 @@ impl Server { remote_signat[3], ]; - let ci = self.crypto.instantiate(data, self_signat, remote_signat); + let Some((ci, data)) = self.crypto.instantiate(&data, self_signat, remote_signat) else { + warn!("unable to instantiate crypto instance"); + return; + }; let pid = ci.get_user_id(); let buf_conn = new_backend_connection(&self.param, addr, pid).await; @@ -281,7 +289,7 @@ impl Server { spawn({ let this = self.clone(); - let conn = conn.clone(); + let conn = Arc::downgrade(&conn); this.connection_thread(conn, buf_conn) }); spawn({ @@ -297,7 +305,7 @@ impl Server { self_signat, remote_signat, packet.header().unwrap().session_id, - &[], + &data, &self.crypto, ); @@ -314,10 +322,7 @@ impl Server { return; }; - let rd = self.connections.read().await; - let res = rd.get(&addr).cloned(); - drop(rd); - let Some(res) = res else { + let Some(res) = self.get_connection(addr).await else { warn!("data packet on inactive connection from: {:?}", addr); return; }; @@ -335,7 +340,6 @@ impl Server { &self.crypto, ); self.socket.send_to(&ack, addr.regular_socket_addr).await; - conn.last_action = Instant::now(); conn.packet_queue.insert( packet.header().unwrap().sequence_id, (Instant::now(), packet), @@ -356,6 +360,7 @@ impl Server { res.target.send(payload.to_owned()).await; conn.client_packet_counter += 1; } + info!("finished handeling packets, dropping inner connection"); drop(conn); } @@ -378,7 +383,6 @@ impl Server { &self.crypto, ); drop(inner); - drop(conn); self.socket.send_to(&packet, addr.regular_socket_addr).await; } @@ -405,7 +409,6 @@ impl Server { &self.crypto, ); drop(inner); - drop(conn); self.socket.send_to(&packet, addr.regular_socket_addr).await; self.socket.send_to(&packet, addr.regular_socket_addr).await; @@ -429,17 +432,19 @@ impl Server { return; }; + info!("len: {}", packet.0.len()); + let addr = PRUDPSockAddr::new(addr, header.source); - if header.type_flags.get_flags() & ACK != 0 { - info!("got ack(acks are ignored for now)"); - return; - } if let Some(conn) = self.get_connection(addr).await { let mut inner = conn.inner.lock().await; inner.last_action = Instant::now(); drop(inner); }; + if header.type_flags.get_flags() & ACK != 0 { + info!("got ack(acks are ignored for now)"); + return; + } println!("{:?}", header); match header.type_flags.get_types() { SYN => { @@ -464,20 +469,18 @@ impl Server { } pub async fn run_task(self: Arc) { loop { - let mut vec: Vec = vec![]; - let addr = match self.socket.recv_buf_from(&mut vec).await { + let mut vec: Vec = vec![0u8; 65507]; + let (len, addr) = match self.socket.recv_from(&mut vec).await { Err(e) => { error!("unable to recv: {}", e); break; } - Ok(v) => { - assert_eq!(vec.len(), v.0); - v.1 - } + Ok(v) => v, }; let this = self.clone(); tokio::spawn(async move { let mut data = vec; + data.resize(len, 0); let packet = PRUDPV0Packet::new(data); let SocketAddr::V4(addr) = addr else { diff --git a/prudpv1/src/prudp/secure.rs b/prudpv1/src/prudp/secure.rs index 604ca58..9bd441b 100644 --- a/prudpv1/src/prudp/secure.rs +++ b/prudpv1/src/prudp/secure.rs @@ -8,73 +8,12 @@ use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher}; use rnex_core::kerberos::{TicketInternalData, derive_key}; use rnex_core::nex::account::Account; use rnex_core::prudp::encryption::EncryptionPair; +use rnex_core::prudp::ticket::read_secure_connection_data; use rnex_core::rmc::structures::RmcSerialize; use std::io::Cursor; use typenum::U5; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)> { - let mut cursor = Cursor::new(data); - - let mut ticket_data: Vec = Vec::deserialize(&mut cursor).ok()?; - let mut request_data: Vec = Vec::deserialize(&mut cursor).ok()?; - - let ticket_data_size = ticket_data.len(); - - let ticket_data = &mut ticket_data[0..ticket_data_size - 0x10]; - - let server_key = derive_key(act.pid, &act.kerbros_password[..]); - - let mut rc4: StreamCipherCoreWrapper> = - Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); - - rc4.apply_keystream(ticket_data); - - let ticket_data: &TicketInternalData = match bytemuck::try_from_bytes(ticket_data) { - Ok(v) => v, - Err(e) => { - error!("unable to read internal ticket data: {}", e); - return None; - } - }; - - // todo: add ticket expiration - - let TicketInternalData { - session_key, - pid: ticket_source_pid, - issued_time, - } = *ticket_data; - - // todo: add checking if tickets are signed with a valid md5-hmac - let request_data_length = request_data.len(); - let request_data = &mut request_data[0..request_data_length - 0x10]; - - let mut rc4: StreamCipherCoreWrapper> = - Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream"); - - rc4.apply_keystream(request_data); - - let mut reqest_data_cursor = Cursor::new(request_data); - - let pid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; - - if pid != ticket_source_pid { - let ticket_created_on = issued_time.to_regular_time(); - - error!( - "someone tried to spoof their pid, ticket was created on: {}", - ticket_created_on.to_rfc2822() - ); - return None; - } - - let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; - let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; - - Some((session_key, pid, response_check)) -} - type Rc4U32 = StreamCipherCoreWrapper>; pub fn generate_secure_encryption_pairs( diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index efb08db..b7ce979 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,8 +1,6 @@ -use cfg_if::cfg_if; use once_cell::sync::Lazy; use rnex_core::common::setup; use rnex_core::executables::common::{SECURE_SERVER_ACCOUNT, new_simple_backend}; -use rnex_core::executables::regular_backend; use rnex_core::nex::auth_handler::AuthHandler; use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; use rnex_core::reggie::RemoteEdgeNodeHolder; @@ -25,11 +23,25 @@ pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { async fn main() { setup(); - cfg_if! { - if #[cfg(features = "friends")]{ + let conn = TcpStream::connect(&*FORWARD_EDGE_NODE_HOLDER) + .await + .unwrap(); - } else { - regular_backend::start_regular_backend().await - } - } + let conn: SplittableBufferConnection = conn.into(); + + conn.send(DontRegister.to_data().unwrap()).await; + + let conn = new_rmc_gateway_connection(conn, |r| { + Arc::new(OnlyRemote::::new(r)) + }); + + new_simple_backend(move |_, _| { + let controller = conn.clone(); + Arc::new(AuthHandler { + destination_server_acct: &SECURE_SERVER_ACCOUNT, + build_name: env!("AUTH_REPORT_VERSION"), + control_server: controller, + }) + }) + .await; } -- 2.47.3 From dad8ac498cecbc319c67ec87e95c0f9c75ebff0e Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 1 Feb 2026 21:31:32 +0100 Subject: [PATCH 57/98] fix having fixed size key --- rnex-core/src/kerberos/mod.rs | 4 ++-- rnex-core/src/nex/account.rs | 14 ++++---------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index 88700a6..4b56f56 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -26,7 +26,7 @@ pub const SESSION_KEY_LENGTH: usize = SESSION_KEY_LENGTH_TY::USIZE; type Md5Hmac = Hmac; pub fn derive_key(pid: u32, password: &[u8]) -> [u8; 16] { - let iteration_count = 65000 + pid % 1024 - 1; + let iteration_count = 65000 + pid % 1024; // we do one iteration out here to ensure the key is always 16 bytes let mut key: [u8; 16] = { @@ -35,7 +35,7 @@ pub fn derive_key(pid: u32, password: &[u8]) -> [u8; 16] { md5.finalize().try_into().unwrap() }; - for _ in 0..iteration_count { + for _ in 1..iteration_count { let mut md5 = Md5::new(); md5.update(key); key = md5.finalize().try_into().unwrap(); diff --git a/rnex-core/src/nex/account.rs b/rnex-core/src/nex/account.rs index 0c7a6f0..b3a5bb6 100644 --- a/rnex-core/src/nex/account.rs +++ b/rnex-core/src/nex/account.rs @@ -4,29 +4,23 @@ use macros::RmcSerialize; pub struct Account { pub pid: u32, pub username: String, - pub kerbros_password: [u8; 16], + pub kerbros_password: Box<[u8]>, } impl Account { pub fn new(pid: u32, username: &str, passwd: &str) -> Self { let passwd_data = passwd.as_bytes(); - let mut passwd = [0u8; 16]; - - for (idx, byte) in passwd_data.iter().enumerate() { - passwd[idx] = *byte; - } - Self { - kerbros_password: passwd, + kerbros_password: passwd.as_bytes().into(), username: username.into(), pid, } } - pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self { + pub fn new_raw_password(pid: u32, username: &str, passwd: &[u8]) -> Self { Self { - kerbros_password: passwd, + kerbros_password: passwd.into(), username: username.into(), pid, } -- 2.47.3 From 785341e883d84470da04b7e55cf94d5cb09d15b9 Mon Sep 17 00:00:00 2001 From: Maple Date: Tue, 24 Mar 2026 15:48:56 +0100 Subject: [PATCH 58/98] fix port binding --- Cargo.lock | 293 ++++++++++++++++- Cargo.toml | 2 +- editions.yaml | 12 +- macros/Cargo.toml | 3 +- macros/src/lib.rs | 15 +- macros/src/protos.rs | 54 ++- proxy-common/src/lib.rs | 5 +- proxy/Cargo.toml | 2 + proxy/src/lib.rs | 2 + prudplite/Cargo.toml | 18 + prudplite/src/crypto/insecure.rs | 14 + prudplite/src/crypto/mod.rs | 9 + prudplite/src/crypto/secure.rs | 27 ++ prudplite/src/lib.rs | 309 ++++++++++++++++++ prudplite/src/main.rs | 45 +++ prudplite/src/packet.rs | 223 +++++++++++++ prudpv0/src/server.rs | 4 +- rnex-core/Cargo.toml | 5 + .../src/executables/backend_server_secure.rs | 1 + rnex-core/src/executables/friends_backend.rs | 65 +++- rnex-core/src/grpc/account.rs | 65 ++-- rnex-core/src/kerberos/mod.rs | 13 +- rnex-core/src/lib.rs | 15 +- rnex-core/src/nex/account.rs | 12 +- rnex-core/src/nex/auth_handler.rs | 245 +++++++++----- rnex-core/src/nex/common.rs | 6 +- rnex-core/src/nex/friends_handler.rs | 56 +++- rnex-core/src/nex/matchmake.rs | 19 +- rnex-core/src/nex/user.rs | 20 +- rnex-core/src/prudp/socket_addr.rs | 13 +- rnex-core/src/prudp/station_url.rs | 140 +++----- rnex-core/src/prudp/ticket.rs | 12 +- .../src/rmc/protocols/account_management.rs | 4 + rnex-core/src/rmc/protocols/auth.rs | 33 +- rnex-core/src/rmc/protocols/matchmake.rs | 13 +- rnex-core/src/rmc/protocols/mod.rs | 1 + rnex-core/src/rmc/protocols/notifications.rs | 17 +- rnex-core/src/rmc/protocols/secure.rs | 1 + rnex-core/src/rmc/structures/matchmake.rs | 14 +- rnex-core/src/rmc/structures/networking.rs | 66 +++- rnex-core/src/rmc/structures/primitives.rs | 19 +- rnex-core/src/rmc/structures/ranking.rs | 52 --- rnex-core/src/rnex_proxy_common.rs | 8 +- 43 files changed, 1532 insertions(+), 420 deletions(-) create mode 100644 prudplite/Cargo.toml create mode 100644 prudplite/src/crypto/insecure.rs create mode 100644 prudplite/src/crypto/mod.rs create mode 100644 prudplite/src/crypto/secure.rs create mode 100644 prudplite/src/lib.rs create mode 100644 prudplite/src/main.rs create mode 100644 prudplite/src/packet.rs create mode 100644 rnex-core/src/rmc/protocols/account_management.rs diff --git a/Cargo.lock b/Cargo.lock index b7ebf9f..b010331 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,7 +149,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -162,12 +162,31 @@ dependencies = [ "inout", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.5.0" @@ -187,6 +206,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + [[package]] name = "deranged" version = "0.4.0" @@ -229,6 +254,50 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[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.104", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -250,6 +319,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "gimli" version = "0.31.1" @@ -471,6 +552,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + [[package]] name = "parking_lot" version = "0.12.4" @@ -512,6 +599,12 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "powerfmt" version = "0.2.0" @@ -543,6 +636,7 @@ dependencies = [ "cfg-if", "log", "proxy-common", + "prudplite", "prudpv0", "prudpv1", "rnex-core", @@ -559,6 +653,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "prudplite" +version = "0.1.0" +dependencies = [ + "bytemuck", + "futures-util", + "log", + "proxy-common", + "rnex-core", + "tokio", + "tokio-tungstenite", + "v-byte-helpers", +] + [[package]] name = "prudpv0" version = "0.1.0" @@ -604,6 +712,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.8.5" @@ -611,8 +725,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -622,7 +746,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] @@ -631,7 +765,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", ] [[package]] @@ -660,7 +803,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -683,7 +826,7 @@ dependencies = [ "md-5", "once_cell", "paste", - "rand", + "rand 0.8.5", "rc4", "simplelog", "thiserror", @@ -714,6 +857,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -740,12 +895,44 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.219" @@ -766,6 +953,17 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" @@ -941,6 +1139,51 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", +] + +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.2", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror", + "utf-8", +] + [[package]] name = "typenum" version = "1.18.0" @@ -1015,6 +1258,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -1099,7 +1351,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", - "windows-link", + "windows-link 0.1.3", "windows-result", "windows-strings", ] @@ -1132,13 +1384,19 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-result" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -1147,7 +1405,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows-link", + "windows-link 0.1.3", ] [[package]] @@ -1168,6 +1426,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1232,6 +1499,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + [[package]] name = "zerocopy" version = "0.8.26" diff --git a/Cargo.toml b/Cargo.toml index 9d6ea8a..046a20f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,4 +5,4 @@ members = [ "rnex-core", "prudpv1", "prudpv0" -, "proxy", "proxy-common"] +, "proxy", "proxy-common", "prudplite"] diff --git a/editions.yaml b/editions.yaml index 1c025b0..5458ec6 100644 --- a/editions.yaml +++ b/editions.yaml @@ -1,7 +1,17 @@ splatoon: features: - - rmc_struct_header - prudpv1 + - v3-8-15 + settings: + AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + RNEX_VIRTUAL_PORT_INSECURE: "1:10" + RNEX_VIRTUAL_PORT_SECURE: "1:10" + RNEX_DEFAULT_PORT: 6000 +splatoon2: + features: + - v4-3-11 + - prudplite + - nx settings: AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" RNEX_VIRTUAL_PORT_INSECURE: "1:10" diff --git a/macros/Cargo.toml b/macros/Cargo.toml index dca135c..f748300 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "macros" version = "0.0.0" -authors = ["DJMrTV "] +authors = ["RusticMaple "] description = "A `cargo generate` template for quick-starting a procedural macro crate" keywords = ["template", "proc_macro", "procmacro"] edition = "2018" @@ -14,4 +14,3 @@ doctest = false quote = "1.0.38" proc-macro2 = "1.0.93" syn = { version = "2.0.98", features = ["full"] } - diff --git a/macros/src/lib.rs b/macros/src/lib.rs index d088561..d0fc909 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -48,7 +48,11 @@ impl Parse for ProtoInputParams { fn gen_serialize_data_struct( s: DataStruct, struct_attr: Option<&Attribute>, -) -> (proc_macro2::TokenStream, proc_macro2::TokenStream, proc_macro2::TokenStream) { +) -> ( + proc_macro2::TokenStream, + proc_macro2::TokenStream, + proc_macro2::TokenStream, +) { let serialize_base_content = { let mut serialize_content = quote! {}; @@ -123,8 +127,6 @@ fn gen_serialize_data_struct( let mut size_content = quote! { 0 }; for f in &s.fields { - - let ident = f.ident.as_ref().unwrap(); size_content.append_all(quote! { @@ -135,12 +137,11 @@ fn gen_serialize_data_struct( size_content }; let write_size = if let Some(_) = struct_attr { - quote!{ #write_size + if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 } } + quote! { #write_size + if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 } } } else { write_size }; - // generate base with extends stuff let serialize_base_content = if let Some(attr) = struct_attr { @@ -215,7 +216,7 @@ fn gen_serialize_data_struct( deserialize_base_content }; - let write_size = quote!{ + let write_size = quote! { fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result{ Ok(#write_size) } @@ -390,7 +391,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { Ok(val) }; - (serialize_base_content, deserialize_base_content, quote!{}) + (serialize_base_content, deserialize_base_content, quote! {}) } Data::Union(_) => { unimplemented!() diff --git a/macros/src/protos.rs b/macros/src/protos.rs index 7dd7bf1..2e95e71 100644 --- a/macros/src/protos.rs +++ b/macros/src/protos.rs @@ -1,47 +1,46 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::{quote, ToTokens}; -use syn::{LitInt, LitStr, ReturnType, Type}; use syn::token::{Brace, Paren, Semi}; +use syn::{Attribute, LitInt, LitStr, ReturnType, Type}; -pub struct ProtoMethodData{ +pub struct ProtoMethodData { pub id: LitInt, pub name: Ident, pub parameters: Vec<(Ident, Type)>, pub ret_val: ReturnType, } - /// This is a representation of the code generated by `rmc_proto` it serves to split the logic of /// acquiring data from the actual generation to tidy up the process into first getting then /// generating. /// /// Use the [`ToTokens`] trait to generate the actual code. -pub struct RmcProtocolData{ +pub struct RmcProtocolData { pub has_returns: bool, pub id: LitInt, pub name: Ident, - pub methods: Vec + pub methods: Vec, } -impl RmcProtocolData{ - fn generate_raw_trait(&self, tokens: &mut TokenStream){ - let Self{ +impl RmcProtocolData { + fn generate_raw_trait(&self, tokens: &mut TokenStream) { + let Self { has_returns, name, id, - methods + methods, } = self; // this gives us the name which the identifier of the corresponding Raw trait let raw_name = Ident::new(&format!("Raw{}", name), name.span()); - // boilerplate tokens which all raw traits need - quote!{ + quote! { #[doc(hidden)] #[allow(unused_must_use)] pub trait #raw_name: #name - }.to_tokens(tokens); + } + .to_tokens(tokens); // generate the body of the raw protocol trait Brace::default().surround(tokens, |tokens|{ @@ -191,9 +190,10 @@ impl RmcProtocolData{ }); }); - quote!{ + quote! { impl #raw_name for T{} - }.to_tokens(tokens); + } + .to_tokens(tokens); } fn generate_raw_remote_trait(&self, tokens: &mut TokenStream) { @@ -208,13 +208,13 @@ impl RmcProtocolData{ // this gives us the name which the identifier of the corresponding Raw trait let remote_name = Ident::new(&format!("Remote{}", name), name.span()); - // boilerplate tokens which all raw traits need - quote!{ + quote! { #[doc(hidden)] #[allow(unused_must_use)] pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection - }.to_tokens(tokens); + } + .to_tokens(tokens); // generate the body of the raw protocol trait Brace::default().surround(tokens, |tokens|{ @@ -299,35 +299,29 @@ impl RmcProtocolData{ }) } }); - - } - fn generate_raw_info(&self, tokens: &mut TokenStream){ - let Self{ - name, - id, - .. - } = self; + fn generate_raw_info(&self, tokens: &mut TokenStream) { + let Self { name, id, .. } = self; let raw_info_name = Ident::new(&format!("Raw{}Info", name), Span::call_site()); - - quote!{ + quote! { #[doc(hidden)] pub struct #raw_info_name; impl #raw_info_name { pub const PROTOCOL_ID: u16 = #id; } - }.to_tokens(tokens); + } + .to_tokens(tokens); } } -impl ToTokens for RmcProtocolData{ +impl ToTokens for RmcProtocolData { fn to_tokens(&self, tokens: &mut TokenStream) { self.generate_raw_trait(tokens); self.generate_raw_info(tokens); self.generate_raw_remote_trait(tokens); } -} \ No newline at end of file +} diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index 93c16c8..3bd902d 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -1,5 +1,6 @@ use log::{error, info}; use rnex_core::{ + PID, executables::common::{OWN_IP_PUBLIC, try_get_ip}, prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}, reggie::{RemoteEdgeNodeHolder, UnitPacketWrite}, @@ -83,7 +84,7 @@ impl ProxyStartupParam { let self_public: SocketAddrV4 = match try_get_env("SERVER_IP_PUBLIC") { Ok(v) => v, Err(e) => try_get_ip() - .map(|v| SocketAddrV4::new(v, RNEX_DEFAULT_PORT)) + .map(|v| SocketAddrV4::new(v, self_private.port())) .map_err(move |v| Error::PubAddrGetErr(Box::new(e), v))?, }; @@ -175,7 +176,7 @@ pub async fn setup_edge_node_connection( pub async fn new_backend_connection( param: &ProxyStartupParam, addr: PRUDPSockAddr, - pid: u32, + pid: PID, ) -> Option { info!("attempting to connect to: {}", param.forward_destination); let mut stream = match TcpStream::connect(param.forward_destination).await { diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index fa56ab2..98e8b2b 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" tokio = { version = "1.47.0", features = ["full"] } prudpv0 = { path = "../prudpv0", optional = true } prudpv1 = { path = "../prudpv1", optional = true } +prudplite = { path = "../prudplite", optional = true } proxy-common = { path = "../proxy-common" } cfg-if = "1.0.4" rnex-core = { path = "../rnex-core", version = "0.1.1" } @@ -15,6 +16,7 @@ log = "0.4.25" [features] prudpv0 = ["dep:prudpv0"] prudpv1 = ["dep:prudpv1"] +prudplite = ["dep:prudplite"] friends = ["prudpv0", "prudpv0/friends"] splatoon = ["prudpv1"] diff --git a/proxy/src/lib.rs b/proxy/src/lib.rs index 2c52a9a..ea5b02c 100644 --- a/proxy/src/lib.rs +++ b/proxy/src/lib.rs @@ -8,6 +8,8 @@ cfg_if! { pub use prudpv0::*; } else if #[cfg(feature = "prudpv1")] { pub use prudpv1::*; + } else if #[cfg(feature = "prudplite")]{ + pub use prudplite::*; } else { compile_error!("no proxy type has been set"); } diff --git a/prudplite/Cargo.toml b/prudplite/Cargo.toml new file mode 100644 index 0000000..902b1a7 --- /dev/null +++ b/prudplite/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "prudplite" +version = "0.1.0" +edition = "2024" + +[features] +nx = [] +v4-3-11 = [] + +[dependencies] +rnex-core = { path = "../rnex-core", version = "0.1.1" } +tokio = { version = "1.47.0", features = ["full"] } +bytemuck = { version = "1.23.1", features = ["derive"] } +proxy-common = {path = "../proxy-common"} +tokio-tungstenite = {version = "0.28.0", features = ["rustls", "rustls-tls-native-roots"]} +log = "0.4.25" +futures-util = "0.3.31" +v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" } diff --git a/prudplite/src/crypto/insecure.rs b/prudplite/src/crypto/insecure.rs new file mode 100644 index 0000000..34d0f93 --- /dev/null +++ b/prudplite/src/crypto/insecure.rs @@ -0,0 +1,14 @@ +use rnex_core::PID; + +use crate::crypto::Crypto; + +pub struct Insecure; + +impl Crypto for Insecure { + fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec)> { + Some((100, vec![])) + } + fn new() -> Self { + Self + } +} diff --git a/prudplite/src/crypto/mod.rs b/prudplite/src/crypto/mod.rs new file mode 100644 index 0000000..38d8091 --- /dev/null +++ b/prudplite/src/crypto/mod.rs @@ -0,0 +1,9 @@ +use rnex_core::PID; + +pub mod insecure; +pub mod secure; + +pub trait Crypto: 'static + Send + Sync { + fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec)>; + fn new() -> Self; +} diff --git a/prudplite/src/crypto/secure.rs b/prudplite/src/crypto/secure.rs new file mode 100644 index 0000000..4aff759 --- /dev/null +++ b/prudplite/src/crypto/secure.rs @@ -0,0 +1,27 @@ +use rnex_core::{ + PID, executables::common::SECURE_SERVER_ACCOUNT, nex::account::Account, + prudp::ticket::read_secure_connection_data, rmc::structures::RmcSerialize, +}; + +use crate::crypto::Crypto; + +pub struct Secure(&'static Account); + +impl Crypto for Secure { + fn new_connection(&self, data: &[u8]) -> Option<(PID, Vec)> { + let (_, pid, check_value) = read_secure_connection_data(data, &self.0)?; + + let check_value_response = check_value + 1; + + let data = bytemuck::bytes_of(&check_value_response); + + let mut response = Vec::new(); + + data.serialize(&mut response).ok()?; + + Some((pid, response)) + } + fn new() -> Self { + Self(&SECURE_SERVER_ACCOUNT) + } +} diff --git a/prudplite/src/lib.rs b/prudplite/src/lib.rs new file mode 100644 index 0000000..05938d7 --- /dev/null +++ b/prudplite/src/lib.rs @@ -0,0 +1,309 @@ +pub mod crypto; +mod packet; + +use std::{collections::HashMap, net::SocketAddr, sync::Arc}; + +use crate::{ + crypto::{Crypto, insecure::Insecure, secure::Secure}, + packet::{LiteHeader, LitePacket, PacketSpecificData, StreamTypes, create_packet_from}, +}; +use futures_util::{SinkExt, StreamExt}; +use log::{error, info, warn}; +use proxy_common::{ProxyStartupParam, new_backend_connection}; +use rnex_core::{ + PID, + prudp::{ + socket_addr::PRUDPSockAddr, + types_flags::{ + TypesFlags, + flags::{ACK, NEED_ACK, RELIABLE}, + types::{CONNECT, DATA, DISCONNECT, SYN}, + }, + virtual_port::VirtualPort, + }, + util::SplittableBufferConnection, +}; +use tokio::net::{TcpListener, TcpStream}; +use tokio_tungstenite::{ + WebSocketStream, + tungstenite::{ + Bytes, Message, client::IntoClientRequest, http::header::ACCESS_CONTROL_REQUEST_METHOD, + }, +}; + +struct ConnectionState { + param: Arc, + active: bool, + websocket: WebSocketStream, + pid: PID, + backend_conn: SplittableBufferConnection, + addr: PRUDPSockAddr, + incoming_reliable: HashMap>, + client_reliable_counter: u16, + server_reliable_counter: u16, +} + +impl ConnectionState { + pub async fn handle_incoming_prudp(&mut self, packet: LitePacket, sorted: bool) { + let Some(header) = packet.header() else { + warn!("invalid data on connection"); + return; + }; + + if (header.types_flags.get_flags() & NEED_ACK) != 0 { + let data = create_packet_from( + LiteHeader { + stream_types: StreamTypes::new( + self.param.virtual_port.get_stream_type(), + self.addr.virtual_port.get_stream_type(), + ), + source_port: self.param.virtual_port.get_port_number(), + destination_port: self.addr.virtual_port.get_port_number(), + fragment_id: header.fragment_id, + types_flags: TypesFlags::default() + .types(header.types_flags.get_types()) + .flags(ACK), + sequence_id: header.sequence_id, + ..Default::default() + }, + &[], + &[], + ); + let data: Bytes = data.into(); + if header.types_flags.get_types() == DISCONNECT { + self.websocket.send(Message::Binary(data.clone())).await; + self.websocket.send(Message::Binary(data.clone())).await; + } + self.websocket.send(Message::Binary(data)).await; + } + + if (header.types_flags.get_flags() & ACK) != 0 { + // we can just safely ignore acks, we ARE sending over tcp after all already guarantees that our packets will arrive + // we can however not guarantee the order of incoming client packets so we should still take care of that + // (the client might be doing some funny things which we dont know of) + return; + } + + if (header.types_flags.get_flags() & RELIABLE != 0) & !sorted { + self.incoming_reliable.insert(header.sequence_id, packet); + if self.incoming_reliable.len() > 5 { + self.active = false; + warn!("client is spamming out of order reliable packets, throwing out"); + } + return; + } + + match header.types_flags.get_types() { + DATA => { + if header.fragment_id != 0 { + warn!("fragmented packets arent yet supported"); + return; + } + + let Some(payload) = packet.payload() else { + return; + }; + self.backend_conn.send(payload.into()).await; + } + PING => {} + v => { + info!("unimplemented packet type: {}", v); + } + } + } + pub async fn process_reliable(&mut self) { + while let Some(v) = self.incoming_reliable.remove(&self.client_reliable_counter) { + self.handle_incoming_prudp(v, true).await; + self.client_reliable_counter += 1; + } + } + pub async fn handle_connection(&mut self) { + while self.active { + tokio::select! { + v = self.websocket.next() => { + match v { + Some(Ok(Message::Binary(v))) => { + self.handle_incoming_prudp(LitePacket::new(v), false).await; + } + _ => { + info!("client disconnected or errored out"); + return; + } + } + } + v = self.backend_conn.recv() => { + + } + } + } + } +} + +pub async fn websocket_thread_unconnected( + param: Arc, + crypto: Arc, + conn: TcpStream, + addr: SocketAddr, +) { + let mut websocket = match tokio_tungstenite::accept_async(conn).await { + Ok(v) => v, + Err(e) => { + error!("error accepting websocket connection: {}", e); + return; + } + }; + + while let Some(Ok(v)) = websocket.next().await { + match v { + Message::Binary(b) => { + let packet = LitePacket::new(b); + + let Some(header) = packet.header() else { + error!("got malformed message, disconnecting"); + return; + }; + + match header.types_flags.get_types() { + SYN => { + let Some(supported) = packet.packet_specific_iter() else { + error!("got malformed message, disconnecting"); + return; + }; + + let Some(PacketSpecificData::SupportedFunctions(s)) = supported + .into_iter() + .find(|v| matches!(v, PacketSpecificData::SupportedFunctions(_))) + else { + error!("got malformed message, disconnecting"); + return; + }; + + let data = create_packet_from( + LiteHeader { + destination_port: header.source_port, + source_port: param.virtual_port.get_port_number(), + stream_types: StreamTypes::new( + param.virtual_port.get_stream_type(), + header.stream_types.source(), + ), + fragment_id: 0, + sequence_id: 0, + types_flags: TypesFlags::default().types(SYN).flags(ACK), + ..Default::default() + }, + &[ + PacketSpecificData::SupportedFunctions(s & 0xFF), + PacketSpecificData::ConnectionSignature([0; 16]), + ], + &[], + ); + websocket.send(Message::Binary(data.into())).await; + } + CONNECT => { + let Some(supported) = packet.packet_specific_iter() else { + error!("got malformed message, disconnecting"); + return; + }; + + let Some(PacketSpecificData::SupportedFunctions(s)) = supported + .into_iter() + .find(|v| matches!(v, PacketSpecificData::SupportedFunctions(_))) + else { + error!("got malformed message, disconnecting"); + return; + }; + + let Some(data) = packet.payload() else { + error!("got malformed message, disconnecting"); + return; + }; + + let Some((pid, data)) = crypto.new_connection(data) else { + error!("invalid login data"); + return; + }; + + let data = create_packet_from( + LiteHeader { + destination_port: header.source_port, + source_port: param.virtual_port.get_port_number(), + stream_types: StreamTypes::new( + param.virtual_port.get_stream_type(), + header.stream_types.source(), + ), + fragment_id: 0, + sequence_id: 0, + types_flags: TypesFlags::default().types(CONNECT).flags(ACK), + ..Default::default() + }, + &[ + PacketSpecificData::SupportedFunctions(s & 0xFF), + PacketSpecificData::ConnectionSignature([0; 16]), + ], + &data, + ); + websocket.send(Message::Binary(data.into())).await; + + let addr = PRUDPSockAddr::new( + addr, + VirtualPort::new(header.source_port, header.stream_types.source()), + ); + let Some(backend_conn) = new_backend_connection(¶m, addr, pid).await + else { + error!("unable to connect to backend"); + return; + }; + let mut connection = ConnectionState { + active: true, + addr, + pid, + backend_conn, + client_reliable_counter: 2, + server_reliable_counter: 1, + param, + incoming_reliable: HashMap::new(), + websocket, + }; + + connection.handle_connection().await; + break; + } + v => { + error!( + "invalid packet type for unconnected client {}, disconnecting", + v, + ); + } + } + } + v => { + error!("non binary message({:?}) , disconnecting", v); + return; + } + } + } +} + +pub async fn start_proxy(param: ProxyStartupParam) { + let param = Arc::new(param); + let crypto = Arc::new(C::new()); + let listener = TcpListener::bind(param.self_private) + .await + .expect("unable to bind to port"); + + while let Ok((connection, addr)) = listener.accept().await { + let param = param.clone(); + let crypto = crypto.clone(); + tokio::spawn(websocket_thread_unconnected( + param, crypto, connection, addr, + )); + } +} + +pub async fn start_secure(param: ProxyStartupParam) { + start_proxy::(param).await; +} + +pub async fn start_insecure(param: ProxyStartupParam) { + start_proxy::(param).await; +} diff --git a/prudplite/src/main.rs b/prudplite/src/main.rs new file mode 100644 index 0000000..b4d8a0e --- /dev/null +++ b/prudplite/src/main.rs @@ -0,0 +1,45 @@ +use futures_util::{SinkExt, StreamExt}; +use rnex_core::prudp::types_flags::{TypesFlags, flags::NEED_ACK, types::SYN}; +use tokio_tungstenite::tungstenite::{Message, client::IntoClientRequest, http::header}; + +use crate::packet::{LiteHeader, LitePacket, PacketSpecificData, StreamTypes, create_packet_from}; + +mod packet; + +const KEY: &str = "4eb18d39"; + +const URL: &str = "wss://g2DF33D01-lp1.s.n.srv.nintendo.net"; +#[tokio::main] +async fn main() { + let login = URL.into_client_request().unwrap(); + let (mut stream, response) = tokio_tungstenite::connect_async(login).await.unwrap(); + + println!("response: {:?}", response); + + let packet = create_packet_from( + LiteHeader { + stream_types: StreamTypes::new(10, 10), + source_port: 1, + destination_port: 1, + fragment_id: 0, + types_flags: TypesFlags::default().types(SYN).flags(NEED_ACK), + sequence_id: 0, + ..Default::default() + }, + &[PacketSpecificData::SupportedFunctions(0x8)], + &[], + ); + + println!("sending ack"); + stream.send(Message::Binary(packet.into())).await.unwrap(); + println!("waiting for response"); + let packet = stream.next().await.unwrap(); + let Message::Binary(packet) = packet.unwrap() else { + panic!() + }; + let packet = LitePacket::new(packet); + + let header = packet.header().unwrap(); + + println!("{:?}", header); +} diff --git a/prudplite/src/packet.rs b/prudplite/src/packet.rs new file mode 100644 index 0000000..bd8d87c --- /dev/null +++ b/prudplite/src/packet.rs @@ -0,0 +1,223 @@ +use std::{ + fmt::Debug, + io::{self, Cursor, Read, Write}, +}; + +use bytemuck::{Pod, Zeroable, bytes_of}; +use futures_util::Stream; +use rnex_core::prudp::types_flags::TypesFlags; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; + +#[derive(Pod, Zeroable, Copy, Clone, Default, Debug)] +#[repr(C)] +pub struct LiteHeader { + pub magic: u8, + pub packet_specific_length: u8, + pub payload_size: u16, + pub stream_types: StreamTypes, + pub source_port: u8, + pub destination_port: u8, + pub fragment_id: u8, + pub types_flags: TypesFlags, + pub sequence_id: u16, +} + +pub enum PacketSpecificData { + SupportedFunctions(u32), + ConnectionSignature([u8; 16]), + LiteSignature([u8; 16]), +} + +impl PacketSpecificData { + fn consume(reader: &mut impl Read) -> io::Result { + let mut option_id = 0; + reader.read_exact(&mut [option_id])?; + let mut size = 0; + reader.read_exact(&mut [size])?; + + match option_id { + 0 => { + if size != 4 { + Err(io::Error::other( + "invalid option size for supported functions", + )) + } else { + Ok(Self::SupportedFunctions(reader.read_le_u32()?)) + } + } + 1 => { + if size != 16 { + Err(io::Error::other( + "invalid option size for connection signature", + )) + } else { + Ok(Self::ConnectionSignature( + reader.read_struct(IS_BIG_ENDIAN)?, + )) + } + } + 0x80 => { + if size != 16 { + Err(io::Error::other("invalid option size for lite signature")) + } else { + Ok(Self::LiteSignature(reader.read_struct(IS_BIG_ENDIAN)?)) + } + } + _ => Err(io::Error::other("invalid option id")), + } + } + + fn write_size(&self) -> usize { + 2 + match self { + PacketSpecificData::SupportedFunctions(_) => 4, + Self::ConnectionSignature(_) => 16, + Self::LiteSignature(_) => 16, + } + } + + fn write_self(&self, writer: &mut impl Write) -> io::Result<()> { + match self { + PacketSpecificData::SupportedFunctions(v) => { + writer.write_all(&[0, 4])?; + writer.write_all(&v.to_le_bytes())?; + } + Self::ConnectionSignature(v) => { + writer.write_all(&[1, 16])?; + writer.write_all(&v[..])?; + } + Self::LiteSignature(v) => { + writer.write_all(&[0x80, 16])?; + writer.write_all(&v[..])?; + } + } + + Ok(()) + } +} + +pub struct LitePacket>(T); + +pub struct PacketSpecificIter<'a>(Cursor<&'a [u8]>); + +impl<'a> Iterator for PacketSpecificIter<'a> { + type Item = PacketSpecificData; + + fn next(&mut self) -> Option { + PacketSpecificData::consume(&mut self.0).ok() + } +} + +impl> LitePacket { + pub fn new(inner: T) -> Self { + Self(inner) + } + + pub fn header(&self) -> Option<&LiteHeader> { + bytemuck::try_from_bytes(self.0.as_ref().get(..size_of::())?).ok() + } + pub fn header_mut(&mut self) -> Option<&mut LiteHeader> + where + T: AsMut<[u8]>, + { + bytemuck::try_from_bytes_mut(self.0.as_mut().get_mut(..size_of::())?).ok() + } + + pub fn payload(&self) -> Option<&[u8]> { + let header = self.header()?; + self.0 + .as_ref() + .get(size_of::() + header.packet_specific_length as usize..) + } + + pub fn payload_mut(&mut self) -> Option<&mut [u8]> + where + T: AsMut<[u8]>, + { + let len = self.header()?.packet_specific_length; + self.0 + .as_mut() + .get_mut(size_of::() + len as usize..) + } + + pub fn packet_specific_raw(&self) -> Option<&[u8]> { + let header = self.header()?; + self.0.as_ref().get( + size_of::() + ..size_of::() + header.packet_specific_length as usize, + ) + } + pub fn packet_specific_raw_mut(&mut self) -> Option<&mut [u8]> + where + T: AsMut<[u8]>, + { + let len = self.header()?.packet_specific_length; + self.0 + .as_mut() + .get_mut(size_of::()..size_of::() + len as usize) + } + + pub fn packet_specific_iter(&self) -> Option { + self.packet_specific_raw() + .map(Cursor::new) + .map(PacketSpecificIter) + } +} + +pub fn create_packet_from( + header: LiteHeader, + specific_data: &[PacketSpecificData], + data: &[u8], +) -> Vec { + let specific_size: usize = specific_data.iter().map(|v| v.write_size()).sum(); + let mut packet = LitePacket::new(vec![ + 0u8; + size_of::() + specific_size + data.len() + ]); + + *packet.header_mut().expect("packet malformed in creation") = LiteHeader { + magic: 0x80, + packet_specific_length: specific_size as u8, + payload_size: data.len() as u16, + ..header + }; + + let mut cursor = Cursor::new( + packet + .packet_specific_raw_mut() + .expect("packet malformed in creation"), + ); + + for specific in specific_data { + specific.write_self(&mut cursor).unwrap(); + } + + packet + .payload_mut() + .expect("packet malformed in creation") + .copy_from_slice(data); + + packet.0 +} + +#[derive(Pod, Zeroable, Copy, Clone, Default)] +#[repr(transparent)] +pub struct StreamTypes(u8); + +impl Debug for StreamTypes { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "({},{})", self.source(), self.destination()) + } +} + +impl StreamTypes { + pub fn new(source_stream: u8, dest_stream: u8) -> Self { + Self((source_stream & 0xF << 4) & dest_stream & 0xF) + } + + pub fn source(&self) -> u8 { + self.0 >> 4 + } + pub fn destination(&self) -> u8 { + self.0 & 0xF + } +} diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index aa603f7..1305d81 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -100,7 +100,7 @@ impl Server { }; /* we leave the sequence id as is for now as it defaults to 0 */ - *packet.checksum_mut().expect("packet malformed in creation") = + packet.checksum_mut().expect("packet malformed in creation") = self.crypto.calculate_checksum( packet .checksummed_data() @@ -434,7 +434,7 @@ impl Server { info!("len: {}", packet.0.len()); - let addr = PRUDPSockAddr::new(addr, header.source); + let addr = PRUDPSockAddr::new(SocketAddr::V4(addr), header.source); if let Some(conn) = self.get_connection(addr).await { let mut inner = conn.inner.lock().await; diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 69a4f9f..3a05177 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -34,6 +34,11 @@ ureq = "3.1.4" rmc_struct_header = [] guest_login = [] friends = ["guest_login"] +big_pid = [] +v3-8-15 = ["rmc_struct_header"] +v4-3-11 = ["v3-8-15"] +nx = ["big_pid"] + [[bench]] name = "rmc_serialization" diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs index 51d9647..91b83b3 100644 --- a/rnex-core/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -17,6 +17,7 @@ async fn main() { if #[cfg(feature = "friends")]{ start_friends_backend().await; } else { + use rnex_core::executables::regular_backend; regular_backend::start_regular_backend().await } } diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs index 2626fbe..7ea03b4 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core/src/executables/friends_backend.rs @@ -1,22 +1,65 @@ -use std::sync::{Arc, atomic::AtomicU32}; +use std::{ + io::Cursor, + net::SocketAddrV4, + sync::{Arc, atomic::AtomicU32}, +}; + +use log::error; +use tokio::net::TcpListener; use crate::{ - executables::common::new_simple_backend, - nex::friends_handler::{FriendsManager, FriendsUser}, + executables::common::{OWN_IP_PRIVATE, SERVER_PORT, new_simple_backend}, + nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser}, + reggie::UnitPacketRead, + rmc::{ + protocols::{RmcCallable, new_rmc_gateway_connection}, + structures::RmcSerialize, + }, + rnex_proxy_common::ConnectionInitData, }; pub async fn start_friends_backend() { let fm = Arc::new(FriendsManager { cid_counter: AtomicU32::new(1), }); + let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) + .await + .unwrap(); + while let Ok((mut stream, _addr)) = listen.accept().await { + let buffer = match stream.read_buffer().await { + Ok(v) => v, + Err(e) => { + error!( + "an error ocurred whilest reading connection data buffer: {:?}", + e + ); + continue; + } + }; - new_simple_backend(move |c, r| { + let user_connection_data = ConnectionInitData::deserialize(&mut Cursor::new(buffer)); + + let c = match user_connection_data { + Ok(v) => v, + Err(e) => { + error!("an error ocurred whilest reading connection data: {:?}", e); + continue; + } + }; let fm = fm.clone(); - Arc::new_cyclic(move |this| FriendsUser { - fm, - addr: c.prudpsock_addr, - pid: c.pid, - }) - }) - .await; + if c.pid != 100 { + new_rmc_gateway_connection(stream.into(), move |r| { + Arc::new_cyclic(move |this| FriendsUser { + fm, + addr: c.prudpsock_addr, + pid: c.pid, + }) + }); + } else { + Arc::new_cyclic(move |this| FriendsGuest { + fm, + addr: c.prudpsock_addr, + }); + } + } } diff --git a/rnex-core/src/grpc/account.rs b/rnex-core/src/grpc/account.rs index a70149f..64be4e9 100644 --- a/rnex-core/src/grpc/account.rs +++ b/rnex-core/src/grpc/account.rs @@ -1,29 +1,27 @@ -use std::{env, result}; +use crate::grpc::account::Error::SomethingHappened; +use json::{JsonValue, object}; +use once_cell::sync::Lazy; +use rnex_core::PID; use std::array::TryFromSliceError; use std::ops::Deref; -use json::{object, JsonValue}; -use once_cell::sync::Lazy; +use std::{env, result}; use thiserror::Error; -use tokio::task::{spawn_blocking, JoinError}; -use crate::grpc::account::Error::SomethingHappened; -static API_KEY: Lazy = Lazy::new(||{ - let key = env::var("ACCOUNT_GQL_API_KEY") - .expect("no graphql ip specified"); +use tokio::task::{JoinError, spawn_blocking}; +static API_KEY: Lazy = Lazy::new(|| { + let key = env::var("ACCOUNT_GQL_API_KEY").expect("no graphql ip specified"); key }); -static CLIENT_URI: Lazy = Lazy::new(||{ +static CLIENT_URI: Lazy = Lazy::new(|| { env::var("ACCOUNT_GQL_URL") .ok() .and_then(|s| s.parse().ok()) .expect("no graphql ip specified") }); - - #[derive(Error, Debug)] -pub enum Error{ +pub enum Error { #[error(transparent)] RequestError(#[from] ureq::Error), #[error(transparent)] @@ -35,20 +33,20 @@ pub enum Error{ #[error("something happened")] SomethingHappened, #[error("error joining blocking task: {0}")] - Join(#[from] JoinError) + Join(#[from] JoinError), } pub type Result = result::Result; -pub struct Client;//(reqwest::Client); +pub struct Client; //(reqwest::Client); -impl Client{ +impl Client { pub async fn new() -> Result { //Ok(Self(reqwest::ClientBuilder::new().build()?)) Ok(Self) } - async fn do_request(&self, request_data: JsonValue) -> Result{ + async fn do_request(&self, request_data: JsonValue) -> Result { let request = ureq::post(CLIENT_URI.as_str()) .header("X-API-Key", API_KEY.deref()) .content_type("application/json"); @@ -70,28 +68,35 @@ impl Client{ */ } - pub async fn get_nex_password(&mut self , pid: u32) -> Result<[u8; 16]>{ - let req = self.do_request(object!{ - "query": r"query($pid: Int!){ + pub async fn get_nex_password(&mut self, pid: PID) -> Result<[u8; 16]> { + let req = self + .do_request(object! { + "query": r"query($pid: Int!){ userByPid(pid: $pid){ nexPassword } }", - "variables": { - "pid": pid - } - }).await?; + "variables": { + "pid": pid + } + }) + .await?; - let Some(val) = req.entries() + let Some(val) = req + .entries() .find(|v| v.0 == "data") - .ok_or(SomethingHappened)?.1 + .ok_or(SomethingHappened)? + .1 .entries() .find(|v| v.0 == "userByPid") - .ok_or(SomethingHappened)?.1 + .ok_or(SomethingHappened)? + .1 .entries() .find(|v| v.0 == "nexPassword") - .ok_or(SomethingHappened)?.1 - .as_str() else { + .ok_or(SomethingHappened)? + .1 + .as_str() + else { return Err(SomethingHappened); }; @@ -109,8 +114,6 @@ impl Client{ }*/ } - - /* pub struct Client(AccountClient>); @@ -148,4 +151,4 @@ impl Client{ Ok(response) } } -*/ \ No newline at end of file +*/ diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index 4b56f56..d02afa1 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -6,18 +6,21 @@ use hmac::Mac; use md5::{Digest, Md5}; use rc4::KeyInit; use rc4::cipher::StreamCipherCoreWrapper; -use rc4::consts::U16; use rc4::{Rc4, Rc4Core, StreamCipher}; use rnex_core::rmc::structures::RmcSerialize; use std::io::{Read, Write}; +use typenum::U16; use typenum::Unsigned; use rnex_core::rmc::structures::Result; +use rnex_core::PID; + cfg_if! { if #[cfg(feature = "friends")]{ pub type SESSION_KEY_LENGTH_TY = U16; } else { + use rc4::consts::U32; pub type SESSION_KEY_LENGTH_TY = U32; } } @@ -25,7 +28,7 @@ pub const SESSION_KEY_LENGTH: usize = SESSION_KEY_LENGTH_TY::USIZE; type Md5Hmac = Hmac; -pub fn derive_key(pid: u32, password: &[u8]) -> [u8; 16] { +pub fn derive_key(pid: PID, password: &[u8]) -> [u8; 16] { let iteration_count = 65000 + pid % 1024; // we do one iteration out here to ensure the key is always 16 bytes @@ -125,12 +128,12 @@ impl RmcSerialize for KerberosDateTime { #[repr(C, packed)] pub struct TicketInternalData { pub issued_time: KerberosDateTime, - pub pid: u32, + pub pid: PID, pub session_key: [u8; SESSION_KEY_LENGTH], } impl TicketInternalData { - pub(crate) fn new(pid: u32) -> Self { + pub(crate) fn new(pid: PID) -> Self { Self { issued_time: KerberosDateTime::now(), pid, @@ -162,7 +165,7 @@ impl TicketInternalData { #[repr(C, packed)] pub struct Ticket { pub session_key: [u8; SESSION_KEY_LENGTH], - pub pid: u32, + pub pid: PID, } impl Ticket { diff --git a/rnex-core/src/lib.rs b/rnex-core/src/lib.rs index 3920565..28bdd48 100644 --- a/rnex-core/src/lib.rs +++ b/rnex-core/src/lib.rs @@ -4,7 +4,10 @@ #![allow(async_fn_in_trait)] //#![warn(missing_docs)] - +#[cfg(feature = "big_pid")] +pub type PID = u64; +#[cfg(not(feature = "big_pid"))] +pub type PID = u32; extern crate self as rnex_core; @@ -12,18 +15,18 @@ pub mod prudp; pub mod rmc; //mod protocols; +pub mod common; +pub mod executables; pub mod grpc; pub mod kerberos; pub mod nex; -pub mod result; -pub mod versions; -pub mod common; pub mod reggie; +pub mod result; pub mod rnex_proxy_common; pub mod util; -pub mod executables; +pub mod versions; pub use macros::*; -pub mod config{ +pub mod config { pub const FEATURE_HAS_STRUCT_HEADER: bool = cfg!(feature = "rmc_struct_header"); } diff --git a/rnex-core/src/nex/account.rs b/rnex-core/src/nex/account.rs index b3a5bb6..eb542ff 100644 --- a/rnex-core/src/nex/account.rs +++ b/rnex-core/src/nex/account.rs @@ -1,16 +1,16 @@ use macros::RmcSerialize; +use rnex_core::PID; + #[derive(RmcSerialize, Clone)] pub struct Account { - pub pid: u32, + pub pid: PID, pub username: String, pub kerbros_password: Box<[u8]>, } impl Account { - pub fn new(pid: u32, username: &str, passwd: &str) -> Self { - let passwd_data = passwd.as_bytes(); - + pub fn new(pid: PID, username: &str, passwd: &str) -> Self { Self { kerbros_password: passwd.as_bytes().into(), username: username.into(), @@ -18,7 +18,7 @@ impl Account { } } - pub fn new_raw_password(pid: u32, username: &str, passwd: &[u8]) -> Self { + pub fn new_raw_password(pid: PID, username: &str, passwd: &[u8]) -> Self { Self { kerbros_password: passwd.into(), username: username.into(), @@ -26,7 +26,7 @@ impl Account { } } - pub fn get_login_data(&self) -> (u32, &[u8]) { + pub fn get_login_data(&self) -> (PID, &[u8]) { (self.pid, &self.kerbros_password) } } diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 0ab6910..4d5392d 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -4,6 +4,7 @@ use crate::{define_rmc_proto, kerberos}; use cfg_if::cfg_if; use log::{info, warn}; use macros::rmc_struct; +use rnex_core::PID; use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; use rnex_core::nex::account::Account; use rnex_core::rmc::protocols::OnlyRemote; @@ -16,7 +17,7 @@ use rnex_core::rmc::structures::connection_data::ConnectionDataOld; use rnex_core::rmc::structures::qresult::QResult; use std::hash::{DefaultHasher, Hasher}; use std::net::SocketAddrV4; -use std::sync::{Arc, LazyLock, OnceLock}; +use std::sync::{Arc, LazyLock}; define_rmc_proto!( proto AuthClientProtocol{ @@ -33,8 +34,8 @@ pub struct AuthHandler { } pub fn generate_ticket( - source_act_login_data: (u32, &[u8]), - dest_act_login_data: (u32, &[u8]), + source_act_login_data: (PID, &[u8]), + dest_act_login_data: (PID, &[u8]), ) -> Box<[u8]> { let source_key = derive_key(source_act_login_data.0, source_act_login_data.1); let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1); @@ -50,8 +51,28 @@ pub fn generate_ticket( encrypted_session_ticket } +pub fn generate_ticket_with_string_user_key( + source_act: PID, + dest_act_login_data: (PID, &[u8]), +) -> (String, Box<[u8]>) { + let source_key: [u8; 8] = rand::random(); + let key_string = hex::encode(source_key); + let key_data: [u8; 16] = key_string.as_bytes().try_into().unwrap(); + let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1); -async fn get_login_data_by_pid(pid: u32) -> Option<(u32, Box<[u8]>)> { + let internal_data = kerberos::TicketInternalData::new(source_act); + + let encrypted_inner = internal_data.encrypt(dest_key); + let encrypted_session_ticket = Ticket { + pid: dest_act_login_data.0, + session_key: internal_data.session_key, + } + .encrypt(key_data, &encrypted_inner); + + (key_string, encrypted_session_ticket) +} + +async fn get_login_data_by_pid(pid: PID) -> Option<(PID, Box<[u8]>)> { if pid == GUEST_ACCOUNT.pid { let source_login_data = GUEST_ACCOUNT.get_login_data(); @@ -84,7 +105,7 @@ impl AuthHandler { pub async fn generate_ticket_from_name( &self, name: &str, - ) -> Result<(u32, Box<[u8]>), ErrorCode> { + ) -> Result<(PID, Box<[u8]>), ErrorCode> { #[cfg(feature = "guest_login")] { if name == GUEST_ACCOUNT.username { @@ -120,13 +141,39 @@ impl AuthHandler { generate_ticket(source_login_data, destination_login_data), )) } + + pub async fn generate_ticket_from_name_string_user_key( + &self, + name: &str, + ) -> Result<(PID, String, Box<[u8]>), ErrorCode> { + #[cfg(feature = "guest_login")] + { + if name == GUEST_ACCOUNT.username { + let source_login_data = GUEST_ACCOUNT.get_login_data(); + let destination_login_data = self.destination_server_acct.get_login_data(); + + return Ok(( + source_login_data.0, + generate_ticket(source_login_data, destination_login_data), + )); + } + } + let Ok(pid) = name.parse() else { + warn!("unable to connect to parse pid: {}", name); + return Err(ErrorCode::Core_InvalidArgument); + }; + let destination_login_data = self.destination_server_acct.get_login_data(); + + let data = generate_ticket_with_string_user_key(pid, destination_login_data); + Ok((pid, data.0, data.1)) + } } impl Auth for AuthHandler { async fn login( &self, name: String, - ) -> Result<(QResult, u32, Vec, ConnectionDataOld, String), ErrorCode> { + ) -> Result<(QResult, PID, Vec, ConnectionDataOld, String), ErrorCode> { let (pid, ticket) = self.generate_ticket_from_name(&name).await?; let result = QResult::success(Core_Unknown); @@ -157,103 +204,135 @@ impl Auth for AuthHandler { info!("data: {:?}", ret); Ok(ret) } + cfg_if! { - async fn login_ex( - &self, - name: String, - _extra_data: Any, - ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { - let (pid, ticket) = self.generate_ticket_from_name(&name).await?; + if #[cfg(feature = "nx")]{ + async fn login_ex( + &self, + name: String, + _extra_data: Any, + ) -> Result<(QResult, PID, Vec, ConnectionData, String, String), ErrorCode> { + let (pid, key, ticket) = self.generate_ticket_from_name_string_user_key(&name).await?; - let result = QResult::success(Core_Unknown); + let result = QResult::success(Core_Unknown); - let mut hasher = DefaultHasher::new(); + let mut hasher = DefaultHasher::new(); - hasher.write(name.as_bytes()); + hasher.write(name.as_bytes()); - let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { - warn!("no secure proxies"); - return Err(ErrorCode::Core_Exception); - }; + let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + warn!("no secure proxies"); + return Err(ErrorCode::Core_Exception); + }; - let connection_data = ConnectionData { - station_url: station_url_from_sock_addr(addr), - special_station_url: "".to_string(), - //date_time: KerberosDateTime::new(1,1,1,1,1,1), - date_time: KerberosDateTime::now(), - special_protocols: Vec::new(), - }; + let connection_data = ConnectionData { + station_url: station_url_from_sock_addr(addr), + special_station_url: "".to_string(), + //date_time: KerberosDateTime::new(1,1,1,1,1,1), + date_time: KerberosDateTime::now(), + special_protocols: Vec::new(), + }; - let ret = ( - result, - pid, - ticket.into(), - connection_data, - self.build_name.to_string(), - ); + let ret = ( + result, + pid, + ticket.into(), + connection_data, + self.build_name.to_string(), + key + ); - info!("data: {:?}", ret); - Ok(ret) - } + info!("data: {:?}", ret); + Ok(ret) + } + async fn request_ticket( + &self, + source_pid: PID, + destination_pid: PID, + ) -> Result<(QResult, Vec, String), ErrorCode> { + let Some((pid, _)) = get_login_data_by_pid(source_pid).await else { + return Err(ErrorCode::Core_Exception); + }; - async fn request_ticket( - &self, - source_pid: u32, - destination_pid: u32, - ) -> Result<(QResult, Vec), ErrorCode> { - let Some((pid, passwd)) = get_login_data_by_pid(source_pid).await else { - return Err(ErrorCode::Core_Exception); - }; + let desgination_login_data = if destination_pid == self.destination_server_acct.pid { + self.destination_server_acct.get_login_data() + } else { + return Err(ErrorCode::RendezVous_InvalidOperation); + }; - let desgination_login_data = if destination_pid == self.destination_server_acct.pid { - self.destination_server_acct.get_login_data() + let result = QResult::success(Core_Unknown); + + let ticket = generate_ticket_with_string_user_key(pid, desgination_login_data); + + Ok((result, ticket.1.into(), ticket.0)) + } } else { - return Err(ErrorCode::RendezVous_InvalidOperation); - }; + async fn login_ex( + &self, + name: String, + _extra_data: Any, + ) -> Result<(QResult, PID, Vec, ConnectionData, String), ErrorCode> { + let (pid, ticket) = self.generate_ticket_from_name(&name).await?; - let result = QResult::success(Core_Unknown); + let result = QResult::success(Core_Unknown); - let ticket = generate_ticket((pid, &passwd[..]), desgination_login_data); + let mut hasher = DefaultHasher::new(); - Ok((result, ticket.into())) + hasher.write(name.as_bytes()); + + let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + warn!("no secure proxies"); + return Err(ErrorCode::Core_Exception); + }; + + let connection_data = ConnectionData { + station_url: station_url_from_sock_addr(addr), + special_station_url: "".to_string(), + //date_time: KerberosDateTime::new(1,1,1,1,1,1), + date_time: KerberosDateTime::now(), + special_protocols: Vec::new(), + }; + + let ret = ( + result, + pid, + ticket.into(), + connection_data, + self.build_name.to_string(), + ); + + info!("data: {:?}", ret); + Ok(ret) + } + async fn request_ticket( + &self, + source_pid: PID, + destination_pid: PID, + ) -> Result<(QResult, Vec), ErrorCode> { + let Some((pid, passwd)) = get_login_data_by_pid(source_pid).await else { + return Err(ErrorCode::Core_Exception); + }; + + let desgination_login_data = if destination_pid == self.destination_server_acct.pid { + self.destination_server_acct.get_login_data() + } else { + return Err(ErrorCode::RendezVous_InvalidOperation); + }; + + let result = QResult::success(Core_Unknown); + + let ticket = generate_ticket((pid, &passwd[..]), desgination_login_data); + + Ok((result, ticket.into())) + } + } } async fn get_pid(&self, _username: String) -> Result { Err(ErrorCode::Core_Exception) } - async fn get_name(&self, _pid: u32) -> Result { + async fn get_name(&self, _pid: PID) -> Result { Err(ErrorCode::Core_Exception) } } - -#[cfg(test)] -mod test { - use rnex_core::rmc::response::RMCResponse; - use rnex_core::rmc::structures::RmcSerialize; - use rnex_core::rmc::structures::connection_data::ConnectionData; - use rnex_core::rmc::structures::qresult::QResult; - use std::io::Cursor; - - #[test] - fn test() { - return; - let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); - let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap(); - - let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result - else { - panic!() - }; - - // let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap(); - let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap(); - - let data = <(QResult, u32, Vec, ConnectionData, String) as RmcSerialize>::deserialize( - &mut Cursor::new(stuff), - ) - .unwrap(); - - println!("data: {:?}", data); - } -} diff --git a/rnex-core/src/nex/common.rs b/rnex-core/src/nex/common.rs index d2fa40f..48b080d 100644 --- a/rnex-core/src/nex/common.rs +++ b/rnex-core/src/nex/common.rs @@ -8,10 +8,12 @@ use rnex_core::rmc::response::ErrorCode::Core_Exception; use rnex_core::prudp::socket_addr::PRUDPSockAddr; use rnex_core::rmc::response::ErrorCode; +use rnex_core::PID; + pub async fn get_station_urls( station_urls: &[StationUrl], addr: PRUDPSockAddr, - pid: u32, + pid: PID, cid: u32, ) -> Result, ErrorCode> { let mut public_station: Option = None; @@ -66,7 +68,7 @@ pub async fn get_station_urls( public_station .options - .push(Address(*addr.regular_socket_addr.ip())); + .push(Address(addr.regular_socket_addr.ip().clone())); public_station .options .push(Port(addr.regular_socket_addr.port())); diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index a2d42ca..be5d684 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -1,5 +1,4 @@ use std::sync::{Arc, atomic::AtomicU32}; -use std::time::Duration; use log::info; use macros::rmc_struct; @@ -20,21 +19,33 @@ use rnex_core::{ }, }; use std::sync::atomic::Ordering::Relaxed; -use tokio::time::sleep; use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; +use rnex_core::PID; + define_rmc_proto!( proto FriendsUser{ Secure, Friends } ); +define_rmc_proto!( + proto FriendsGuest{ + Secure + } +); #[rmc_struct(FriendsUser)] pub struct FriendsUser { pub fm: Arc, pub addr: PRUDPSockAddr, - pub pid: u32, + pub pid: PID, +} + +#[rmc_struct(FriendsGuest)] +pub struct FriendsGuest { + pub fm: Arc, + pub addr: PRUDPSockAddr, } pub struct FriendsManager { @@ -50,9 +61,9 @@ impl FriendsManager { impl Friends for FriendsUser { async fn update_and_get_all_information( &self, - info: NNAInfo, - presence: NintendoPresenceV2, - date_time: KerberosDateTime, + _info: NNAInfo, + _presence: NintendoPresenceV2, + _date_time: KerberosDateTime, ) -> Result< ( PrincipalPreference, @@ -89,10 +100,10 @@ impl Friends for FriendsUser { nna_info: NNAInfo { principal_basic_info: PrincipalBasicInfo { pid: 101, - nnid: "dummyaccount".to_string(), + nnid: "dummy:3".to_string(), mii: MiiV2{ date_time: KerberosDateTime::now(), - name: "Dummy Account".to_string(), + name: "TheDummy".to_string(), mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), unk: 0, unk2: 0, @@ -149,12 +160,37 @@ impl Secure for FriendsUser { async fn register_ex( &self, station_urls: Vec, - data: Any, + _data: Any, ) -> Result<(QResult, u32, StationUrl), ErrorCode> { info!("register"); self.register(station_urls).await } - async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { + async fn replace_url(&self, _target: StationUrl, _dest: StationUrl) -> Result<(), ErrorCode> { + Err(ErrorCode::Core_NotImplemented) + } +} + +impl Secure for FriendsGuest { + async fn register( + &self, + station_urls: Vec, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + let cid = self.fm.next_cid(); + Ok(( + QResult::success(ErrorCode::Core_Unknown), + cid, + get_station_urls(&station_urls, self.addr, 100, cid).await?[0].clone(), + )) + } + async fn register_ex( + &self, + station_urls: Vec, + _data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + info!("register"); + self.register(station_urls).await + } + async fn replace_url(&self, _target: StationUrl, _dest: StationUrl) -> Result<(), ErrorCode> { Err(ErrorCode::Core_NotImplemented) } } diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 732c1ea..0a155fa 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -2,6 +2,7 @@ use crate::nex::user::User; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; use log::info; use rand::random; +use rnex_core::PID; use rnex_core::kerberos::KerberosDateTime; use rnex_core::rmc::protocols::notifications::notification_types::{ HOST_CHANGED, OWNERSHIP_CHANGED, @@ -208,7 +209,7 @@ impl ExtendedMatchmakeSession { .process_notification_event(NotificationEvent { pid_source: initiating_pid, notif_type: 122000, - param_1: self.session.gathering.self_gid, + param_1: self.session.gathering.self_gid as PID, param_2: other_pid, str_param: "".into(), param_3: 0, @@ -240,7 +241,7 @@ impl ExtendedMatchmakeSession { .process_notification_event(NotificationEvent { pid_source: initiating_pid, notif_type: 3001, - param_1: self.session.gathering.self_gid, + param_1: self.session.gathering.self_gid as PID, param_2: *pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, @@ -261,7 +262,7 @@ impl ExtendedMatchmakeSession { .process_notification_event(NotificationEvent { pid_source: initiating_pid, notif_type: 3001, - param_1: self.session.gathering.self_gid, + param_1: self.session.gathering.self_gid as PID, param_2: older_pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, @@ -393,7 +394,7 @@ impl ExtendedMatchmakeSession { Ok(true) } - pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> { + pub async fn migrate_ownership(&mut self, initiator_pid: PID) -> Result<(), ErrorCode> { let players: Vec<_> = self .connected_players .iter() @@ -414,7 +415,7 @@ impl ExtendedMatchmakeSession { self.broadcast_notification(&NotificationEvent { pid_source: initiator_pid, notif_type: OWNERSHIP_CHANGED, - param_1: self.session.gathering.self_gid, + param_1: self.session.gathering.self_gid as PID, param_2: new_owner.pid, ..Default::default() }) @@ -423,7 +424,7 @@ impl ExtendedMatchmakeSession { Ok(()) } - pub async fn migrate_host(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> { + pub async fn migrate_host(&mut self, initiator_pid: PID) -> Result<(), ErrorCode> { // let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect(); self.session.gathering.host_pid = self.session.gathering.owner_pid; @@ -431,7 +432,7 @@ impl ExtendedMatchmakeSession { self.broadcast_notification(&NotificationEvent { pid_source: initiator_pid, notif_type: HOST_CHANGED, - param_1: self.session.gathering.self_gid, + param_1: self.session.gathering.self_gid as PID, ..Default::default() }) .await; @@ -441,7 +442,7 @@ impl ExtendedMatchmakeSession { pub async fn remove_player_from_session( &mut self, - pid: u32, + pid: PID, message: &str, ) -> Result<(), ErrorCode> { self.connected_players @@ -468,7 +469,7 @@ impl ExtendedMatchmakeSession { .process_notification_event(NotificationEvent { notif_type: 3008, pid_source: pid, - param_1: self.session.gathering.self_gid, + param_1: self.session.gathering.self_gid as PID, param_2: pid, str_param: message.to_owned(), ..Default::default() diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index 1666d56..d8450e9 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -9,9 +9,10 @@ use crate::rmc::protocols::nat_traversal::{ NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole, }; +use rnex_core::PID; use rnex_core::prudp::station_url::StationUrl; use rnex_core::prudp::station_url::UrlOptions::{ - Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID, + Address, NatFiltering, NatMapping, Port, RVConnectionID, }; use rnex_core::rmc::protocols::matchmake_ext::{ MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt, @@ -31,10 +32,7 @@ use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification use log::info; use macros::rmc_struct; use rnex_core::prudp::socket_addr::PRUDPSockAddr; -use rnex_core::prudp::station_url::nat_types::PUBLIC; -use rnex_core::rmc::response::ErrorCode::{ - Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired, -}; +use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_AccountExpired}; use rnex_core::rmc::structures::qresult::QResult; use std::sync::{Arc, Weak}; use tokio::sync::{Mutex, RwLock}; @@ -52,7 +50,7 @@ define_rmc_proto!( #[rmc_struct(UserProtocol)] pub struct User { - pub pid: u32, + pub pid: PID, pub ip: PRUDPSockAddr, pub this: Weak, pub remote: RemoteConsole, @@ -423,7 +421,7 @@ impl Matchmake for User { .process_notification_event(NotificationEvent { notif_type: 110000, pid_source: self.pid, - param_1: gid, + param_1: gid as PID, param_2: self.pid, param_3: 0, str_param: "".to_string(), @@ -444,7 +442,7 @@ impl Matchmake for User { .process_notification_event(NotificationEvent { notif_type: 4000, pid_source: self.pid, - param_1: gid, + param_1: gid as PID, param_2: self.pid, param_3: 0, str_param: "".to_string(), @@ -459,7 +457,7 @@ impl Matchmake for User { async fn migrate_gathering_ownership( &self, gid: u32, - candidates: Vec, + candidates: Vec, _participants_only: bool, ) -> Result<(), ErrorCode> { let session = self.matchmake_manager.get_session(gid).await?; @@ -479,8 +477,8 @@ impl Matchmake for User { .process_notification_event(NotificationEvent { notif_type: 4000, pid_source: self.pid, - param_1: gid, - param_2: *candidate, + param_1: gid as PID, + param_2: *candidate as PID, param_3: 0, str_param: "".to_string(), }) diff --git a/rnex-core/src/prudp/socket_addr.rs b/rnex-core/src/prudp/socket_addr.rs index 4ffac83..e7cdf94 100644 --- a/rnex-core/src/prudp/socket_addr.rs +++ b/rnex-core/src/prudp/socket_addr.rs @@ -3,19 +3,19 @@ use macros::RmcSerialize; use md5::digest::Mac; use rnex_core::prudp::virtual_port::VirtualPort; use std::io::Write; -use std::net::SocketAddrV4; +use std::net::{IpAddr, SocketAddr}; type Md5Hmac = Hmac; #[derive(Eq, PartialEq, Hash, Debug, Copy, Clone, Ord, PartialOrd, RmcSerialize)] #[rmc_struct(0)] pub struct PRUDPSockAddr { - pub regular_socket_addr: SocketAddrV4, + pub regular_socket_addr: SocketAddr, pub virtual_port: VirtualPort, } impl PRUDPSockAddr { - pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self { + pub fn new(regular_socket_addr: SocketAddr, virtual_port: VirtualPort) -> Self { Self { regular_socket_addr, virtual_port, @@ -23,9 +23,12 @@ impl PRUDPSockAddr { } pub fn calculate_connection_signature(&self) -> [u8; 16] { - let mut hmac = Md5Hmac::new_from_slice(&[0; 16]).expect("fuck"); + let mut hmac = Md5Hmac::new_from_slice(&[0; 16]).expect("?"); - let data = self.regular_socket_addr.ip().octets().to_vec(); + let data = match self.regular_socket_addr.ip() { + IpAddr::V4(v) => v.octets().to_vec(), + IpAddr::V6(v) => v.octets().to_vec(), + }; //data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes()); hmac.write_all(&data) diff --git a/rnex-core/src/prudp/station_url.rs b/rnex-core/src/prudp/station_url.rs index a4665c2..e2d4abf 100644 --- a/rnex-core/src/prudp/station_url.rs +++ b/rnex-core/src/prudp/station_url.rs @@ -1,32 +1,35 @@ -use std::net::Ipv4Addr; +use crate::prudp::station_url::Type::{PRUDP, PRUDPS, UDP}; +use crate::prudp::station_url::UrlOptions::{ + Address, ConnectionID, NatFiltering, NatMapping, NatType, PID, PMP, Platform, Port, + PrincipalID, RVConnectionID, StreamID, StreamType, UPNP, +}; +use crate::rmc::structures::Error::StationUrlInvalid; +use crate::rmc::structures::RmcSerialize; +use crate::rmc::structures::helpers::DummyFormatWriter; use log::error; use std::fmt::{Debug, Display, Formatter, Write}; use std::io::Read; -use crate::prudp::station_url::Type::{PRUDP, PRUDPS, UDP}; -use crate::prudp::station_url::UrlOptions::{Address, ConnectionID, NatFiltering, NatMapping, NatType, Platform, PMP, Port, PrincipalID, RVConnectionID, StreamID, StreamType, UPNP, PID}; -use crate::rmc::structures::Error::StationUrlInvalid; -use crate::rmc::structures::helpers::DummyFormatWriter; -use crate::rmc::structures::RmcSerialize; +use std::net::IpAddr; #[derive(Clone, Copy, PartialEq, Eq)] -pub enum Type{ +pub enum Type { UDP, PRUDP, - PRUDPS + PRUDPS, } -pub mod nat_types{ +pub mod nat_types { pub const BEHIND_NAT: u8 = 1; pub const PUBLIC: u8 = 2; } #[derive(Clone, Eq, PartialEq)] pub enum UrlOptions { - Address(Ipv4Addr), + Address(IpAddr), Port(u16), StreamType(u8), StreamID(u8), ConnectionID(u8), - PrincipalID(u32), + PrincipalID(rnex_core::PID), NatType(u8), NatMapping(u8), NatFiltering(u8), @@ -35,82 +38,52 @@ pub enum UrlOptions { Platform(u8), PMP(u8), PID(u32), - } #[derive(Clone, PartialEq, Eq)] -pub struct StationUrl{ +pub struct StationUrl { pub url_type: Type, - pub options: Vec + pub options: Vec, } -impl StationUrl{ - pub fn read_options(options: &str) -> Option>{ +impl StationUrl { + pub fn read_options(options: &str) -> Option> { let mut options_out = Vec::new(); - for option in options.split(';'){ - if option == "" { continue; } + for option in options.split(';') { + if option == "" { + continue; + } let mut option_parts = option.split('='); - let option_name= option_parts.next()?.to_ascii_lowercase(); + let option_name = option_parts.next()?.to_ascii_lowercase(); let option_value = option_parts.next()?; - match option_name.as_ref(){ - "address" => { - options_out.push(Address(option_value.parse().ok()?)) - }, - "port" => { - options_out.push(Port(option_value.parse().ok()?)) - } - "natf" => { - options_out.push(NatFiltering(option_value.parse().ok()?)) - } - "natm" => { - options_out.push(NatMapping(option_value.parse().ok()?)) - } - "sid" => { - options_out.push(StreamID(option_value.parse().ok()?)) - } - "upnp" => { - options_out.push(UPNP(option_value.parse().ok()?)) - } - "type" => { - options_out.push(NatType(option_value.parse().ok()?)) - } - "stream" => { - options_out.push(StreamType(option_value.parse().ok()?)) - } - "RVCID" => { - options_out.push(RVConnectionID(option_value.parse().ok()?)) - } - "rvcid" => { - options_out.push(RVConnectionID(option_value.parse().ok()?)) - } - "pl" => { - options_out.push(Platform(option_value.parse().ok()?)) - } - "pmp" => { - options_out.push(PMP(option_value.parse().ok()?)) - }, - "pid" => { - options_out.push(PID(option_value.parse().ok()?)) - }, - "PID" => { - options_out.push(PID(option_value.parse().ok()?)) - }, + match option_name.as_ref() { + "address" => options_out.push(Address(option_value.parse().ok()?)), + "port" => options_out.push(Port(option_value.parse().ok()?)), + "natf" => options_out.push(NatFiltering(option_value.parse().ok()?)), + "natm" => options_out.push(NatMapping(option_value.parse().ok()?)), + "sid" => options_out.push(StreamID(option_value.parse().ok()?)), + "upnp" => options_out.push(UPNP(option_value.parse().ok()?)), + "type" => options_out.push(NatType(option_value.parse().ok()?)), + "stream" => options_out.push(StreamType(option_value.parse().ok()?)), + "RVCID" => options_out.push(RVConnectionID(option_value.parse().ok()?)), + "rvcid" => options_out.push(RVConnectionID(option_value.parse().ok()?)), + "pl" => options_out.push(Platform(option_value.parse().ok()?)), + "pmp" => options_out.push(PMP(option_value.parse().ok()?)), + "pid" => options_out.push(PID(option_value.parse().ok()?)), + "PID" => options_out.push(PID(option_value.parse().ok()?)), _ => { error!("unimplemented option type, skipping: {}", option_name); } } - - - } Some(options_out) } } -impl TryFrom<&str> for StationUrl{ +impl TryFrom<&str> for StationUrl { type Error = (); fn try_from(value: &str) -> Result { @@ -118,35 +91,30 @@ impl TryFrom<&str> for StationUrl{ let options = &options[2..]; - let url_type = match url_type{ + let url_type = match url_type { "udp" => UDP, "prudp" => PRUDP, "prudps" => PRUDPS, - _ => return Err(()) + _ => return Err(()), }; let options = Self::read_options(options).ok_or(())?; - Ok( - Self{ - url_type, - options - } - ) + Ok(Self { url_type, options }) } } -impl Display for StationUrl{ +impl Display for StationUrl { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - let url_type_str = match self.url_type{ + let url_type_str = match self.url_type { UDP => "udp:/", PRUDP => "prudp:/", - PRUDPS => "prudps:/" + PRUDPS => "prudps:/", }; - write!(f, "{}",url_type_str)?; + write!(f, "{}", url_type_str)?; - for option in &self.options{ - match option{ + for option in &self.options { + match option { Address(v) => write!(f, "address={}", v)?, Port(v) => write!(f, "port={}", v)?, StreamType(v) => write!(f, "stream={}", v)?, @@ -168,15 +136,15 @@ impl Display for StationUrl{ } } -impl<'a> Into for &'a StationUrl{ +impl<'a> Into for &'a StationUrl { fn into(self) -> String { let url = self.to_string(); - - url[0..url.len()-1].into() + + url[0..url.len() - 1].into() } } -impl RmcSerialize for StationUrl{ +impl RmcSerialize for StationUrl { fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let str = String::deserialize(reader)?; @@ -197,9 +165,9 @@ impl RmcSerialize for StationUrl{ } } -impl Debug for StationUrl{ +impl Debug for StationUrl { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let str: String = self.into(); f.write_str(&str) } -} \ No newline at end of file +} diff --git a/rnex-core/src/prudp/ticket.rs b/rnex-core/src/prudp/ticket.rs index 9fd094d..98e181f 100644 --- a/rnex-core/src/prudp/ticket.rs +++ b/rnex-core/src/prudp/ticket.rs @@ -2,7 +2,7 @@ use std::io::Cursor; use log::{error, info}; use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher, cipher::StreamCipherCoreWrapper}; -use typenum::{U16, U32}; +use typenum::U16; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::{ @@ -10,19 +10,17 @@ use crate::{ nex::account::Account, rmc::structures::RmcSerialize, }; +use rnex_core::PID; pub fn read_secure_connection_data( data: &[u8], act: &Account, -) -> Option<([u8; SESSION_KEY_LENGTH], u32, u32)> { +) -> Option<([u8; SESSION_KEY_LENGTH], PID, u32)> { let mut cursor = Cursor::new(data); let mut ticket_data: Vec = Vec::deserialize(&mut cursor).ok()?; let mut request_data: Vec = Vec::deserialize(&mut cursor).ok()?; - info!( - "done - request data" - ); + info!("done request data {}", SESSION_KEY_LENGTH); let ticket_data_size = ticket_data.len(); @@ -62,7 +60,7 @@ pub fn read_secure_connection_data( let mut reqest_data_cursor = Cursor::new(request_data); - let pid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + let pid: PID = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; if pid != ticket_source_pid { let ticket_created_on = issued_time.to_regular_time(); diff --git a/rnex-core/src/rmc/protocols/account_management.rs b/rnex-core/src/rmc/protocols/account_management.rs new file mode 100644 index 0000000..541d1f6 --- /dev/null +++ b/rnex-core/src/rmc/protocols/account_management.rs @@ -0,0 +1,4 @@ +use macros::rmc_proto; + +#[rmc_proto(25)] +pub trait AccountManagement {} diff --git a/rnex-core/src/rmc/protocols/auth.rs b/rnex-core/src/rmc/protocols/auth.rs index 594d9dd..ca387f9 100644 --- a/rnex-core/src/rmc/protocols/auth.rs +++ b/rnex-core/src/rmc/protocols/auth.rs @@ -1,9 +1,21 @@ use crate::rmc::structures::connection_data::{ConnectionData, ConnectionDataOld}; +use cfg_if::cfg_if; use macros::{method_id, rmc_proto}; +use rnex_core::PID; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::qresult::QResult; +cfg_if! { + if #[cfg(feature = "nx")]{ + type LOGIN_EX_RET = (QResult, PID, Vec, ConnectionData, String, String); + type REQUEST_TICKET_RET = (QResult, Vec, String); + } else { + type LOGIN_EX_RET = (QResult, PID, Vec, ConnectionData, String); + type REQUEST_TICKET_RET = (QResult, Vec); + } +} + /// This is the representation for `Ticket Granting`(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[rmc_proto(10)] @@ -14,25 +26,22 @@ pub trait Auth { async fn login( &self, name: String, - ) -> Result<(QResult, u32, Vec, ConnectionDataOld, String), ErrorCode>; + ) -> Result<(QResult, PID, Vec, ConnectionDataOld, String), ErrorCode>; /// representation of the `LoginEx` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[method_id(2)] - async fn login_ex( - &self, - name: String, - extra_data: Any, - ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode>; + async fn login_ex(&self, name: String, extra_data: Any) -> Result; - /// representation of the `RequestTicket` method(for details see the - /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[method_id(3)] async fn request_ticket( &self, - source_pid: u32, - destination_pid: u32, - ) -> Result<(QResult, Vec), ErrorCode>; + source_pid: PID, + destination_pid: PID, + ) -> Result; + + /// representation of the `RequestTicket` method(for details see the + /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) /// representation of the `GetPID` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) @@ -42,7 +51,7 @@ pub trait Auth { /// representation of the `LoginWithContext` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) #[method_id(5)] - async fn get_name(&self, pid: u32) -> Result; + async fn get_name(&self, pid: PID) -> Result; // `LoginWithContext` is left out here because we don't need it right now and versioning still // needs to be figured out diff --git a/rnex-core/src/rmc/protocols/matchmake.rs b/rnex-core/src/rmc/protocols/matchmake.rs index 595127a..94edce3 100644 --- a/rnex-core/src/rmc/protocols/matchmake.rs +++ b/rnex-core/src/rmc/protocols/matchmake.rs @@ -2,8 +2,10 @@ use macros::{method_id, rmc_proto}; use rnex_core::prudp::station_url::StationUrl; use rnex_core::rmc::response::ErrorCode; +use rnex_core::PID; + #[rmc_proto(21)] -pub trait Matchmake{ +pub trait Matchmake { #[method_id(2)] async fn unregister_gathering(&self, gid: u32) -> Result; #[method_id(41)] @@ -11,5 +13,10 @@ pub trait Matchmake{ #[method_id(42)] async fn update_session_host(&self, gid: u32, change_owner: bool) -> Result<(), ErrorCode>; #[method_id(44)] - async fn migrate_gathering_ownership(&self, gid: u32, candidates: Vec, participants_only: bool) -> Result<(), ErrorCode>; -} \ No newline at end of file + async fn migrate_gathering_ownership( + &self, + gid: u32, + candidates: Vec, + participants_only: bool, + ) -> Result<(), ErrorCode>; +} diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index 6896cf3..8feb2f3 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -1,5 +1,6 @@ #![allow(async_fn_in_trait)] +pub mod account_management; pub mod auth; pub mod friends; pub mod matchmake; diff --git a/rnex-core/src/rmc/protocols/notifications.rs b/rnex-core/src/rmc/protocols/notifications.rs index 164bf83..eef5c6c 100644 --- a/rnex-core/src/rmc/protocols/notifications.rs +++ b/rnex-core/src/rmc/protocols/notifications.rs @@ -1,19 +1,21 @@ -use macros::{method_id, rmc_proto, rmc_struct, RmcSerialize}; +use macros::{RmcSerialize, method_id, rmc_proto, rmc_struct}; -pub mod notification_types{ +use rnex_core::PID; + +pub mod notification_types { pub const OWNERSHIP_CHANGED: u32 = 4000; pub const HOST_CHANGED: u32 = 110000; } #[derive(RmcSerialize, Debug, Default, Clone)] #[rmc_struct(0)] -pub struct NotificationEvent{ - pub pid_source: u32, +pub struct NotificationEvent { + pub pid_source: PID, pub notif_type: u32, - pub param_1: u32, - pub param_2: u32, + pub param_1: PID, + pub param_2: PID, pub str_param: String, - pub param_3: u32, + pub param_3: PID, } #[rmc_proto(14, NoReturn)] @@ -21,4 +23,3 @@ pub trait Notification { #[method_id(1)] async fn process_notification_event(&self, event: NotificationEvent); } - diff --git a/rnex-core/src/rmc/protocols/secure.rs b/rnex-core/src/rmc/protocols/secure.rs index 3df23c6..503bf93 100644 --- a/rnex-core/src/rmc/protocols/secure.rs +++ b/rnex-core/src/rmc/protocols/secure.rs @@ -12,6 +12,7 @@ pub trait Secure { &self, station_urls: Vec, ) -> Result<(QResult, u32, StationUrl), ErrorCode>; + #[method_id(4)] async fn register_ex( &self, diff --git a/rnex-core/src/rmc/structures/matchmake.rs b/rnex-core/src/rmc/structures/matchmake.rs index 9194b97..a1518d1 100644 --- a/rnex-core/src/rmc/structures/matchmake.rs +++ b/rnex-core/src/rmc/structures/matchmake.rs @@ -1,14 +1,16 @@ +use macros::RmcSerialize; use rnex_core::kerberos::KerberosDateTime; use rnex_core::rmc::structures::variant::Variant; -use macros::RmcSerialize; + +use rnex_core::PID; // rmc structure #[derive(RmcSerialize, Debug, Clone, Default)] #[rmc_struct(0)] pub struct Gathering { pub self_gid: u32, - pub owner_pid: u32, - pub host_pid: u32, + pub owner_pid: PID, + pub host_pid: PID, pub minimum_participants: u16, pub maximum_participants: u16, pub participant_policy: u32, @@ -73,7 +75,7 @@ pub struct MatchmakeSessionSearchCriteria { #[rmc_struct(0)] pub struct AutoMatchmakeParam { pub matchmake_session: MatchmakeSession, - pub additional_participants: Vec, + pub additional_participants: Vec, pub gid_for_participation_check: u32, pub auto_matchmake_option: u32, pub join_message: String, @@ -86,7 +88,7 @@ pub struct AutoMatchmakeParam { #[rmc_struct(0)] pub struct CreateMatchmakeSessionParam { pub matchmake_session: MatchmakeSession, - pub additional_participants: Vec, + pub additional_participants: Vec, pub gid_for_participation_check: u32, pub create_matchmake_session_option: u32, pub join_message: String, @@ -103,7 +105,7 @@ pub struct MatchmakeBlockListParam { #[rmc_struct(0)] pub struct JoinMatchmakeSessionParam { pub gid: u32, - pub additional_participants: Vec, + pub additional_participants: Vec, pub gid_for_participation_check: u32, pub join_matchmake_session_open: u32, pub join_matchmake_session_behavior: u8, diff --git a/rnex-core/src/rmc/structures/networking.rs b/rnex-core/src/rmc/structures/networking.rs index 03627af..bc95b9e 100644 --- a/rnex-core/src/rmc/structures/networking.rs +++ b/rnex-core/src/rmc/structures/networking.rs @@ -1,9 +1,37 @@ -use std::io::{Read, Write}; -use std::net::{Ipv4Addr, SocketAddrV4}; +use crate::rmc::structures::{Error, Result, RmcSerialize}; use rnex_core::prudp::virtual_port::VirtualPort; -use crate::rmc::structures::RmcSerialize; +use std::io::{Read, Write}; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -impl RmcSerialize for SocketAddrV4{ +impl RmcSerialize for SocketAddr { + fn deserialize(reader: &mut impl std::io::Read) -> Result + where + Self: Sized, + { + let val: u8 = reader.read_struct(IS_BIG_ENDIAN)?; + match val { + 4 => Ok(SocketAddr::V4(SocketAddrV4::deserialize(reader)?)), + 6 => Ok(SocketAddr::V6(SocketAddrV6::deserialize(reader)?)), + v => Err(Error::UnexpectedValue(v as u64)), + } + } + fn serialize(&self, writer: &mut impl Write) -> Result<()> { + match self { + SocketAddr::V4(v) => { + writer.write_all(&[4])?; + v.serialize(writer)?; + } + SocketAddr::V6(v) => { + writer.write_all(&[6])?; + v.serialize(writer)?; + } + } + Ok(()) + } +} + +impl RmcSerialize for SocketAddrV4 { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.ip().to_bits().serialize(writer)?; self.port().serialize(writer)?; @@ -21,9 +49,35 @@ impl RmcSerialize for SocketAddrV4{ Ok(6) } } +impl RmcSerialize for SocketAddrV6 { + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { + self.ip().to_bits().serialize(writer)?; + self.port().serialize(writer)?; + self.flowinfo().serialize(writer)?; + self.scope_id().serialize(writer)?; + Ok(()) + } -impl RmcSerialize for VirtualPort{ + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + let ip = u128::deserialize(reader)?; + let port = u16::deserialize(reader)?; + let flowinfo = u32::deserialize(reader)?; + let scope_id = u32::deserialize(reader)?; + + Ok(SocketAddrV6::new( + Ipv6Addr::from_bits(ip), + port, + flowinfo, + scope_id, + )) + } + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(6) + } +} + +impl RmcSerialize for VirtualPort { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -36,4 +90,4 @@ impl RmcSerialize for VirtualPort{ fn serialize_write_size(&self) -> crate::rmc::structures::Result { Ok(1) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index 3bdd835..e3888d4 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -1,5 +1,5 @@ use crate::rmc::structures::RmcSerialize; -use bytemuck::bytes_of; +use bytemuck::{bytes_of, bytes_of_mut}; use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; @@ -110,6 +110,23 @@ impl RmcSerialize for u64 { } } +impl RmcSerialize for u128 { + #[inline(always)] + fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + #[inline(always)] + fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + let mut data = 0u128; + reader.read_exact(&mut bytes_of_mut(&mut data))?; + Ok(data) + } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(8) + } +} + impl RmcSerialize for i64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { diff --git a/rnex-core/src/rmc/structures/ranking.rs b/rnex-core/src/rmc/structures/ranking.rs index 1782cba..778c5cf 100644 --- a/rnex-core/src/rmc/structures/ranking.rs +++ b/rnex-core/src/rmc/structures/ranking.rs @@ -20,55 +20,3 @@ struct UploadCompetitionData { struct UserData { name: [u16; 0x10], } - -#[cfg(test)] -mod test { - use crate::rmc::structures::ranking::{UploadCompetitionData, UserData}; - use bytemuck::from_bytes; - use rnex_core::rmc::structures::RmcSerialize; - use std::io::Cursor; - - #[test] - fn test() { - return; - let data: [u8; 0xBD] = [ - 0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0, - 0x00, 0x00, 0x49, 0x00, 0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00, - 0x46, 0x00, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00, - ]; - - let mut cursor = Cursor::new(data); - - let data = - UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize data"); - - let user_data: &UserData = from_bytes(&data.player_data.0[..size_of::()]); - - let pos = user_data - .name - .iter() - .position(|v| *v == 0x0000) - .unwrap_or(0x10); - - let mut name = user_data.name[0..pos].to_vec(); - - name.iter_mut().for_each(|v| *v = v.swap_bytes()); - - let name = String::from_utf16(&name).expect("unable to get name"); - - println!("{:?}", name); - - assert!(u8::deserialize(&mut cursor).is_err()) - } -} diff --git a/rnex-core/src/rnex_proxy_common.rs b/rnex-core/src/rnex_proxy_common.rs index 29cb161..7f2c363 100644 --- a/rnex-core/src/rnex_proxy_common.rs +++ b/rnex-core/src/rnex_proxy_common.rs @@ -1,11 +1,9 @@ +use crate::{PID, prudp::socket_addr::PRUDPSockAddr}; use macros::RmcSerialize; -use crate::prudp::socket_addr::PRUDPSockAddr; #[derive(Debug, RmcSerialize)] #[rmc_struct(0)] -pub struct ConnectionInitData{ +pub struct ConnectionInitData { pub prudpsock_addr: PRUDPSockAddr, - pub pid: u32, - + pub pid: PID, } - -- 2.47.3 From b6b7d2559d218938e4fed81f3749439c8e0b6f5d Mon Sep 17 00:00:00 2001 From: Maple Date: Tue, 24 Mar 2026 15:20:38 +0100 Subject: [PATCH 59/98] fix type errors in auth_handler.rs --- rnex-core/src/nex/auth_handler.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 4d5392d..3fa5485 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -146,16 +146,16 @@ impl AuthHandler { &self, name: &str, ) -> Result<(PID, String, Box<[u8]>), ErrorCode> { - #[cfg(feature = "guest_login")] { if name == GUEST_ACCOUNT.username { let source_login_data = GUEST_ACCOUNT.get_login_data(); let destination_login_data = self.destination_server_acct.get_login_data(); - - return Ok(( + let ticket = generate_ticket_with_string_user_key( source_login_data.0, - generate_ticket(source_login_data, destination_login_data), - )); + destination_login_data, + ); + + return Ok((source_login_data.0, ticket.0, ticket.1)); } } let Ok(pid) = name.parse() else { -- 2.47.3 From 4ad883a54d90a62a52e5d93e18ca22cd32c025a4 Mon Sep 17 00:00:00 2001 From: Maple Date: Tue, 24 Mar 2026 23:17:22 +0100 Subject: [PATCH 60/98] add debug logging to ticket generation for debugging --- rnex-core/Cargo.toml | 2 +- rnex-core/src/kerberos/mod.rs | 2 +- rnex-core/src/nex/auth_handler.rs | 80 +++++++++++++++++++ rnex-core/src/rmc/response.rs | 89 ++++++++++------------ rnex-core/src/rmc/structures/list.rs | 32 ++++---- rnex-core/src/rmc/structures/mod.rs | 51 ++++++------- rnex-core/src/rmc/structures/primitives.rs | 4 +- rnex-core/src/rmc/structures/qresult.rs | 25 +++--- rnex-core/src/rmc/structures/rmc_struct.rs | 60 +++++++++------ rnex-core/src/rmc/structures/string.rs | 13 ++-- 10 files changed, 227 insertions(+), 131 deletions(-) diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 3a05177..d44c000 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -17,7 +17,7 @@ rand = "0.8.5" cfg-if = "1.0.4" hmac = "0.12.1" md-5 = "^0.10.6" -tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } +tokio = { version = "1.43.0", features = ["full"] } hex = "0.4.3" macros = { path = "../macros" } diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index d02afa1..205c62a 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -161,7 +161,7 @@ impl TicketInternalData { } } -#[derive(Pod, Zeroable, Copy, Clone)] +#[derive(Pod, Zeroable, Debug, Copy, Clone)] #[repr(C, packed)] pub struct Ticket { pub session_key: [u8; SESSION_KEY_LENGTH], diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 3fa5485..341dc93 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -134,6 +134,7 @@ impl AuthHandler { }; let source_login_data = (pid, &passwd[..]); + println!("{}, {:?}", pid, passwd); let destination_login_data = self.destination_server_acct.get_login_data(); Ok(( @@ -336,3 +337,82 @@ impl Auth for AuthHandler { Err(ErrorCode::Core_Exception) } } + +mod test { + use std::io::Cursor; + + use rc4::{KeyInit, Rc4, StreamCipher}; + use rnex_core::PID; + use rnex_core::kerberos::KerberosDateTime; + use rnex_core::rmc::structures::connection_data::ConnectionData; + use rnex_core::rmc::{ + response::ErrorCode, + structures::{RmcSerialize, qresult::QResult}, + }; + + use crate::kerberos::{self, derive_key}; + use crate::rmc; + use crate::rmc::message::RMCMessage; + use crate::rmc::response::{RMCResponse, RMCResponseResult}; + + #[test] + fn test() { + return; + let packet = [ + 26, 1, 0, 0, 10, 1, 30, 0, 0, 0, 1, 128, 0, 0, 1, 0, 1, 0, 86, 4, 0, 0, 116, 0, 0, 0, + 144, 209, 130, 175, 45, 215, 95, 55, 226, 192, 51, 54, 201, 84, 118, 150, 159, 164, 32, + 103, 134, 252, 199, 168, 178, 5, 6, 208, 206, 241, 94, 23, 136, 37, 109, 247, 156, 252, + 189, 233, 142, 115, 206, 72, 180, 57, 106, 223, 37, 59, 144, 208, 250, 197, 51, 202, + 185, 156, 51, 159, 219, 117, 250, 103, 184, 1, 103, 108, 15, 14, 174, 160, 192, 146, + 135, 10, 55, 125, 68, 181, 88, 127, 183, 34, 4, 213, 19, 146, 81, 56, 248, 213, 241, + 168, 205, 253, 29, 10, 123, 198, 177, 157, 247, 209, 113, 167, 231, 42, 214, 15, 12, + 200, 192, 230, 125, 227, 74, 0, 112, 114, 117, 100, 112, 115, 58, 47, 80, 73, 68, 61, + 50, 59, 115, 105, 100, 61, 49, 59, 115, 116, 114, 101, 97, 109, 61, 49, 48, 59, 116, + 121, 112, 101, 61, 50, 59, 97, 100, 100, 114, 101, 115, 115, 61, 57, 49, 46, 57, 56, + 46, 49, 50, 56, 46, 56, 54, 59, 112, 111, 114, 116, 61, 54, 48, 48, 49, 59, 67, 73, 68, + 61, 49, 0, 0, 0, 0, 0, 1, 0, 0, 162, 243, 240, 168, 31, 0, 0, 0, 51, 0, 98, 114, 97, + 110, 99, 104, 58, 111, 114, 105, 103, 105, 110, 47, 112, 114, 111, 106, 101, 99, 116, + 47, 119, 117, 112, 45, 97, 103, 109, 106, 32, 98, 117, 105, 108, 100, 58, 51, 95, 56, + 95, 49, 53, 95, 50, 48, 48, 52, 95, 48, 0, + ]; + let rmc_packet = RMCResponse::new(&mut Cursor::new(&packet)).unwrap(); + println!("{:?}", rmc_packet); + + let RMCResponseResult::Success { + call_id, + method_id, + data, + } = rmc_packet.response_result + else { + panic!(); + }; + + println!("{}", hex::encode(&data)); + + let mut data = + <(QResult, PID, Vec, ConnectionData, String) as RmcSerialize>::deserialize( + &mut Cursor::new(&data[..]), + ) + .unwrap(); + + println!("{:?}", data); + + let key = derive_key(1110, "AAAAAAAAAAAAAAAA".as_bytes()); + + let mut rc4 = Rc4::new((&key).into()); + + rc4.apply_keystream(&mut data.2); + println!("raw tick: {:?}", data.2); + + let tick: &kerberos::Ticket = + bytemuck::from_bytes(&data.2[..size_of::()]); + + let remainder = &data.2[size_of::()..]; + + println!("tick: {:?}", tick); + let data = as RmcSerialize>::deserialize(&mut Cursor::new(remainder)).unwrap(); + println!("inner ticket raw: {:?}", data); + + println!("{:?}", data); + } +} diff --git a/rnex-core/src/rmc/response.rs b/rnex-core/src/rmc/response.rs index c994f8b..b042877 100644 --- a/rnex-core/src/rmc/response.rs +++ b/rnex-core/src/rmc/response.rs @@ -2,17 +2,18 @@ // attributes but this gets it to not complain anymore #![allow(unused_parens)] -use std::io; -use std::io::{Read, Seek, Write}; -use std::mem::transmute; -use bytemuck::bytes_of; -use log::error; -use v_byte_helpers::EnumTryInto; -use v_byte_helpers::{ReadExtensions, IS_BIG_ENDIAN}; use crate::rmc::response::ErrorCode::Core_Exception; use crate::rmc::structures::qresult::ERROR_MASK; use crate::util::SendingBufferConnection; +use bytemuck::bytes_of; +use log::error; +use std::io; +use std::io::{Read, Seek, Write}; +use std::mem::transmute; +use v_byte_helpers::EnumTryInto; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +#[derive(Debug, Clone)] pub enum RMCResponseResult { Success { call_id: u32, @@ -25,13 +26,14 @@ pub enum RMCResponseResult { }, } +#[derive(Debug, Clone)] pub struct RMCResponse { pub protocol_id: u8, pub response_result: RMCResponseResult, } impl RMCResponse { - pub fn new(stream: &mut (impl Seek + Read)) -> io::Result{ + pub fn new(stream: &mut (impl Seek + Read)) -> io::Result { // ignore the size for now this will only be used for checking let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?; @@ -46,7 +48,7 @@ impl RMCResponse { let is_success: u8 = stream.read_struct(IS_BIG_ENDIAN)?; - let response_result = if is_success == 0x01{ + let response_result = if is_success == 0x01 { let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; let method_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; let method_id = method_id & (!0x8000); @@ -55,11 +57,10 @@ impl RMCResponse { stream.read(&mut data)?; - RMCResponseResult::Success { call_id, method_id, - data + data, } } else { let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?; @@ -68,7 +69,7 @@ impl RMCResponse { RMCResponseResult::Error { error_code: { - match ErrorCode::try_from(error_code){ + match ErrorCode::try_from(error_code) { Ok(v) => v, Err(()) => { error!("invalid error code {:#010x}", error_code); @@ -77,36 +78,35 @@ impl RMCResponse { } }, call_id, - } }; - Ok(Self{ + Ok(Self { protocol_id, - response_result + response_result, }) } - pub fn get_call_id(&self) -> u32{ - match &self.response_result{ - RMCResponseResult::Success { call_id, ..} => *call_id, - RMCResponseResult::Error { call_id, .. } => *call_id + pub fn get_call_id(&self) -> u32 { + match &self.response_result { + RMCResponseResult::Success { call_id, .. } => *call_id, + RMCResponseResult::Error { call_id, .. } => *call_id, } } pub fn to_data(self) -> Vec { - generate_response(self.protocol_id, self.response_result).expect("failed to generate response") + generate_response(self.protocol_id, self.response_result) + .expect("failed to generate response") } } pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result> { - let size = 1 + 1 + match &response { - RMCResponseResult::Success { - data, - .. - } => 4 + 4 + data.len(), - RMCResponseResult::Error { .. } => 4 + 4, - }; + let size = 1 + + 1 + + match &response { + RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(), + RMCResponseResult::Error { .. } => 4 + 4, + }; let mut data_out = Vec::with_capacity(size + 4); @@ -119,7 +119,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re RMCResponseResult::Success { call_id, method_id, - data + data, } => { data_out.push(1); data_out.write_all(bytes_of(&call_id))?; @@ -129,7 +129,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re } RMCResponseResult::Error { call_id, - error_code + error_code, } => { data_out.push(0); let error_code_val: u32 = error_code.into(); @@ -151,23 +151,21 @@ pub async fn send_result( method_id: u32, call_id: u32, ) { - let response_result = match result { Ok(v) => RMCResponseResult::Success { call_id, method_id, - data: v + data: v, + }, + Err(e) => RMCResponseResult::Error { + call_id, + error_code: e.into(), }, - Err(e) => - RMCResponseResult::Error { - call_id, - error_code: e.into() - } }; - let response = RMCResponse{ + let response = RMCResponse { response_result, - protocol_id + protocol_id, }; send_response(connection, response).await @@ -177,7 +175,6 @@ pub async fn send_response(connection: &SendingBufferConnection, rmcresponse: RM connection.send(rmcresponse.to_data()).await; } - //taken from kinnays error list directly #[allow(nonstandard_style)] #[repr(u32)] @@ -464,25 +461,23 @@ impl Into for ErrorCode { #[cfg(test)] mod test { - use hmac::digest::consts::U5; - use hmac::digest::KeyInit; - use rc4::{Rc4, StreamCipher}; use crate::rmc::response::ErrorCode; + use hmac::digest::KeyInit; + use hmac::digest::consts::U5; + use rc4::{Rc4, StreamCipher}; #[test] fn test() { let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; let mut data = data_orig; - let mut rc4: Rc4 = - Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); + let mut rc4: Rc4 = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); rc4.apply_keystream(&mut data); assert_ne!(data_orig, data); - let mut rc4: Rc4 = - Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); + let mut rc4: Rc4 = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); rc4.apply_keystream(&mut data); @@ -494,4 +489,4 @@ mod test { let val: u32 = ErrorCode::Core_Unknown.into(); assert_eq!(val, 0x00010001) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs index 890be9a..7c7db8e 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -1,19 +1,17 @@ +use crate::rmc::structures::RmcSerialize; +use bytemuck::bytes_of; use std::io::{Read, Write}; use std::mem::MaybeUninit; -use bytemuck::bytes_of; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::rmc::structures::RmcSerialize; - - -// this is also for implementing `Buffer` this is tecnically not the same as its handled internaly +// this is also for implementing `Buffer` this is tecnically not the same as its handled internaly // probably but as it has the same mapping it doesn't matter and simplifies things -impl RmcSerialize for Vec{ +impl RmcSerialize for Vec { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { let u32_len = self.len() as u32; writer.write_all(bytes_of(&u32_len))?; - for e in self{ + for e in self { e.serialize(writer)?; } @@ -21,27 +19,31 @@ impl RmcSerialize for Vec{ } fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + println!("reading list"); let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; + println!("readijg list: {:?}", len); //let mut vec = Vec::with_capacity(len as usize); - let vec = (0..len).map(|_| T::deserialize(reader)).collect::, _>>()?; + let vec: Vec = (0..len) + .map(|_| T::deserialize(reader)) + .collect::, _>>()?; Ok(vec) } - + fn serialize_write_size(&self) -> crate::rmc::structures::Result { let mut val = 0u32; - for i in self{ + for i in self { val += i.serialize_write_size()?; } Ok(4 + val) } } -impl RmcSerialize for [T; LEN]{ +impl RmcSerialize for [T; LEN] { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { - for i in 0..LEN{ + for i in 0..LEN { self[i].serialize(writer)?; } @@ -51,20 +53,20 @@ impl RmcSerialize for [T; LEN]{ fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let mut arr = [const { MaybeUninit::::uninit() }; LEN]; - for i in 0..LEN{ + for i in 0..LEN { arr[i] = MaybeUninit::new(T::deserialize(reader)?); } // all of the elements are now initialized so it is safe to assume they are initialized - let arr = arr.map(|v| unsafe{ v.assume_init() }); + let arr = arr.map(|v| unsafe { v.assume_init() }); Ok(arr) } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { let mut val = 0u32; - for i in self{ + for i in self { val += i.serialize_write_size()?; } Ok(val) diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 7a1610c..996cc4b 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -1,12 +1,12 @@ -use std::{fmt, io}; +use crate::rmc::structures::helpers::DummyWriter; use std::io::{Read, Write}; use std::string::FromUtf8Error; +use std::{fmt, io}; use thiserror::Error; -use crate::rmc::structures::helpers::DummyWriter; //ideas for the future: make a proc macro library which allows generation of struct reads #[derive(Error, Debug)] -pub enum Error{ +pub enum Error { #[error("Io Error: {0}")] Io(#[from] io::Error), #[error("UTF8 conversion Error: {0}")] @@ -18,51 +18,52 @@ pub enum Error{ #[error("an error occurred reading the station url")] StationUrlInvalid, #[error("error formatting text: {0}")] - FormatError(#[from] fmt::Error) + FormatError(#[from] fmt::Error), } pub type Result = std::result::Result; -pub mod string; pub mod any; -pub mod qresult; pub mod buffer; pub mod connection_data; -pub mod rmc_struct; -pub mod list; -pub mod qbuffer; -pub mod primitives; -pub mod matchmake; -pub mod variant; -pub mod ranking; -pub mod networking; pub mod helpers; +pub mod list; +pub mod matchmake; +pub mod networking; +pub mod primitives; +pub mod qbuffer; +pub mod qresult; +pub mod ranking; +pub mod rmc_struct; +pub mod string; +pub mod variant; -pub trait RmcSerialize{ +pub trait RmcSerialize { fn serialize(&self, writer: &mut impl Write) -> Result<()>; - fn serialize_write_size(&self) -> Result{ + fn serialize_write_size(&self) -> Result { let mut dummy = DummyWriter::new(); self.serialize(&mut dummy)?; Ok(dummy.get_total_len()) } - fn deserialize(reader: &mut impl Read) -> Result where Self: Sized; + fn deserialize(reader: &mut impl Read) -> Result + where + Self: Sized; - fn to_data(&self) -> Result>{ - let mut data = Vec::with_capacity( - self.serialize_write_size()? as usize - ); + fn to_data(&self) -> Result> { + let expected_size = self.serialize_write_size()?; + let mut data = Vec::with_capacity(expected_size as usize); self.serialize(&mut data)?; - debug_assert_eq!(self.serialize_write_size().unwrap(), data.len() as u32); + debug_assert_eq!(expected_size, data.len() as u32); Ok(data) } } -impl RmcSerialize for (){ +impl RmcSerialize for () { fn serialize(&self, _writer: &mut impl Write) -> Result<()> { Ok(()) } @@ -72,6 +73,4 @@ impl RmcSerialize for (){ fn serialize_write_size(&self) -> Result { Ok(0) } - - -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index e3888d4..6ce1c2f 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -280,8 +280,8 @@ impl Self{ +impl QResult { + pub fn success(error_code: ErrorCode) -> Self { let val: u32 = error_code.into(); Self(val & (!ERROR_MASK)) } - pub fn error(error_code: ErrorCode) -> Self{ + pub fn error(error_code: ErrorCode) -> Self { let val: u32 = error_code.into(); Self(val | ERROR_MASK) } } -impl RmcSerialize for QResult{ +impl RmcSerialize for QResult { fn serialize(&self, writer: &mut impl Write) -> Result<()> { writer.write(bytes_of(self))?; Ok(()) } fn deserialize(reader: &mut impl Read) -> Result { - Ok(reader.read_struct(IS_BIG_ENDIAN)?) + let result: Self = reader.read_struct(IS_BIG_ENDIAN)?; + println!("reading qresult: {:x}", result.0); + Ok(result) } -} \ No newline at end of file + fn serialize_write_size(&self) -> Result { + Ok(4) + } +} diff --git a/rnex-core/src/rmc/structures/rmc_struct.rs b/rnex-core/src/rmc/structures/rmc_struct.rs index 52184bb..7660f96 100644 --- a/rnex-core/src/rmc/structures/rmc_struct.rs +++ b/rnex-core/src/rmc/structures/rmc_struct.rs @@ -1,15 +1,13 @@ - +use crate::rmc::structures::Result; use std::cmp::max; use std::fmt::Arguments; use std::io; use std::io::{ErrorKind, IoSlice, Read, Write}; -use crate::rmc::structures::Result; - #[repr(C, packed)] -struct StructureHeader{ +struct StructureHeader { version: u8, - length: u32 + length: u32, } #[cfg(feature = "rmc_struct_header")] @@ -38,7 +36,12 @@ impl Write for OnlyWriteVec<'_> { } #[cfg(feature = "rmc_struct_header")] -pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { +pub fn write_struct( + writer: &mut T, + version: u8, + inner_size: u32, + pred: impl FnOnce(&mut T) -> Result<()>, +) -> Result<()> { use bytemuck::bytes_of; writer.write_all(&[version])?; @@ -50,29 +53,31 @@ pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred Ok(()) } - - #[cfg(not(feature = "rmc_struct_header"))] -pub fn write_struct(writer: &mut T, _version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { +pub fn write_struct( + writer: &mut T, + _version: u8, + _inner_size: u32, + pred: impl FnOnce(&mut T) -> Result<()>, +) -> Result<()> { pred(writer) } - -pub struct SubRead<'a, T: Read>{ +pub struct SubRead<'a, T: Read> { left_to_read: usize, - origin: &'a mut T + origin: &'a mut T, } -impl<'a, T: Read> SubRead<'a, T>{ - pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self{ - Self{ +impl<'a, T: Read> SubRead<'a, T> { + pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self { + Self { left_to_read, - origin + origin, } } } -impl Read for SubRead<'_, T>{ +impl Read for SubRead<'_, T> { #[inline(always)] fn read(&mut self, buf: &mut [u8]) -> io::Result { let max_read = max(self.left_to_read, buf.len()); @@ -83,8 +88,11 @@ impl Read for SubRead<'_, T>{ #[inline(always)] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if buf.len() > self.left_to_read{ - return Err(io::Error::new(ErrorKind::UnexpectedEof, "Would run over end of SubRead")); + if buf.len() > self.left_to_read { + return Err(io::Error::new( + ErrorKind::UnexpectedEof, + "Would run over end of SubRead", + )); } self.left_to_read -= buf.len(); self.origin.read_exact(buf) @@ -92,10 +100,14 @@ impl Read for SubRead<'_, T>{ } #[cfg(feature = "rmc_struct_header")] -pub fn read_struct(reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead) -> Result) -> Result { +pub fn read_struct( + reader: &mut R, + version: u8, + pred: impl FnOnce(&mut SubRead) -> Result, +) -> Result { use crate::rmc::structures::Error::VersionMismatch; - use v_byte_helpers::ReadExtensions; use v_byte_helpers::IS_BIG_ENDIAN; + use v_byte_helpers::ReadExtensions; let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?; if ver != version { @@ -108,6 +120,10 @@ pub fn read_struct(reader: &mut R, version: u8, pred: impl Fn } #[cfg(not(feature = "rmc_struct_header"))] -pub fn read_struct(mut reader: &mut R, _version: u8, pred: impl FnOnce(&mut R) -> Result) -> Result { +pub fn read_struct( + mut reader: &mut R, + _version: u8, + pred: impl FnOnce(&mut R) -> Result, +) -> Result { Ok(pred(&mut reader)?) } diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs index 1231956..8830822 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -1,18 +1,18 @@ -use std::io::{Read, Write}; +use super::{Result, RmcSerialize}; use bytemuck::bytes_of; use log::error; +use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use super::{Result, RmcSerialize}; -impl RmcSerialize for String{ +impl RmcSerialize for String { fn deserialize(reader: &mut impl Read) -> Result { let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; - if len == 0{ + if len == 0 { return Ok("".to_string()); } let mut data = vec![0; len as usize]; reader.read_exact(&mut data)?; - if *data.last().unwrap() != 0{ + if *data.last().unwrap() != 0 { error!("unable to find null terminator... continuing anyways"); } data.pop(); @@ -27,7 +27,7 @@ impl RmcSerialize for String{ } } -impl RmcSerialize for &str{ +impl RmcSerialize for &str { fn deserialize(_reader: &mut impl Read) -> Result { panic!("cannot serialize to &str") } @@ -45,4 +45,3 @@ impl RmcSerialize for &str{ Ok(2 + self.as_bytes().len() as u32 + 1) } } - -- 2.47.3 From aa18d1ee3ebd0c51a30051b01e3faa5a13b143cb Mon Sep 17 00:00:00 2001 From: Maple Date: Wed, 25 Mar 2026 00:42:30 +0100 Subject: [PATCH 61/98] fix prudpv1 --- prudpv1/src/prudp/packet.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prudpv1/src/prudp/packet.rs b/prudpv1/src/prudp/packet.rs index a4d87e9..5a27d33 100644 --- a/prudpv1/src/prudp/packet.rs +++ b/prudpv1/src/prudp/packet.rs @@ -17,6 +17,7 @@ use rnex_core::prudp::virtual_port::VirtualPort; use std::fmt::{Debug, Formatter}; use std::io; use std::io::{Cursor, Read, Seek, Write}; +use std::net::SocketAddr; use std::net::SocketAddrV4; use thiserror::Error; use v_byte_helpers::SwapEndian; @@ -281,7 +282,7 @@ impl PRUDPV1Packet { pub fn source_sockaddr(&self, socket_addr_v4: SocketAddrV4) -> PRUDPSockAddr { PRUDPSockAddr { - regular_socket_addr: socket_addr_v4, + regular_socket_addr: SocketAddr::V4(socket_addr_v4), virtual_port: self.header.source_port, } } -- 2.47.3 From 55b39597979b89c017bb37beb85122d6336a846e Mon Sep 17 00:00:00 2001 From: red binder Date: Mon, 6 Apr 2026 13:35:55 +0000 Subject: [PATCH 62/98] Add NEX results and fix timers --- Cargo.lock | 372 +++++++++++++++++++++++- rnex-core/Cargo.toml | 4 +- rnex-core/src/nex/matchmake.rs | 32 +- rnex-core/src/nex/user.rs | 152 +++++++++- rnex-core/src/rmc/message.rs | 3 +- rnex-core/src/rmc/protocols/ranking.rs | 54 ++-- rnex-core/src/rmc/structures/qbuffer.rs | 3 +- rnex-core/src/rmc/structures/ranking.rs | 18 +- 8 files changed, 586 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b010331..d34993e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,35 @@ dependencies = [ "inout", ] +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc4bff745c9b4c7fb1e97b25d13153da2bc7796260141df62378998d070207f" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation" version = "0.10.1" @@ -232,12 +261,38 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dotenv" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "flate2" version = "1.1.5" @@ -254,6 +309,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + [[package]] name = "futures-core" version = "0.3.31" @@ -337,6 +401,12 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + [[package]] name = "hex" version = "0.4.3" @@ -393,6 +463,118 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a8a2b9cb3e0b0c1803dbb0758ffac5de2f425b23c28f518faabd9d805342ff" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.4" @@ -441,6 +623,18 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "lock_api" version = "0.4.13" @@ -605,6 +799,15 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -828,6 +1031,8 @@ dependencies = [ "paste", "rand 0.8.5", "rc4", + "serde", + "serde_json", "simplelog", "thiserror", "tokio", @@ -935,24 +1140,47 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", "syn 2.0.104", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "sha1" version = "0.10.6" @@ -1018,6 +1246,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "subtle" version = "2.6.1" @@ -1046,6 +1280,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -1108,6 +1353,16 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tokio" version = "1.47.1" @@ -1209,11 +1464,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" dependencies = [ "base64", + "cookie_store", "flate2", "log", "percent-encoding", "rustls", "rustls-pki-types", + "serde", + "serde_json", "ureq-proto", "utf-8", "webpki-roots", @@ -1231,12 +1489,29 @@ dependencies = [ "log", ] +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + [[package]] name = "v-byte-helpers" version = "0.1.1" @@ -1505,6 +1780,35 @@ version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.8.26" @@ -1525,8 +1829,68 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index d44c000..ff2b7b3 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -25,7 +25,9 @@ paste = "1.0.15" typenum = "1.18.0" json = "0.12.4" anyhow = "1.0.100" -ureq = "3.1.4" +ureq = { version = "3.1.4", features = [ "json" ] } +serde = { version = "1.0.228", features = [ "derive" ] } +serde_json = "1.0.149" [dev-dependencies] # criterion = "0.7.0" diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 0a155fa..032fbad 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -247,27 +247,29 @@ impl ExtendedMatchmakeSession { param_3: self.connected_players.len() as _, }) .await; - } + } } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { continue; }; - - let older_pid = old_conns.pid; - - initiating_user - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: older_pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; + if old_conns.pid != self.session.gathering.host_pid{ + continue; + } + for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid){ + old_conns + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: new_conn_pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; + } } } pub fn has_active_players(&self) -> bool { diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index d8450e9..2e63b98 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -5,10 +5,14 @@ use crate::nex::remote_console::RemoteConsole; use crate::rmc::protocols::matchmake::{ Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake, }; +use serde::{Serialize, Deserialize}; +use std::env; +use std::str::FromStr; use crate::rmc::protocols::nat_traversal::{ NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole, }; +use rnex_core::kerberos::KerberosDateTime; use rnex_core::PID; use rnex_core::prudp::station_url::StationUrl; use rnex_core::prudp::station_url::UrlOptions::{ @@ -29,12 +33,15 @@ use rnex_core::rmc::structures::matchmake::{ }; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use log::info; +use log::{info, error}; use macros::rmc_struct; +use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::prudp::socket_addr::PRUDPSockAddr; use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_AccountExpired}; use rnex_core::rmc::structures::qresult::QResult; use std::sync::{Arc, Weak}; +use rnex_core::rmc::protocols::ranking::{CompetitionRankingScoreData, CompetitionRankingGetParam, CompetitionRankingScoreInfo}; +use rnex_core::rmc::structures::ranking::{UploadCompetitionData}; use tokio::sync::{Mutex, RwLock}; define_rmc_proto!( @@ -582,4 +589,145 @@ impl NatTraversal for User { } } -impl Ranking for User {} +#[derive(Serialize, Deserialize)] +pub struct CompetitionPostResults { + pub splatfest_id: u32, + pub score: u32, + pub team_id: u8, + pub team_win: u8, + pub user: PID, +} + +// Seperate function because I cannot give a fuck right now +fn fetch_team_votes(fest_id: u32) -> Result, ErrorCode> { + let endpoint_votes = env::var("RNEX_SPLATOON_RESULTS_VOTES_GET").map_err(|_| { + error!("RNEX_SPLATOON_RESULTS_VOTES_GET not set"); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let url_votes = format!("{}?splatfest_id={}", endpoint_votes, fest_id); + let mut response = ureq::get(&url_votes).call().map_err(|e| { + error!("GET for votes failed: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let body = response.body_mut().read_to_string().map_err(|e| { + error!("failed to read votes body: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let body = body.trim().trim_start_matches('[').trim_end_matches(']'); + let votes: Result, _> = body + .split(',') + .map(|s| u32::from_str(s.trim())) + .collect(); + + votes.map_err(|e| { + error!("failed to parse votes: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + }) +} + +impl Ranking for User { + async fn competition_ranking_get_param( + &self, + param: CompetitionRankingGetParam, + ) -> Result, ErrorCode> { + let fest_id = param.festival_ids.get(0).copied().unwrap_or(0); + + let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET") + .map_err(|_| { + error!("RNEX_SPLATOON_RESULTS_GET not set"); + ErrorCode::RendezVous_InvalidConfiguration + })?; + + let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id); + let response_results = ureq::get(&url_results).call(); + + let results: Vec = match response_results { + Ok(mut res) => res + .body_mut() + .read_json() + .map_err(|e| { + error!("failed to parse JSON: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?, + Err(e) => { + error!("GET failed: {:?}", e); + return Err(ErrorCode::RendezVous_InvalidConfiguration); + } + }; + + let team_votes = fetch_team_votes(fest_id)?; + + let score_data: Vec = results + .iter() + .map(|r| CompetitionRankingScoreData { + unk: 1, + pid: r.user, + score: r.score, + modified: KerberosDateTime::now(), + unk2: 1, + appdata: QBuffer(vec![]), + }) + .collect(); + + let info = CompetitionRankingScoreInfo { + fest_id, + score_data, + unk: 0, + team_wins: results.iter().map(|r| r.team_win as u32).collect(), + team_votes, + }; + + Ok(vec![info]) + } + + async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result { + info!("fest results for user {:?}:", self.pid); + info!("fest id: {:?}", param.splatfest_id); + info!("score: {:?}", param.score); + info!("team id: {:?}", param.team_id); + info!("did current team win: {:?}", param.team_win); + + let endpoint = match env::var("RNEX_SPLATOON_RESULTS_POST") { + Ok(url) => url, + Err(_) => { + error!("RNEX_SPLATOON_RESULTS_POST not set"); + return Ok(false); + } + }; + + let payload = CompetitionPostResults { + splatfest_id: param.splatfest_id, + score: param.score, + team_id: param.team_id, + team_win: param.team_win, + user: self.pid, + }; + + let json_body = match serde_json::to_string(&payload) { + Ok(j) => j, + Err(e) => { + error!("error making json_body: {:?}", e); + return Ok(false); + } + }; + + let response = ureq::post(&endpoint) + .header("Content-Type", "application/json") + .send(json_body); + + match response { + Ok(res) => { + info!("POST worked: {}", res.status()); + } + Err(e) => { + error!("POST borked: {:?}", e); + } + } + + Ok(true) + } +} + diff --git a/rnex-core/src/rmc/message.rs b/rnex-core/src/rmc/message.rs index cf951bf..4fcdfbe 100644 --- a/rnex-core/src/rmc/message.rs +++ b/rnex-core/src/rmc/message.rs @@ -42,7 +42,8 @@ impl RMCMessage{ error!("received incorrect rmc packet: expected size {} but found {}", size, header_size + rest_of_data.len()); } - + // println!("rmc packet: protoid: {}, method id: {}", protocol_id, method_id); + // println!("{}", hex::encode(&rest_of_data)); //stream. Ok(Self{ diff --git a/rnex-core/src/rmc/protocols/ranking.rs b/rnex-core/src/rmc/protocols/ranking.rs index 93dcb87..b9dba06 100644 --- a/rnex-core/src/rmc/protocols/ranking.rs +++ b/rnex-core/src/rmc/protocols/ranking.rs @@ -1,33 +1,51 @@ -use macros::{rmc_struct, rmc_proto, RmcSerialize}; +use macros::{rmc_struct, rmc_proto, RmcSerialize, method_id}; + +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures::qbuffer::QBuffer; + +use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::ranking::UploadCompetitionData; #[derive(RmcSerialize, Debug, Default, Clone)] -struct ResultsRange{ - offset: u32, - size: u32 +#[rmc_struct(0)] +pub struct ResultsRange{ + pub offset: u32, + pub size: u32 } #[derive(RmcSerialize, Debug, Default, Clone)] #[rmc_struct(1)] -struct CompetitionRankingGetParam{ - unk: u32, - range: ResultsRange, - festival_ids: Vec, +pub struct CompetitionRankingGetParam { + pub unk: u32, + pub range: ResultsRange, + pub festival_ids: Vec, } #[derive(RmcSerialize, Debug, Default, Clone)] #[rmc_struct(0)] -struct CompetitionRankingScoreInfo{ - fest_id: u32, - score_data: Vec, - unk: u32, - team_wins: Vec, - team_votes: Vec +pub struct CompetitionRankingScoreInfo{ + pub fest_id: u32, + pub score_data: Vec, + pub unk: u32, + pub team_wins: Vec, + pub team_votes: Vec } - +#[derive(RmcSerialize, Debug, Clone)] +#[rmc_struct(0)] +pub struct CompetitionRankingScoreData{ + pub unk: u32, + pub pid: u32, + pub score: u32, + pub modified: KerberosDateTime, + pub unk2: u8, + pub appdata: QBuffer +} #[rmc_proto(112)] pub trait Ranking{ - //#[method_id(16)] - //async fn competition_ranking_get_param(&self, param: CompetitionRankingGetParam) -> Result,ErrorCode>; -} \ No newline at end of file + #[method_id(16)] + async fn competition_ranking_get_param(&self, param: CompetitionRankingGetParam) -> Result,ErrorCode>; + #[method_id(18)] + async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result; +} diff --git a/rnex-core/src/rmc/structures/qbuffer.rs b/rnex-core/src/rmc/structures/qbuffer.rs index fb30e64..2f7b23a 100644 --- a/rnex-core/src/rmc/structures/qbuffer.rs +++ b/rnex-core/src/rmc/structures/qbuffer.rs @@ -3,8 +3,7 @@ use bytemuck::bytes_of; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::{Result, RmcSerialize}; - -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct QBuffer(pub Vec); impl RmcSerialize for QBuffer{ diff --git a/rnex-core/src/rmc/structures/ranking.rs b/rnex-core/src/rmc/structures/ranking.rs index 778c5cf..773889d 100644 --- a/rnex-core/src/rmc/structures/ranking.rs +++ b/rnex-core/src/rmc/structures/ranking.rs @@ -4,15 +4,15 @@ use rnex_core::rmc::structures::qbuffer::QBuffer; #[derive(RmcSerialize, Debug)] #[rmc_struct(0)] -struct UploadCompetitionData { - winning_team: u32, - splatfest_id: u32, - unk_2: u32, - unk_3: u32, - team_id_1: u8, - team_id_2: u8, - unk_5: u32, - player_data: QBuffer, +pub struct UploadCompetitionData{ + pub unk_1/*?*/: u32, + pub splatfest_id: u32, + pub unk_2/*?*/: u32, + pub score: u32, + pub team_id: u8, + pub team_win: u8, + pub is_first_upload: bool, + pub appdata: QBuffer, } #[derive(Copy, Clone, Pod, Zeroable)] -- 2.47.3 From 0ef484ffd255f4406edb4c2772dc86e3fd00aa2e Mon Sep 17 00:00:00 2001 From: Maple Date: Mon, 6 Apr 2026 16:42:08 +0200 Subject: [PATCH 63/98] fix friends --- Cargo.lock | 1 + proxy-common/Cargo.toml | 1 + proxy-common/src/lib.rs | 19 ++++++++--------- prudpv0/src/packet.rs | 1 + rnex-core/src/rnex_proxy_common.rs | 33 +++++++++++++++++++++++++++++- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b010331..f681663 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -647,6 +647,7 @@ dependencies = [ name = "proxy-common" version = "0.1.0" dependencies = [ + "hex", "log", "rnex-core", "thiserror", diff --git a/proxy-common/Cargo.toml b/proxy-common/Cargo.toml index 6ba9ba7..bd13ffa 100644 --- a/proxy-common/Cargo.toml +++ b/proxy-common/Cargo.toml @@ -8,3 +8,4 @@ thiserror = "2.0.12" rnex-core = { path = "../rnex-core", version = "0.1.1" } tokio = { version = "1.47.0", features = ["full"] } log = "0.4.25" +hex = "0.4.3" diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index 3bd902d..dc6ed11 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -187,17 +187,14 @@ pub async fn new_backend_connection( } }; - if let Err(e) = stream - .send_buffer( - &ConnectionInitData { - prudpsock_addr: addr, - pid: pid, - } - .to_data() - .unwrap(), - ) - .await - { + let data = ConnectionInitData { + prudpsock_addr: addr, + pid: pid, + } + .to_data() + .unwrap(); + + if let Err(e) = stream.send_buffer(&data).await { error!("unable to send establishment data to backend: {}", e); return None; }; diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index e94ab46..50bfe55 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -268,6 +268,7 @@ pub fn new_connect_packet( .checksummed_data() .expect("packet malformed in creation"), ); + info!("header: {:?}", packet.header()); packet.0 } diff --git a/rnex-core/src/rnex_proxy_common.rs b/rnex-core/src/rnex_proxy_common.rs index 7f2c363..d103e43 100644 --- a/rnex-core/src/rnex_proxy_common.rs +++ b/rnex-core/src/rnex_proxy_common.rs @@ -1,9 +1,40 @@ use crate::{PID, prudp::socket_addr::PRUDPSockAddr}; use macros::RmcSerialize; -#[derive(Debug, RmcSerialize)] +#[derive(Debug, RmcSerialize, PartialEq, Eq)] #[rmc_struct(0)] pub struct ConnectionInitData { pub prudpsock_addr: PRUDPSockAddr, pub pid: PID, } + +#[cfg(test)] +mod test { + use std::{ + io::Cursor, + net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4}, + }; + + use crate::{ + prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort}, + rmc::structures::RmcSerialize, + rnex_proxy_common::ConnectionInitData, + }; + + #[test] + fn test() { + let data = ConnectionInitData { + prudpsock_addr: PRUDPSockAddr { + regular_socket_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::BROADCAST, 19293)), + virtual_port: VirtualPort::new(10, 2), + }, + pid: 100, + }; + + let ser = data.to_data().unwrap(); + + let de = ConnectionInitData::deserialize(&mut Cursor::new(ser)).unwrap(); + + assert_eq!(data, de); + } +} -- 2.47.3 From 5392e08ea239575c3c2c8c8c900a8c0372de09b9 Mon Sep 17 00:00:00 2001 From: red binder Date: Mon, 6 Apr 2026 22:09:38 +0200 Subject: [PATCH 64/98] Temporary debugging --- rnex-core/src/nex/user.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index 2e63b98..f16e813 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -659,6 +659,12 @@ impl Ranking for User { }; let team_votes = fetch_team_votes(fest_id)?; + let mut wins = vec![0u32, 0u32]; + for r in &results { + if r.team_win == 1 && (r.team_id == 0 || r.team_id == 1) { + wins[r.team_id as usize] += 1; + } + } let score_data: Vec = results .iter() @@ -672,11 +678,16 @@ impl Ranking for User { }) .collect(); + println!("Fest id: {:?}", fest_id); + println!("Score data: {:?}", score_data); + println!("Wins: {:?}", wins); + println!("Votes: {:?}", team_votes); + let info = CompetitionRankingScoreInfo { fest_id, score_data, unk: 0, - team_wins: results.iter().map(|r| r.team_win as u32).collect(), + team_wins: wins, team_votes, }; -- 2.47.3 From 26fc8cb077a6f648ffb943f7b59a4e6a1af6486f Mon Sep 17 00:00:00 2001 From: red binder Date: Mon, 6 Apr 2026 22:34:40 +0200 Subject: [PATCH 65/98] Remove debugging statements --- rnex-core/src/nex/user.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index f16e813..c86ae73 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -677,11 +677,6 @@ impl Ranking for User { appdata: QBuffer(vec![]), }) .collect(); - - println!("Fest id: {:?}", fest_id); - println!("Score data: {:?}", score_data); - println!("Wins: {:?}", wins); - println!("Votes: {:?}", team_votes); let info = CompetitionRankingScoreInfo { fest_id, -- 2.47.3 From c5677e304da1f1d177cafd40b6e147e4605ed5e6 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 11 Apr 2026 16:36:57 +0200 Subject: [PATCH 66/98] add more debugging logs --- prudpv0/src/server.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 1305d81..ce6cd21 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -284,6 +284,9 @@ impl Server { }); let mut conns = self.connections.write().await; + if conns.contains_key(&addr) { + error!("client already connected but tried to connect again"); + } conns.insert(addr, conn.clone()); drop(conns); @@ -346,7 +349,8 @@ impl Server { ); while let Some((_, mut packet)) = { let ctr = conn.client_packet_counter; - conn.packet_queue.remove(&ctr) + let packet = conn.packet_queue.remove(&ctr); + packet } { info!("processing packet: {}", conn.client_packet_counter); let Some(payload) = packet.payload_mut() else { -- 2.47.3 From 1c8352a23536eed274e144215d7343bcd0b0537b Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 11 Apr 2026 18:16:20 +0200 Subject: [PATCH 67/98] actually delete connection if someone disconnects --- prudpv0/src/server.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index ce6cd21..63fefe7 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -414,6 +414,10 @@ impl Server { ); drop(inner); + let mut conns = self.connections.write().await; + conns.remove(&addr); + drop(conns); + self.socket.send_to(&packet, addr.regular_socket_addr).await; self.socket.send_to(&packet, addr.regular_socket_addr).await; self.socket.send_to(&packet, addr.regular_socket_addr).await; -- 2.47.3 From dd4015b2c4b49d196ea29d53bbaf5c96d681fd31 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 11 Apr 2026 20:02:10 +0200 Subject: [PATCH 68/98] tie connections to a session id + prudp socket address --- prudpv0/src/server.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 63fefe7..4921b3f 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -73,7 +73,7 @@ pub struct Server { param: ProxyStartupParam, socket: UdpSocket, crypto: C, - connections: RwLock>>>, + connections: RwLock>>>, } impl Server { @@ -167,8 +167,9 @@ impl Server { self.clone().send_data_packet(conn.clone(), &data).await; } } - async fn timeout_thread(self: Arc, conn: Arc>) { + async fn timeout_thread(self: Arc, conn: Weak>) { loop { + let Some(conn) = conn.upgrade() else { break }; sleep(Duration::from_secs(3)); let mut inner = conn.inner.lock().await; @@ -214,7 +215,7 @@ impl Server { drop(inner); let mut conns = self.connections.write().await; - conns.remove(&conn.addr); + conns.remove(&(conn.addr, conn.session_id)); drop(conns); break; } @@ -284,10 +285,10 @@ impl Server { }); let mut conns = self.connections.write().await; - if conns.contains_key(&addr) { + if conns.contains_key(&(addr, header.session_id)) { error!("client already connected but tried to connect again"); } - conns.insert(addr, conn.clone()); + conns.insert((addr, header.session_id), conn.clone()); drop(conns); spawn({ @@ -297,7 +298,7 @@ impl Server { }); spawn({ let this = self.clone(); - let conn = conn.clone(); + let conn = Arc::downgrade(&conn); this.timeout_thread(conn) }); @@ -325,7 +326,7 @@ impl Server { return; }; - let Some(res) = self.get_connection(addr).await else { + let Some(res) = self.get_connection((addr, header.session_id)).await else { warn!("data packet on inactive connection from: {:?}", addr); return; }; @@ -372,7 +373,7 @@ impl Server { info!("got ping"); let header = packet.header().unwrap(); - let Some(conn) = self.get_connection(addr).await else { + let Some(conn) = self.get_connection((addr, header.session_id)).await else { warn!("ping on inactive connection: {:?}", addr); return; }; @@ -398,7 +399,7 @@ impl Server { info!("got disconnect"); let header = packet.header().unwrap(); - let Some(conn) = self.get_connection(addr).await else { + let Some(conn) = self.get_connection((addr, header.session_id)).await else { warn!("ping on inactive connection: {:?}", addr); return; }; @@ -415,14 +416,17 @@ impl Server { drop(inner); let mut conns = self.connections.write().await; - conns.remove(&addr); + conns.remove(&(addr, header.session_id)); drop(conns); self.socket.send_to(&packet, addr.regular_socket_addr).await; self.socket.send_to(&packet, addr.regular_socket_addr).await; self.socket.send_to(&packet, addr.regular_socket_addr).await; } - async fn get_connection(&self, addr: PRUDPSockAddr) -> Option>> { + async fn get_connection( + &self, + addr: (PRUDPSockAddr, u8), + ) -> Option>> { let rd = self.connections.read().await; let res = rd.get(&addr).cloned(); drop(rd); @@ -444,7 +448,7 @@ impl Server { let addr = PRUDPSockAddr::new(SocketAddr::V4(addr), header.source); - if let Some(conn) = self.get_connection(addr).await { + if let Some(conn) = self.get_connection((addr, header.session_id)).await { let mut inner = conn.inner.lock().await; inner.last_action = Instant::now(); drop(inner); -- 2.47.3 From b503363e5698cb547c8c3b90bd43f47336968d3c Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 11 Apr 2026 20:24:13 +0200 Subject: [PATCH 69/98] add check setting status --- rnex-core/src/nex/friends_handler.rs | 4 ++++ rnex-core/src/rmc/protocols/friends.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index be5d684..09e9c9d 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -143,6 +143,10 @@ impl Friends for FriendsUser { false, )) } + + async fn check_setting_status(&self) -> Result { + Ok(0xFF) + } } impl Secure for FriendsUser { diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index 775016e..07dcd1a 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -143,4 +143,6 @@ pub trait Friends { ), ErrorCode, >; + #[method_id(19)] + async fn check_setting_status(&self) -> Result; } -- 2.47.3 From 8164317b1980259fb25d1ce9d7ded934201fd398 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 11 Apr 2026 21:59:37 +0200 Subject: [PATCH 70/98] fix friends connection --- prudpv0/src/server.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 4921b3f..34c7647 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -6,7 +6,6 @@ use std::{ Arc, LazyLock, Weak, atomic::{AtomicBool, AtomicU32}, }, - thread::sleep, time::Duration, }; @@ -30,7 +29,7 @@ use tokio::{ net::{TcpSocket, UdpSocket}, spawn, sync::{Mutex, RwLock}, - time::Instant, + time::{Instant, sleep}, }; use crate::{ @@ -170,7 +169,7 @@ impl Server { async fn timeout_thread(self: Arc, conn: Weak>) { loop { let Some(conn) = conn.upgrade() else { break }; - sleep(Duration::from_secs(3)); + sleep(Duration::from_secs(3)).await; let mut inner = conn.inner.lock().await; if (Instant::now() - inner.last_action).as_secs() > 5 { @@ -259,6 +258,7 @@ impl Server { }; let pid = ci.get_user_id(); + println!("user with pid {} is connecting", pid); let buf_conn = new_backend_connection(&self.param, addr, pid).await; let Some(buf_conn) = buf_conn else { error!("unable to connect to backend"); -- 2.47.3 From 7dd6265eddff46be751098d2c4d1746ccf03420f Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 12 Apr 2026 17:10:07 +0200 Subject: [PATCH 71/98] fix guest login on backend --- rnex-core/src/executables/friends_backend.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs index 7ea03b4..74983f7 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core/src/executables/friends_backend.rs @@ -56,9 +56,11 @@ pub async fn start_friends_backend() { }) }); } else { - Arc::new_cyclic(move |this| FriendsGuest { - fm, - addr: c.prudpsock_addr, + new_rmc_gateway_connection(stream.into(), move |r| { + Arc::new_cyclic(move |this| FriendsGuest { + fm, + addr: c.prudpsock_addr, + }) }); } } -- 2.47.3 From 3c651e874c413650c129acfbef7c62ddc50c3344 Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 12 Apr 2026 18:05:52 +0200 Subject: [PATCH 72/98] start work on implementing account management for friends --- rnex-core/src/nex/friends_handler.rs | 20 ++++++++++++++++++- .../src/rmc/protocols/account_management.rs | 19 ++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 09e9c9d..36d08dc 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -2,6 +2,9 @@ use std::sync::{Arc, atomic::AtomicU32}; use log::info; use macros::rmc_struct; +use rnex_core::rmc::protocols::account_management::{ + AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement, +}; use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends}; use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; use rnex_core::{ @@ -32,7 +35,8 @@ define_rmc_proto!( ); define_rmc_proto!( proto FriendsGuest{ - Secure + Secure, + AccountManagement } ); #[rmc_struct(FriendsUser)] @@ -198,3 +202,17 @@ impl Secure for FriendsGuest { Err(ErrorCode::Core_NotImplemented) } } + +impl AccountManagement for FriendsGuest { + async fn nintendo_create_account( + &self, + principal_name: String, + key: String, + groups: u32, + email: String, + auth_data: Any, + ) -> Result<(PID, String), ErrorCode> { + println!("{}, {}, {}, {}", principal_name, key, groups, email); + Err(ErrorCode::Core_NotImplemented) + } +} diff --git a/rnex-core/src/rmc/protocols/account_management.rs b/rnex-core/src/rmc/protocols/account_management.rs index 541d1f6..64bd3bc 100644 --- a/rnex-core/src/rmc/protocols/account_management.rs +++ b/rnex-core/src/rmc/protocols/account_management.rs @@ -1,4 +1,19 @@ -use macros::rmc_proto; +use macros::{method_id, rmc_proto}; + +use rnex_core::{ + PID, + rmc::{response::ErrorCode, structures::any::Any}, +}; #[rmc_proto(25)] -pub trait AccountManagement {} +pub trait AccountManagement { + #[method_id(27)] + async fn nintendo_create_account( + &self, + principal_name: String, + key: String, + groups: u32, + email: String, + auth_data: Any, + ) -> Result<(PID, String), ErrorCode>; +} -- 2.47.3 From 2fc2a0ac1ef954675ba6f42e40fa431dbaba582a Mon Sep 17 00:00:00 2001 From: Maple Date: Sun, 12 Apr 2026 18:56:08 +0200 Subject: [PATCH 73/98] implement nintendo_create_account --- rnex-core/src/grpc/account.rs | 36 +++++++++++++++++++ rnex-core/src/nex/friends_handler.rs | 30 ++++++++++++++++ .../src/rmc/protocols/account_management.rs | 13 ++++++- rnex-core/src/rmc/protocols/friends.rs | 6 ++-- 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/rnex-core/src/grpc/account.rs b/rnex-core/src/grpc/account.rs index 64be4e9..d6ad140 100644 --- a/rnex-core/src/grpc/account.rs +++ b/rnex-core/src/grpc/account.rs @@ -103,6 +103,42 @@ impl Client { Ok(val.as_bytes().try_into().map_err(|_| SomethingHappened)?) } + pub async fn get_pid_from_token(&mut self, token: String) -> Result { + let req = self + .do_request(object! { + "query": + r"query($token: String!){ + token(tokenData: $token){ + pid + } + }", + "variables": { + "token": token + } + }) + .await?; + // this breaks switch nex servers and should be fixed eventually + let Some(val) = req + .entries() + .find(|v| v.0 == "data") + .ok_or(SomethingHappened)? + .1 + .entries() + .find(|v| v.0 == "token") + .ok_or(SomethingHappened)? + .1 + .entries() + .find(|v| v.0 == "pid") + .ok_or(SomethingHappened)? + .1 + .as_u32() + else { + return Err(SomethingHappened); + }; + + Ok(val) + } + /*pub async fn get_user_data(&mut self , pid: u32) -> Result{ let req = Request::new(GetUserDataRequest{ pid diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 36d08dc..42e5c71 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -1,5 +1,8 @@ +use std::io::{Cursor, Write}; use std::sync::{Arc, atomic::AtomicU32}; +use bytemuck::bytes_of; +use hmac::Mac; use log::info; use macros::rmc_struct; use rnex_core::rmc::protocols::account_management::{ @@ -27,6 +30,9 @@ use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; use rnex_core::PID; +use crate::rmc::protocols::account_management::NintendoCreateAccountData; +use rnex_core::rmc::structures::RmcSerialize; + define_rmc_proto!( proto FriendsUser{ Secure, @@ -153,6 +159,8 @@ impl Friends for FriendsUser { } } +type HMacMd5 = hmac::Hmac; + impl Secure for FriendsUser { async fn register( &self, @@ -213,6 +221,28 @@ impl AccountManagement for FriendsGuest { auth_data: Any, ) -> Result<(PID, String), ErrorCode> { println!("{}, {}, {}, {}", principal_name, key, groups, email); + if auth_data.name == "NintendoCreateAccountData" { + let Ok(data) = + NintendoCreateAccountData::deserialize(&mut Cursor::new(&auth_data.data)) + else { + return Err(ErrorCode::Authentication_InvalidParam); + }; + + let pid = data.nna_info.principal_basic_info.pid; + info!("create account: {}", pid); + + let Ok(mut mac) = HMacMd5::new_from_slice(key.as_bytes()) else { + return Err(ErrorCode::Authentication_InvalidParam); + }; + + mac.write_all(bytes_of(&pid)) + .expect("failed to write to hmac???"); + let mac = mac.finalize().into_bytes(); + + let hex_str = hex::encode(mac); + + return Ok((pid, hex_str)); + } Err(ErrorCode::Core_NotImplemented) } } diff --git a/rnex-core/src/rmc/protocols/account_management.rs b/rnex-core/src/rmc/protocols/account_management.rs index 64bd3bc..8ef2d9e 100644 --- a/rnex-core/src/rmc/protocols/account_management.rs +++ b/rnex-core/src/rmc/protocols/account_management.rs @@ -1,10 +1,21 @@ -use macros::{method_id, rmc_proto}; +use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{ PID, rmc::{response::ErrorCode, structures::any::Any}, }; +use crate::{kerberos::KerberosDateTime, rmc::protocols::friends::NNAInfo}; + +#[derive(RmcSerialize, Debug, Clone)] +#[rmc_struct(0)] +pub struct NintendoCreateAccountData { + pub nna_info: NNAInfo, + pub nex_token: String, + pub birthday: KerberosDateTime, + pub unk: u64, +} + #[rmc_proto(25)] pub trait AccountManagement { #[method_id(27)] diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index 07dcd1a..3f6138f 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct MiiV2 { pub name: String, @@ -12,7 +12,7 @@ pub struct MiiV2 { pub date_time: KerberosDateTime, } -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct PrincipalBasicInfo { pub pid: u32, @@ -21,7 +21,7 @@ pub struct PrincipalBasicInfo { pub unk: u8, } -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct NNAInfo { pub principal_basic_info: PrincipalBasicInfo, -- 2.47.3 From 6d139075886665b270442bec7dc070bbeca9e660 Mon Sep 17 00:00:00 2001 From: red binder Date: Sun, 12 Apr 2026 22:15:15 +0200 Subject: [PATCH 74/98] Dynamically define access key --- editions.yaml | 2 ++ proxy-common/src/lib.rs | 5 +++++ prudpv0/src/crypto/friends_common.rs | 2 +- prudpv1/src/executables/proxy_insecure.rs | 2 +- prudpv1/src/executables/proxy_secure.rs | 2 +- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/editions.yaml b/editions.yaml index 5458ec6..7a6869c 100644 --- a/editions.yaml +++ b/editions.yaml @@ -7,6 +7,7 @@ splatoon: RNEX_VIRTUAL_PORT_INSECURE: "1:10" RNEX_VIRTUAL_PORT_SECURE: "1:10" RNEX_DEFAULT_PORT: 6000 + RNEX_ACCESS_KEY: "6f599f81" splatoon2: features: - v4-3-11 @@ -25,3 +26,4 @@ friends: RNEX_VIRTUAL_PORT_INSECURE: "1:10" RNEX_VIRTUAL_PORT_SECURE: "1:10" RNEX_DEFAULT_PORT: 6000 + RNEX_ACCESS_KEY: "ridfebb9" diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index dc6ed11..9c18f2e 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -31,6 +31,11 @@ const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT Err(_) => panic!("unable to get default port from env"), }; +const RNEX_ACCESS_KEY: u16 = match u16::from_str_radix(env!("RNEX_ACCESS_KEY"), 10) { + Ok(v) => v, + Err(_) => panic!("unable to get access key from env"), +}; + #[derive(Error, Debug)] pub enum Error { #[error("error getting environment variable \"{0}\": {1}")] diff --git a/prudpv0/src/crypto/friends_common.rs b/prudpv0/src/crypto/friends_common.rs index b11af1d..6ae6e42 100644 --- a/prudpv0/src/crypto/friends_common.rs +++ b/prudpv0/src/crypto/friends_common.rs @@ -1,5 +1,5 @@ use hmac::Hmac; use md5::Md5; -pub const ACCESS_KEY: &str = "ridfebb9"; +pub const ACCESS_KEY: &str = RNEX_ACCESS_KEY; pub type HmacMd5 = Hmac; diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 975f837..4049566 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -43,7 +43,7 @@ pub async fn start() { .expect("unable to start router"); let mut socket_secure = router_secure - .add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81")) + .add_socket(VirtualPort::new(1, 10), Unsecure(RNEX_ACCESS_KEY)) .await .expect("unable to add socket"); diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index 8446391..a16360e 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -30,7 +30,7 @@ pub async fn start() { let mut socket_secure = router_secure .add_socket( VirtualPort::new(1, 10), - Secure("6f599f81", SECURE_SERVER_ACCOUNT.clone()), + Secure(RNEX_ACCESS_KEY, SECURE_SERVER_ACCOUNT.clone()), ) .await .expect("unable to add socket"); -- 2.47.3 From fc39e3295b249e53818876654f57a90f8650cc56 Mon Sep 17 00:00:00 2001 From: red binder Date: Sun, 12 Apr 2026 22:33:02 +0200 Subject: [PATCH 75/98] Correctly evaluate access key --- proxy-common/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index 9c18f2e..75665a0 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -31,10 +31,7 @@ const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT Err(_) => panic!("unable to get default port from env"), }; -const RNEX_ACCESS_KEY: u16 = match u16::from_str_radix(env!("RNEX_ACCESS_KEY"), 10) { - Ok(v) => v, - Err(_) => panic!("unable to get access key from env"), -}; +const RNEX_ACCESS_KEY: &'static str = env!("RNEX_ACCESS_KEY"); #[derive(Error, Debug)] pub enum Error { -- 2.47.3 From c9c4a575b572bde91d454f1dceececd20db41250 Mon Sep 17 00:00:00 2001 From: red binder Date: Sun, 12 Apr 2026 22:35:07 +0200 Subject: [PATCH 76/98] oops --- proxy-common/src/lib.rs | 2 +- prudpv0/src/crypto/friends_common.rs | 1 + prudpv1/src/executables/proxy_insecure.rs | 1 + prudpv1/src/executables/proxy_secure.rs | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/proxy-common/src/lib.rs b/proxy-common/src/lib.rs index 75665a0..5cc13b7 100644 --- a/proxy-common/src/lib.rs +++ b/proxy-common/src/lib.rs @@ -31,7 +31,7 @@ const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT Err(_) => panic!("unable to get default port from env"), }; -const RNEX_ACCESS_KEY: &'static str = env!("RNEX_ACCESS_KEY"); +pub const RNEX_ACCESS_KEY: &'static str = env!("RNEX_ACCESS_KEY"); #[derive(Error, Debug)] pub enum Error { diff --git a/prudpv0/src/crypto/friends_common.rs b/prudpv0/src/crypto/friends_common.rs index 6ae6e42..a8f1629 100644 --- a/prudpv0/src/crypto/friends_common.rs +++ b/prudpv0/src/crypto/friends_common.rs @@ -1,5 +1,6 @@ use hmac::Hmac; use md5::Md5; +use proxy_common::RNEX_ACCESS_KEY; pub const ACCESS_KEY: &str = RNEX_ACCESS_KEY; pub type HmacMd5 = Hmac; diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 4049566..06299d1 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -19,6 +19,7 @@ use std::time::Duration; use tokio::net::TcpStream; use tokio::task; use tokio::time::sleep; +use proxy_common::RNEX_ACCESS_KEY; pub async fn start() { /*let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index a16360e..6bf3434 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -21,6 +21,7 @@ use std::time::Duration; use tokio::net::TcpStream; use tokio::task; use tokio::time::sleep; +use proxy_common::RNEX_ACCESS_KEY; pub async fn start() { let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) -- 2.47.3 From e874bf142dcdb96bf010ec0585023ea53fda81db Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 21:38:31 +0200 Subject: [PATCH 77/98] fix self holepunch --- rnex-core/src/nex/matchmake.rs | 36 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 032fbad..085c8a1 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -236,6 +236,9 @@ impl ExtendedMatchmakeSession { }*/ for pid in &list_of_connected_pids { + if other_conn.pid == *pid { + continue; + } other_conn .remote .process_notification_event(NotificationEvent { @@ -247,28 +250,31 @@ impl ExtendedMatchmakeSession { param_3: self.connected_players.len() as _, }) .await; - } + } } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { continue; }; - if old_conns.pid != self.session.gathering.host_pid{ - continue; + if old_conns.pid != self.session.gathering.host_pid { + continue; } - for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid){ - old_conns - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: new_conn_pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; + for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { + if old_conns.pid == new_conn_pid { + continue; + } + old_conns + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: new_conn_pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; } } } -- 2.47.3 From 81824b1540120533c93b18bd29dc5a290a2fa91d Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 22:09:02 +0200 Subject: [PATCH 78/98] try fixing matchmaking again --- rnex-core/src/nex/matchmake.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 085c8a1..e1afa21 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -235,10 +235,11 @@ impl ExtendedMatchmakeSession { continue; }*/ + if other_conn.pid != self.session.gathering.host_pid { + continue; + } + for pid in &list_of_connected_pids { - if other_conn.pid == *pid { - continue; - } other_conn .remote .process_notification_event(NotificationEvent { @@ -261,9 +262,6 @@ impl ExtendedMatchmakeSession { continue; } for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { - if old_conns.pid == new_conn_pid { - continue; - } old_conns .remote .process_notification_event(NotificationEvent { -- 2.47.3 From 09e5b1f92a1738e3a969bb82bed2d883659a88d3 Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 22:38:25 +0200 Subject: [PATCH 79/98] try fixing matchmaking again really hopefully --- rnex-core/src/nex/matchmake.rs | 7 ++-- rnex-core/src/nex/user.rs | 58 ++++++++++++++++------------------ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index e1afa21..dbaf9c0 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -234,10 +234,10 @@ impl ExtendedMatchmakeSession { joining_pid == self.session.gathering.owner_pid{ continue; }*/ - + /* if other_conn.pid != self.session.gathering.host_pid { continue; - } + } */ for pid in &list_of_connected_pids { other_conn @@ -258,9 +258,10 @@ impl ExtendedMatchmakeSession { let Some(old_conns) = old_conns.upgrade() else { continue; }; + /* if old_conns.pid != self.session.gathering.host_pid { continue; - } + } */ for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { old_conns .remote diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index c86ae73..29d5332 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -5,15 +5,12 @@ use crate::nex::remote_console::RemoteConsole; use crate::rmc::protocols::matchmake::{ Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake, }; -use serde::{Serialize, Deserialize}; -use std::env; -use std::str::FromStr; use crate::rmc::protocols::nat_traversal::{ NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole, }; -use rnex_core::kerberos::KerberosDateTime; use rnex_core::PID; +use rnex_core::kerberos::KerberosDateTime; use rnex_core::prudp::station_url::StationUrl; use rnex_core::prudp::station_url::UrlOptions::{ Address, NatFiltering, NatMapping, Port, RVConnectionID, @@ -31,17 +28,22 @@ use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::matchmake::{ AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, }; +use serde::{Deserialize, Serialize}; +use std::env; +use std::str::FromStr; use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification}; -use log::{info, error}; +use log::{error, info}; use macros::rmc_struct; -use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::rmc::protocols::ranking::{ + CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo, +}; use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_AccountExpired}; +use rnex_core::rmc::structures::qbuffer::QBuffer; use rnex_core::rmc::structures::qresult::QResult; +use rnex_core::rmc::structures::ranking::UploadCompetitionData; use std::sync::{Arc, Weak}; -use rnex_core::rmc::protocols::ranking::{CompetitionRankingScoreData, CompetitionRankingGetParam, CompetitionRankingScoreInfo}; -use rnex_core::rmc::structures::ranking::{UploadCompetitionData}; use tokio::sync::{Mutex, RwLock}; define_rmc_proto!( @@ -617,10 +619,7 @@ fn fetch_team_votes(fest_id: u32) -> Result, ErrorCode> { })?; let body = body.trim().trim_start_matches('[').trim_end_matches(']'); - let votes: Result, _> = body - .split(',') - .map(|s| u32::from_str(s.trim())) - .collect(); + let votes: Result, _> = body.split(',').map(|s| u32::from_str(s.trim())).collect(); votes.map_err(|e| { error!("failed to parse votes: {:?}", e); @@ -635,23 +634,19 @@ impl Ranking for User { ) -> Result, ErrorCode> { let fest_id = param.festival_ids.get(0).copied().unwrap_or(0); - let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET") - .map_err(|_| { - error!("RNEX_SPLATOON_RESULTS_GET not set"); - ErrorCode::RendezVous_InvalidConfiguration - })?; + let endpoint_results = env::var("RNEX_SPLATOON_RESULTS_GET").map_err(|_| { + error!("RNEX_SPLATOON_RESULTS_GET not set"); + ErrorCode::RendezVous_InvalidConfiguration + })?; let url_results = format!("{}?splatfest_id={}", endpoint_results, fest_id); let response_results = ureq::get(&url_results).call(); let results: Vec = match response_results { - Ok(mut res) => res - .body_mut() - .read_json() - .map_err(|e| { - error!("failed to parse JSON: {:?}", e); - ErrorCode::RendezVous_InvalidConfiguration - })?, + Ok(mut res) => res.body_mut().read_json().map_err(|e| { + error!("failed to parse JSON: {:?}", e); + ErrorCode::RendezVous_InvalidConfiguration + })?, Err(e) => { error!("GET failed: {:?}", e); return Err(ErrorCode::RendezVous_InvalidConfiguration); @@ -661,9 +656,8 @@ impl Ranking for User { let team_votes = fetch_team_votes(fest_id)?; let mut wins = vec![0u32, 0u32]; for r in &results { - if r.team_win == 1 && (r.team_id == 0 || r.team_id == 1) { - wins[r.team_id as usize] += 1; - } + let won_team = r.team_id ^ (!r.team_win); + wins[won_team as usize] += 1; } let score_data: Vec = results @@ -677,7 +671,7 @@ impl Ranking for User { appdata: QBuffer(vec![]), }) .collect(); - + let info = CompetitionRankingScoreInfo { fest_id, score_data, @@ -689,7 +683,10 @@ impl Ranking for User { Ok(vec![info]) } - async fn upload_competition_ranking_score(&self, param: UploadCompetitionData) -> Result { + async fn upload_competition_ranking_score( + &self, + param: UploadCompetitionData, + ) -> Result { info!("fest results for user {:?}:", self.pid); info!("fest id: {:?}", param.splatfest_id); info!("score: {:?}", param.score); @@ -732,8 +729,7 @@ impl Ranking for User { error!("POST borked: {:?}", e); } } - + Ok(true) } } - -- 2.47.3 From 7ff0950617777779b983c6a02fc32427ae35be39 Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 22:53:12 +0200 Subject: [PATCH 80/98] only let hosts see their own joins and let all other players not see their own joins --- rnex-core/src/nex/matchmake.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index dbaf9c0..1129c76 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -240,6 +240,9 @@ impl ExtendedMatchmakeSession { } */ for pid in &list_of_connected_pids { + if other_conn.pid != self.session.gathering.host_pid && other_conn.pid == *pid { + continue; + } other_conn .remote .process_notification_event(NotificationEvent { @@ -258,11 +261,11 @@ impl ExtendedMatchmakeSession { let Some(old_conns) = old_conns.upgrade() else { continue; }; - /* - if old_conns.pid != self.session.gathering.host_pid { - continue; - } */ for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { + if old_conns.pid != self.session.gathering.host_pid && old_conns.pid == new_conn_pid + { + continue; + } old_conns .remote .process_notification_event(NotificationEvent { -- 2.47.3 From 757ca292b9bea687991496bae49f9c22fc8f5d39 Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 23:05:53 +0200 Subject: [PATCH 81/98] yet another attempt --- rnex-core/src/nex/matchmake.rs | 36 +++++++++++++++------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index 1129c76..f449ddc 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -239,33 +239,29 @@ impl ExtendedMatchmakeSession { continue; } */ - for pid in &list_of_connected_pids { - if other_conn.pid != self.session.gathering.host_pid && other_conn.pid == *pid { - continue; - } - other_conn - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: *pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; - } + // for pid in &list_of_connected_pids { + other_conn + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: other_conn.pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; + // } } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { continue; }; + if old_conns.pid != self.session.gathering.host_pid { + continue; + } for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { - if old_conns.pid != self.session.gathering.host_pid && old_conns.pid == new_conn_pid - { - continue; - } old_conns .remote .process_notification_event(NotificationEvent { -- 2.47.3 From 9fdca492c407faf0fac28a45d90ac8d7505135ab Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 23:32:47 +0200 Subject: [PATCH 82/98] yet another another attempt --- rnex-core/src/nex/matchmake.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index f449ddc..d5bdab4 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -246,13 +246,36 @@ impl ExtendedMatchmakeSession { pid_source: initiating_pid, notif_type: 3001, param_1: self.session.gathering.self_gid as PID, - param_2: other_conn.pid, + param_2: *pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, }) .await; // } } + for other_connection in conns { + let Some(other_conn) = other_connection.upgrade() else { + continue; + }; + + for old_participant in &old_particip { + let Some(old_particip) = old_participant.upgrade() else { + continue; + }; + + other_conn + .remote + .process_notification_event(NotificationEvent { + pid_source: initiating_pid, + notif_type: 3001, + param_1: self.session.gathering.self_gid as PID, + param_2: old_particip.pid, + str_param: join_msg.clone(), + param_3: self.connected_players.len() as _, + }) + .await; + } + } for old_conns in &old_particip { let Some(old_conns) = old_conns.upgrade() else { -- 2.47.3 From 9352687a4a4671fb1377173b2d141f920a080d7f Mon Sep 17 00:00:00 2001 From: Maple Date: Fri, 24 Apr 2026 23:43:57 +0200 Subject: [PATCH 83/98] fix building --- rnex-core/src/nex/matchmake.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index d5bdab4..a1a1f4c 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -246,7 +246,7 @@ impl ExtendedMatchmakeSession { pid_source: initiating_pid, notif_type: 3001, param_1: self.session.gathering.self_gid as PID, - param_2: *pid, + param_2: other_conn.pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, }) -- 2.47.3 From 40793af5c3fc7742ed0851a8c022426c7529f715 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 00:06:04 +0200 Subject: [PATCH 84/98] revert mostly back and try less big changes --- rnex-core/src/nex/matchmake.rs | 36 +++++----------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/rnex-core/src/nex/matchmake.rs b/rnex-core/src/nex/matchmake.rs index a1a1f4c..0a18f74 100644 --- a/rnex-core/src/nex/matchmake.rs +++ b/rnex-core/src/nex/matchmake.rs @@ -234,42 +234,15 @@ impl ExtendedMatchmakeSession { joining_pid == self.session.gathering.owner_pid{ continue; }*/ - /* - if other_conn.pid != self.session.gathering.host_pid { - continue; - } */ - - // for pid in &list_of_connected_pids { - other_conn - .remote - .process_notification_event(NotificationEvent { - pid_source: initiating_pid, - notif_type: 3001, - param_1: self.session.gathering.self_gid as PID, - param_2: other_conn.pid, - str_param: join_msg.clone(), - param_3: self.connected_players.len() as _, - }) - .await; - // } - } - for other_connection in conns { - let Some(other_conn) = other_connection.upgrade() else { - continue; - }; - - for old_participant in &old_particip { - let Some(old_particip) = old_participant.upgrade() else { - continue; - }; + for pid in &list_of_connected_pids { other_conn .remote .process_notification_event(NotificationEvent { pid_source: initiating_pid, notif_type: 3001, param_1: self.session.gathering.self_gid as PID, - param_2: old_particip.pid, + param_2: *pid, str_param: join_msg.clone(), param_3: self.connected_players.len() as _, }) @@ -281,9 +254,9 @@ impl ExtendedMatchmakeSession { let Some(old_conns) = old_conns.upgrade() else { continue; }; - if old_conns.pid != self.session.gathering.host_pid { + /*if old_conns.pid != self.session.gathering.host_pid { continue; - } + }*/ for new_conn_pid in conns.iter().filter_map(Weak::upgrade).map(|c| c.pid) { old_conns .remote @@ -299,6 +272,7 @@ impl ExtendedMatchmakeSession { } } } + pub fn has_active_players(&self) -> bool { self.connected_players .iter() -- 2.47.3 From 731fa91b72d5316266bc4513020685e854bdf4af Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 10:52:40 +0200 Subject: [PATCH 85/98] fix potential crash bug --- rnex-core/src/nex/user.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index 29d5332..57c36d8 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -657,7 +657,9 @@ impl Ranking for User { let mut wins = vec![0u32, 0u32]; for r in &results { let won_team = r.team_id ^ (!r.team_win); - wins[won_team as usize] += 1; + if let Some(team) = wins.get_mut(won_team as usize) { + *team += 1 + }; } let score_data: Vec = results -- 2.47.3 From 58c9e43fa3e2352822e2d470b979526ddd673e3f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 12:59:49 +0200 Subject: [PATCH 86/98] add fragments to v0 outgoing packets --- prudpv0/src/server.rs | 85 +++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 34c7647..a336abb 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -106,50 +106,55 @@ impl Server { .expect("packet malformed in creation"), );*/ let mut inner = conn.inner.lock().await; - let seq = inner.server_packet_counter; - let packet = new_data_packet( - NEED_ACK | RELIABLE, - self.param.virtual_port, - conn.addr.virtual_port, - data, - inner.server_packet_counter, - conn.session_id, - 0, - &mut inner.crypto_instance, - &self.crypto, - ); - inner.server_packet_counter += 1; + let pieces = data.chunks(1000); + let max_piece = pieces.len() - 1; + let mut frag_num = 1; + for (i, piece) in pieces.enumerate() { + let seq = inner.server_packet_counter; + let packet = new_data_packet( + NEED_ACK | RELIABLE, + (&self).param.virtual_port, + conn.addr.virtual_port, + piece, + inner.server_packet_counter, + conn.session_id, + if i == max_piece { 0 } else { frag_num }, + &mut inner.crypto_instance, + &(&self).crypto, + ); + inner.server_packet_counter += 1; - let packet = Arc::new(packet); - let packet_ref = Arc::downgrade(&packet); + let packet = Arc::new(packet); + let packet_ref = Arc::downgrade(&packet); - inner.unacknowledged_packets.insert(seq, packet); + inner.unacknowledged_packets.insert(seq, packet); + let conn = Arc::downgrade(&conn); + let this = Arc::downgrade(&self); + + spawn(async move { + for n in 0..5 { + let Some(data) = packet_ref.upgrade() else { + return; + }; + let Some(conn) = conn.upgrade() else { + return; + }; + let Some(this) = this.upgrade() else { + return; + }; + info!("send attempt {}", n); + + self.socket + .send_to(&data, conn.addr.regular_socket_addr) + .await; + + break; + } + }); + frag_num += 1; + } drop(inner); - - let conn = Arc::downgrade(&conn); - let this = Arc::downgrade(&self); - - spawn(async move { - for n in 0..5 { - let Some(data) = packet_ref.upgrade() else { - return; - }; - let Some(conn) = conn.upgrade() else { - return; - }; - let Some(this) = this.upgrade() else { - return; - }; - info!("send attempt {}", n); - - self.socket - .send_to(&data, conn.addr.regular_socket_addr) - .await; - - break; - } - }); } async fn connection_thread( self: Arc, -- 2.47.3 From 20fc294a36a0f276c4a0b466412a89c2116bf37e Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 14:15:42 +0200 Subject: [PATCH 87/98] implement friendships --- rnex-core/src/executables/friends_backend.rs | 11 +- rnex-core/src/nex/friends_handler.rs | 136 ++++++++++++++++-- rnex-core/src/rmc/protocols/friends.rs | 6 +- rnex-core/src/rmc/protocols/mod.rs | 1 + .../rmc/protocols/nintendo_notification.rs | 39 +++++ rnex-core/src/rmc/structures/any.rs | 21 ++- rnex-core/src/rmc/structures/mod.rs | 3 + 7 files changed, 196 insertions(+), 21 deletions(-) create mode 100644 rnex-core/src/rmc/protocols/nintendo_notification.rs diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs index 74983f7..6dceda1 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core/src/executables/friends_backend.rs @@ -9,10 +9,12 @@ use tokio::net::TcpListener; use crate::{ executables::common::{OWN_IP_PRIVATE, SERVER_PORT, new_simple_backend}, - nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser}, + nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser, RemoteFriendsUser}, reggie::UnitPacketRead, rmc::{ - protocols::{RmcCallable, new_rmc_gateway_connection}, + protocols::{ + RmcCallable, RmcPureRemoteObject, friends::RemoteFriends, new_rmc_gateway_connection, + }, structures::RmcSerialize, }, rnex_proxy_common::ConnectionInitData, @@ -21,6 +23,7 @@ use crate::{ pub async fn start_friends_backend() { let fm = Arc::new(FriendsManager { cid_counter: AtomicU32::new(1), + users: Default::default(), }); let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)) .await @@ -53,6 +56,10 @@ pub async fn start_friends_backend() { fm, addr: c.prudpsock_addr, pid: c.pid, + data: Default::default(), + current_friends: Default::default(), + this: this.clone(), + remote: RemoteFriendsUser::new(r), }) }); } else { diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 42e5c71..2d9c2a8 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -1,4 +1,6 @@ use std::io::{Cursor, Write}; +use std::ops::Deref; +use std::sync::Weak; use std::sync::{Arc, atomic::AtomicU32}; use bytemuck::bytes_of; @@ -9,6 +11,10 @@ use rnex_core::rmc::protocols::account_management::{ AccountManagement, RawAccountManagement, RawAccountManagementInfo, RemoteAccountManagement, }; use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends}; +use rnex_core::rmc::protocols::nintendo_notification::{ + NintendoNotification, RawNintendoNotification, RawNintendoNotificationInfo, + RemoteNintendoNotification, +}; use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; use rnex_core::{ define_rmc_proto, @@ -25,12 +31,15 @@ use rnex_core::{ }, }; use std::sync::atomic::Ordering::Relaxed; +use tokio::sync::RwLock; use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; use rnex_core::PID; +use crate::nex::user; use crate::rmc::protocols::account_management::NintendoCreateAccountData; +use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; define_rmc_proto!( @@ -39,17 +48,32 @@ define_rmc_proto!( Friends } ); +define_rmc_proto!( + proto FriendRemote{ + NintendoNotification + } +); define_rmc_proto!( proto FriendsGuest{ Secure, AccountManagement } ); + +pub struct UserData { + info: NNAInfo, + presence: NintendoPresenceV2, +} + #[rmc_struct(FriendsUser)] pub struct FriendsUser { pub fm: Arc, pub addr: PRUDPSockAddr, pub pid: PID, + pub data: RwLock>, + pub current_friends: RwLock>, + pub this: Weak, + pub remote: RemoteFriendRemote, } #[rmc_struct(FriendsGuest)] @@ -60,6 +84,7 @@ pub struct FriendsGuest { pub struct FriendsManager { pub cid_counter: AtomicU32, + pub users: RwLock>>, } impl FriendsManager { @@ -68,11 +93,26 @@ impl FriendsManager { } } +pub fn friend_info_from_user(data: &UserData) -> FriendInfo { + FriendInfo { + nna_info: data.info.clone(), + presence: data.presence.clone(), + comment: Comment { + unk: 0, + message: "litterally everyone is friends here =w=".to_string(), + last_changed: KerberosDateTime::now(), + }, + became_friends: KerberosDateTime::now(), + last_online: KerberosDateTime::now(), + unk: 0, + } +} + impl Friends for FriendsUser { async fn update_and_get_all_information( &self, - _info: NNAInfo, - _presence: NintendoPresenceV2, + info: NNAInfo, + presence: NintendoPresenceV2, _date_time: KerberosDateTime, ) -> Result< ( @@ -88,17 +128,15 @@ impl Friends for FriendsUser { ), ErrorCode, > { - Ok(( - PrincipalPreference { - block_friend_request: false, - show_online: false, - show_playing_title: false, - }, - Comment { - last_changed: KerberosDateTime::now(), - message: "".to_string(), - unk: 0, - }, + let mut data = self.data.write().await; + *data = Some(UserData { info, presence }); + let self_fr_info = friend_info_from_user(data.as_ref().unwrap()); + let Ok(any_self_fr_info) = Any::new(&self_fr_info) else { + return Err(ErrorCode::RendezVous_ControlScriptFailure); + }; + drop(data); + + let mut fr_list = vec![FriendInfo { became_friends: KerberosDateTime::now(), comment: Comment { @@ -144,7 +182,51 @@ impl Friends for FriendsUser { unk7: 0 }, unk: 0 - }], + }]; + + let users = self.fm.users.read().await; + let mut curr_friends = self.current_friends.write().await; + for u in users.deref().iter().filter_map(|u| u.upgrade()) { + let data = u.data.read().await; + let Some(data) = data.as_ref() else { + continue; + }; + + let mut fr = u.current_friends.write().await; + if !fr.contains(&self.pid) { + fr.push(self.pid); + u.remote + .process_nintendo_notification_event_1(NintendoNotificationEvent { + event_type: 30, + sender: self.pid, + data: any_self_fr_info.clone(), + }) + .await; + } + drop(fr); + + fr_list.push(friend_info_from_user(&data)); + curr_friends.push(u.pid); + } + drop(curr_friends); + drop(users); + + let mut users = self.fm.users.write().await; + users.push(self.this.clone()); + drop(users); + + Ok(( + PrincipalPreference { + block_friend_request: false, + show_online: false, + show_playing_title: false, + }, + Comment { + last_changed: KerberosDateTime::now(), + message: "".to_string(), + unk: 0, + }, + fr_list, vec![], vec![], vec![], @@ -154,6 +236,32 @@ impl Friends for FriendsUser { )) } + async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode> { + let mut data = self.data.write().await; + let Some(data) = data.as_mut() else { + return Err(ErrorCode::RendezVous_PermissionDenied); + }; + data.presence = presence; + let Ok(any_self_fr_info) = Any::new(&data.presence) else { + return Err(ErrorCode::RendezVous_ControlScriptFailure); + }; + drop(data); + + let users = self.fm.users.read().await; + for u in users.deref().iter().filter_map(|u| u.upgrade()) { + u.remote + .process_nintendo_notification_event_2(NintendoNotificationEvent { + event_type: 24, + sender: self.pid, + data: any_self_fr_info.clone(), + }) + .await; + } + drop(users); + + Ok(()) + } + async fn check_setting_status(&self) -> Result { Ok(0xFF) } diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index 3f6138f..fb179ce 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -29,14 +29,14 @@ pub struct NNAInfo { pub unk2: u8, } -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Clone, Copy, Debug)] #[rmc_struct(0)] pub struct GameKey { pub tid: u64, pub version: u16, } -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Clone, Debug)] #[rmc_struct(0)] pub struct NintendoPresenceV2 { pub changed_flags: u32, @@ -143,6 +143,8 @@ pub trait Friends { ), ErrorCode, >; + #[method_id(13)] + async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>; #[method_id(19)] async fn check_setting_status(&self) -> Result; } diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index 8feb2f3..eed0597 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -7,6 +7,7 @@ pub mod matchmake; pub mod matchmake_ext; pub mod matchmake_extension; pub mod nat_traversal; +pub mod nintendo_notification; pub mod notifications; pub mod ranking; pub mod secure; diff --git a/rnex-core/src/rmc/protocols/nintendo_notification.rs b/rnex-core/src/rmc/protocols/nintendo_notification.rs new file mode 100644 index 0000000..f7503fd --- /dev/null +++ b/rnex-core/src/rmc/protocols/nintendo_notification.rs @@ -0,0 +1,39 @@ +use macros::{RmcSerialize, method_id, rmc_proto}; + +use rnex_core::PID; +use rnex_core::rmc::structures::any::Any; + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoNotificationEvent { + pub event_type: u32, + pub sender: PID, + pub data: Any, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoNotificationEventGeneral { + pub param1: u32, + pub param2: u64, + pub param3: u64, + pub str_param: String, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoNotificationEventProfile { + pub region: u8, + pub country: u8, + pub area: u8, + pub language: u8, + pub platform: u8, +} + +#[rmc_proto(3, NoReturn)] +pub trait NintendoNotification { + #[method_id(1)] + async fn process_nintendo_notification_event_1(&self, notif: NintendoNotificationEvent); + #[method_id(2)] + async fn process_nintendo_notification_event_2(&self, notif: NintendoNotificationEvent); +} diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index c4dc2ce..45ab453 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -1,8 +1,8 @@ use rnex_core::rmc::structures::{Result, RmcSerialize}; -use std::io::{Read, Write}; +use std::io::{Cursor, Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct Any { pub name: String, pub data: Vec, @@ -14,7 +14,7 @@ impl RmcSerialize for Any { let u32_len = self.data.len() as u32; - u32_len.serialize(writer)?; + (u32_len + 4).serialize(writer)?; u32_len.serialize(writer)?; self.data.serialize(writer)?; @@ -35,3 +35,18 @@ impl RmcSerialize for Any { Ok(Any { name, data }) } } + +impl Any { + pub fn try_get(&self) -> Option> { + if self.name != T::name() { + return None; + } + return Some(T::deserialize(&mut Cursor::new(&self.data[..]))); + } + pub fn new(val: &T) -> Result { + return Ok(Self { + name: T::name().to_owned(), + data: val.to_data()?, + }); + } +} diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 996cc4b..99bef0c 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -61,6 +61,9 @@ pub trait RmcSerialize { Ok(data) } + fn name() -> &'static str { + "NoNameSpecified" + } } impl RmcSerialize for () { -- 2.47.3 From 0d026373db1db1a0f355ee348700a291e8b52715 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 14:24:33 +0200 Subject: [PATCH 88/98] fix compile error --- macros/src/lib.rs | 12 ++++++++++-- prudpv0/src/server.rs | 2 +- rnex-core/src/executables/friends_backend.rs | 6 ++++-- rnex-core/src/nex/friends_handler.rs | 5 ++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index d0fc909..432fc03 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -10,8 +10,8 @@ use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, LitInt, Pat, Token, - TraitItem, + parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, Lit, LitInt, + LitStr, Pat, Token, TraitItem, }; struct ProtoInputParams { @@ -400,6 +400,10 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { // generate base data + let str_name = Lit::Str(LitStr::new( + &derive_input.ident.to_string(), + derive_input.ident.span(), + )); let ident = derive_input.ident; let tokens = quote! { @@ -414,6 +418,10 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { } #write_size + + fn name() -> &'static str{ + #str_name + } } }; diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index a336abb..d7a6dcc 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -145,7 +145,7 @@ impl Server { }; info!("send attempt {}", n); - self.socket + this.socket .send_to(&data, conn.addr.regular_socket_addr) .await; diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs index 6dceda1..5dfcf02 100644 --- a/rnex-core/src/executables/friends_backend.rs +++ b/rnex-core/src/executables/friends_backend.rs @@ -9,7 +9,9 @@ use tokio::net::TcpListener; use crate::{ executables::common::{OWN_IP_PRIVATE, SERVER_PORT, new_simple_backend}, - nex::friends_handler::{FriendsGuest, FriendsManager, FriendsUser, RemoteFriendsUser}, + nex::friends_handler::{ + FriendsGuest, FriendsManager, FriendsUser, RemoteFriendRemote, RemoteFriendsUser, + }, reggie::UnitPacketRead, rmc::{ protocols::{ @@ -59,7 +61,7 @@ pub async fn start_friends_backend() { data: Default::default(), current_friends: Default::default(), this: this.clone(), - remote: RemoteFriendsUser::new(r), + remote: RemoteFriendRemote::new(r), }) }); } else { diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 2d9c2a8..adab2b9 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -37,9 +37,8 @@ use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; use rnex_core::PID; -use crate::nex::user; -use crate::rmc::protocols::account_management::NintendoCreateAccountData; -use crate::rmc::protocols::nintendo_notification::NintendoNotificationEvent; +use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; +use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; define_rmc_proto!( -- 2.47.3 From 02c08e6c759e43e746662761950078fa3bda6db1 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 15:06:00 +0200 Subject: [PATCH 89/98] add debugging --- rnex-core/src/nex/friends_handler.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index adab2b9..64b359c 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -127,6 +127,7 @@ impl Friends for FriendsUser { ), ErrorCode, > { + println!("updating own data"); let mut data = self.data.write().await; *data = Some(UserData { info, presence }); let self_fr_info = friend_info_from_user(data.as_ref().unwrap()); @@ -183,8 +184,10 @@ impl Friends for FriendsUser { unk: 0 }]; + println!("acquiring user and current friends locks"); let users = self.fm.users.read().await; let mut curr_friends = self.current_friends.write().await; + println!("started summing users"); for u in users.deref().iter().filter_map(|u| u.upgrade()) { let data = u.data.read().await; let Some(data) = data.as_ref() else { @@ -207,13 +210,16 @@ impl Friends for FriendsUser { fr_list.push(friend_info_from_user(&data)); curr_friends.push(u.pid); } + println!("finished summing users"); drop(curr_friends); drop(users); + println!("adding self to users"); let mut users = self.fm.users.write().await; users.push(self.this.clone()); drop(users); + println!("done..."); Ok(( PrincipalPreference { block_friend_request: false, @@ -237,11 +243,11 @@ impl Friends for FriendsUser { async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode> { let mut data = self.data.write().await; - let Some(data) = data.as_mut() else { + let Some(inner_data) = data.as_mut() else { return Err(ErrorCode::RendezVous_PermissionDenied); }; - data.presence = presence; - let Ok(any_self_fr_info) = Any::new(&data.presence) else { + inner_data.presence = presence; + let Ok(any_self_fr_info) = Any::new(&inner_data.presence) else { return Err(ErrorCode::RendezVous_ControlScriptFailure); }; drop(data); -- 2.47.3 From aaa530341d6748dae2cc77a676c2c8d379d8e23b Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 15:23:53 +0200 Subject: [PATCH 90/98] minimize the time we hold locks for and add sleep --- prudpv0/src/server.rs | 1 + rnex-core/src/nex/friends_handler.rs | 37 +++++++++++++++++----------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index d7a6dcc..9a32bc7 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -153,6 +153,7 @@ impl Server { } }); frag_num += 1; + sleep(Duration::from_millis(16)).await; } drop(inner); } diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 64b359c..1a0b499 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -31,6 +31,7 @@ use rnex_core::{ }, }; use std::sync::atomic::Ordering::Relaxed; +use tokio::spawn; use tokio::sync::RwLock; use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; @@ -186,32 +187,40 @@ impl Friends for FriendsUser { println!("acquiring user and current friends locks"); let users = self.fm.users.read().await; - let mut curr_friends = self.current_friends.write().await; println!("started summing users"); for u in users.deref().iter().filter_map(|u| u.upgrade()) { let data = u.data.read().await; - let Some(data) = data.as_ref() else { + let Some(inner_data) = data.as_ref() else { continue; }; + fr_list.push(friend_info_from_user(&inner_data)); + drop(data); + + let mut curr_friends = self.current_friends.write().await; + curr_friends.push(u.pid); + drop(curr_friends); let mut fr = u.current_friends.write().await; if !fr.contains(&self.pid) { fr.push(self.pid); - u.remote - .process_nintendo_notification_event_1(NintendoNotificationEvent { - event_type: 30, - sender: self.pid, - data: any_self_fr_info.clone(), - }) - .await; + drop(fr); + let data = any_self_fr_info.clone(); + let u = u.clone(); + let sender = self.pid; + spawn(async move { + u.remote + .process_nintendo_notification_event_1(NintendoNotificationEvent { + event_type: 30, + sender, + data, + }) + .await; + }); + } else { + drop(fr); } - drop(fr); - - fr_list.push(friend_info_from_user(&data)); - curr_friends.push(u.pid); } println!("finished summing users"); - drop(curr_friends); drop(users); println!("adding self to users"); -- 2.47.3 From f9ce137c046a4983b0c987825165fdb2d68efe6f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 15:41:58 +0200 Subject: [PATCH 91/98] sleep inside the packet send task instead of outside --- prudpv0/src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 9a32bc7..022f6da 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -133,6 +133,7 @@ impl Server { let this = Arc::downgrade(&self); spawn(async move { + sleep(Duration::from_millis(i as u64 * 16)).await; for n in 0..5 { let Some(data) = packet_ref.upgrade() else { return; @@ -153,7 +154,6 @@ impl Server { } }); frag_num += 1; - sleep(Duration::from_millis(16)).await; } drop(inner); } -- 2.47.3 From 2c08e35c36c0a910f4429bc3901ad3ac8b4a6d18 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 16:40:54 +0200 Subject: [PATCH 92/98] make fragment size smaller --- prudpv0/src/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 022f6da..899bbd6 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -106,7 +106,7 @@ impl Server { .expect("packet malformed in creation"), );*/ let mut inner = conn.inner.lock().await; - let pieces = data.chunks(1000); + let pieces = data.chunks(700); let max_piece = pieces.len() - 1; let mut frag_num = 1; for (i, piece) in pieces.enumerate() { -- 2.47.3 From 666a0b1ad7c6f202e1b94c3959d79d4e9159860d Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 16:56:55 +0200 Subject: [PATCH 93/98] fix nintendo notifications --- rnex-core/src/rmc/protocols/nintendo_notification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rnex-core/src/rmc/protocols/nintendo_notification.rs b/rnex-core/src/rmc/protocols/nintendo_notification.rs index f7503fd..ae31467 100644 --- a/rnex-core/src/rmc/protocols/nintendo_notification.rs +++ b/rnex-core/src/rmc/protocols/nintendo_notification.rs @@ -30,7 +30,7 @@ pub struct NintendoNotificationEventProfile { pub platform: u8, } -#[rmc_proto(3, NoReturn)] +#[rmc_proto(100, NoReturn)] pub trait NintendoNotification { #[method_id(1)] async fn process_nintendo_notification_event_1(&self, notif: NintendoNotificationEvent); -- 2.47.3 From 51e7c63d667e80ee596b1dfab13c2303edcd4167 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 17:24:28 +0200 Subject: [PATCH 94/98] add delete persistent notif --- rnex-core/src/nex/friends_handler.rs | 9 ++++++++- rnex-core/src/rmc/protocols/friends.rs | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 1a0b499..88190b2 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -99,7 +99,7 @@ pub fn friend_info_from_user(data: &UserData) -> FriendInfo { presence: data.presence.clone(), comment: Comment { unk: 0, - message: "litterally everyone is friends here =w=".to_string(), + message: "haii =w=".to_string(), last_changed: KerberosDateTime::now(), }, became_friends: KerberosDateTime::now(), @@ -276,6 +276,13 @@ impl Friends for FriendsUser { Ok(()) } + async fn delete_persistent_notification( + &self, + notifs: Vec, + ) -> Result<(), ErrorCode> { + Ok(()) + } + async fn check_setting_status(&self) -> Result { Ok(0xFF) } diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index fb179ce..b575c08 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,6 +2,8 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; +use crate::rmc::structures::rmc_struct; + #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct MiiV2 { @@ -145,6 +147,11 @@ pub trait Friends { >; #[method_id(13)] async fn update_presence(&self, presence: NintendoPresenceV2) -> Result<(), ErrorCode>; + #[method_id(18)] + async fn delete_persistent_notification( + &self, + notifs: Vec, + ) -> Result<(), ErrorCode>; #[method_id(19)] async fn check_setting_status(&self) -> Result; } -- 2.47.3 From 3c8ba491ddf2864634a5c84df685d2e7938254dc Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 18:40:32 +0200 Subject: [PATCH 95/98] add data --- rnex-core/src/nex/friends_handler.rs | 3 +++ rnex-core/src/rmc/protocols/friends.rs | 4 +++- rnex-core/src/rmc/structures/data.rs | 5 +++++ rnex-core/src/rmc/structures/mod.rs | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 rnex-core/src/rmc/structures/data.rs diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 88190b2..b7f44e8 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -42,6 +42,8 @@ use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; +use crate::rmc::structures::data::Data; + define_rmc_proto!( proto FriendsUser{ Secure, @@ -95,6 +97,7 @@ impl FriendsManager { pub fn friend_info_from_user(data: &UserData) -> FriendInfo { FriendInfo { + data: Data {}, nna_info: data.info.clone(), presence: data.presence.clone(), comment: Comment { diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index b575c08..766797f 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; -use crate::rmc::structures::rmc_struct; +use crate::rmc::structures::{data::Data, rmc_struct}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] @@ -76,6 +76,8 @@ pub struct Comment { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendInfo { + #[extends] + pub data: Data, pub nna_info: NNAInfo, pub presence: NintendoPresenceV2, pub comment: Comment, diff --git a/rnex-core/src/rmc/structures/data.rs b/rnex-core/src/rmc/structures/data.rs new file mode 100644 index 0000000..0350c96 --- /dev/null +++ b/rnex-core/src/rmc/structures/data.rs @@ -0,0 +1,5 @@ +use macros::RmcSerialize; + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct Data {} diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 99bef0c..35dce08 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -26,6 +26,7 @@ pub type Result = std::result::Result; pub mod any; pub mod buffer; pub mod connection_data; +pub mod data; pub mod helpers; pub mod list; pub mod matchmake; -- 2.47.3 From 3e8b96c82008bfe9dcc0f7c2e7b367a23119d6c5 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 18:49:18 +0200 Subject: [PATCH 96/98] fix build error --- rnex-core/src/nex/friends_handler.rs | 3 ++- rnex-core/src/rmc/protocols/friends.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index b7f44e8..08cca05 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -42,7 +42,7 @@ use rnex_core::rmc::protocols::account_management::NintendoCreateAccountData; use rnex_core::rmc::protocols::nintendo_notification::NintendoNotificationEvent; use rnex_core::rmc::structures::RmcSerialize; -use crate::rmc::structures::data::Data; +use rnex_core::rmc::structures::data::Data; define_rmc_proto!( proto FriendsUser{ @@ -142,6 +142,7 @@ impl Friends for FriendsUser { let mut fr_list = vec![FriendInfo { + data: Data{}, became_friends: KerberosDateTime::now(), comment: Comment { last_changed: KerberosDateTime::now(), diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index 766797f..fa32120 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -2,7 +2,7 @@ use macros::{RmcSerialize, method_id, rmc_proto}; use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; -use crate::rmc::structures::{data::Data, rmc_struct}; +use rnex_core::rmc::structures::{data::Data, rmc_struct}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] -- 2.47.3 From 9d89bc56e02f963fe379af8e622490dfb972ff53 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 19:15:23 +0200 Subject: [PATCH 97/98] add data to structs which were missing it --- rnex-core/src/nex/friends_handler.rs | 98 ++++++++++++++------------ rnex-core/src/rmc/protocols/friends.rs | 22 ++++++ rnex-core/src/rmc/structures/data.rs | 2 +- 3 files changed, 76 insertions(+), 46 deletions(-) diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs index 08cca05..941b747 100644 --- a/rnex-core/src/nex/friends_handler.rs +++ b/rnex-core/src/nex/friends_handler.rs @@ -101,6 +101,7 @@ pub fn friend_info_from_user(data: &UserData) -> FriendInfo { nna_info: data.info.clone(), presence: data.presence.clone(), comment: Comment { + data: Data {}, unk: 0, message: "haii =w=".to_string(), last_changed: KerberosDateTime::now(), @@ -140,54 +141,59 @@ impl Friends for FriendsUser { }; drop(data); - let mut fr_list = - vec![FriendInfo { + let mut fr_list = vec![FriendInfo { + data: Data{}, + became_friends: KerberosDateTime::now(), + comment: Comment { data: Data{}, - became_friends: KerberosDateTime::now(), - comment: Comment { - last_changed: KerberosDateTime::now(), - message: "I'm just a dummy account :3".to_string(), - unk: 0, - }, - last_online: KerberosDateTime::now(), - nna_info: NNAInfo { - principal_basic_info: PrincipalBasicInfo { - pid: 101, - nnid: "dummy:3".to_string(), - mii: MiiV2{ - date_time: KerberosDateTime::now(), - name: "TheDummy".to_string(), - mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), - unk: 0, - unk2: 0, - }, - unk: 0 - }, - unk: 0, - unk2: 0 - }, - presence: NintendoPresenceV2{ - changed_flags: 0, - message: "".to_string(), - app_data: vec![], - game_key: GameKey{ - tid: 0x00050002101ce400, - version: 0x0 - }, - game_server_id: 0, - is_online: true, - gid: 0, + last_changed: KerberosDateTime::now(), + message: "I'm just a dummy account :3".to_string(), + unk: 0, + }, + last_online: KerberosDateTime::now(), + nna_info: NNAInfo { + data: Data{}, + principal_basic_info: PrincipalBasicInfo { + data: Data{}, pid: 101, - unk: 0, - unk2: 0, - unk3: 0, - unk4: 0, - unk5: 0, - unk6: 0, - unk7: 0 + nnid: "dummy:3".to_string(), + mii: MiiV2{ + data: Data{}, + date_time: KerberosDateTime::now(), + name: "TheDummy".to_string(), + mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), + unk: 0, + unk2: 0, + }, + unk: 0 }, - unk: 0 - }]; + unk: 0, + unk2: 0 + }, + presence: NintendoPresenceV2{ + data: Data{}, + changed_flags: 0, + message: "".to_string(), + app_data: vec![], + game_key: GameKey{ + data: Data{}, + tid: 0x00050002101ce400, + version: 0x0 + }, + game_server_id: 0, + is_online: true, + gid: 0, + pid: 101, + unk: 0, + unk2: 0, + unk3: 0, + unk4: 0, + unk5: 0, + unk6: 0, + unk7: 0 + }, + unk: 0 + }]; println!("acquiring user and current friends locks"); let users = self.fm.users.read().await; @@ -235,11 +241,13 @@ impl Friends for FriendsUser { println!("done..."); Ok(( PrincipalPreference { + data: Data {}, block_friend_request: false, show_online: false, show_playing_title: false, }, Comment { + data: Data {}, last_changed: KerberosDateTime::now(), message: "".to_string(), unk: 0, diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs index fa32120..81dd63e 100644 --- a/rnex-core/src/rmc/protocols/friends.rs +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -7,6 +7,8 @@ use rnex_core::rmc::structures::{data::Data, rmc_struct}; #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct MiiV2 { + #[extends] + pub data: Data, pub name: String, pub unk: u8, pub unk2: u8, @@ -17,6 +19,8 @@ pub struct MiiV2 { #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct PrincipalBasicInfo { + #[extends] + pub data: Data, pub pid: u32, pub nnid: String, pub mii: MiiV2, @@ -26,6 +30,8 @@ pub struct PrincipalBasicInfo { #[derive(RmcSerialize, Debug, Clone)] #[rmc_struct(0)] pub struct NNAInfo { + #[extends] + pub data: Data, pub principal_basic_info: PrincipalBasicInfo, pub unk: u8, pub unk2: u8, @@ -34,6 +40,8 @@ pub struct NNAInfo { #[derive(RmcSerialize, Clone, Copy, Debug)] #[rmc_struct(0)] pub struct GameKey { + #[extends] + pub data: Data, pub tid: u64, pub version: u16, } @@ -41,6 +49,8 @@ pub struct GameKey { #[derive(RmcSerialize, Clone, Debug)] #[rmc_struct(0)] pub struct NintendoPresenceV2 { + #[extends] + pub data: Data, pub changed_flags: u32, pub is_online: bool, pub game_key: GameKey, @@ -60,6 +70,8 @@ pub struct NintendoPresenceV2 { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct PrincipalPreference { + #[extends] + pub data: Data, pub show_online: bool, pub show_playing_title: bool, pub block_friend_request: bool, @@ -68,6 +80,8 @@ pub struct PrincipalPreference { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct Comment { + #[extends] + pub data: Data, pub unk: u8, pub message: String, pub last_changed: KerberosDateTime, @@ -89,6 +103,8 @@ pub struct FriendInfo { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendRequestMessage { + #[extends] + pub data: Data, pub friend_request_id: u64, pub is_recieved: u8, pub unk: u8, @@ -103,6 +119,8 @@ pub struct FriendRequestMessage { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct FriendRequest { + #[extends] + pub data: Data, pub basic_info: PrincipalBasicInfo, pub request_message: FriendRequestMessage, pub sent_on: KerberosDateTime, @@ -111,6 +129,8 @@ pub struct FriendRequest { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct BlacklistedPrincipal { + #[extends] + pub data: Data, pub basic_info: PrincipalBasicInfo, pub game_key: GameKey, pub since: KerberosDateTime, @@ -118,6 +138,8 @@ pub struct BlacklistedPrincipal { #[derive(RmcSerialize)] #[rmc_struct(0)] pub struct PersistentNotification { + #[extends] + pub data: Data, pub unk1: u64, pub unk2: u32, pub unk3: u32, diff --git a/rnex-core/src/rmc/structures/data.rs b/rnex-core/src/rmc/structures/data.rs index 0350c96..c6064ae 100644 --- a/rnex-core/src/rmc/structures/data.rs +++ b/rnex-core/src/rmc/structures/data.rs @@ -1,5 +1,5 @@ use macros::RmcSerialize; -#[derive(RmcSerialize)] +#[derive(RmcSerialize, Debug, Clone, Copy)] #[rmc_struct(0)] pub struct Data {} -- 2.47.3 From c705b59e314059cda872a68d8665e1d0d046390f Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 25 Apr 2026 20:49:31 +0200 Subject: [PATCH 98/98] fix anydataholder --- rnex-core/src/rmc/structures/any.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index 45ab453..0f531d8 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -13,10 +13,7 @@ impl RmcSerialize for Any { self.name.serialize(writer)?; let u32_len = self.data.len() as u32; - (u32_len + 4).serialize(writer)?; - u32_len.serialize(writer)?; - self.data.serialize(writer)?; Ok(()) @@ -26,11 +23,7 @@ impl RmcSerialize for Any { // also length ? let _len2: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let length: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - - let mut data = vec![0; length as usize]; - - reader.read_exact(&mut data)?; + let data = Vec::deserialize(reader)?; Ok(Any { name, data }) } -- 2.47.3

%qUhgU}nb3ZP!*C&aFg)vLT#m&)5@W zvYartb|klL9xtvtH1Ey_%Rr~|CjLIh=_&r+dG|~93Cvy)fCH>EWMIC?e3<& z85*npFm~<7sg1=EKquXURYV*aV?ye2cS#yKO+_$a-BOjNr5^F4(J7^niD%{RHdiVb zb+qESfwIbSU(m$vUY^)LssK$;caY z!qs_K$6nYX=8pK64iGZ{q{7_ENR}>t?NAe>Y01PIV&qwjSpy|<$DfwR*!YAz#^BS{ zWXz1eMEHc$gS{tx?3~HX>D$I0;nfz-u9|ms*_Oek(LaSh$oJ8hx_)8(E{xB;}OCFNaTJjea{1B4PUH zoQD>)XY>DhA^wJ_PW0KWyu_MfIw2W>J_39NaEwLc`ZNwQWFJ~{k7oEk(iTMu$xD%9 z9!d9ITEz2Pq~7iiqR@>0K=1AI zxU(Y6c|1fF;B9|ZJ>D0&vRDRhthF0W)n6p~X6rL*+gSfE22OSMIplW|3+1f-&574L zttpmanh3zoMg9ai&M$(O<%rTkvCXX^}COR{tpKw}0w!G{Zn=k=Ez zHv96%<1!b1Nv?3ZsK?FhJN7}ebE7|`QEj@(m$1hrZpDq=4=u`LH+E!nmr)|K_6$w; z^2u%~__N#wY!2HN^JS`VA6!KjK1qkjsm}D6qjP!(-G$~`OS|>%)c!AeK5BMh0K3)k z=&-mWq+i{pIX$HM&%=+VCA_hA=Rnd3+SnaWf%9FS+MQ!eYG~i~JI}6;jwdX#QpR`j zH1Fg}>>XpgJ-C9fW9CV|=p{HY9%(JTq-*WY?#(+7_cZV5R{PGFsvfI*tZyN6RgZOC zUeLU=m#4?ts_^Rc{-5ISeB5B;NVOGACOmlw44%W#OmuT?!@n(#T~Mdn zh1$917A6=~cg+re*~`@~ZpDQH5skV!e0TpuS3>MmhffE(K8GPoFK&K_vqYuL{kW2A zT?!bgBL!Oksa*S7aZ$6Du2bNHLQi|#V*(1DO`eQA*H?bPsymWT{_tm5Spk^iu%nsN z-yfan@`hhe%rnRHOn$xr(Sdk%T;ZyHcZ?_W)%H72=k1~{&F>0WJ>K9`$IMeHpHJIY zbR~CpAboiAI{=#kJznwlcp>oz((MW8@p|HDUb>Q}S5=Sop76#Tc>u<1)n%Iq|A0-` z9#8GQ0_#3Ms{)Iz602^Ee$D?f#N5xE<_)j+G=Eq~o`Lg@_Tmt9CO`WH&sT`a_Q{!Ku* zZ?UKSL(lHj1g7Xpa!P+>@=I~&4}V!@t-Lfz&*mKEkKUE^Mz3H%Ulq)JGjVGce66LI z9{_|+b58`Smw#=3k$peS+_4{%DS)}F8-T3p@p+;T2?v1cK=bSC+IKA`!G`iSkNNoy z*!@PTCF{Q14d^uf>kR1j8PHwg4Zq@PP5`>E4CuBAbYJxgp5vLn&jH=)`0=LbR}?+W z{xvLk9O(||R>xg@O@ku-IiT~EeOB#S?<-r+84b*}_a7M}g0Di>8vv8gH+n`faE(;_ zKkU5=d{pI`_@5yI1Vzt8h=5v+l`2tJ6Q#;Hs2P~RIdD!ug%)ouZI#tpSDIuH6)I*D z<@9*AR2R$c)|PGSmhEMWt{`60CfpK0A%P00RRi8;oUR5`2%yaG`@HAOWD-H?UjF<0 z{eM3`A2R3ip7-*+&-*;j``q3$@f$Jhmh^d2jreH|%R!V(f7y5daRc07g!hpBl82Vv z2AD>Gu_s$Zg+%S#U~67XEduO3!4vQds+7Ah*DrH71MGWS!K!M|2ZFH?zL#t( zGr-v00C_jdAB+}2zY-g?E&U7L^Udx7RfG2S0Q7c7oj#9O;P39iRUmgy548FzyzR4o zJnXwfKnQT@V9m8hfqpa}`X4ED73jb2U6ser%!fWF+AHWQu%%iB`gR9E_n^N9_^N4G z^ZbH)qXl(^5Xvm$mSZM_i&PfKnQ^t~4p13OeB9OdlVL|fHZNEDH-|s~=b9p^2kMl* zWc~O`@gYe5nxP1fCO2l|)=Exrt}NPIclv^RqJj8wywrxSA0H*Ao#-s}t%;8hJNB$Q z&hyW+9hTm}=uP6gBx?)#Q^i1>$OLOoP0w};qLJ8`kF|zoU^R;~C1-7Go^|Hxx=kNw z&uui_!6%YJOA=mxOv1w2t(LvI54@|K5mk{>;_Hk=OVCKH4pOWpo&J~Hexs*K63Q?X zoQfrFvSePA7NCcNPprDED855-=W7ku@SJDniGixi^gx_ENtu3H!{q{lM5ZuGN+sS- zJF#EYWmEfcx4NomV{`%Tol8<9ROM?HTzO4gTR-q>vfw^)@-?hy9FYaowUkWK@YEH;aO!ZQSC=-sv2H4?ca8SLR!PW(X>gF z25}?9spzB_=OXJ4(#CYOE+-3zGn_|6vCe@DpI|!Xw+0uJuZ*$+?WV1c05xrO{4Pn5 z+Z0x=XqTVX#-04|K>@y(k~{7t6jiYIno7 z?=`k{T7%YBHe@vWLF!4gkgI5Ye9IF<(%KUd(ykJw&4GjIfc0vMd4*>f9?Yh09nU7WO;TLGfaAPAgdSqOwmKY|xhTFPl>xFj@ zUvTfY1M%a1*hoh*CGPXcSK`roBjp$YvFb+4TS3FQf2ly-ZcI`y<7u_4o|L1C?M6Xj z28`s6J+pichFmAT>R&f?`#pB9_GP?}Yq zfQ0_F$S8H&d&x-^sT-t}bN47kjK&F$IOEE-r=Ge9>@ja!KU;5YVK|uzC?3x19d+lL zkzZ^J<@fT%LJf@NG5@I)w@I`^-!$a_EBf5`h% zE~Th4IcgzJG|k#e8JC=U1w{A_I9KDHxQO#b8fo1Fi}gQi(Q8*Q=e8 zaJ9z0w55_W2-;>!ZeL4U*>O@K+2Iqdi)6`a4F>z~)D*F|qMd~S-2TIuGykEO_Eh{4 z$ruGl1yG_>U^m<({qx%PJv=fchu6?z%iE=lN|uyt+^~l?3HWmQqfE(8N?C*UL&ZSs zwp0bKI3Sd&&QTDL+Al_1{vAcb4x{CLQcvSxQ?&}Jks3fzj|%eeiIYQ@Eval z-AjLf{2&%^*|U0Qd;myU%jJMcW`)Z!TzXHd7W%)7yjR{)AG-5>#s3p6(9s%r(yK$lVS-eR7xJ%@xRh>(&YH9@HO{;jQH7vk^*O{c7PQ7f^4QFLiTDMn(cx#s7 zvb~~|D|_>OZx_%Td&O_mUCVnRdxg+bVfGu?#t~f|eMaggaIYPy21@w*5ET~uULH!2 zxv9l=nD*k~e55;1EK`krZ#exB@}`%eDOU;kVz&Dv4`TKf=1F%RT0%j{b0yCZcsi*J zESe#o*o$?3Od^o%#kX*!t$dNIQL3PLr76bGlXfZW4!uY|5d5{>ovQQ(u4c+RyQy3i z!4KSa$8hNfizR27%X95_Z6I-_Ab;6LtzHn11eJ-y1GNWkfuc}MEev*t z?&YuT+?vZtipkXg^`(~^R`J{hV{139W7+qoUmdY{f+ z_t~9`<#jI5w{vG6v2*A8os;7$@;i43gar&s0opP>ap2^-I}-AQF07u zc{?;{y9C0&JqjVCNFT(xi@#|rA}2&)<8Z!BPh*Sg=TxRksefjc)e~7;s*{LhT&5&h zv3eov&wEj|AoYF4VGk5)_x~8Yp`AiS2OmeT*_N86ULFi+_lq03_EbSSLQo=|6gP5m zw|s6Vak}6b%==$MB6SKLr=RXE(zqui@-vsa)WBRTD=C-P$}i>i*jt&~(~24*6kRpO zD1U)0w-05l*6^O9Dve`+h~YF0XjivxIk%Scixd6Z*#f$}g@+Q0Z{q zN;rMIzY=8KNftplxdI0tt??UzmJkTLr6mQ2vD$pAN!@IP^cqMxxGexQv#&4ht3$Z&ji7>)0(v#q&Y&!ZyMYE-W zkorX7mg$bm(-|t1cK(SNd#O#4(pMt|K+v$9>R;J|Ir+UC9+f~8_za~wZ?k%OJ^X1EUogM^7 z(#3~6Mp7Qnzj}TWUR;NNHCaTcSuCpg&h6WA8ArvjuWlVVcJdvpx2OM&Ns<}!I@HU* zT^;_^wlYXWGl$dsb`>xH&amIAwv;G~+5gF6^S9tJySpXHMq+-u>?8!lsUcFY94MqV zkcQe}tHw-cMLF;IQl`}mch32W4~J$Eb-s+g@hyc`?rF`wY>(9V5_xPGzgTzK@r?Ag zIyPzZ$I{1iO|~HRXYRdCmw=iCM2jT(u!U1-c&F^HJVT^9(G+3yQDeDH~43^_2X7u$ed zESi{K0D?&rr_ovkljYZ~;=4FoOeS5lv2t)M@R=wlzD9KzI7@NfCk4A3J1p##sd*kjK`B%lb624 zBlq%u{0J$`ExGEE+o)shU-A zI^VI&l?0TNH%qJUBtJl->3u0nJo)7F>}p;~_vg{S!EcUEg|v3rd)wb-|16ZlUc5lf){2Gdr%4>gW6nRxiqS&%?PSuKI7xf1 zJNG38C+w<)+RFQ6_p(qOi^TI)>bW`uiMwX+PMs9tTsu=3w&~n@OSL;%Tp?7xtaFKX zdYq2Z0f8;&PjV+_bO_K;KMM=z(LT#lFL@4zbS8uOm%}AgdXzhOC#obi@e8O0G<|^| z{IW+^%7VpLkz92oK)rn#v~z*h@V*psuA7@Fxm;RC3iVpPRO(SIfla}XQaP1CcTWhv z05qNH?dh-N`A@L_j1?Af$}^kJJ(%E%WbZ;<%c|=!h(0a?>X|!~f@{Hud&4xX8 zfMv%9Kym5@gfR5rO}CX7tLpxSW76tKz&*Cm{8sR3BhVJjbeay8%T^X4r^;T9Js2vr z#%M{GrXN)Abf>N`lztV;(o--cR?*m}zf66F=PJ9a8XK&|bXF~rF+0nb@H5FhZ3RC} z#=g1>GbQIP_a_5&3vmYAiN6bzFKH1)MJP$|l+#q7tHD}>>&Gx3gjv`yXN zA+!B=GBHR3&Jwk)ZG1(Rt$O>YoE4%q{DSXIXW26Ox$V%5Ov$hL#Geu9{9{sqY|$2< zE)+*BAD;f)3h%GG8O_rLte-AwN}hU)2pEkblTNl{qo*PPm2*8_D~^p8aYzaw4i)eW zaVVsI9xe4s+%USFa??ha^4A<4;%{&?0b(-{07Ub7`?B-^j{z}ZZI<(UkunVDCn7Z) z&hNYUv7AS``FZ97{zMa3Tu}Enq&UJwSoIB08Owe#c^8Ia%YIjPB)#A5%MjPRJ~ehr z*UB2pRSz4Bq-$l3mEPTO?{2DhH_E%4>D`U-?q+j`X8isj%P{KvZGTy;`UE}bq813QPD?C-1w5I`B~NB}PY?kY z&s3Mf&sW?cm-gb>>d9hnq8HEg-Y@6<0=fK@Qbg7tPenB6N-l+&`Io|>`~o63tEcwj zg;Eh`tEsA22r5y#+`$Nz$U}R@Qt#bT@7*%*P7xwc*@lF@N|k)HnI9n5?m?_gm5eW> zik<4cQZS%wOLFI(zG$!L;(B4@hy1l&v1w~7-A+DV=pK+8lBE=>t(b2C;E?Gt*a%9)-0^RLj{;;e?MQAy90eHukk$>?@1P$qk zYIPhIl_NE|-cx{T#r3lAy(ZT;Mx;qT5J6FzUhj2+^H|5KC#J)(ilQ3hpc8$FI$Tnb z5VY}#At11H)NsFxHRGPMH!<2IYhrmIcG;r}Hi@5c8$-|}o6qsu z11HJW&Ar@h6Gh43ALxMtnO)JQ3n`;qc5?Ppm&^h&b7CI%+MIFz4dK| zDz#Ch0Va7vR#C#@3C0*1;c{N2 z&(5x&ycP1NY;7CWQW;47Mz~9BC&pji*8bGs#(dN^WHhKblugk($R_^JHpwG$$ysX@-@`g)X z4B%axs-x~`(6d;gzI4@DcsM+0NdPcn2!~jxp$CS&0F`+{^|evxa_C zV|-)kPtYH2<)gyBsd<%9IIz&;Mkw$P@fx~u*G_ z>}d2Qm3@?wV+IETX|!?#8E4TkG3pF53fF3t#7cr*@>*k1uEX_05GyvEt8@j;yEq86nXfbYwxkhm)*h(h zEr!qndDN=Fz&sVCuFS9eqMphbK;BFp39#cBj{tVCEYreAJ;3f1tk4?11kg#g=fieQ z>I>W-d5jUI%+L}C;ZL3b7fAiOn*px~)6+oer(7TTOIs;=Q{SV&e+E(4S1l|ASrw+f zN061?y4nNVZajM{{~$o(MA#jP1C_dF?Jx%YF-OkS1*^egHSE$`Qmh7?%=T|5$z!ys zg71*ig#o30M74lk=ptw6A#>|oeReg`rpvqvgh!{o@*k<-Vy^<>x~URXfhW5ja}O@^ zDiF?<`XfOpS>gAXD=7CW5LT3Wm{1|(l7^6&W<`;zY`P{bxo#^C8EQJhZ_Z$ZZ2vIeDaGQ2AUErj4&;Sb}R zQjb%rnzLw;RQySh?6&(ms@?O?lx-h#f#2gII;lIVO*724>s~m^tukRm7nbcX@!7|j zy#79zq8Zo~v$warS7gT_h+KdII4f{cM$3DkKz!AxZQ9Ch(E#`FLlsq((Wc88sBUkr zvi}%cc;iC9K?R4qJ`{N+f7wF1Shk(4ToTP{536mBmRJnDpqPCZ@b`H9*#tV;6s2*5 zLi;gcFRIZXjiP~6f}(bR1oL*4_S9ME2eDI10qy>Cc!ua1JL$M_+EeC91G%1e(jXMi zgSJd?ZaS%uxW!Sp02IN84DB~-i*RdC94Pd@O~Xd3oU=Z!TUYwsy16}7$GLwfJ`Y>r zkF>H{iQ*ZN<&9|Fp?Bx_v;Q%(|3i@g5cZ=suJ&&-`)^u<-U4%!m+2%B3qf7s z!3HGdOwI38%EJKCzyD=K57~_9;SMb!S~P#(%2h$?0wBY#PrY}?9;ferNe^#)T3(Ul zd`q8gOyirh11tJ8eXP4hXk(Y!0QF`%;)0_HW9r*n<fYClyEh(!t$Pf_&>XXy!CRl%rEbJa`)IY4e`YNw_0*E(zYP*zvY<&gcR}4WUn`-z z%F#zDC!$ADPH4sV{XKx?XAwVr^&!zei2gaX0$4NOM^jb!rG7vu2-h+uLWz*;fTQVN z@68AzACtmT$)A*2FxMkZ%3VV|xsjD(g%89xq?(XLs5(j2G8#``cdXpCtCtvf2E&B6 zUO*;g5dt56UxXM1H?6_t9VWnKD6O@Iy9F;C&$ZO~?F=AG5F4~|Iv;xem!GREBmMFH zJETrba!MhdQ;v_!dW^o0f)X}OzK(ws1=AW)xHkSX-=uCA@Z~&FMU@qER><;q9xdfB zs@-Mcjmigfc|qN|7!_0Kwy~5pbI?J!G(KFOnD*SRm_57Op7AlJO3zh8KE=gmDz%VD z%2ns2XG*^E6VVrwnFP7T9+|4P=cS4!*mWt9Bo>UbZ%7T53M90`Rw;(lUo-7A9h}Pt zX5_J3q&BgS%SEQ7RMn>Zu9OtAi|lNt6`{vmrrXns|?5cvto>T^JpbMp6yjEIP!0S z5ndbTl+iz>bZG)d=1j?oAB))+tdwmNb}o*{3SLBvKnjC^U*sW*FuQm#l&Zt<*aqqL zjF1dTzKb@gzbgI`?NIs>PoFPe$c_m-T2*bIU%`FzBs*47RBhi>5i;yo$&-iyXQ`xf zgZItI?mBDFRtX1D$BD<506|N9Kr=oZ%)o*4XvxQBMto#1U?^KZ=P`k!o(IBpq%nxxxJYaKqCzAA z;%t^#N}|tnPFfQ7Ju&hx zre6hQ$_Q_UliK~4Fp8`dUdfIp@j%%!k=hXQG9~?%^epxwUaHB55@brI(tK(GcEcgG=wLY8mK=uP-kxd(M_BA9vHbg`I1Yjtn7=Ar>^~|@k?~HA$>bm$)l*2skZccC z$1){_Krdv4coU$4wYTvsOKAYe3SCyM?=L@9u6r`jEu$z%HdB@G zeD7~jCGw)RGbQz^)QY)z^(^RJ&rGi#(Hjd8#4}&fifkUbOvx2q38BiAARr7FQcCD? zFNop)LCMtV^4blaqUQWx0krPZn=j!QOJLwT;^hpB&t3Z@I%+XeELO+2LMhv&nmNzluqD6QfG?V=)YeXc@ zEXIBIoPGGvvCP?KRqC_m>^ELLpD}0Or-b<3cw&M~tOREqVamRts(Mtg8s{KknPTz1 z+)olPp10|f^63rv0f>P7ocsX(Vxc0*z1TlXVKOBj{E*mfeA3(y^O^_;>gMRJ_}mJP zMA`aXiyz0WAy{xbCov8;?Qbae8}KR5{YF_6=C`M22*Qeo+KufgQ?8vRwKSD)ijdmm zPteAMseMZG>wgc<`mC_YIO4iA+A8x!aB8;xfRAAk|(|?dC?Pcefdq> zlo!P*br_^Eh~Vmd4rA(B)n(kJZ}9IAXG%uMy~&45@02i#-2%|dG24BETi0+nx8;WmYQmcB!pO*Dy&Tu^taN}x%BvwXl#oOU^Dh&x8-_T4QS$MXnGC)* z{^b4qcZ~LP*TQt_!TaV(z7kn6*|bXVB9r_Q^(sFZ=FRDNKl98edLR+s#P;^`pXq%k z{yN=SsQ>!A-@~jske7YS_lj4UD(9ivAK>_0RP!~oV^{`Ihj#YI;#E1x9et&F>#k+A zJINh-j$yx$Y^H}ot9TXR*;#5bQ^|i(kJng%{Z`;Z<&|{Uw0Gkbm;8aefy;;+pPZ0z zJO_s z{u}ldJlh8PeecZc`&z&6xN2N6*&TYe>SrqXTOQLp&IB?799so)X8ZoIH!A7A>1ZbT zw#aNHnURg~)>_;-FE*X=p~nMOcy-O?cV0&Tea$85Ybv!z))NuUkSa^}_+=h70Kcn&~e0NvZoWL8PQmH-ET3NcIviyLlRdMtpwWOE1q@sy)pIh4B9ucn5SF^^DZQLd6UgHxp> z^jV8>l2wZq8mNV);8kDE{{dPkpoI*%E7yuAl**ZvA)VU^l{~^nt)CW}B)2oUot@89 z`p{b+`cSn7mEt6^Rgd(O*h?_nltb6lM+1mvpKUtVk#g1yzaCW^eIwD1 zgZ=AKr3tr2Y|!27%1yUsHqYq62V_)XLdLQ)Zmnd{)H8q?pUoa4XmDTcOgpI(>p0Ld zBSViPrUWE?cs*L$ zQqvhZqS`tCIKuP(z?w$Yv?If{H*#x4GhPU&!FZzEo9OJzQ6f#JxPvc~wzW_pO-{v` z=X6XWjJ7j4#Thw_Hi7Px$Vd_{JJQ4qN=$A^s>!^4H!iAf!7hDf@Yu@oI+e^jh|b!kpAorT7eGs>OuB>S9q^lIKf_$ z()Ju4ktx~wK)#D~ul0w2Gy*z9CrH1Z^IQ-;2}#F+s!LAlP8=@M>UXoXQORYUYjhSR zA?uOj8C^5(L)#!>j1=b zgF}o&Gou>IZ!064H>4cjpzEjbF`^!BT(aJTT(nxwm?_RsdQMKU4;jlloLM?0a{fyo z$xFQ7#Use~wIPOqiE9TWr%OJ?t!N3oGM#}|Bsh|3&Mt=H#)Ukm$j6owWxx$3GGb5% z+S5=XWA-n-ks6Hj!IIqg8%oqz<)9ZHdk|nbHk3%Ex>KzlOT)wk$i`@&L>?n1UXzkI zOvU|e*8_237R2sgA8><-?wWQyRs7uvUXkGORDFW<$=_f3)oF>Bq;_{wz#aUe2Xwx5 zo1`Rx6X|mn8TLWTJ`TsaW}+&_72&2p6oirJ011h$z-b}zBfeur6$0`~%Wjj1*&#$v zcp!jV4hdB=Lg`1f^PqxDb>zX4QQX%)ZUkNiVB?DLW^6X>jhrV@?fkf8jFh#1tiGYT z230s$rI9!|+{?FRxz{D7t`Oxd`{kN7mOJ!3dzIou&p~7?qZ)jneqW2c)5CkU z#FKPe54?r-X+2x>hdT_)9cPf6dP{32C&-?Y^i;R zqSt&M)JDZdCK*w`N%l0YOJah$b@!@L zD0V5?o|yBx>qrJ>I8)1w$kb5n8?wyH_{4H5$8efwZ~U?B4zMCNtdqayur81T#1Ir2 z1|FBzEwbFJIwwV@Y3(&Hf*$EazU(Fam4t3RT^48S1L<>n_4klv7h3i;1aw>j7)dMc z_fx?|jva6xQOycg-l%nLI|AV`wtMpNNM6L6-2Lx?i)2 zk{m|`O#J}PA26C1)pB>Vi69s4p6X>!s^Cex# zn{^eqfV3Mn3a@oM@uNK6LGQyI90Mf~Z(EgCoa`d;Pcv72Z{Tx8Ss5NLk#{(1u>Si+03i>NMFHWBO3t_Db2*YD zeuU4@QT^MW95^b6(w_xiQlx{B9g<@q55$Yw3o)I^UqHN%pdUcoWh4&gK>V6<-{JcJ zWlaS(H{3`1V>6D(VIfbW*pz?w8sX;(i9_5oC@d;9T^3E^)Zw9}UrDGm_=nKDXcjd$H1@4X=ekGp;zwcAk(bo1+ z;P+M4`u^mlBmblDE5$Q4+9ZEJgILo6U8>}OXmR#Jk9?4P0h|Sq*a=x^6dndk3JAx-GoBT=wDybsUW=@&WjLQ7 ztXx$|4M;5HD?({wA553%5XJC$OX%hnGh#K@&RsD7LA=)gmc}jnu#w1k(hT~6E}B}d+rg2_ znMTfhM^lq2x#@cn%(^q%rx*;^9bLstkn{%-BDwe#c9tA=6*9xG)Se}E#m7i8 zz<$~T=K&7OUjHm@c@~}2Z@5xLV(Ot^u8?vm(sD3vj0)2ium$X=;yDcaC0MeByzUf< z`t3^Ga}d(ejqZ)7(ia@L_@Z2SbcuQ8IW1d{5K71tT0}tCyO`yq&zC(b!}d1dq7jf< z!G(@@F{1!p(JTNPPU!-Zp5`0*r^Sm&+c z7s&>pi$8d$7f<2>SsSiZvB^M}A!P7ydexg-loSoPm;w|J$t~*_P z=l5?F9Rzz5lpjGffrC%hiU+gr4q|NwCB1Rcr5mM7dGe%bCqjHIO6MWPXf|)AHS^RUl z^h8_0)S8;n5nfppke}~m*C3UvL5X*CrleD`%lEyYTL7Sj=FteLJ^nLQoUpieP#(Rb z3}HvD8Iq~$eDLUXs=n4sl1&6?6h=)7hd;3J9^3^WGoh~-4 z^^nAlO0;T9BU_-fVsxXmOVnS1k8mUIvcm6Z4axuxJ+#8>;!mdbVp|0j2saXx@z2{K zWrOA^vW^qG8Y)S8#TFLz3hL+L;7F>}18g_fLRH=)$1asDYy%id1@^_Abd)dI@#E7@%@buK1NZ8G_TAaAE{`@qa{RTO$HfRys)CDk-g%Cn53Yxw2!+G_ zoaOT;Sw8<#sQ8J;-}(bj+7tfPYDTKsYIWgnb>I99-Xm~@zDq%W2@h)=1&M9V*-YX01CB&04h3Y zH|cWc5x`0=eFC^Sj{u%?ha!MDAx>`x1CK-ie1n{&T0$7|SfCq#C%JC~6{p%0?Yxd}$rRZP$um2K4mx+s1m`CVj2#U}_R3W4A zE2M~;)cFiTsY`m~1GT(5bA+(}F%v@P=xut0@DDjcxZ=}<@MpaUVgJ5_5Qkll5W2Su zA+#WbF9;$04unvqv#0;i!%k>mCs~-1VqR!AB6lXmI4DYZA&NO$o0#7UFon@rE0nPl zj4=Z6qII2$GQI=Rg1vL|Li|^$mlS0r0!n!*=kaT#55t*KoP!e;swi?kGL{TJ0BQV&az~*tH=59!Ke@lJugAMyJHgqe@Iu z@||Do4N>m?kXIHF+P?hfeMW#c0$?9}%E@=NSK>#HoW#Ii_T<4Mex55|qve+u18w9+ zUvAo?)!(Sp$gkDjs(g^q*Y>N$-`f}Pp5~=wT|tiWMW(=dlNcqT2^_XrsJzB}`ly8_ zbTLO=*j@QQk!x(VnpS)w?mH+=OEK1UBGAOK&Ums~>UwJb3z(26{@)G*XLBXor8g5g zHvTi`v-l5&bG2Vmv@y3|ItKpJ-ot-B`Htd009bOs;}GZZpYl)hpY9(1gP5uWg)IL; z%JO$nd-C{?hr!-X<`v;Qzk?a%_B(iG&heSgdUjUrwbhFA+yZUQZK;GCF88)nn+buV z6}DlD^PK+O?5;}n9KwofUhS&VqiG^02rL{=_)oPv*b-rzQ|NoG2Qs#XTiCd@Spm`m ziS#YG2NdJE#FM<~;EK;=JZ#eHUt(&J(m$dFTpPz$eirv(LyY*nLU;(!l*OAi@FS*O z#e~Q!h0OP}TXIYY_XEUWheH+pfPr4ZxT?n!#;fUs2;&|vnjri{gz;aj^LWuaMhEVL zzA%1<2;-&1pZUUgNtPEWVLZsU%3mHKs|@{nkO2|F=Z;<<-M2O;md9sG-to_ozZuS9 zHCwY`t3F$j!T9pGnmNUmu)BQR&mUs#t*KLh%ObVX-T_PQm5qWs7U2{Bw9ggG`yaij zyhgP8l{uy)c}UIhAsLT0ZVk>YTK(VqOlh(^_+HB$x!J&uZ|_4k|B$^MHYWmJe73ZY zgcA%26oM_iK8JLPiY+Pm+#H#NAtmz|Qr*a297%U3g>)NsB+e5BG*(Gt&%+}yC`rTL zc_B%Zrq=MX$C0>sf#8|vvmD74=_a?H3}^62m=Qh;C&G&`)1nR$8>yT|V%ZaDM1=MM zSgx*yUc!mi4_BNhp*WGuGmWpc!q3N7r0(FE#|uPW7ZehC-Qz!T_|LBu|7n)s_Ku_x zAk)Suo>%*<^Hr8-0r??*I7soa>za0+Lk8iNctpfE5 zJgSirQB{?hn&m-K@FnU^{e)Lg1JH5-BU!J$g6j8a4{NFE46yJ=x(c6fF@uRi0Q!g{ zd@A^!D_?VFetFA2Aea%6^v*lAdNC=df#-qTlLUroXcc{ zHhDO%Ko>EbF(#2f<1Ye?T%%{v=wHmVnr}M_)AF`X$FhHdH_86#fzRS!S$$t`{?+{X z`zJV6cK>ua3(yyF`4C;7BpY*QPyICi>gwTNoqhOMz83J#?D-;+#GzC6N7N_#qs?%s zRr&fqOgA}B)z!nPh@{IY|L*;^&!*6Aa@b1#2I*UU@U`!LP4s{DV0!86eauTNOKco!++U_c;zGDU{7{Fa6R# z`5esCFCBebb;(TOUpf8Koq7DriDR5x$A0Qwep@>qhxZ>O&c9{^Y9Y_v+A4t4@D!Kp zIEN9w+k1zlt?XE^2ZzoLxNsVQEx2_Wffv;d>lKfmvBO#yUy_ovQ0Sf@f_?az_?uRX zuWjuRwJ#x65X-*IU!NQlg#)M&9*F6-w9RgzE&SNolxbBvXq32fzdQMxFmWc`oZEz5 zOUvFC%m`=Vf15J6&+*fv@juyr&GY%+r}kgUkf7aPEtkoYx8CTh`ukO447VIE&{x)HB_Eyoy=k2_9^xk<1#mm_vj%EKv zcFj23|LruJ8l+m-o(lYB46RKGp!;w7T!waR`?3Faec!a^t$r9eoG|4Y9e?Jfrrp1_zubQ!W<=aV&r_jnuO)x; zf^g`!@oB^je(WWB;5B)v-?v&upZr_is&kqUvCOjFa;8Q7G$Q9yFY%{J@}lEYV3X{F z3=EciQ2Y}Uf9B{tIe5dw(=8XmIKbq{$lE$*n}NOfSymE-OCG43SJiTaC&|pgwmqVg zH=TZ_7p+IQU3k6NEi210Zda{t*nj}HJ{>~-CIWAL^2LpGo6O#%ezwX8a+F+RSVyhp zL^E(mDE`X}#6O{+?gZIj>EVEus6n8z!Y^v|hw*tcyx5B&gdB(=g^jy2eL1~af>ud( zQHl2pRe%9IChWg&WB=VJF;y|$B5;u+G!BF+=JG1Nx-_MfV{2;mW52^oWKZ$aaAh`x$T1Br)r z6i^!icUR3;we7`^wM-~Ea=&tCAbccNjOn$7|CF=$rk-M(k=rk;QXaOEpoZfcUb;qT z^mNR8+s!ggn@#{z|UIRdA$kb8u`b=G?rh%I-8>YeA;uC)Y`gJ)7dp znOY*iJ|R_$jGr&hDvW!O%1pZ*#Q``fg4*ek#Xy_2^e z`12@5#!|%paBiufA9b}$4N~Sr!7`~zeV|$b%b03GH0mrT8JpB6h(>X=ORtJa3`A?! z>c0h|A&~d4Gu{%?8_f<+%hBWN3%HG!+cHt;x1>PnT3?YiEA%X5)0nV)v60te`rL2Dp zeiVisw(KZ@rEjCVC(KTfWA19dY6t~6?9;s909m$$lQ=M9Qe<9XSM6pau#*@F0ufgC z&=(1Q7$RX05~y`BRQFTMozzA7A)Q!SYjzodm(oA*=M3fl#VXz3gEFwdKDbjr9T=HD zr>8zDN7ZcElZe^wki)kV?ewpe_1q!-LpMXxlwCoZ4W1~i77@o*R2_*Gss6QCjzRwp z_0%W*8?O3CI;TUbf7f(TemMQxCjDD2{W~BO9Gp6l6(>X#L)3SUXGuDp~ zQkbubF5Kuv(O4ti6#U^xZXPd>F5EykF?VDZr^A?Qh#XPN7~eiC@T#IKf!)%CLaWU4 zbzc#zG@aovX^8{HmJm5zdl=k$sA^RW*&6n!5VL`>3Cp<|CU>qxDyl#oBe4xWJiUzv zNN-yGP0$vkrnc1eT(AN|idLK}^&+lp_u@+t^sq#Z+YA;3;AgU6&A@v4EN9G8uNQ{o|p71l?2vxSXXG-4V z6)yiimxdB%N-pLRVodV9{ek=wVvZz_F3*!kKNfjZON2#1E53R4&*aOba;l`rpdJ4% zbW4D#-M^RTLh;#fVnN+ej|}>CS{ABQl<2pa}dPw;rNE+6Q5Q{Rw9qOZ8(%$;83HRSqgbDk8CPkq9ul z6B~02y8`xGzd|8a%9@jB8L4%K|}iVE`8c26pA9Wi$;@e%G40l?IJLRF^+HJcSeY! zJGBr}=ik5>#xtlYx@kf6DzE?uvC~3#g{bFMcn-%phx+k<5{E5?aS|F_9S z1^@37>c@Wwp%B2ykiFZcYQ^8G)Qaz!trgeKjN#W3;oIV1gg?_FrTo1iQqJF-B9;98 zPGl;7>mpKcUS#$&9>F|pmc6G~;ZE*TKVav;t^yXC-Bld!#qXo)bW(7WV-&=!v8QK` zG0+Tj>bG`uDr&{DJzQBE6`W$wvw^0+!x#r4ZINyG5w{p?(<7w09(p8J4)z;wJ%@W2 zq^@kY(eiG81#k?sW!55pr?I?%JV%bTT!)@URJ-+TV<@P6Y>;yQmyU z6DvZ}3vdxE@+9?^Qa-F{GsFApF2>M~d_s2vUa|r6qAtF;s8cFL%qqnyl>Xbk;}vhVl$nH5Yoa0C(2n=LwGXt2nMT*}XAA%HrhpN5@ zp3q2No-f6xO=S7r?Sr_%k^I3yN-Lg1cPHY$l@;y#BiaWG`C}IH7Vl}IbrY?XXzrnu z?Gl#QtYrKzdNO{0PsZ;rbrPZ+BJ>pu1z?`EkLaibe$$dP#b*lQIrHiNI}9U~FYw0^ z_`5uTe?>J%^4Un=haq6lIXT5FH3Z#rmfxr;{}A+KPwG!O8|qI@`M<*&1-gqwxMPZh z387gJFJeFGO}9wt{q@LQMY0`5K=&sR9%>F$0gLR+MEsWd-cti#*;{w9d`Z%!-g7Q8 ziez#|hHfcEXPkze!un};=YNRM3JD@ zz))EOLlqiGY`4U8JFy`mR}D$lw!mVB63J~jq`qqblk?$E^a2uAVJF`g0)4;BoS{kv zdhxV2puJRcYFo{VdSGX2rV>*W_hZ)@A$CJkk1hU z;St5LiY`9WS)YtYc1YaGc(xH1K@>%Q5e?7ak9md~&j=aM2ubTQg7KIm7>}f?Fanz_ z=TtUVA=8Frm0pFdnl)ji=2Y565ug=IIU&0w3Wt%XN2J zAtaVv{WrLOJ$++tJmk@DjxJo|A<&3svRANHUm`8djjOyQ65Q^PQ7K136_#rV@&zOb zq-@-23BPq|NVu$#d7k5BMHDi8rth;Sl!TOv%H%%@-|~XG(TP zJ<+oL&w+xz^5on;`b{NI)_zSyMNgg_m@iL`%E^yiXzn`*BXHk!H*x&Zxu zC%KBeg5a@wD0{7Z`Yc(6jPPm%mRKpCOR5s7;*0nPN)j{qD1KRbhPVrIdFK=^BnR3# z=_)=YV~FJCSY1{6GS6dUI#luV^43rE39_ASsW}nTeXAL6mcr4}gRye5993c7#mL)5 z_<+%p6jJ9!o+I`wklY|@<03lNkp>w?;1JDvI2x)sS$klZNdGc;U-ddrsa{{z>gS?1 zW-n}cam;vNo~5K8GWfDll+?hur}_Nwz4S!U9~sUS0)kvdC(;PEbdr}z={&2}RB9{9 zwwxhYCM%R73YlZnQGGB{$q+z#iLTmFs8>UlBti+d*8W=R_yh78h`BSZ1dtp(!5g^_ z-MA8hvSMDbSqy236^qQoe_WO^JYU1`(Rcer^W`OLX{O|(D@0bBzEt4dBPF5SQyR~o z(sVCbX;XY4veLJxueW@({68Qc^%LIE4>I@{$wwzKz2-@L)mJ`RhR?y0I^7B%((3;~ zmcdbEr00~3q|VevFIpulyxWtJo)))<2!E76T^Ka@F7=QgM7S9^fD#^EXeT(J;K?~N z$RmN>-uz=6sMLPcYJ@M5NTbRk>>V=yxH_Swt~$j0?=u7MVbsXZzp#%B6(_mSoBxkc zE!GZa55Okqd*~(hd-Kos%-)h_f$Xe1PwMnkj@eqMM1;kx?y;23VCoypIO|n}UpzZ) z8im5k_5i&jgs$J^O7Dn6pr?1lqJ!S?LtpPGVo6OUtxGQWTPNltNNAM4u9sf})VTjc+AAl*)6a#H1Y2pljKf2VeQsZIT*YnVVuT9a%O! zwrLNP%L_7cw586L$|7>?Ei5YWp&CE>we0v264m@8lo<9H%bv>kXES~sOvd#vyhr3; zB_Il?-lHX+P~?p4BDh|0qL3$=3c)r92<{-D@;4|-Go&7(Q=PgX3u0{0h|~oI2Fr}d znA)GSg(j&UFwg}CBKNY*EiUlzic`QE?(ku7mT%voL?QoGDiTki@E{PQoV10?nf9>3 zsAf8}2QJ`+5sB2SPmSbC7J|qgNFCx%$!-q$3-^}5PN~Ll&5_){oW458k2$5`r6^8a zB8XXmKXEHcJm|$n;9N>iywxIGLnt7x5!pzf8fcdK%(50~L4>e76^AyRnox9kAPQTy zcU$2PYEJP|0YVlAvkQHwg~wH;FU3h@x;3wEmBLR9d#3ZatTO$R(DE;R4R{9OUM+s-YJ2fYqJvc^$vlAn}aQ0i?C|-rq?*OkP&j)J-8YYTw z&OPRtX#KwYhOhPOE1%7P_$^l&e@XS4H9%_#30n6Av@yPbriZKAkWH0@=3AlB_{Guq zjaM4K3B$2i=oMSVLNNfxbg@ww?)P-Voj@X=YBHh)=b+ zG~hQr#Tkr~8tT0dfZNNHBSA8!pc4azzAA6Kr`g*tpDN=7ySAO&AY@=`L5GIN>su@v zD9_kRB+NEk-LF8*zG670iYs&_p8HC?U>Logh*CHtVySd*7^BODIKC#D%Vl?LM$9m& z&d#4h%Dk)Dfqf|IBF|{D({PTT>;ykl8okXt+)LiXDUslxr??~k%Kp4|3b-;cga7WjUM514@mz$JDCcZD=M@ z=X+@l{*1lsz2sy6EF$$f?4efK9z)y^R{i={-ak$RYBQ9Er)nu+i8hzt@x48nqnH+dFYaxD!d&=uN6Iy*VYY-8T|p!ip#kQQ%&+Dk>A zleA#Y7$Y(t0F&CwGu4A1_fEFwwK2s7qPxRvqRcv^*6ONx9$?m;gTD7(5n6P+uA^Hd z(c+lo6r?s1onh!qFIM~k6#m3R;h~_g*glX@P}bFr76BCD^BG?ea|XLbC4BxP#Z~-_ z8)UtSrtW#{?V0p9d)eFNFcfG0LgGS5Iwmn|Ise+b8N^&V4xz>3>E4Cey@T->h@HVr zJgXdz;(e2_DvWlljl}A940Oy^e2r4hoi0%<`hGmshu&*A^R_WU03q18O(3Dn@K$r( z1S|Y8PNg7<*I6Qcdem~PiME(?J9@b!dbvfJk}pBv#MwnD<>VBB)E!DG=TG2PubP{{ z$mPu58YWWo^K9Fg#9sIb*h$tW+-T@_5gf=?0OHMZW9_8)HtL+vy|f zAhIYey+{W6j#ai_YuJjY1z^aq<|P?411ZD(3X}OqX1y6nlM{JvUnR=9gL-23VTL60 ziK1ilVQ`T7l-E7Tk>jsw!>Z;N+2PpccfB{i2jgp$sLA|-xiY__Wqv=9`R!2i`vIUK z-{Xf`eT?1V`Yf?0ppPrc_8--o%5>5pia4-yuk?Sn^k32?0xHQ!f=&SyvuUGCGo8T! z7+WA&yAD>D?Y@OUIj{f4(*I)B|6SfOD zlkdXwFI@g#V$X$jnLBm6H z_FPnYElLnPlFR7P?71)gROG{Bvgd}d=Z22mo*VjHdoJ39BieHVqL&x-Wsy=}{>RhLRWJHU8gV&%G#be}KG*7#Kiw z7Mm{Fil?30{b_UVyrY?O(K@5R4h|7>Zb;0zU3uo*tHqVH?|$SM?YZPL{tN86M&-W^}rXCXYj8{|M z`ol}qtFLBletpvVboK<|lS>~vy$mMqV3EOJNFvBrYz5_GV!j9tBReA*e+CZ&aXHYY zZW!Aj9OBr|4TE^sp%PbF71+Ln+v8jMBnX$jqNfRT#g8MQe5J~!yid>IUAS5=+gp2? z+Glcj6$i|YWJ5JjlT78D4zPudM{o-&Yu)Ch!%Ir=P;#Hsk1cqc62EV^puXJ9-fp_G zUJ?WSQ`8wJ<&7W9Pd_3kYKNkdsgz9<`R=!HS_J#0c9aJ#e2aE+s4>YI+R9NcJFs_Z ziLU|xPIqZ#W$v)-;f5{Nz{(>2OyW9HW zW3cP4Qpq?yOa2JYVutE^OwUFq_0K;h9R+8Fp;2==-t-$i^g!T+W2ERTr?=A~j(jLX zdFxDjp8Z59_&hxejx+!!K%34^ljr{72*Ky|{U~TTgg_-v5uaT>ap+8~{%*P)O}vj9 zaw=*FNoy_oLH1>0iST>~Jr(3`%2(E2E-6%wIYw!%S=Px3)A7>uc?zG@aMvUFCwFt= z75Yf;eccI$GsuVx4r&R>$BG_tnXj3(@<*wxHlZLMMrxFzx<%D&*y3*F9RYzg2O}b? zbaUh=)ZX$jw*n(}n6D~q7yT58B(bHiB^x@DO!0HD$gBc!_+8yzu`gf0g}))Pbumi! zIn~a0+GJNBY}1OPNseXYT!fgYEX7MH*ydT_T2Ni>q&l|nWKdnrnmADNY#u&Zjm_9u z4J~$94-buF~}UE8f{cD{}S6c1PqQmNG5j=l^B@aClK;p5K`ji@E$m|&)9 z4*vaX8S3&Q0&J~9i?yEu*xDSx)>`iQ_~WdDnRa;?B6EbkGe%Aq+`^J!)Q4!Amg7>Q z5GJuj^ocS4hnez)i!5MJs=o7c z@YC}{`cCF2aw+puDf838{B$rs*D*iT?#)k!H$OX7bWn%XoIgJ#!MRFI{Kp?@eP_P( zC{96QN+Jb5^Q}W@Ncn8SKV%Z;-t;KHhv3iv* z%9Om$Kq2srM9XA!Eq2g9sSpG;%W!>ZopZPTG^DEFZ2o(S&_HX=ore7)%YmaCN$orl zznJbp(dQ(cKmOmHoG?+ObNmRs@KmQ>{v_-z$$#MFhJ<<(h!^*%H~mFF(+6gxBGblg z_1&yd;XpEa^&G9~wb7dY&5+=QeT)nXr_aLkmPa2DSvhXjf(kf5!< zHl5o*QO}aXshJ0o##M*W6+m*T+SGZ7k^}S}iV*2TT8r8u{7(S2bTLzM^J&rtbyHCH zSGwDO-UpoSpfaR!PE)L1&7NhypB|>J^k=funm$gs!0a{cdqRL$z?KJIPDg<1bHwVK zb)jTp;nUeQe2RbRTkVODu zJVbwa;)Kuvm+Fa){Rllt9Li{a#}9{K-6*q~U9@B+W|78`o8%YkaY7;V+K?*MBLVcC z|KY$Ns2TQ0cym*9&2mLO>8#5(e$I6{h&jVWHaTp{`=TVjA)mf~3CA}lO zO;_h=krjeQrnC4Keuy~AXbora0cmH(@Bj_8ro1bLN>k3GGRda1Vz~Ng93`Jf)C`Go z%J`YzOwW$fwV!XQt->XM-~@8RZGv21X4udB_A?CkwO4W~^*Kg(KjFj}7A<$)$iPHx z<@sNnc-i@-7_sVJG0XPj)RrzJJ0%BfNhc)K1UK)W`p2*DF~Xa)gt$@Z8I;Z~T4EVB z(NfruC}oEmTpz|BH{r6e{pz;qg~YL96-uv&Pk}ru&rA{u4jK_GXl#yZf44SuE;Rw# z!-hMb@gAzZ+;lE~cX&{pcP~~L=s+~Hqmh%pKf#hFHml4gBmC-|UGyvU@AAlvlZ{V( zTmybJC9yi|4Wx44sv zbbGM^wOe(i9^N@iyLUR3-h1OB)VA$@zC=cWtT6n>iuC`xzkZEThY zT)6FABo|IrcXy~e9^c`;*Y5B>(C+XnxI=2Y|ICiM6yJhJk|z^)~2@5PZ}saS_8?ofPo5++(Rn(rB^|D?+TJGpY<6|(b{}C z*UQQF=>bfpAc)f_h>CqnO+f>*C{xgQ4;Ol(s-2?|)Ik6iu1Ws-72E)y_&ZoI1VdOa zEICCMs(6T~Dr>(i0eVzf*Oum>EuT^`oyoThHM|~>_k2{dNk8vVL3`rU0KO|K9_0vfR+QFZdq%XB`A|v)0GDitj0`RaxRTUfm!T-v35T2Q5DzX&n5vj7`Z`+ zqV-R(!6yC;nG7KlKk*joQ{$A>mIe7}zZ2cDht59ud0Obk49LoF;G?gOcx(l zNKv*8OV1xS*m44istv)c>gCD<)cli=7^zIrGPKjCXd}`fT!VwwphC_?tc}aoW%e=U zwM}yel-aHEEBO=t=p;T~evHoyZ@b8>>F$_$4!?uPWO6EXpc&qJQF+cAeD0cA$mg4`sH;Y;MwM71~;n^A0A4{j# z4hN>Rp|;7e{k)IsaDCF3zSjx(hR#V;hWve>XJIUAI12MJ?vrD82aSol`TQZD>BvO> zZ%E6`SbV`*t3aT_vl>e>rFait#bNK*eHeyUPR)ASe7UAhzbCo}EoyrQ)nm_GQQq<@;KtN-%v_DYxA zNTPDR^_)D>$3|VwcCD04{!8ggmtQ9Lu$U@%n%9RXnkvYt*NJ($6V2zP7jZB_A2F=r zcQ80})^1KdhBm)0H|v7Zx^sQ*f0IpVwt4}8BfM#&^op}`XX_~OzhYWX1oREUUeTE^ z+Mm{JyQt=+8WkU)bD*w!))2F%t*NXo+gEqF&ljI;)^xzWZDiVIHoLhRv01~+nspsz zb-BK>x-y^S%#4pTYqpYeT}|`HN0rvR)+LCQ)dhVjOD0*e0&tBzhp+%Ll&&{#=%Y^d z*pr}-cpT!%!jZCj@`A;fp;>uY(r5rj%3Y%XvES`% zDMW^GSOTZ;__N9GcqK9F8U{e>XHWfCm|zgziE->J{On4(CC#W+i$}5TRg{J=WDq_q z_9PIpBB+t4iA<3b2hrIhjK-gzEh?7izklL8%L)1;fWr*92>o!IK~`1eUCEk2;dPU5jWo17>p`L z>>lW|V(5g3(b^^awIb_`+7rnnaUcmY9bMcGQ_00|p+74OqN9RCWGRmB_l4SUNY#&h zK1iSfAUyvNNU)~)Ox+q~Cf@YG=u!Zy-heOHDuI{G+T~p^g-qNg}<)kYk}&S$;vIFvP4T9J6psxr3k;ninFUi}i_1C9kAkb*Ih@_G&*pd-!du zQ&i9lgX?p5^$V6g#c#zbxI_yC?dh0@=EDZJ_(OIzhV8W@(xx=&iZNbSRDEakdUbvy z+HfHK<0q(G-SFStP|B4H9aw|AkJ1)Wc$FT)kCNYg_phRh54)pOvxCukRY3KZYf24~ zrhd3Ak#8R%Q_uLpyJUvCJXddLj31_cmaCr(^OXGkcgOcpbpAgd-=Z`e#`uIeR0n=xE3%uvOtZCyr7x@3;_!fwV8s92CT65TsRVrtH z<2%`By~np?4@S?Jl;e$WY4ic(J5P{ge9x6Lp+Qz43k6jZt07_|}aPd7K*G@+nDc&1H%F$Jv-90tt%Hzr#u*Y%Ji-I%RE*oD!p;E!6NI??+r|~MV#dwt5xdj=4XlY5+?IOGG z2szIeD53*kVN71xwrOG~g0oStpw)3N8qJlJw4%qtR>?y2g%4>Sq{2LV{Q#A|DnJYw zM2y`Y?%;gZ{Q9g}#iQ4`ON9)g*GZH=IP2yM)Ykaezhz}SU&JTQHBvsjZJgL+PO9Y# z91#7}Yf??nKF@x=(!NhrFZsre!1ArkndpOY7AHTKq&{b+e;&hUG>~jcgkxEi_VY@E zL%~@t4NpIB7KlFJ)pvHK{WFy<(G0Ite{`Txo+f-bQ8l5$r3vS#CTz}DqbA={3FVUT zEtSxs6CTkeUg=CV`f(Cc3UTlG(%V1b0tZG-SVjc47EW==c)A{C7)@P9+RxRv;TniV z-{WJYt#UGk)OTWy?Fl$n&R~Og1>U>=5UK{9;QgD}6kX28dOqII^C1~y?7bax6)#I= z6YZEW{0$ysr5{LUO(Zvlvct~xLyW8@Ht>^7>}12z4>Z?Mfn_gKwvN2AW?|&!Loza1 zhLQzlgOPRlNp{s5HpEY7_$W@EWY@+8Zf|C0A1)ZblfPy086oFZc2vsSCOLPn$%83h z?S|=t(Qm(;DZ}_9GeJ1(E2Y@xQ!0REFI-6#7uiTnjRon2K%6bF4ujM`nKD`rTFA!9tw;;66-C^m`g?)=wu}lDoV^t+rv>_}u2>V+$2bBn(XV)q2 z5AX9;RZ5zS0n(gFnLSCFRg)!2jRQ$y3?xfsRh39mX|hyyPf~Uj%ih`zRx)XTmn0TI zVv+dN_zr)eNB8~720tS&&iKXOQ6u2dk5Y`@#7-hBuYC;fp7l=jPp|9oePR0eeqE36 z3;T@k*Y)_8&*|g)b=594zAyaeKJ`B!RRS)635som_5{tfDE{|P{Fd55tF0>vcRtu-0;f{wb383hgH73vfN&x zvACmcvUB%NiG;NiAmz+*=dv5$nitsfR)9-&moTm8(7#XJm+Dc`Am~gSS}HGPUE;9O^%3VJK!u4#1Nq!0jEJ;y{=E>-})8SM!6#k!)n8H0be*O_?|O_SFYL<#$KB;i zeMCWCYh{(!A>nGMlG%Z2@e&vvubl%njEl`8qLaVug#E~iG%1QrQ}rb>8A5>8bK zEjr1DSRi z%%8|$mLLjyHcD{T=8qW91W|a4y2Q|e8sSY~L=(GPMre?MVTWqu z4KNwDF;Q*n`JrY@JyOxJ8`%F>koTK-OC?Y}w3vxb_E(0xv*+Ax5r#Ulu4;aOS%avW zMq`8O`pE7o?mqd;F7+cpq*F)i;IvooRjQ3(+FZcLpzX*;N6=P23;dGJ5l{6o8k>A= zi6$j1u40E^Fqz1!X66&d*@JRq|AZpB36+v0IGg&WbJ+o&o{c;RAt9 z@`y!bpNLG*Oz&jbj_eIW=58J!k)e=KV%+qtHN*RIX9cNPfZ%ZA%wH}ubmtC^+r@9{ z+20n_*{%}wls&q$;ZvYVXw?L65Z8gE=q9(+$GLa+VYP!6Ra=Ub5y-mC`hN%_IbT_r&~fFt6KrHm0_*mN5gu!97ih@XN=Uq;vX zp{8;Tne+vo8)^6$OMVCfnC9rsQ1l{Y5#T~BNWYt7>pr9L*P3NE!w_n5RV(X>Q1po{ zntNUja@8#8kvvU39=?i4(0+1;`nB>l^>FUgzvl8_{6vHYE_Q}zBwE6IQL5PlktqP7 z#Ie!+d^m>>VELfr3pjI`P3N~MMcHOcy}Zel$g=73KABfGp=(d4a45P&ORLp+s^--r z4@f@&Lg)shIVtKZQ}9XagQ5DzIVss?pG-yeWheL?dVK zwcnJz(t@0f#FZNLaa)-CSb7Gx_`zQ^Sw1k|+wUVH*cS9egcTj|Gy&c0v+DeB;YV?3;!?N{YtLp}Y}sdSCbG^KSu<}xz&`tbGQahn z-ZNKGKD$h9;q;6zk=FrG8t zcUjIe@{^OS$oYR{v9-0etaukU;o4oI@(`{5)8u?@apafv`CFPCXI9$3Qlk@(D5!zE z*VbV1E;Y>yHIk%V^bvd8T0X!pFY2sA5kL|Fo0v zq+{=AcNHG@KP~X`$0R>KSycsHR${Wh`q<}7s4^*{wUb(6)FUdF=dh;i6VusCJ;`!@ zn%C(ZO7_}HmLinzE{dI{^H&R~SxPlR(O5Wpi-eJA+Ci2IUkF{>+u|3#( z>#3gl#vjwSzS1;|b$z=&Jy?C|dGYTfpVasG!zpU%`aF956nZ79j)8Cmt%F$0@2*PH z`R9~WEje1Z1e*xLR49}f^^M(u?bWSqnN*%3zYvXUlRE*NEzqP zetvWwF`{n^i}>7|qDFcPy>c6%jCd^$Bke#!r-4Z1x3fhf4X^)=7atJ(&@E}~No)WU z2SKN+mv?aN%BW{XMtsZX+^nO6BpWW_W-@Gj_+(2 z#v?zf(I#`1=mO@mqA}ph*LfqOEIfacuWC4=y2DZ)vV>e+TcE3q&hJ23!TYc{z0!Z7 zz5;5M`gSopA5MMGcBM7)U#M?{SKq?JtS|6y)_0XxAD$40)xLK=`S;qV+^<8q9^&R_f);GqhZ!6>QaN74c zJ3y&HFXMqx-gz^~_IC8n#94^wSK`Y&r>DffFn&Zz$apmm6Th6E+Ir@X!;(j|0eQr* zQT4sS^Kj_#>z#e*VP0uYXAZHy6yFc7{owr5IAd9p^=vmf1^@1mee4IBxJ~7%S2b7( zLYyMvlVz3}#tCL6T{kgMkiFH#@nIpppMcCJ4y^ZaxD}h=7t*W}eu)oNFhppo-?#(> z?Q>c4U!dlq9?u^|fAGWGCPchr&JfyPvVb?Z^HE~O;U+e+-P*I28N^r$#(`D+z$_!C>|)W@Gt*$)*E5aUDcsdL0~Jj= zw0f|bV4_!a#<6erOf{>dVf?E}O**~#$G36jwH)yyzK@#P25~!khUbzudL1!kd}w3f z;s^slt)Sr38-oQN235zW*PEQ;Mzez!WHSs!&ztHlMNoBFPR4o}FvSQ^;lAmXr_iXo` z%f06cdB#Vv!mAOh0&B;m>FZrFF9tY0Rx8oGSo{W0%0x>RQvzYa%Is~Oac1>C#sz&C zfCa#rMy*`fO|f%Nauy`QiR?KS;Vb#Xz)uo^o6cRuT^xyzyp_{{Im;|3e zIO~y!`lHjb>?{7v{ud|BI3XHZZZwpl)RnJL=P#2e7)ypoaVP&f2cpsDekuzHz04b6 zEcrlwIr;w>Z~($hZX0PBIe_2h{w4L^NE55>Hp>WznW4@7O)9 z`JW|+ZBAxIZJU-HAd5=(i$zFThVpn~996a;O=h!zb(1DFW+Ab%+hz$*T4Ijj3F>Ak z&*eO)@?248UWvs>SUBBcBb$xd88RW+^H<e&C3fn4`Klx82eWB%dSfiv{KE$Pd_FIICq=%OiBemYBT}}htC-@U`%J&DjZ>)ATCSLz@EjK<>#1`u-N6FX{&}m-}{x>{9}<3cr-CA0|=Qz@=`Yzjb0x z-)eDdPOp{~P`%a>qVrb~Cq45ysW*}T)poc!y!NWJaisVu+?*N5g9gqDH)qvzVMuyS z_LYNU6LSR#%buDS|5g1!j(Era`htK|bMy-WRSXaPS6Zi%w{+fiU(W&>&8PWqextFu z%qjiK40n&3Gr@8Ooag%_G3BOgxm(*zbXd`&#e0?sfQ#p=2T{F%7_MnVBxSkMLG%ZxyA zGh4B8v6>#=(-PkJ-plxYlcEf;_2u>kGrXPgy*-$-sl0Z*Veh12jPU?NS~haO@KvvI z{|r2sBe&9?I@pR05~0iD76NlgCv}IrGmXW6kO?!~^c5TIS*i^ckke;0T#_jlT;%06 zH@p7$=_>ZUqG6V?_#suKc^}Qr_L?2duqC72()_nP^Vt)qX!LIP6d{kaQx(kPu2D@d z419PbX?m$*a)Ob9mb#-8xs$L)wrXOSO1*U7lU|D+9RzC$ipLGDqt}gYihpxyFFJT4 zPAJf(X!0vMj6H39d7Hr~Xrug9h&;JOk#r4l?e3{sT^?CqwW@xQ8=?1;*os5-Y!TEP z$HNNf;aW2$1HIaO77od9gCzHKV%3cPIGfr~jl{Z`j7sOk3)Q zxoqQUUOY7o+wd3g;!@oyUzZng21>PB4Ul8xgBl>y7$BOb8+GrR>eRA(IqaHFs0Cn- zU%T3GxwvK=L#Fn>Kt?&dHdp`My}s|T`A}E!HBmhTr%+plyGjU<8tSm=9O*zN0){$l zs)ss}hKrkLmAEgZWtPr`AIthpq2N3MC2diK;$c#Sr{tBbv zc&?54GSm3w8pH^vLtD+-_l?MT6f3hgBSNeV+XEs(HXHUsd{ivh62e!Ft-*mw_IrAm z%jx74lGxI@hC|puk@p}{fC3@~3epO)Cwp=~EmQJhoy3lIF(-NxqWe^m*GH!@oZ|Jz zbk$#zfn2$_LJ4xwUy=k@07bL=7X*2CTE{7x9HHU#BN_V_ao>z#@-qTn*PM<97Pki@}e2Jhx%n=-p<`-csTKZ47_GBec=VX+MOFL6&AHhk_oCIYe$H zUjBI6so)5GFZn-0)oX$krG+VL|nC?FWFqEN;_!S77qr`_s77?$ngi*1Ro`#cEEwXiN4)c77-3iO$kfZIGB1 zd*0yUy_}$ZJr_c*nRSe%G-w$MsLeg>6e?~G`qqVfEkWOU);{j}?3DF3Zyd1RyNxwm zyE13U@y~;qGulRPjt|l2le9ge>ZX(}Le{39E#d}onehA>xL?{Jj$AQL6XEVNt4<`| zPrU>rsWijmPV!YZs*t_}DUs!N{BcQTsn9M#imh0NS}h;T0)r?$U+BWiQ^_`pT;JP5 zS3fT++OyaT?9*Pc6)Ia!FnXdlhg8iVDBNV{_#@J$kd(h9feg;&X4(Bj2mfVEPatc{ zYxh;3Q*Q4u!#hwwcZ71f%WHSfo6$3K5U~Hm@GmoS3rW@9mbNZKdmVHA{ zKVEBIC-%fOxV%$b_%vj{7AoEtaIVM50tYzr5}~ngS6$AD)sS!FXx3>x{&3)b^Dv(% z&;!kyeZD#8ppbn~ZhvToKLqy=gE?`IbI-dpiTm5tm=n)S;*MDnyhkX!S>M9)p<<#U zHSa&ToR*c1Yr+Ct8vxx}xj*?lxeZBH%JV3C=9rWCJ6BYU~ym@5xUd@n9H39r{F;oQh zuz|MVAahHQ1DmeHGPNh8M9vvH(PAvgphrrxypf?bafGlUW3q%U!Ubn)sry|D_Apt> z-s_#eD&pch(|&_vrGAqoOLH8(9|J&RV6gHkt!@|NO3?ZC@t=R3sI)`R6E!SoZ|ArJ zz9>7&ogWqw+Uu*+j3u%%n0iy;AGv|YOnjgYWR7GGEXVfi{Fu90Zeo2MY7g2YiEG92 zflWrkH%xnraA@u3c~2@M%HAQ;5+bJk7>mUWmg`imO*ohaN`3Ykl%eMB+%eLaFmtxl zHZdv;Tkc0urT?Nzv!NWrJ~1OpMjw8UmOWPt3#FNOIAK>f<|vsJo0>a@Xeb!Gzar|7 zTMQI);o3w8kMO<%W66(M23yXN8$bIvG3ln^k06B;+hiA2jveNcM!c>IOtotsDBf!& z)}R`#6NDw6_JrhmQ0zUQFqMJ;Q68E+drvT@MGkoX5BO@XrZ@{7U-eq|kCM6O3s$o4 zORsWeuMo{x{6o-Id$=()stI&8I`BNC@dQ?~le4ADfm~aXXXdm;hjEQ1i`i{{s$ntP z;#b#VCsDtK3J!+4_P6MZ|5*pae?&j{f6TmDRKbrDWN|qVFNFJeE#$<$4xrtFib)7T3BLbvt`%^4e;* z(^B&}vB0?d)k<87{qZo1G1@ZRn3q}j^bTr1SZDX`W{bT2vS~Be^kq}I63}B)-8hd; zUo?^pRHSrOyd0PqSE=49((hl3$nH!Tk7D^;JR(I77Hkv5sFwoOs9DB*PLbj{Wk{0R z&-iz1-yoeKB>hj;j?#rh&~PRwiI!@{FjJY{IM!rRvFc|*H&an4c5qx-LuI%_G_K?y zn=E{YB8ovaqiD)y^>P}Ct6{~Ghn4kPR9q&jX$RNdr$1-2lza9c)#Ew;TGSP+beE0yBtk9E}_ zZrLB+JI7e^mV9#teEPAVKYS^HP!a@N5V0oKZYJwPi$Y3gxVV7{eY0nttn*)%tqH4{ zB6>uy_;n-viWo5niX1D&R8JuxouYu)vba&_a4E2bu0MbRH-Kwz3W$1P*(hA4B&l_X zyGSq)rjd|12WJ|QO)$;zG%7_tU>K2+G**gv6qJ$c5pj?v;;Zo#5rqeYjtIADlE_J9 z7>=E|6vG{+a&S=+>1NRC7wMV{u&K5r$FeJa9a{EJm!c^ZWgSc+<&&6vEfwVqKvjn4 zKR?olRPgFi!HVX&r_0#F5p7hzxET#dU2U6EA(ARp@4GQzXdF3UmWJb~e+Ne#FathP(3M2O#b-->vrj#ox}-1S6|qtg{28sKVhJmS;kie2nEMxR zj+=e8hIH^LQT1pO7HepWG@0#Jrib-8FQMZajW6Xi2XnaE<7nA54B1oi@M)ht!o3af z)JDxxZ>*H@?^Qg(n^Iw;>;7q>)Oy z?CzO$6@Ig|f^9rAR)NOMUy*4TE~ezU|H)W-n%h{{yS1=6M9RfmeC}XZ?TXl~Vm0>E zi$f@x@I!{Xfi<2`)qZ!Cl73@l0!=B{XTV44y>}Q2wqlz3K<$B|rxF?AhpnbdQ{C?X zrBeBo#L8Qw?M7pHvyemfR86~LFt5UApm=?ryTs#f5oN|=xh(o?Vy=v#YcQih&wx8w zGB#EL4vu&uHQskmlJQ^OH11Mvg_NUz2Vbht=^5@h0EmW~qgSjo?diFu zJtc?swFz^;#Ch)hk(%PMi7JX6XLnTV-1$L; zxz$*7GYt(Dzsz0sm}HYZVB=df)$g9DI_0pyoN#b3hv*p5QQW8G7{cK+4RM*_EsqBD{pj+&TUXPJc*&6NkQMjoj#%E+?qHebtWi57D;ZC`j-1+v4AAFqP z*L%u-Z!}&#n8o3j$``ZTxmE0Qr_C9Tsqy#P)VNBK_$`EHx$}n(ZNST%IDls zOy!gtD&7)c?->kxuYZk(tCYDfr-s{_mpn)zqhYgYzh{O&z<&KfDCa}jxOJec(i~#q z03`4Y5$SlDH; zKiA>@N`XRwy+MP*68n8j*+;JIIQ^le) zc60SE_jUyd-dil5v%n;#v~rx%q;5RbT|;*(5`Dl+fH>0Hg~IEKQ{6}9vy)9&*d}Yw zhJcT=qY9y*+?XQlwTKMzydR0gGyX#-EKDoTNsEFgHVfCtuoKA`J`Nlts|YWi$_Xw$ zPTph+il5CJUO}hH2YNmuK2qMq^btRXH?De@tG#GFahpB=T}Nr?$xD zbCDg)yE3p(@wUx_#qO-U)(kh(q)ffGZROBki#h;;J@7Zfw2jT8@LuP!1Dh{W6)t1@!WX2|nG|PzB;TPCh zKd{n#;pmL`mUQ{*`MVp96(h!%jLgWm=ZD0Z82>X08A~3cA~r2<-zs*3?1kI_D!z3C z+0W!6`D;K;f&$iF!izgkvL=%*N+zABUIrVHYg95GXb_Y=CQRh|#NPPPRB6;UfaUnJ zd9Au-{5kR^QcQvHg_JDlT~bzI-f^vgaw|``8?)9vii77F$oUkWs_=G6P*F@&wMQol ztHjpciN_=pRWq76P1}u|^&=YeQOJiBXmQS$xSP8>x1iccbRByOA$)7A$y>+9S!_^I z5|*myy51G#Clh<%JlG44ST8i3;sdk(uvbI28rW+Guw61k zuFjC3o7Y`Wir|NWk9DL| z5PoyT-$-F}V{eRxr-M<%%Q2RW*HCt+LoxF3${eb=RwP}j6{)KIy3ok}n^D22>1l?{ z4!RlNOuvlXD3og8{zS*et^a+H^PM1mAjg!g+&#U;#=ZXUL zv^m^%rQf{(m;oQB5*V zUe7OeG%vD#-ut7Q)))=Fl8nY)KU0IVPkmfAc;wQ)^@xsTVHiiYN0KM1z1eY{x;6{c{tx=oi($|qC>^=zB!(4E<{;Q7&EV9#g(X< zZLU`8_UX*#h=+_d{rPQ{MSocM86n>a0^wKDblW6)dhJ;b>f}ew6E^_4RBUs$C^V=|Qu-Uu= z@0BfO(Yvy_Nxg`ZiT+T|{*dv+`+oBoKVWA*j%5%Y7$TlsxV!mge?Q<%*&lS~W*Utn z)GBZ7eioJcvW)OcR7hjHj71;whC?1z%g$`b`O)s6Gi@*@Kyu2A#<>HjdIm9GKgcW3 z*;f{wn;B^SfU0*;^$rO}YdrC~-(3rc1KesaFZ`l+E7ys8edBuZxe@oshIQ;%SUGR7 z0)2~9g}@cp$zV=LU#XDt+Zx2g#SEErrPIW7!wiwi@RtLO$lKBqk>e|Qq5WA#WT$)z zH)VN*Ugusb;z4;iFC{7DRPL2Vk%i+`Eh_H)<9r9F!RBglO$p;@wB%b9T6Hvkj7Qsy z@Ugsb4M&iL@Ft85T&}{(D~Nw)F)oAC#pRE3$OCcvyfqIAHX>;MxPaM?X``%g6E7t= zt1(XRDXp7omDSx4V5u|7{U#j9MN7g&Nwyfh4$11iNCS<=HC*3esx(<>KuUG;G1)FK za2N8OZlkRp;&W!QGy+-E;Cd3S+-bNiGvqA5DzUd~<}Dal=yFk6_{Q}EcNcCV$6T(; zyStDZks4=!{SON}q|{(Ylnse;3H1vbdd~2 zrW3GA4+zseT>zP82mx}%)S;>vQWm`p|J0^DfnAox*EG;Tear9uQo(AQ>=(d0^pM;o$06i_cjGy2Px@FNkAgd83klQunZ6Li3$ba*je__I4?!ma?J}6r( ze-V+Se=p&8T3vrYh;cLHzf+ftFb(@O1v^Fd$qM%W0oi9(B}x8E>azZIlE+PR^~Hc- zBs>ao3ToDDQ$hUP>#$t!s=edA)Nl4pWm=`Z^o4HpdGwa_hI?%KL>QUGzOS*}b<1_ACiy)w3CEe~L$fQ8=YqLf@Gt4!_k{&GC6}`OVb9>nY zhNl2F#nKF2a#er}bz%_-69!JGWRVrT%Ce1DIg2e{m4mGcZx?iyb@CDU#hLdN z=%sB$FW{Ik>eA>Y%vHVZ!HCy$v&EfxaA}R`$9X7&rAEVkdq1abtqmUqa{f_ToA6Hi zHU-AER=?_YL38E9`mFdOI#W2q+icXjEItXOWfivoGnnmD=XE(#JCp$2a-=s~j`VVa zZ~Ru73008=*edwqC1$B|nf6N@%hjiHb2d_bAP&-B#m~m~nd7*vM(vXnA}4_vIW)AS zonKygDrnxv$xXavD*xmCn!=rsH;`iRjDRH!PaS4IqL48(@(Pd9n-wZP zMY_8P8)x}IDNp&p)vljA%|*9*lc;M|4%)WVs*VVci=8}H=i z9hkVAa=P*2K8tcjZ7tc1h8#_;E_58aAxlVVG&1W$DUL`4@nW`LtCZn#uLw^m7o=R! zslXNbE}zjb*4|66zzK7|Nr*o=lEA^|kyV!(jql3l!xu0YT6fLp&7S!dNMFg?R_Q!< zWuh~2=T*0O6yx{{hU?36T7YKMy#s-WLz#qF{YRN-34F0yzHlnyTYc=wGIqmT*{aw| zK*3_&%-P#eHl*3}SxQL08Q3XR-?#OOk?3*_KO_V7}fPVAKriC}V8OP5;CO8J<` zKboUu+?7Lo{Fi-d8>S4<-rv=R%1KYb^N@l)^MjRQXnVAkn;o9$25VH^8Ov z_R1s`jL2h@c6aed^+gkV>Op5VeQ_gwG1TLgc~`1|eH?vCBD&>`(3zmteb`{M%Jn(* zg2nJcePDeC+~0$SKDf>qnSlKYc1K}^$S(xZsN!6Lc(&2nV03l6YP7S7ha5i13vllI zk^&>|>JpgzPWf8w)Tqa@rRwqUavoeZT58!&y}XJQzIK9wtv@)+>eSZlq*8(;DiB2) zM3Dwjq(B%$uPHHxURq!bos?$`<>W-st;!-k9<2?|aIgMVP!Kni12h<7$naOjQiQV zd}dh4-q9L)hw>~jBJax+DJkn>8A_5}$Q!Q=W+_fqRvqpq#SpVu4Gu`3vnG&3+-Nm= zGOErZ5TI}tOkVX(#(cZH6L3gHiwoKBC-OghR0h^(N%5DnSwcG4s^iS)#q`mn&uvHb zk*1vf>wUQs%xq^Cf4ydRJ|E+XVj4@B557iKn(e50H&V(MW^E(#6GUKilC|)QjEn)y zg};m~+$wIPqnr4`tcwY%nOh+oOVrTZ(Ys}aHEUO^3tx;fqWF~I6FD<47`=Fe405^K zXn$s@aevI?ggi7PUWIEi^lJgHU33SWC5*)wlD_7n^byQmDiS9a5l9F0H;O7=2Q} ztswNjY>>SXzb&ddBC0yYWIr44qq4#rv+mkLoagQ?#LFkUP}FYsRtAsJxUv;k(bX*i zF}h4K6KivrsKmxMklLnoi$igVki&ms!aS~f&g^()f zJb9-Sa2}R1i^-4~M@^{lixsUt?p*hQf~S*pStl}r%v>Q4Qp$$lYYRG{?*xk;lZxl}6L|O4b)gW(dw& z>Jq*d-xHM$Z7bY;*Me)*)}Hb6r)Xce>ArCHamJFHpab@$wd>ODS;7n-cXn?ClW7!CdbUp6BflJ}Qi%@g0-G_Xr~rRSc8FSH_wv@mIa9 zN2anKV?<{3$|{4<4fSN*wyg(k;ezx&E`i$a$ez3n>3MZfs1(V%1nxgndlhwmMqW+b zqm0O3<$Efthy(W}`4nC)e9A`XUwR5&k}7yc^{L511bT+Ak%%%;iMUXXExb#4cY&0S zsdsW@xIf}|lIca65zE4AamssE{+KljikK$mw^b8AMQIj+(*_bp#xqn`lq59(kKH7| zRwPP63HJ4{h(AW(G#-KQSFr4LV8u{v=K}?WWXP{g{G$JbkBo+8$I6)W^Z|q#A4M3A zU@z92&1;mvf({$02Gvb80@Tr~1PYfu@Q};djmQA%a!=+DUzZAOE+x_xJ|tNWQlaFO z3je^)aH^&VH6eJUruYH|>_CRA8eIgc@{Z>!`L;o}3ZqKeFtuXjzoUkFWT}#(qfz@O zpeSZGTaj?=c?7U#^vKAc1A_xF2ezpCJMk+=Zx-;1$qpcHM6rL*L?cwF8U?6O^w!cq z^h%2k?3R`nw;16#`06d3Tp7-;g_doCv0QmiSDeNALbZNnopcPdK8&z>sl4}u z0{Zkn3EC5lELS<2s*WSa3Y9}9-E&KoZji`-Mdez#Dh*CkZ#e&>;k0{jq^3>s{)4Wo zJQ#K4fPn-v_-l+jqLF%O6*0)=7jrHTVOy~@;Y!*jpeun zuhLdzbek?%qrjNUW&Eg8Ci_WVAofV7&Xb`AdZbJLTB;9RoaoW^|wFNMb6c4kJUxK zt>0pG5wZ4A;&*kC@94MR*G0zg1|Gscb&;|9hX@sP=QAzBM;Wz#8IZDS-6dTl*C#~& zp*kyslFyA7(Yr=4WadiI;@4)5LLiKw!7LD4@HHW&i9ft zZpPg37dWX&Fg0&Oqd2B`2W&H1BO4*7sMK%D6IZk+H}I0&&?r;e80B_c4m*eJPXf)K z6u7lu3T>nTQ2sV~XqEoCChAD!FMB8}!z~Bd(#Grn@xutR78V<;xe_0s&91lvcuS$> zRK-$g1&^rnIDgS2)%z3bU9@Kwe)T+zyvQnfpqEO0QKyYx(4a#h(QNH`=dK&on&G#f zGYg32-BbQupL~$*74HKf9o@fw*83aLJOv|9)9<}dFd`es?S91{BrUZ@mkD0>vYiYu z+i_)}F&4pt89e(4!#%}1Iqy0fga)GO*OuXPX0DvKf6#Uqh_GcJ)Yl#=s# zF|Z}_ujMx^Chan6JC(5!MP9)(^0c0ww@iu}c@Jk$mofAz)?3q9Z&|3*^wAY7+^4{s zMF1w~A<}K(7Vaf4L$Ng)stS+5U+``uH}`oLvaKYCqPxqng0ipFfyG>m&n@iieCjW4 z^b=Q4I&zVmPzZ8kfte8=8EdF z3L|cY`y2i|<9AQsgDjL|@yuriA8N6DN1J>8E@-K?9U-PW9I6DIOR?k35O>q=Y-90_ z08=ZCc3ubom&y1sR~{SQ&qkPdzCI^gN*JwH7>|Bxgn!BxSc0v#7lh83`P?Icsg6mE z-W(XY*?yN3e5`a9ZkP3}`-3hlRML)cEHnN+DLH#WlqiaDvEr=rU@Z5y`q!Y@c#Hh= zKy-JKTM1A$omMd@+-LaX)sgkgFd0QXG|`5GSmZsAy=3^ir+^gphPMJpQV9`R!|{@; zOU;#K?tP+L$}t8dW6of(%8Qa>+92Tm?Gq)dWHMHH-sN|?*ui|EzR%>l+`Ep~2!s!R z(KR!GKp!;w4u)oTz^N)^q*Zf+AVYFcfL&>cOO(ye%L@l$7R(_W#yjQF;|tk3WrS|` zW6@xQuAxv@{5Ul;6k3Fo!5A&W9DmvJrII~Z{LZWq3?1p~7wH!*iaA=jk{^gsnS_-) z!>x2`&|W6$W$C~CQ~N#5SHV*D;}#|Up0?uU?~ZB#kQ8m za1CbC6(*WFR&B!$6Gn+f)GY2;+;1Lwh@VnGLRHk2#|ZII3v);&1xCV?$o}oSLU0wF z^p>S8*?rYx72as}ghg?`qQA|R$GiXF$yi_Ey7FT0a<}sI7*CO077E~MVdf0CQhoJ9 zRrkQqzS6qt-vJ(9>syuzgY*0MrM0`O<`IE#S@|ERF{|o6jN3#KTqcSDExm`pg7^&F z31L@`krqdl{XX%UY+GR3P>N3R-dQ)KA<8u&lGP0taXV$L?++p(9&mXiA=N(+B|(9J^8~H)_R+BaKGUWl|+X zk|uK@pER%Ym6h_YE!NQ|1$P=QG-AJ=HEs?df)}imel#LKmEzifo5;WEmuPs`^QFx0 zZtnDR#HP&t5)Dz*LmkXj(;pV6O+tTZ6U`A=Xf#!q$ihnAl{GW9u$pxrH@SQpo%U_g z&__@&R=>ronG<8OFNj7&0|@ZLZnf7m6P&gA6P%=er>L%d)iSD1U~H%!Pp;~yN*bNW z&j&hDkW72C+q{Rm!3@cuFpEXz^6CwNnx3!8?ugGVvpbV5ji>3tMF383ae8zA8GIRu z17@9Q$tIR4#j=fxiA~zOTE>KXCLh!Ku=DiagSFm3peHr2Ng!(2W6vh9>+Txng(GKj zsz+mYWm_s8h=ld&&AUr_cvl-t7(Hz=F9-*>QoKJ7E(A@FgCl+jWK zAio3*BN2d-2i*0;X#)HtJ6O^=#lE|wi^d3d%7<=rX|WTst`!@gQM9Z>Js$4j!DY4C zC30_VNgjVMFDc;fwIwAKR|8JMX{qfSwrg>R(;vq=(iEe1e{Whwmq`N{QP8NPbNeIm zt^^3el+OCki zK<_hoEBe*Kfr_^k z#)~K6xFKY&8iI(IGo@oUBI1jMG3=LAWW5$G;+bG%W`0akdITa{@0~yXU)90V3Xg^! zN7DIWlPn=sZkHT*Cx_WQ?B|O)T^nsn(+)-JqAydg$ud>62eW%Q8p6UztU)SLPVFE7MXZY-N-w z)=Cms=&I%4Qo(#$ z$->$sBfwUcVpf$(%(GW0T$rbslxpVftIEWFAj0JB?a#MRY%xA=vK}c&DmAy}Vo#evlb$f@Dqy{&NBTpa8em zZ~-Ra$CKNgCj&(7D0zm@cImU^c4s30i^V|F(|c$B|J$F4pPI-YAkYEfDEn#W0?e}P zG;}tM_Q`c?_8Pec%l#ky@ew{I@;3++iFuxCuUypSEwfLFswzs*b34!WV0~W|`whj! zUpGK_@o>{e7}IbD+)gX76x>_?G51+yFAT~7tw5B}+#pp`21bcJbdC8 zQj3)WsDVtG#sP(^qe1sG)^~yh)R$g%QN>9z>oZT91`lae{4bIT~q+P@auEv2$ z9D7eiCL~wVr~sv2AiVY{id#ooAiS6S@mxyave^wwRAKZ4WSh#Gjtz9DgE?;&Sy&u=vwiTw0`4B%o;gLF$|w{{_oz|LlRhPl`vTIH#Y3 z$B|JhM`|IS5%~|9ZNq!BjYUtf>s%h4pJ6&v6Xu_$sEAoy5t0#j!IzVfndKiaFy!2l zEiSYjLFaq>nzv>JHhdz!xT~mv^M8K?k~ji4;e89Z?*dL8f{x~3PxT^j$sKLtKS`b# zVKBefEl^e`;RiPST>#*RC0;o1O5F-nn{3-ejUF)Pr-8`@%;)`q=>iNFiGH8F8qC7J zU?dV&5*u9ozt`0tm`=cC8@0<*V9xIg=7}^g!vV9iKQNmBGr*{QH3jA~)_J`ebxRtU z5rFCJ4-Edu-2>TBNP&5xFPIb4z#I>l5BdY6t*y0>(Pf%8w*aO*dXe-!9Z&ZgOLn5b ziPJWH^D|;JQV>2z; z+<1=9N%qAHKF@tisnasx^Fh;$h8VcP!d1da*l+J&Yc_smuK%RGV2AmqkXeHhYvkLa z%}RKI%xwR_L5Jkl$T!ILFQXr{x24?KSGi{+Gi6w;n&K1|tMOrteQ6d4p}nz)D}RRw z4L6Gxu}B>wraBtFtt6PU7a^N;<<5Ci5{PNHtss~~1-P4YkYhw3=WY4kg>8@g^0}MO znB*IG1ay&AWG7gP$he?H61Hy`!Lfk?s91zxW$|;lAaLavew3Ek6Rk3PYOu_{a$2Q5 z@pAVrCR+izs;ur-&ZOLv>q;1ww1IrTbc{qZkb(SalKe6APmq6SdBHw8lVn7WO=G*X zk?r+GuaO-ItFHbUd;`5h_E&V5c=xYz#Xm>U|7(d}#Z;ou!`-eypJ~qjfnqL%%R!rV zp$IllXr)P;-c3`|rn>lWhJ!1{VO{yhaG??c2d!N0{YqAzCZl>+u4Gho!67PlpJkfX zb&CJkq3aB#)tM&Hde^B0S~a1_`}U(dB~_K2W;}FN+hB!c^U{P~@2Zs0!*3>8mAexL z(2WsI=g>9Oq}7ln4|~_($-@UcxHGRVkDg^ZA!MP5njT)qS|aR@#4#eTs0GRa@-YRN z6EDK7!x>HF7dy*;Py#-7%c;iGZ$$N)D96(EoiT%E--uzJNHkyPejQ|spO_5jnn^HO zv$@!{&xHq1Un=?P3<4%_slp&M6$zx^MOKicH3vjlcv?k(ph!|1lk;*cMAh-ks!Fb& z9c(JqGEm&6j;Jp^m^(w{yq(WdqmWm4k$yXwa{D|AzCO~}`5 z68Y03nwTt}Cc^=@b@W4BWAPHn*_Xlx=JcuVBtBF6O(+Lu^Upm0U+;Alh$*AaU~ytk z_4V|uB9V$8#BI_z%TDK^ctdo?EUs|Po4 z&nwH>91U>M=XRDLTm4qfJ3-@#X1`gF&*cWd&U`%N4A1dG5wR$M?(B+rhn!0W!<~2KQ1a@5yv^gJl{!XgMz7{9;|{9c z?hodCN!6eE<1-F8#aJengU~o;)nwoi#fcM(vpAtnK!3H@huY(|A|Q>%*49C?mhi{_ zsyb#oSHbO7RfU_mSMDYD+Nvr*W3bt9tce_&Gff}SE0-gBWsuHSeHLd5Rh6z*48E18ROE^i8-WQ>gXJrlyXp zvW%u||3v599FAU^yLTH6Yt5oorsUctwjNteqbx>3pm@!!0TP_0F~BKDiQjeuY$2<< zsq8)6P(Xb}Wpxv|dw$NTnkYS@MZKk#debac7Bw7`DhfuY6hv{pYnXCwU9j*$yLtCJ zO;z$|92$2->40&*FGg@roO$fOaYphJnt{@>?O7~^y?MRUN$@J zkqBqRqR2!!-KFB$Patz2`HHa$?k2*$#ME}nk{MF*u1rVnQ-IHx95)1!J4<+N8{qM|Fw z(P5+Za*BkU>&boz+2xG+^+m#<#^TcyutovKZnKFLNCIn|$6+fEm{I$R(3qIp7oZpu zL;;tQvbRmU9l1oGzJWN&i3Y%Wky06BXX{=B>@M}eOS;`6!FL~m3wchvrdr~Ja~j^ z0qdLLx&=_^5-5~v0V#3vfG4=oJd@^msDDdBCDPRT>Snhl3Dr)6TG`_-eh~PQ zyI=Uj7-R}-4}O7UT%}x!oS@t!0_U%$$(A$zufI{Q-aof|-QFl2KxWP6Nxq$3L@o1t zu2_%zf|;$sY&-zW^ElWD7#ZlqbW_};!02G)?gUO?b^-20HIq!cG^Jl*{h@T2En1$qS+X$jr2!4U@GuQ#Hpa z)2b$swqsqflUeG>9-ysnQk>`6}Y>bp0sz8%!}E&@+TVC{LA zF;k?k3m}|{`$sY!1|oYYpG2e=|MkY_5wg+#1Mw;7gU=)~ik#+#2}ZYc62lqoRfe;$ zRpUHg{AMyBu^gRY4;gZLGBlX1H5vm0=udNycC~9Wqx82jyzcM^b7Ge9M9d#Q5h%z8 zba<)eOP~x$K_Nfq>4MSWh1{+{2Cbimin}=Tk&3pMHr}XAEIw)=b6x0?^QDZ@&}^p8 zF@|zpQ@hz0f_4;iGBs->_w0hE=ri z#)kOZ>6~*Vr&9sd0#I#Afp9%$e&{((;ROApwQ&A`9?oyPJKS%+xqo~5hYLrzq} z)Nu5uOXDsXq}-&0w&EjYAu1aCWP}3Fm{9RYWc^Ap zu?lG_rlGEQ#X<8hF5nEzxbc$@ng=nZ@^q@nQ;y!Mnf?oz=|lDxYM!s1O)l>Ejyx!r z24&xm4-s;E?6rk;M)*>R-73qCjyyORJz*O(Yr(_n?O@J&Ii+7GSD>*{X|qPQ5T!IQ zlFglWjYV5P&donmVFC!MoGT?~Tq4sRtePp#@Kb}|6ic2!j!6DLs|(O1a>oVO{ES7z z=>@Mm9o-I=#FR$w#6jilknz+$oTHSHAXL1M=qfa~43BLZ&!ja$iqe330wRw=(R|@o zO40l!il%tOqTh1KD|b8`lx0qfoNZCmnX}`=D7` z?bDLA(_~Ctqn=o%n*5ufuS1%wYJQC((&V2>llwN2{*R%8Y0T}4JohvlyHVSbA-|Gx zjYq{VQd<0Cwk-j3u|(LoMq+{dL@9>lIa{Jf>6M;b__UX?+oJZl2!pfua*9Nc!i*C% zp1Qm6p`L!5PlE0lP%I({JC>jp)^HS9|%EQ*)j>hNegiTVwGk?|Yqiwo0IF z9eHJl`V3Ed7+)$FUjxS5iC(fnFy4+36O7+g7|WWcjv0aWUOcFK z;0itpA1;SOC(0#cSBipuL$X!n(PN}p+Qa-^gdrWly{^&`-$;RrqO4zD*p#f)2wy;* z=$S_NY+j_w8X_!1URY(CKWI`Xt|3|o zThFKx*{D-;8(u|$)_Zlnj{rM5p}$BubwVp`Le%c10+NgG)TN|B-={K9C+khCG(e7D z0Z*a9kN7b;Iinp!gqUN1{DGKpyp)^xUDdQGV8lgT6h*O~Ab!?S_Sd6xumi*r zqiQRAUm=-{=W>~~aOW!3g3qkzMRs>sPJ12svtOj29wk&-lwD>!#=Q}^I}eIcs|PHC=j?T#Axf%c_@)vzSD}x=} zx|85doPZ?-FN;L}skh_0=*+KI;rWQk+LFkB{Z{!@-9|dc{1W+7DT*_whB?3|pzX*Q zRYUm)yh@!`bU>#d>v?2FFR-Gs{7eJi8TEG%ainY_|4hjdttN`#ZlVZA=eIv6gUnu& z$ba+ZtPFcoe7ZCiYr{YO2!W#67_^UkcZ!tB{X*_T#2;~$<*1Wl9x`vmSHtL6bl9Oz%bDMXTQRp%UD45b``^Dx5CRfM ztmqY+4DK;9%J>srTY4RKbHzW?vA}}mh?^mWAc0m>(+(Yj(GryPDo%@KN#vT#q7!m4 zz7kxLEW};0C+Aw>pW;6ld6f_Lgj^hlD&v=7Nu`s%!FmXP5j5mP)m1^~PF#MCr@uXb zuhsFOJz9gTdQ#aPMmKdCPfzw&|0rmm6Pu7LeWd_b&*c|CGOQR=4C1V5$pk-p?^U^@ zn_>sm!FJgEq`?PpmTJ?lN8pHVCEGvyS4&~Q{U z8LD@1wWbDE^-Pk6rt$O??=H!ZeTrPOB9sh-7f2T^m)BTDo{WzdL~JqQkOPVQ^C41z zC`>k|^60DFK%yegOianGJ}dr>ME+y6zbslnD6fJ*_?665;!)fd0uZ{yTvDO>WS*sB zd<*>G$PP>0j?P*cAEGv6SyR9$e~%eCVLZ?*uLaGl;iz8xOfWsulM~LRC!O(ymQcOn zdqQ=74thj&+;3%g=#G2&M$mN@&~eAoh3+t_L;cqbK;)a=4Dh~WxtT1UtJm{)Ygey^ zBa$6>IQ;(&kN+no`Tu2_m1u(DwgT;>d{S!{7q2P zvN!1wv-xaA=Qk^a&Ql*Aoo||v93W4V$-PGC%qRd2841-t)g$4K z!9JKr4UX@5pRVDPC!BaB=O>f#5#E`H{X>tDex;2XBbwT4tILzr7X4jQdy=Mh6WVby zzJcP|+f!rXcO;2?8L7H#ZPlOCXk zzJsLX!s{fP{${iy-;aN*=rxe@tRB72;RXdQP!>YD__FjKK{E94CFGJ$nLvgApS^dF zkE*&FzcYlu1c+x)1|ysL6-^9ChGgIj%m5V;ZzvW)tyPfB09Jv4NhF8kSXys9 zZEb1$*z&ZsjW-BZApuMRS`FX@#RA@7#z6$M5I~vtyY@MA38>He`~CI)@$&hQnK@@) z)?RzobMsOyzm#I_kv09 zR`yJ8pOO`))oZ!gLLt8X}QHXz)kW{FZl#WecEuI2_f4P_ad#cE5JwhU2ngI{Z3G36^O)unyC^b)?}=@KbTAlO zNMfWces1Rz=kC%lUu3>W7{5=E(0_b5vI22Zp)cuPCX*PQFC=t_&v={bcR;Nze3J43 zb2cQSVn89m;`{utObP6*WFM?Yi$p2oGv_lfP6&H(vr4*;+yFs3b_I;t#UdKV`u)iw zt~v>q9p5Z?v>FYb=QBqN9hO3eXAt2s_T@8n(NFABeq(ncSNYRRk3xhC|Hi9$seo4Z zDb@gf5yHAHV0@M+6#wO<`<>BX!bf8ary{Kb$Btzg@61h=7bEU96PCv^Vc0JmH7tv&kpj;~^2|_z_@W zb`^4g-V1VZjE@ez>jIIQ#)*SkV@>k^vO6khyiKw=Yl+&T<|kL1lhShgu7YPV>??-nwEOjZ=T@lY9iFfXQFT;VtZwY`PbdilZ&eJ71DA|n1R>4UUF+@TfHrp@`yyP4 z0xsTj2^!q6`AiWB!|bz>xmd1D;#Xi8L}Et=F!}lnQ}4vj(E+s4A6(tf;B@m$zd6kr zDBm5rnlY4JJ)$f$C_KNsOX$MzJpK-p6~}Rg@UNVl6t}#dmhHI&ueFD1jGC??-GT^I zIBFWvVbG`M8rfTOjXj${Yo+qDq^?LlR*bzGeauL_N9UJoE3S8ik5CQgh*EA~i#sDZ zGpII3stK7>Z6BmVl`&V7^s|ikmrIZ(me!+tD7IQGw%YIQ{k_&ZfR?3h81;}dnyTx) zZQSkNP#-{V^z=BM63j(z;?%24Q`DEHxgVuE>Rop`ue9FL`=z>BC&183c$yKaudWX) z)}yb={U;90OSu2R3J9y;J+#`lW%8m=>%1j4o9f3L{2V3x(Pv!h;k`?g!$aCWNn3Ko z2)^n`z8hBGX-Aj}9mk{>)EInlKS}x|21c9ucw(!3lsr+YKB7hHLj^;nUIV{$qpFlj z(m0itsE;R>$w%+;M9UaWv<%E4u>b9`rMU6cHU$Y!ug1Z`RIo^YlIurCAAME8*P}1V zn3C@8tb(w5)PvQO=tk0}E)5Q}6+%u~+{0SGHvO;4sT97@gSzZdP`}z_T}k&0s3@}n zWQ`x?+{Xt>H_Bixi)^h) z_W=~%_M*vZu=9F|>?uCzI|zgK_D?J)tpC(GxZow5UCB&3vkeeL1oVLhZB$`G!nE#hFZLF_G;EAlyD%c5wC*W`J;-Ly* z50=xIAj~C$hHbciB+Xk~CWA1k&wP@y0OLlZ{L!_lcBLSIzY06(G__BF^dFqs21h6G z-XPIIrZc`-{n_oWktyud{^0+ueN`U@DpXRxRQ9Mzu~j%e&v=Cwz7h4sM7e04z57SV-7=! zFaJc8ydUbBF^(PZBugKFs3{`xO~h-_Lf7f$Z3MQw6QOB-5g8?u!9F}6>kJjFE~dVs zZK#La)It38=Wb0OWn^%fqs(8`QHE!fP5f4-G<^`_BzfGKLg8imSY#%^aP9K}Mh{4H zYtlUkWQjKGe@Iu6bZ?`GJwIt5H}G5>8P)~8oH<)pVQ}Sg9=B+TF+RUi-A|*b#?%?Q zjd4fjHabGrBCoKcPilj?Pu;Luz3Yl9=vMfgj0c|@FoG3Uw95WkVhINVRS z#wJrP>nl3AWy#*;%c5CK4m>6EPTpJe3Ea1qdBUXbs~v}~j4i4>%w4kDDt_puB$7Z~ zdcE`Dh^rm4Gv4O(n`2#`ve&r^0>kvlv3?@QvazmsZ)(VkMUoK8NA&J~N);V0BRIjE zl=ZyOCCrg_VO+kGQ!;oBR;JhSr^F%DCB2D(zG(kl1Xq3Zm&K3#zscN&exyqB`$9E_vH&6E{c+V)jQnPyo~fhYnpTgTBBMzB&tZ@YjX^Hv#%S z8+5J|%D}$L=LRNcFueph|1&zYK-Tdx7GOhjm<(Wt`I44XW+gIGpqDKf-%vH5HhQ(% zB|_85jX1bUN#m>o&1WDSrL4^&^^JXlWrjwsH^MG65e5Li79GH z#7TZ3Z=wYQt`OFUrRLqFyTLEtt?JeF-C0T(h;SQqpGqOcIf%O@Wyq~{IpMd!Y0jX7 zgElAKvv`_r{7<}py7T+%c`sC-`IqKz_W7<14^$+{TMOZZ4RSzws)>wLE`Rw^?U&8Y z=3sZMkaClru-7aM3N=ACBZ^0GYpB~<5EfFg2$^1zjr>RO5*<-Qq2&<3dc*rlB3~L> zDEcB~WYGhdfu>Q>E6NciTs4>Da0#KFfrOQoud2%i^bKB~x~hrLF{o)dL3QFPr3vf9 zocoG0ExjlsCnppy`^OK{z9Jz>1GtADnf81RIn1M9z^&ukK*?)l?eSO4ZP1=#a9Z81 z%s=WXKpIjkySQJhR)a=cO(Rj%4OInXgwvsq`PRMK_+v62jzr+5p07~jo)dT7=xda~GTA3* zPf^y;VR}na+C$6DOC2^y&?1J1*dIVHx(sP7u_{e~>Hd^{N*1fok9ldpoazjiAy=TB z`iIbWeB&$m#+N%c$5;L~3K` zd10LAKdkVJRR@iTc3WXuE-Z zdvN0qD5Pa%3AsOMsW;#g(SlQJ_9p$D&q)SOT4Uzy68K5bE1H~ zm$^1Vx_9i=laP< zE*uZ4^V@LZviRwpoVP}DvYlNCOgi6nICLQ_pol948R-QZ@EC-HX|C@YoVsVHtxS(R zek$BVKqql_@d@Copj&vTq(>GPC1VC}9%F+Cyu~HhP<3Yfgq-j&eid?yRVL>w^D32x zOjHT(5uH{$@5K;2(U}(7?cdyrkzIv(`|4tu@v*5ADf;CMA?D9xB72l#;z7^oWph%M zL^8jQUuxmELY$#f)E>oIHR-;Y7wQ*u<0FB!;v{`}D16HzIJIVM4w33ltrz4|(2h%i z(g;!9z-BJDEpT{)kCz{?+4u;+U}xbSw+V(!CZG%D(cx;K%WS&v=K_F@chAXO@XCR_@#; zKnau|QlLmE4)0QXH)&*{BhEHqr>+*{96-^yjFo#PWe`)wsbMUX+pUa**n6`gaZ&im zTfcEvA)gI=vO?#i!Z~=`NgiMhECr&p73Mg2;SuZ~r2xvkHJJF!-g>SV5D~Zbv9~+h zg4bkqKl4<&p7qZJ;S&U;8wg8a8+WW&UTi6Fko9`z6f3OLc~N>x0Y!}O%c?Y$>5lib zB~2poEnQo>HgvjUKUo1b{;FbTPm%=9=(V6Z=gO(*$vcdV>tw2tbuKfNtn>PXX<4T& z(;VkZy`ua5*bGO45O4#eBo;6k#4KlW;CUdHS3Hm_KAfyuk^|4lsx9;`%;?B;`k2y( z6v`WuAFKO=P&h1r#DHU*>gE_8NF^iV_W2y)%(EcVQDneb<{r3xUbF3wF{CZOK zEB+Q|ai&6rc?CN5HF89^LqPDz(R3JY{c?m8sGRwUz4T46Z`oyOcVWSF3B%iyCO% zbFc||zL7;k6u~-)PK_VQ5)>(6Jg{rUQ;$HU>V$HJG|xqvS$D}ctz#GwTX0M4PaPbd zkvK4kl(Nb>E|e10!;3$%DN93JpX(AHh7|sl z^s3d}#|wa-wJ?4=-&!im9nU#r5D(u6`-=zUt%7%+4Q~Zcvf=H=?-acE$~#WiKM`LWpqA((pP`coVa}PZyOOOq0&mdE zU!V2U^c<)Wo%4S_q9OEp+=#3>_*|$$1~6U*Ae=619)`)Y*LWt>@+zO%gA$IF8q}Ba zjuGA78PEp~{vV@W1nlnsG~^Y$FG^H&LV6JR62&~qmCnyn=;UAs8c#`FE{{DcyXld= zj+x|}o#CvmA7&lQvYDDH{h5XI?Vgp0(R&>=n_wKzo-bB3IcoL9s=|Xe)C0AN9ll1M z44oIW_!lqivs$BiQDCI&zQqGs%>0w}ES?hREyX$lZyTeVRl;|7GG<}xF(yeq_o?3* zo);aw{4D8k?oRyQ1Q-+L6O3-AeSn`>)0BE0DI?kV@2DfpqH$kRCge#?i0h zhb6c$mG?jskhTG7gAdneNs{3+&*XG~*guVk{K^FY+q6>}6&tlQnsk3X1pXrcWgnFO`b;15n5E@xsz4cwm>deeM#3n{5%Y>8;R$ zHctsHk5WS<i*fc|nA3*NG~Ky1I#7O+Hab--UyNR}GQN^k5KfHMh-YhLn>-51%;!1^ky4(3*_R z(w3t-L%+wfL~lK6xp88zCCLe00aT-iIG9Z2CpM|&y7)I%vGWX${|q%*Z^6;HLatQR ziGdz_OA!T$g(jA49^_QlKT|1BqTXc~H;UEQyaD|{xKUTCih7qyxfbtxLJdo-@9#M1 z8s9uGOxOx@7DX~6l$+Jmdwji1eO0C)e$B96yv^4+*4HJFcbFF5;j^9y5_(x$8MH0cN~1JIL&25I$#R=u4kq1`v0dPE`g@rvR@-rtHJrDdCo6G= zwI-Jlz(9c~1TAaRYBTB9s3L3g%TJFdzc+BKIiEv|+)JuED&Sy$Q{fKxsvje`vP2N# za|q1}U%|&*!U}A$UU91A)!l;*#$}3ZeWRSlHpNFruWJ`ejyfRKF;j*0IEs4qWFl|Yv_Dk7O zf1rJNooXMotF(POZL7!9w#0*@?NB%U!g0=;0wPLXt+YNO$gzM#+$p0|NrsL>u!)=o zW1?M2Tiw)EBEy%o%>0*L{$>qRguuw1aM&*ug(+wK>nv|A*dvr35D_8(+k$9A5GDGT z=j#O*u#z!8^Qk5BJt~WEyG$JVB-~6`%4EjI8|u*eGp^RvMov>7>R)Kie?90~L(Yk^hl5O8)v#SE&=NUcF0k^jQXjfGeQ?GbB1rrd`IDPr)Cu< zFR9bm*epRD-qf4-y7Vd>ch?IjI*Ei&EYTm_ReMA0!Js)3g zi=P-#;Uy&O5+>p^f4&SLQ9(}h$+Y+_p2#M+BsR1`6n=7woY0Py4{>)Bo#|1P(=h2i z6Qdd|Tlf!C7}ldz4ocRGb94a+f|E{mTDRe%bHUuMr2D5Zd16JUmT~B8S_hAE=y+C* zveTg>(3ZH=<{LPSGG7C)6oN_Bcrd$$I+`d$W>e=8DOmkcFPjDit_f*(jX`Mi-2ZLi_Ov`Mc zVHTcniEBVAgU6qLIxcX!BJc!jYUB;}2Fj}$6w@W; zGmaZXg{|uV5p0)Eut_07D!X|hAN0)*olZx^JT~ajm!x>?j=3Oj#e|0N5h8_4zueOh z%3w7}O`x!HpOVcFb}^NmeA03_#QaftjiqPj4uqBH$?L!Csfi+unzj*H=D# zCQy$dn8Z#O3CQTOQVn})I7Y)>8V<;YvD7Cy6NqY#adnwi_c`U!=LUfHIWzD)ZLY|) z*%*(5@8`Yok7Y(dM0ied4q+lCw(y0-nXD|PHr?rHQ>}&v(Z#*Xutw)E0nQVwyeU~cNrVkXJ4vS!?QFY@@fcOJgqoe?@u(4uurMBW=^Dd{J|1MZ? z>G}JhY$06TP(DB~`$hITsulm`A=ieg*qMuDOGRUOvfq4O2{lBrR2LT#WdZYw0bDF_ zN%pTJB!iExk@~TRrX3?(zWRP`@Kx5JJhfX|#j5OtI83%yMi(;asWtbK8l&-qT6)n3 zk+C88=o4y%sW5h}(nJm{Q20O=3)G`EEb{Dq>s8evca&nr{|MgdEc8XC>4pSVac z0HWf1`C<peLYqi=hC=$Pr+FH-=m3Jb0?&2hKf#3WwZ1-m*^!_$C)W>h! z=|b^cNH{@(Ua4tBdt+W1S-lTZ0*+Jp(4!A`$VUVTtq&7z`4v$XB>lW9Bhm4Ly)IofN3KY9g%SQRuI3Rl0@;z+V?PyFZ;Yxu z2W6xpl=)e&YRD0pmw4_SM0W)bj19a)N`FiRj+Pu*6)bh4`Cy92I60WR!sH7r=9L1j zc8ZY6>Na|Igf7w-w6qHh3?O(jn@-|xk9mE*$DGy6nBB*i*t=c=^NuWx_mke`Xow4S z^kJzi+ln3?Gnq<~$(_T1zyq$<#!goEL5^@v;h8iYdPYFOo~%F#h@8v|_89J=AO;{` zN-AMvN6;&}dUL{hW5P06@QZR2(U{mD8w=sLu2RDJ*dh+|cV(>)z!hjiuNV_n)l1GK zblNV-2k3pAdan3n+1sP;d3_N#jJN#gf!#mGka4{Jbitl71_eTO<5k6%)RZ75N)+?M$3@t2bXLZ9J74!aM0TZ z1Gp5liV>vtJRurRK#5Z<|0tq36sZ?nsmt+I+*UYiQlMhGvu3xiqWi3mTfJ`!OYucV z7D)=)QkdW;&XSaAz||zq?f(0dqYJ&bvINe~PNaBYxv>;-W11;P@6L@8dX! ziq@`2z01+08jvX4oCq{w`er+C1iz^b&B{(5^Ae&#Ku1~<>{E_{QLCV5G7W&S5tB8S zXB-Kp$MMPZk!bq3oZrXgmR7{}B+aQ@O*W)v=xyUAX}H>W`V~G%;~;J${ohoixqb|}%7|{~^Tr~r_m5m!@BEepa$4=e-X&`&Yi;_CO}Mp)G{cbcDC09W z#|KJpmK0cROnRJ=+`tnf@HQHvvy` zWar{e`b8k1fxtRe1sa^gqD9ASuc@2=-*(mkA? zTF*q6#M#!VMwUbn^m8U?-j%B~i%EAKs$~1vgZ7R+6-|{3Dbgut%(+XG?oVMzqN=Li zEbM6(#j}J9z8-)6X_F~8h_ETrrl*vv(`85;5Bjjzhm%f;yoO&u$y&lGZYKI4`7721 zO2{zw*jisXUS7Xk=dJx9IM;7Jrp`RkKJUnAi6{x@s$u?~7Ov?xo~{&(lbw_g-cz7| zH(yCRQ9{uqs0g8He;6{d5Kd4&`~7r&=$&tu~BAiQyFb1e&sJ|M-*7X2JANiVX^Oo=lsMG>S-gH zvdk(z$lsO-Ias<}@ofC7aDC3Y&7XDE&4{RFgoWEFki8A~YWSlsxqz81snzhl!Hu!R z*ld3=6+&Iy^dlXELYy)1?o>YQv2}NWF0xt+*2HyjSNvPy->;!F<@9iKsqYZ67)O^W5#uxwqRi3I*@&cG z;c;mZu~*B&)^j~hwTMn)D^_EdX)E=+B8M>%;8{}pGg;-LcWzb5zLWe+x|d?? z!ZFyxg;$|pB?6c)iClobIW}rC6SqPM217V}y#rWWc^aozyreq8Sfo9=mv%Vz`pwbc z^5(Jz@|CL8iuDw>J%~#_2t;ouVp~(^`!C=kC}9m%z&1h9 zcEmQKhpv}wnW2_=KT4wc20i%SjxXa3h_=&fs^9Jt!D+gSq@;sLtS{Ly!y{w-E^ z7V2+Otx^}9gKc{Tw4c{8Q}MHLPlpXz6W@k@bX@!-^~fHnTUG8n(lmb;VomXPYsjN2 zUQF?KHDtx#zhlS&BsIm~Un=O#-_t|ZYJbWSkB4NPldREi-g5(+>tuz1GY7!lWd-f( zE_At`TX3we2@PC#X;sl%gh#a2p?_2RF8R^zZ@d;sR=xH7=J1iYj(aob{_rgLCc$Xcs(}1^Fiac&@xQY-!|UKz>=%(1mySzR?R|_y zZai=Z>v{#-1FHvySXF854cTiesL61>RzG)E)Z?1`~O;QijI0WI5DCl?cbaBVEM)!wojwRCy8MrfeWdbMy?#EaPRs zh@t%Wi7Q!iS8S4y2z(U)mh%dpC~d+(8u%4a#j$CeDFd|*67h@ZEOPk1V6O#-WxLYq zPUk_u*b^}R!`3UKwRRx|#(jX{Go!ZoWCG?B)ug!bvV-M3C5RP}azX@bN+su#^GauU zNL#62kx1SSY>0sk45(V5NZqWru!d&PC|ZWpnIKP7IaSqPJnJIFIDPl zkdw76)02=V`*5_NfSUHL+Rl^EpL)klg6B3NIhlitw7UOhpJzsda+wjS8|sC9VBV-a zZQ&!lQ@brR*(Std)YS_?1f@=TRYX`b-$|73-};?I$#M}QgD~mW`nDGvL+qx<(^Se* zS}Of%)lbO!V429GQO8YP6Ng839s$QHWjtX~vIvtf37bLG?I3?bTx>JP4S)Ep(xS~T zth02aqcAu%($QC|lN$-v@U7lxum;DDhZ{k&hntvuutL|`pj5ZxtO?ye=P&|~$K}op z4h!~)z{Y9nI2dY=4+S8IMw;@G0+N<|=1Va?Fmb1dTU&T74mDo$dZB9-sTl?87A|Gz zlJchHO^f);DC2W%@GSU55?*^29L*6DGTO8{bx;G} zmFU^LQUZo@TvU2_?Qbnkd=V43wAvirR0pucb!sr}Y62_*u~IR|gXBU{?}YoOh{yIY z0b%j$c#m9~YXR{~4kG9!9Zd>LYKrUww4rXz#s^Z|Vi|_of#Q9nzV$@7M15C&+pi9j zHJ6=wA3)hpcFU8M*-zf#iB+2;a=MuZ-0@d3l@lPut|MDr{P(;Pc~E=!YuEr`6eTjg zox6GD|E!xynQqh^*vJ>> zY3XK52M8o-A|r#mWXqOP_E(uu`I?&TtQ|hR?Psz3jC{c6gHYk}S6rw`v^%!sDkm;B z_ex`ahp1LKE82>$J{(=15N1J4NhezThn#GEPgtw=Iw#r+Yt8bq$b3S?4!#vzHf_FL zk`P_`pbbMM*|GLmGo1#^S9-MrgU@`V*H%9DlKoob zzxd*L@f0GOZ-|R22p%HnpkqNr(Z+*o*>5MZ6lq>fQH46vYmq$`{krzE;4qc^9!%-K%rWxwsJk5BbAHTH6>iP>b zou!lAzm*XyR>x*8JRTQ<8B$IqN|P8r;vxScpMmmkYMMnE5=gS&u5Am`hFR@ z-x#3g5ms@XGd0Q4Loo9kuJQTJ zDfBW0?5-8`s4hM_4!c4z--Xuo97Ku}qVu^nbQOp7uy`?>PZY_RP>cd}?ArbE-I5g; zysk#=T_(&(xM$*;YU88kIAhs~>JzF=Nfp-X>iVhS`oIFiyU;fCK8)F^KC2xT*z)k) zFe2*BLRNU-_%Vf}UBN8wUB-g9I-F9;xyCx-GQv{)nwsSTaH$-1IsP^g;keD08yryV zD>YstfOA}yV}q57)4wx=_u)v?khoUT()BXu@;f2lmqoD%-VDKLayZyuZ9?Z zg2|NpJ1yxaZ}B8O`tEEK@&om4_!M4^*LaC#sd-JKl zv{PVGKiA1m!Zbl*fkxkgkAz}<`TL(c&4L4O0T5RoK;ao!01RNawBEbO`c{NFy$&>{ z@ErfOYR9|Gw_vB$&OT|!nxS+%UfO9&wx%H(bI6U?6Qw*E1rl0mif}>{N?;1CSa()NYCGo;#+n$L3-k4 zt(YL6y}QTffJpR3G4;aRBs!j{JZd;u&dtqI4_sLLEU*ajiD8%h>hdeQ>ibc5|s=@70c&W;7*=ZL|c^f>}61!p;7vC+IgecmM}QOwF~i=V4_wztj4+T+I9neiu8P322N$-hxD zISzZaybYGo$pCFgFKy8bO7SDIlNdS$yDQVZNa9^DLwPMh98O?=A-HmWfG%&+8Wh;Zej>aw`p2RKXYPxvQ}^0!b9T}Fpv_C*P+GO|CImqmpe?&piLWAS zyL)Rl%=tv_nI7y+Ka@Y!YrO4=d^#V8l`WrAA&~!Bq=gEb=X~sIT`xpLDzYt~hL2V% zM_j^TeG=)Y^lMe0=$8FPdfFM_+G}duVG;9r=y%+UI~j`W&-j6OGCJC)8(|dGI1yf1wi^d%NkSqR2h`0*?g1&A^D#WgI(H!W;O1tmR)O~>@00F*Szu)FrJSK~z3(QN z$rEw5-6!{gv09%>bT=1IvPb?pO=W(s^WnW@moBhN6aR=ZGWta?r2TeN{YgAqe4b2# z@tJqxmx8yAbPL+D0`;U~j^d7g3r%GZ04yTwS##jwmFoVuNTt*|@Az6t_bE0^Up=p2 zQt*I(Oy(t9W|r&a`)6OFJC5j%!@8Mwm5VW&!t*=SWk;^sY)rOu|F<`3-w?XXNn9|Z zMa_U6>yG=YnN z2M4QI78^rfA+xQUrrp;%O`F_wK%3D-jN}(n!#DYSK2F0x?`>A zt8#GGcvp|?f~&NM-(O{=_E@VP^#Cdv{GM#`6m@vQ1gn`LTd<~=96$yt5(v`v`f1wq zAMc~}oqXxX=T<(ib@8R0FQbaAey8u5rX>UMNYQUCRyXET0dA#*W@6EIaZm@(r(X_gVaWO`a z+Gmh7M@(k0^4@yJezrY!d2EfJ2W#2h)ej~@3a*1+*1d~V>Yb@%UHq0p&8zHg z+PK3^b46BjYCbvVMapD4jRR`>_NnRXtETV&pRfN<%~y)OjOUOp(d6ZRWeKjdm@a0! z^b!gCNz9d8*qTb2pzfK*bKxJ3PQenCHa#74MU|@PMJaQZE76>08Ap@ui+QS;(XDI- z#ZpAJ95ey_`3^ISJ@R*9{Hy6gswLgMq(Z0LN?qg%sTHW`=M)oudwPQ-JnWWWUk-nc z;7Q^6j;4o@?T+Qn&I=O8W?guGZqq}DrY)H7xcV0EVX2G$3|KCYifHf#>xH{%E|f=( zP#$7yqJ)zgx(DU>+qDNiKcrsC!?pJ`7tX)U_?~b;mD006@Zpuk3x|t@M>Hc}3v1^2 zIWw7LCuH%=^b-R@8t%%WnwY|yQGN%E*L|B3c#fT-NBjGH<$bntxou;h{n&lm00q*|{S;jB4VH~Z?*D=JCrallC~j{~m6 z$*tYxoS%vIG^okE-(~vxFtWOX9ymm`(cPHcmBi-+66l3GfURm`Vd70Zv7Y>*3l-l& zyh*yB?~)aLPTek*D0pcq;b?s^2Z2k2SIPzF;MpF9_I~`xo!vE? z#l|K(ydTCwu*lnq1JKloY=}R!T`o4CgRmjdcRZ1~xN_I3aP{WBoDw;S98;uqm&2l! zKZ>MhoEI?ebK1c>3bQmC0rNg}mDdW39D7@dg`Wm5sBLPz1^leKls_04AUA%Txf4X_d`pjf?wEP1Za#8Yc@z9uOpZ7o z;KC;xgOCZiVktdS62_)_^%765`Qu#Mz>kxP^4Mz5?$YwuVt=H|?O9z0P=ZCibj-YL zl=(=r>hdolBI<+<@f(#;(2OG6cZbePB@q$#L-1-*o3ZsVRpjVL`0O7F`GU z$b(D8P$O4HfRQ`k>2{LtR;u}u)dO%t6+?%2t6UdDeUGx1ap0Jib-^2_MR9^h_QN$_ z$;~PfrU+>6MYIE#i~Zw&>;OzkfbyGtN%OQ=U}4qwtf^G)>>Zw{&oRwosOO`N$2V>j zWx+j%XZRiOt-=R`hPHpDKjS0ph~Hr4%7;!sMzWJ|`Ttv|WQcJei+9OUazN7k&tqNe z%jS^^pp!HK8R!)2jd!z_Q}1l(+F0p?;B~@zd|VN|&TmT6SmonFq`w}sZ-|Z(DC-sU z#*6I&rGC#5plr>C(x`2(WPAu{ej}`qZ!9V0feo+wUIDaJMim`;jc;!<0ZVkxNI}oT zix?2|_wD~ShynH>{L3>jt|VsGL9}|@qvWl4m9{DvWbV^M;5QnDNYPCM&+!?*Q!sj3 z7YUGpYdJDxiS0o2c??aE`|T7&tCv#Jy7w;o*r(rgQTy2XKWE^uVh1hQQ?FV?h(FJ7 z-iJ5-%Gv>fzJRgUcj#TbFsD@;&&z|+X6+tp*8c-Ocj?w0euY+<`N*+eT4VujDMu_c zR?*r4s(3VjaVgM_!*C2S5vqP!9+N!oKQb2h5U}a@gxaN1-#zcnfFmc}r}J={*Z7+P z1(i3|)J3~gcaS}_0NHOvX)GhiVzHd}dV!6Xd-7OfyK^rwNOL440M`)}c|b_cGTvmU z4!_*4)`Ix$pE6jIC=_!n5rnwls=#+n7|n^PN3mt1_0*f_XwFB^WAfdkEDLjmKjO+BpC#; z4XN7b!Q<_oZ`C_1Epzm!q)9Rn5<MwI!Fuz7s7!u(Xw2^-sDThh^!e7O#M9E#3~kWiQ@UIo9I+=nt92o1%;k#zFKy z#hFAmGA+_5Yoq7PJ`$9U%d&Yj-c^t>TF);Mcle{vh&>h=N}NB9{YiI}w#D;pfZPjm zVaAd$wwR4077av}^DE8~At!hWjdcsTSJ8To=Or9NKTROvegP)LXJP%}Ram^_h1?cm ze_t+21;L(ypdWozx+TAv>TShq$Tga)HtzD;i{UQ7Maa($CYRl1d|L;zm3v1pnI~y1| z3Gy;sw)Nkry_8rDhWG7&wJYqgcLiVhcG(q9f&_JXwpq!$FoeWysePPqefvm>5-8zB zG=WgCeZFOoU@}1XqB>xa)y#IFM1)T5;NMR})^@-KFWbRx-#zcK9gLxxwFm45^XZ<2 z4@DpB!u)sfmAB3+@5!eE$9te4uN%0$%WmbzpD-K<&46sTfJcYxobhCpdzsomur^uS}Q z!T_ltb8c7Ye|!abM|^v`0RL3foC7(I=0Y)iWDIzlJkr=v;ix4Js6<_uNyk{_!1 z95wZ5^?-e1#>c-`9gzFrFt|}tspv+KH@xmp@#ru|aQ#3P#rGvhKvncY-8iSy$Z_XK zmrpbtM@31KGEe z4R6x@i+zgUz^T~}`7ZN!630%bLbq&m`A84eFTZgGXZ&-m!)PWfzckkdXrWv=;yVt^ z>_~}lB4u-SWpD1TJ5Y14)wPjp(Mm1oaIj*vUve>_!=Xp7yVl`R6oF0a0HHel5`Bqe zYnBp+Gf~pr4{^a08D>Ry*$VaVOt@i9TLn_`3+hTCENHY;Cra8*L7~J2PG@g=jCZo8 zLV}X1sn~@t|8Y~X-&al`Nup#E6f&fVWFT{-I!RPZuFL-HiNt;VQjmu{A(vu;eUt8^ zJV^9Om6s?-iBpp9!8{ebo+X$BVikNz9dbH{9Hu;jnc_-3nFd`Y7A&%?KYmiQ2?{R5 z_lql*Q=B2D2Ek(QA(}TuQ6LUrU6C2OX}!BTB@-2@gSgz{@{z_NlFSP|K)x!jzpNR@ zGkXm#<+l=N!#tBn44y_7A>YIwi`%HfovY+lA6if)NDfB}@LtmWGu5ZJ-Ri7z9G*~H z6*Fs3$L^NW_=b?2ig@C_Kns;ise#ipe54NBTBqPo8E>ysLif zPgcoBZfQ2?J*CcY_x*Ga{&fZ2=@6bAQ*osv3DUGQZ~Q)`Mjs%MO?yZRf{C8%t(=hK z$kA$lA%L8yBw5e)mq0){78*(hyW$*D21MuK z9QcrIi!8J?fr|5F@*%;)YP0=@o09XK_69E+8wpdMxE$?Jp+7pc(V|f}LDKD!@{u6} z=$!B^h%R%NS{o2KSuW-s>;?}L&@xW8jnt`Cp#4sDPCu&1$cLjjU1zUPRJ`WwLc;M8 z0~W=2w;ECgwn8>c!2vt&ZNbZ1k*8!<2SLEk?qQ0BY!tUo4t(uvi;H{IL{3(kA#=7E zeR}7JU+TiE*?G|s`Q#!gVc+qQq8}12l<^#UpsPAMYK$3VF4vjU=bwn%c)e!;K=3vw2Ps-nyr{-Z`zcl7}so zavXv05VA52F=<+sfW$pY!L^LRge%B41F%}%5(=@UE@eS1<5F9jNYJRzyQ>xV3@`DR zAhKxvQ6YrrSclOb{}E4BZ9E{Fw1s2%`LakF{M^8wL^=PNHwt&T(+bIMV zw^JA_N+wHB)5l%C&MnpTg{X{=$+cg)4;UNCv!N*mtN3c*GTI|M&!W?@4yJ8b_{fe~ zaxr>j7h;ol^F($I^X9jOkL;UyDJbenWV2ixu9|nAObqjGk&lN}=daCgPn@A}mN_w1sOvj-shsvA;FN3%zr&O3fepe2oL0ozei(bA`iAB?RX3O#k zl!M{&oY+4n3Vu-v7;IO}KIb+$;+c7iMS>B@Eh>tu5m0{KeCtsmhrc3zE|s>85yiBB z)5<+^Ryb4jSxVCxZdEB8lZxQPn)cEHL0NNxXTv`mh$`GfP~mpXHEE~T`{vTDlvs)G zBy<(pu(sq%H7aRT3{GNI11|R`gZCy?JUk^dshezjMA(TOan0&ZvPR7R)Ze6Twml=? zxmLOv?B{rKoI)jw1*au(D}N%pWQue(MHs4g%(_flF-J{NWH*!W7SHz0ynrH=x!iB+ z8rjvodDqF!yVV4G@;f|uioM8-F3r1`oi`J3g{Iu*UA^)T8ON%lBOs%lkWo{Q=)CsG zFIKxM73szP~Z)%ssDl^aG+wb_+uO=_N_J4@OAH8Xf z`Z+kf_7e|^ZL2-sp^s;r3+LIQJKAerOcbWNiI7c^@Ze3D#++CKyNL^JgM&mUMu%-X z6ivOjcyRtkJ>zR_X8fE&H$l@iH&z1=P5DsEdu@m$Qh*1T!biLDt=dVF%jVi`T=E0% zP_eS^ZN%P+oO^*@exT;u@DNwi+_U`AyqC5Jsp2;22a(*k7tcGn> zz_`)np>c9wHp$z217`24#a;V#Z6DI3X0lxXtKg;DiY6u7NTC5$i~IKruWJt<&7aN9 z1J#Ir=%X2>_Kb0yvsyceBtHFa3w5{4_=#ifXr7txGkjdB+&{~mg|`f*q=%kTu}OPm z4=5EE;m6lfp5PA69_OY|Pl&I_8tqYWGv`_zOD}j0+7E(XixIa8Z-(F~KcNxA5A{vn zhUW=Mv5jU<>&n>SXeO>b7TZg~LAN#YFN+J~^&1@halR&7DVqaRIkJ!sZofl3YM)K` zL}m{P9SlM=uPGpzXg9~2c}V~7N>~iSEP;RIhrG`=$tM3EkLZ;6%e%Uefd_lN-|;S& zh<(NZwVUNCs-)Ag2(c5{?}@2&gej+ipw)n162I;HOm?Qc2hwed8Fm{F6*Ei=PMn(v z|AhHMRAcHW5cA_Ej}e$~;fuYS>LG~%z9az#yj%U{J8SxQ%rS+@<^_kpX0)@;ZmDuQ z5?%Srz-7m@Ib`P0Vu_*9T$RfhU6|OZn}{tHBb_zm;?%Siy&Tq(bVWUDhV-lHExzTf z&H?HOfN}lwaC05uG@8PPcS(X3`xJ+Gq7C1u=eK1JfwnDsjzVr-1+Ha+U073(7%e(lkRX(rM!QTw?@fk;O{s~x4jjM3_P@t@L{6O2`ZQ1~_jN>Mitm9oA{{pbhebMW#Lb%usa9kL z{`LBvq@9uAbM$*QOyUrknSq@6GyJxKvg_)r;qn+fxCr)xz3E z_{8bU!WWoac8SOwLw`(HwN1L_JscM|T?7o4+m6_8-BeiNP;US7yW3fvAvCFNk5kV; zNE|RV)ax0t4K%(hh!o!ha9_(pQ_dF*kV2p-pX!214nI`D$Mlx z_D-wPGg3qyXqNIVIl3^ugwNxV@-Ob~2~xB=iIbIu7(}vY-cuJVMBKP>Pm&o26CK%@ zLhnOg_F%4*?yO~9UH_mnelEYsJ)EMSuPJ*rX-i=K#Ft5mVMOQ35u;P@Z-Nw5=6ZxSU>j*DxU zDt1xYbi1LHu5k7lnVNkzR7PlJXtlY6wyidq1|ajenC~;e30G=D_TJz;-+Y| zm+=K*I-GMZ2l%=Hs_x)}7ZMyCU?G*&s0~SQSV~}xBF>NXN%tN#nh>{NXe&DS^-S4c zs+e!JBJp{9td3Jr>03{_OxtWj9etm}&w zJX-Bftd^$HQhc<0SJ7XrhhsC%Yj*RBNM%Ze6fd!wh7{Y_nuQIhH0v}SzaB7-+pE<^ zeU)ew%h647xpj)O=6Zrl4LQ$;&J;g^Dpxh0#*@DmAew>?vSHE9hTv_MZykE|3>rs+ z#{Vv{2hTL7x9sG=sUM2)Zed%}cwgL-=Fg*erPh4tq%7W?p7C@e>&&XcWRp=hSad#2E0c%Y0!_A#*5dT^{UgNv2S%)gF}}(V>H-jwtow9GX&ZgC)Ev z%(S+N4Z|MFFKEqgUT#H8RyC>+OR5k{=J5*wm*nSlHS$7EJLoIbbu7ir?mqw^oOrd` zKD=jZ*p$MCYz+?ymT}ox|2a2$<&oJ_7UKh=LzelfnI0bE@RN!@HBBi^d~D-BnI_o{#Y&hpO-KocE0ff}~lH4{By{5%C@Xsf7luap5i z!YZ`~&|kf?2wiYEk526gzLL5!JBJAw0hM1X5y3Jm;*n3%$S$Cu-Q2$@D?OYpbu1a; zWqD-D5PTEi<{3WOm@&sBgP*0^l+I6*&aDk()q7Uw4@qrf2lkcNyBxq0&!$;=an|kz`FsJp&&YfV10l#42`q+Q+Jsf?9~>7T(&MRxVJ}hhR-)IxHQb zp>ZeQSgT8H$>V1bLBKqZcUtW*I^d4%QgsDtfe>M2?(!V1ZWdqZ4u2Om6xkPKbAFgZ zgJtFsi_TKCV0Kqm(*frT%Sx@Z4AYUnB<}Kbv}hyQ@TM2*jkhrt`OlNmmXT!+?ir(z zjoo)KkK{acjslqbFxIA`%tn{fi410_fJS)Zls!6MwIdb{3db%?H6gBR7=v&qAr^}= zkSS6EcF(yabQG{ZddF%pK~VxZFt{&*{gr5!l~MHDa`KY=crZlqcy_p4%%`sk%X_XPgs-bz{Xn_8C6OSu5rfS zq`_2EGO-1;VXvbLGPT~2QdTWFAIF6N)o{Nc?FfsH{?*o_hI0VL8oCH4J=%$1traBO z?wqW0G*rhp3FFRN!{0qb+6gY>jNPQfGc)!wtI0L(~7zf$dns%+ka!PVwHLhqQO3( z>iWi(?rLy?8duHf;O}o4;C&+DuJTY34VPMHObAJ12tEKhxEQLMCNd7 zS*P$JQ~W>Dg@w|QnJ)GS*v1a7gvai|>Ba8&U3sb)*#^D|BWvc<6ZyuY)$V5=`8Hgu z`EK{$$eqRk(2d0*AYMdS z)=8)nZ~qN7ZLAF1oJRb+nLd<)<=RZCo|#e&7AB6{EpGjHn(lU>xw0`@D=nsEvVX8u z$M3gzWeQ&vpJ(uOlIp%QzQ)C5ci1E`4v1}0)NHg5&eTmQ@GD z4((oWOc^i=WNLm!+==+PBJE`DY5o71Uhw4^C^;K+TJW#)`vjETeP$YE$J)~a{G(LO z>fnM*sjZn(bEOn8Nqjc7?6ta|$fM5U)9s3|hQ`iFck~2JDDIr;MXSBqDz=tl@z?o& z0;Fp)4P2Lj;jmOoO~t%D?B3Qk_K`d{NsiYPye_3Dt2s|w(KV$bi*$_FYWo2}q~kiR zR*ZU)jtN?=vWlb#QcP5k>#M8M=>6a=FNCe-A>zfk^! zk^CoBHtAl>dmG|Q6~q}q<=ITBJ2Iv6r4%?HWwBa8ql9~<4-yh&WFoD$hb2=@&a`r- zz#c;`IRT(MGKCJmnFi>$vSHXnAbdY@dU^)8q)LSz5@7alEKvjy;%bQ+0jE%FF|W*2 z`Yn~Le7}qFQL!7ogsty!%FzDxjo-8NO-=WfI^MEXKw zD4nyYa^lA_Q^pOh=+GN8V0EW;)EY0yK+a_#!pEkurX{tRH5*c4xKv;zvxB_*FI8co zR4}XxbrKmjJ@n}o*_LAfQO^&Ty%UL_irps>Ovl$3WAvtA{prv`8b z1JL`~vj@h=0x1^$@Pjy<;uONFg7*(Iv-dZgA9YP!8BO zBtX|2C!kErStg>&)L18Go%@_>pjbMm+5`PVr-3#xQ0$+?;B^JCeX4;9w&#AS2HC(M z@qJZ~6Df)d{urpIoR%4+vWjy54~Vmdhz+-30Hr9r>!t4;;vx8C)(~wNGDFN*TjjRU z4^8JeyZ^7J^F^xu;B-Dvm>Fq$I)?yy)>vga%P7ZKkG%MuW9`{_tUo-RVxzIm8hXl@ zaX_&n%r%3XHi~^`=vSvAFh}ogRA&v#JW{4#YSk6M4p!NH>KJ`a2K`hZxAB{ zc$HSo?may?Ez{L=0w{D0;Sml)R*{uZB`#6O$mtIB!&A_gdz2$m3gBP$-_$1-YXP_rn2qf1IErLaaEWKt!^d^DS=5M)Rd}y8GIvsxPVN0QysKyc|JuZK`SS6mtuBT4C6*V!|W_&CMsQp8f2B9>Fs+#cmv#MyMC8$vNJHs}RTo|@Ja zt%!H6PcHb8wbYu;)9u;Z?Mc2PxVAQGwZV@|*B$|-`BB|i#K7d>oUuLDbEgC$Z_5dd zQr?kFKotkU#Mu-cP5vmmu+mL@{1uqO)V(9t8=qeC~Vpu-~`Z*i;jG95%^sBd%9jcRxED5*eV_4uiLF&&s z@`Yn2&|TjNI%xN8AUd7%h5{jWBbq@Tko#3m9ideTm-1yv;1>XBV_bu_r5r)N2Q0PC z+9uaOTZG33)CgdGEx^)5W3#6RDWrhAAT_UNE7Y+p&SXRiK&=kdgUv1E{A?YMEUVJ4 z?LuXZNDnW`GUvb*_rGwHF-jmIh`BVA<|ZOY0Lq$^)1atsQlf7O zA@5{aETdQ=b13S}B&su&<;HW0v=6`@l&>*Fy(-ls+iBj>-ioMS{rh(kb>iY5;wWpZ zx(ldVs|=h;_tWb;ag;vIRW6g=6P_C_1$BWfz=|{!E>r{l@ty zx}32gA6RE-OEEZsG)1#Sg{IZ+mZ?%gB3B<5Fi1r0_@8)aFCuG;f;OhQGBQDNX1OK@ z4p`SEXYnK=$5@N*BBr*8vQ+u_Z%ofN(Kd1AAS32|wbnibgh;O;rhptz{jJW#WE-a7 zM5a&ijc1s`%Sy7;b+uC2Xcf;L zTc*zfU;Mnxe~9YlHHs-xNc$cUs-_4Jmm+}>&GI~!Al(rfucio=h4sg}u>1>623zoL zgK|N+p2l!<{&F>bfwX#7s?}`y#-2W{mQy)}@$(d2?!nlPf!=QtAqkc0X|MurD=qaL zT#ugPLn+wEN|Jx`eP^#98@-5$tw8UMQu7|UW>!cMPUKaRpijvG+B@XakhA^F{b(x1 znEWJf(i1Prc43I;@JZYrCh-NOqO}PE#q2QDrL<1qG26{YkRh$dUVNLTtu}?_WSW^w zGse33A9 zPVi>_-V!QQZ*ED9SD&Sc(du(%qKYn)pmtX8YU9hK`#B{YX?3z%)q~~MgW5&v!M$w_ z3!V!n`l-snL^t($4&K9Jwa;n5ze`&=p?w-xuej5IkTRjM+Pt?B4dY?{@2n>8M);fX z>~6zJJTVkU0GvaYqrDUcFM%(K(HAJ+J#(vILiY34&FDRh*X;QggKoShe?&t^Q%QFp zU?c2a6OlqWcuSUCZ`I)e` z(j8;%cjC)%JtV!`*w(iNC-{u7Vb8QNo;DPVRY5g=O(kVs30)~Xu*z#rFAkJ^CNW2b zPF!vil`45ZC7DBw0GNU?kGR(%j#xhG*@6-^$Mnqf(OHa24lJP^Ze#VU>FbHSb~_k( zyV|%Ep)l#*y#_PdIUtE%HCEskpy?L|@XQdn^OfF%T&#iVZ)IyAn{5Mc*( zo>R-!r})Ih(jThUbAlIn7JQ@Bd$l4=@Tk}P%e`Pj=WBj&K7V_J{EA@iOUzF#T%=yl zD^d%Qd{z8wK}qBrMY-Rc9~{s34CPuBTbih{DYt_Dl0vx!)e`XX&}(Xdv(=9S>PPS= z)yCBCqS*6)m|~|Yiq%$ZMdKVknoX}tNDqyJP<`b)X702=kAIscN&=S5r|bW>L^<=Z z#4C8;bs-9R8#A1}JESn)`EhdKoD_Yk%|dA*)a5R%b{)t|*&VcqNKx1xhGViw**zuT zijv!ICoZeyZ1Y#CW9ek#e9h=&zE4%LfJMXszLTnAGX3~MBkg|JQP{Fxrwh-DE|B`L zl;kDqroT9Cl1{qs{HL0)A~}@&9;uiMWS(O!3EP-zN__%i=GaTa(oUqB8njrP)(bAD zH5&cTf2U-zPCA`#s)Jx2U=TPrt#wfv50+fwPsdX|#yLxU_5YCeCh$>K*W-64nLq{t zPpAZeq67_=C@QE_A|M&azzohPR&Ymcsi{_r2nmadOqhw}VH~9{RohyvON*_oSZ#~pP3}IzxVz9|F0j(JkNd3-OoMuoO91Tr=<0W;KQ*D zOSEwdtx=|4Pw>hfkdl!^&-Zpm)r=`LWGdyC(N(c_;6cDqFRLx7}dUt5Vu@5-TD?CtolRD>1 zHsBm^O6`5?vmf4gxS`?dehML<6Z-gXH9Rh;&B^ zWj#=(5cq3!#^_o=iwhk)VLW>ZS~CBKDfol}n1a|6$!&FVdTP|4(Ln3=XLRw0c93 z;bLi?)-g|8qLE>(fT({C&?lNZs*;QJiq<-8+`qA!CE&l33PkUo$bBmX4s$OwDp@C& z^ma#IXG75Zz_%z4E+rfC`3$mH=ffPUTIa*4Hf*j^6gYag3^h*hK3Z?^S1Igf3S;T5 zh`(e(5eZLiI3rHKk{YI76dn`5gBBH*`h$P(dMwy_HarjNO1pbeK*rC<6A_WEos zxcSA9r7k`ahd?}wi}!t!;3@oJ`gC__?V|e5asTdLBrmmFBnGiaOpY09( zdywj=?78CjvV#%qN;=2iMj*jxGPvh1HJ)ykfemMdUSsyg(G>Ev8#}d5bbwG9D(0Zg z_>r>M7k+?|9^RX0uE6E@R-=fKEhD*c`qd~M@M0ovy~4wX;iX{u#XNLYqxc(c134FP z9b&c(XJlMnbzaklkjuTeG5#vMBD1@4|P0)SEJ)*U*hqfXr${3(g!G6MTL zM)s*2baLa)<%l>Pr<~=d)B&@T@wdl+%-?jbZ*j4UFvDGV%ZTjD<|3ENjNmqGRp8VK zoep57d`9#mX2zej{(^a>4?haU0Dt)$|$;g<~|KqUOB|8XpXq$1lRpsZDTQLqOc9iJ_uW$71-d+rL=zv$jt>YSnnYyBfuMcq-0Q)u zeXnpeRX)aIEOBb*3^4IgvcR%DMRDT!WJsrDe+Ndj%4%kun>=$f`0%P^wta_NKM>=}tYFJS)F)Pa(e!yln$0wW3fkwG(H=4_Kdq#4f zZTF1Jc;m7iHy-zJ*{+7PBhv-}Zzq6kMxe1{r13}caodw7po8`bd-e1peY`Tp4g0blWGgZT+10xejVfLjOYHI0z6okHhVHjE)G7$Z5C+CQ?C$QE@BpY6fC*tw{ySRFUP-o(UxuM@1CG z)pM>N@snqc9RPRzn{`?%I*xgDhg1e^-Vy(d;A%DeD&UAw6~2K6MjCRACC~eKa;(7} zNnR-Ik!CxvN!5XCA`Mw?M+C3I(|@(Vey&|E2;JoltC%98sXdEBMSa}b!4>`nb4*f9 zQfiCxs4155*}qYN30O5ytl<6lxy+5C?e8`v&2CYbf?nvbnYDcL*^o zYYH1X*3>QOfnz@_aX@HZXPo5}4;*+MF|b~mPpIjbT!l)$FYQF4+_Y|T81t8~U~nnP zt25Bl$q1+unv-ml#JH$&il+rzJ-#1Y!sLd4<^FR;fL~AHdSZU^fPY6HmJF+B;lp5M zF~;GO`NM)BeIg5@Q4_Zzyt-Hsjn)le?l*EP`Vz^UfqNCZUK6rnQWS1e{9V52b+I|# zg=bj}PDg#Qxy)Jy!BY^2*hm?AF>+GpPtvYNk{OnXX?U{Fq*?J&CqYQLwVY~{+*)=@ z?N*zFs&0~7%flsK2CyAz3?#QfUs_(n+Duj&q;zR>{CsJjwArN^74Ir-5WCyhZ}`J%%aGMp1WK?XGgxg5Wg-@)XgnIo_4^;R0cmjVBp&L3A3axJMudu2A5DtiC5H61${9c#lef^Sd}_rq2HYt;C; z9LHSdCh30-{coiITU_Q&sk^*!cY;t4fn`g%ir$;cuFG8E+vIwBClw+){P1okVOe-y z<;wcXm9?#mi?KJZ0`{Vr=Xj0R>!)||6xNpxaV_BD5Cg;pR?Y@?dU}jdLuzx1pRZ0j zV^xfttR;)2y~V5gAR`z118;D+BTtD7%r1Zby;6<+@+DD?Jui%prBq(?cRtuox(i!y zeS!nK-1~t{Mep`xJi(%A@X0I%wS?zP&jPiH{s9GgOe80{oGwXzNeYcj^q>Ep6hnyXA(KuXOsEzn`Zv?vl+@Mg z7x=j7n4z*=arA_YsU`WVYWt8i{qlAP;VCdX9f}O{MR2 zrR$6ySC=0j2CMz%vB>^xvDvewO+UxKW>4kB)0Mt6m97>&u6_NDBmHaqkwZT!@^3gI z6;w_vp-oowNb3=1*36GPw=iZ{9F!J$Cbzc{AiZLGBXHabpVDcpVYr%?X1>Rx5Sv>PX zoEBtGpCSFm6Ivbu8d`QrxOkB+fvSq7!GVWa({Z~TD6JYzIPOqqE;?Zr498(3zy~hu z+=gqJ|Is3D0K0HM+t^+WiA7q5r(lILm$gN_<|Q~pj_-tU9Ft`x%%&W7;s^V+zse$L zGLHsU+l)_E2afiM#M0g28(UW4dkR0Y#ratIIn5)^NVGfaYuB^ra2D8y7FQPMpVG-W zY&1qPty!mKw@v#&r{VIt74Ec7v$stEmaQtzKJlor z#GBtzf)=XL?!F^?c z6)(V;!Uv2iivQPoYD7Y^9tKbH^_B49X`fFZ2Q5Tk0g;yjcy zk6K||@O^M&M#_x`e3zryaZIx;r6suaw&MXY5YhfTR+-1dqesN@=+W#cKjo)|M$ktG zMw!orr8hXDz)wNx#W7h;o=_RBoyaaArux$JR#r68|F$~Ma{OBw-( z2o%wR2b^s%9xc6n#^~<}rBm9?SGXP7TDYPGxOk|=ork%@d7=hujv$HQ@vr!sdr!*= zkFWPP!|F~Y&AuPT)~I69*SJsaHT-u95wvlBb`uXi!fN#YQ0gZr37$gp@kt?j<;li> zaeZKwQLYpwau?lg+i1+olPuwf`P78phm)+URg6G2F*AtIVa&4$9JvY7XH>}9k6W9B zYufM(&FwfjoY8w!C>VZ{=@?}Ot!csS_Nkdsg#7Y^A3!5; z7d4shD-={ClB;U2gZQ4rc+A8@46Rd+DFm}{=qAzSrWJTTGWNgPRsLr*JSV@_w(Xh3 zpU(&8mTT1pHS=q66^}o>TGxWU%qbP7h3z$g$VG!Umz+FmEZO0;t#t=nb@pl|nO5We zRD2+pRmZH$$bUG(azy*X?lozVT6q_v5W@c|np`(Td7&6QT`Y(dDtj@J+l7yO;pkz= z?8D@wsg%lk{qE1|L#~EgOwLymxw}Q0xw9{&l1m zfrgHe1|?YlUhMeXu}0IVvU6i2s1A9{u?Zp45otiwTU$)Tvt`Imou*&pEsSFN56IXB z)J2hqPd%ljiH-0Io?ZI9O$1qoE#j@p=bdB6#;QPH38 z=uz!H+hNI^iwcR6%h$OS@Tz!c1(`z{7Jb98uC3T74aF!T^s^jDwm+@kF(bHzH0J3( zqhd8rLcmM2X~sYses%hiSBXI75zCwXSrk6HNrdJ9Hc0 zlc3G;-7~J`Wt@^dwZ34}@FUZ%L4Vp_au?-W9r`zAu7lu8xk_7lzGzERf_n{yo#;zb zf_q(f>e9g8uauLtBD5spNez({hjdR&0>$79$sr?006TdRr=fv4m1(6HD2W0Oa&;`p zr}lF|l{*q;kHCofWS}S+(b>TnEe0`PoOWJGdEwppWj&IE(gFaA<$+=?nb^QJKaaUi zl(R(&X9G?7M({8r8ECq!>{7vCqv8W*O;bo+>D;(fy5^5UDUDzNkubIgE{+h21BGX8 zU_&>8Gf9E*H>wJYM2+cY3qy^0XHt#nVT>EJ8uJQaIvA*wUpJ-596$~`42Y%3lyTH- zh@&~qf!)JeWwS;+x;-o^8&oHO=KNAcxC=JA5wPKyn^9s+kr;s|DkT{05lQ{gtd*qk)Z7*@; zE|sla$sBo1OG@4_g7-q3QT$%x#Yq>2rJWh*g@Af&+gV*cTo}I;8wH5WthnVZvu^?kO`OjknIM~21-yvT?%ZwYLZNqEkjF07!Zq~6*D62F-9Yv3v zD$L|AJO*>-D6B9L6pji9!oIF*i? zQ|>$$f>guHjEceh0)R`xAv8_;l3rtkg*l2XCOb&sIHInrmXr^}!(DhtWAtF6^kLpc z$y;zAZ+#ZFbq52^DSRWS z%yhA{icWpE5qz6Qv+fAPspwyAyj0F`0u4g{?q+SWrHVhlB3^G{ZHkJn5e44oq(TEp z9Sad`K!GRQY)apXQ$}ZblR7cF9uJ==@A#{hw#$L0u1;uREi|wJ<=q;WS?>zFp?Rl> z3MI!zH7`N`nt85q<#9081nIe+u`c3yOIe?(}_<^r_ygL&!Wo%O*zwh z(^0DcC(JEnEQi5~ONcL+tw{M%x!74Ak(-?yvvIZa19j{&Dx#zdS43|p&qa!|HkMst zy50^nNoAjaBpwJ%i@#0P+(x7l=Bw5BGXlPu{?|wpe z;@9x-DWBqlb&G#3&zFv6-ACouPF~-Ad#@KK91XfUB1%WuvyrZ2kxvwvu zK1pJ`_zKq%Ys+VhC0N;)V!z-siis_^+*7!A`c2n|vwM5s0|K|xBwzSC8_pEZAAL=q zz675u{nDG^TjVvbAK)|NP(KdF#V$qU;LxPH_`?*=k^l7rq|DM^lPn4G+Xd2Re(jVa zsx<1_p&PN*2)sptM*>ByHrU3cK6^Jc9vM_l#a*d5y>u(^ute8mndz#wYL*I1J9^DA zLx~hl`l~)0mJayX?Z_IB9i?2=q;K```ycPkz9k2l#S6x8hF5cyt&$*q65%5>M&@I@ zNSR~h7_dmW&>YT$cLL#+K|6EZLG(Q+7RCFkbf*+&jAMpMe^fXX^<`|1^4d_gLI}o> zpwC8yFf6Oa^tQzytwOc4bJS5-vAH@X1IMo>+;`?!l$$Mi5O5Q6+LLY$!zLS5#W^YY zh%H&T*Lp`JJ|6z7*s(M2mH>hHe&KLX#r$)?P;^@QxILa^W+c#n(#1eioUz!3 zwsvk#qW|@%?fx@fuL=#9y#6Smo#hnyHTV4ExOx?F_Ctn7{_`U*iI`zxK5=yLYBdn8 zpj+`qA86`miW#zN#k3n##AS&C`ML3$cm5W0yVI;wX=4#cLmwqre`W$P`;}UV+7TJ?!?ksOeXOVIEt@Xv7kfE~7Bax_s^V7yOcr>?T zO@EnRHzo$hNJ=Y8i|p?TyG~7nue_+(Z16bhTm(Og#Ja#!6geH6ip~8%k}0yE4RnpD zQLuyYME3S@na4QpqoGBTLwlt3L>jK}fpE!BeqKCk&;==xpI`L#JEqcdc;~-7U%zF# zxxHwv%|`%jRC?um4f1kQ&4=G> z6d!S(tYs$BO7p6FQF<#rS)-00Wz?QWJdRbx?A~TmU{9V^yt~?2R(jvPQ%djm4#x62 z;x0cr+3720c1nK?xpIHtp8czbri{IJig)l%_mHytr`(HY(y|Msh$47t^OW>3FO44l zggoW@WC}cv7LQ|{x#MKLklAdbf*4N>>ZIzZU)WBw_9SQJ31HJYq%G=TR2;H_RAv*y zxd(W+qSie4>3v|%itHJM)uO3VNbE6p3a+hXzjbrEvB(Bh|Hfk!Z@?C%G2OPAaf?LL zK^$7iKnc5pcNIy+02evU&*2EcfyN7*<}N4Yfxs+}zCQFz=6BA(H*mb) zs9pqD9n)NA*PdUj?st`Y)s9AK@GJ=H6S?@7Mv1?6QBpR$nB;wx1=1x{nq~Tmn z(j#AYl^#$G8{1;BXK18R((^tF*ZuTtPggxWbh+Vty=G7kz+T+Tn%PSCR42h%Fn1j@ zNM&3{acwQf0Ix$@X)omgD48gOsXt&J6q>l$tfvoY8Q|tQ(zPO~`dqhT8LEo96r%OQ zipJd0U$<-zXji8Z<@{;Gs?R68LX;HsQDk{M_<5;x$Io}lEKnpyb#2eZV2iZV+@lsz zRvJ!JPA->m#k+FW8V?sGsl*1v8pABym@I!cfR*< zm{&{-*R>LLcQxxtmXgOac)2XHAyZ24ebDP*{WZ|bA`s}4#8TLaMB6-!xuO)u+~NCNc<$W!b6~a$=^p1;3)=5sz}wL->qBlaYUT8NF)-~p(((g4$j$jH zCrHnWRc3K$4(GTN30vaD1ceB%Ze#Q^=ZRXoW%b1Q-xJ@EqKpf0C*@+GXOdg3e@rA3_bgW`gw1U{4DtB2tRTN zz)o3bPF%;Seo^I|t<;}hEobzKBc}!C#P>|~ftpP#7o-cVS^2l~jOJmU1X z^fc!8?ID`RI?v?nC%v|YM1ygQTn(vV2VPHO(~JR`C1nRNCF&MfN3jcBf0YYG5uz?( zeZ_szv^1_UOVpZk2n8>iLAkC#zZW}{ zhUcJ|C55P(6LRTTl#cNm+Rv{o0-gk9ZHn!IC_w{v%X%iVvoZe;c_OwLGM;&)e}YZN zX)OJCblQ*8(kc?O&NY_Qj*$Ixnm2OT;VwKitvH5Tc+n7ao>o|m|Dm+va8b+2?FcTb z0^8Hd6C(jO=KqyRk#ZhQyHLt8OtCG7IZM=d@teNR9f;eEdGBKm!5G`zTlUBpJMeZ+ zJHpN^@Qw;P&?MstbzZlbdPGiIgL8@z{V2)^_?e^BY`C?Fq1XIMsRsLtfE_AZ!~j%T z1MxclOG-oyK=K1ip_o zij2b?_ZFn{vYLWAS;2GG5!b;8tYTYZ&ya$hmBTX<%dp8zeA7KU08VDD-~hh^@_esG!fp>WxZ_#14_%FrQ3tUj8b;j9eE;Hi60 zT?R8kZM?U#NdJ$rAN#CLcGjOvZJsSJ?L$#zSSXV-Kla!~ZnOMF z=^6CpVO6+LJ4&Hsg)8WZ7Dcas#nfxxXC4!hAS?IJVm)YXWAUn`dj&p|V!m!NNUp7N zDHX&)6A`#3OV*hzln^+82snmf9;{H7+brwJUhtW=#~=;<OZV%MmQkesU($qA2#;&_bL zx3-};LllMz#i3}SI337?Wf2P5P185%aonN%Wf2_3$cO>k{aJX8Rul*QlSOgXQi{U- z$E`fhP)POHO}*^qWk15&SZ&f<_KN})7OGyaE~418o1{6F;dQa$Izo^n zPOy%|I-ng*5pg-@)5Ezzp48TYN4wS$^+PWIhY{VX^0toXR7R958OPd;=+_E+7*RjO zTt@U&@?bN?h#pOj=nd4+mV_@8N^mv_zn_H>yH_fdgCY-EK)GsP!8UK+j?^+qT`9mqXp&VRNdD`5ojbW8#a%!;r&S^O(fke*W4{*3SSnis(bGFQmq-wz6%WACYwVMg45ZrhahLopT)6`8!DL(D z)~3{1k-1nc5YDO$r~e}%Y*^XMvGOzMa$wVh5a9QrCoI?rh8)UpN~DodN5jLv2Rf}l z)`+LzC=t@U1#69YcTkO5Kl{BIilNCL>aJbIDB+xlZNhzWo4emOS>evAo{Gf^cBQ)1 zB0D#hK*vn$MWYpH%9x2OuCf{;YPvHN&xC&Is=%p^GyAAM6|qSR@esP9Nw=c~%3V}B z$Q?NZ0cTxDn&3j>=fa-Lm>Fb{L0BO4rl@jg_>pv&4i0$}HG$@gX@3^>LO3*jpWVxE z$>3$!9y+V~mIRtPu$fHToK@XR#G3mSo-0U|zijTyc(t1}tI{F6LjZlyR zk9vw{BbcwU_bWejp1jV_|-g`BX!B~gP+ovdhOsfQ*h4KDgt`dq7`QG>^6=El%->N*-ei2G|ob`{hK zog`gP3%ex ztY_oFL`lX~vrC-j`;W@5DuK~NOS~$Ouo+L>LvuuXte8;KX$XhijpK^?5@+Be;j8*O zKXuU1YB(cCZ1j;5XZc4`OkbNKS~uc%y4Y+fsyUP%@}VEEcNf%Q0a289%vp85yUCci!_nWbVr&Sgqc#NRr?8R= zxkPk|?ZKH;hzY?SPiTupZH(ZzSxlU{*?q~xg>dl*6SL@BCTXaa)ORz^Y1 zFyVdcSeHXu*X7$Z=D)2=qpIbsg_&zD%ty$fsgtbCNMn`*b5m7Cc$QkCuy7f~(&Mgr z{8@KxEuB*YW#7r|{Z1xXLfF1K+njaIsvfZq0Q`RkqdP|I83oo#p5%`Hmcw$NuRscu z@GKy0g&-|If-LUZiu?Fsall5dV|YOK9HZjT!g_|sCNvMaz@8ENEh(Y0b;S!fCga$E zNrs+r9K9ZL=N^&4*J+*D;kp>}|H<&eM4V65un-r8V~}Uq>eF!4s1a8<1MBnJ@Djn% zBC=G}%<5=H;HKk4-tEj8?a6v9o)p(mpEg3o6qx85m}sC`PB76mvvvv-U2QSZAh>4> zs)T!MoCWKJLx8Gaj-O@B>q(cD{=wqjpSw=gx0(7jNqxi2lhpWd;^gKcqv`}zeizux zwJ)pA&D8naO;(+oXKj}{KTOuy(!NSXW}bL})s>NYHe>{1uWh$cbtI9y`Vo=6CM|N=T8hye zIIB9z^3am-`qd&K#bQO&liJO)VuN{gR@q|(>bF;{pZpq2x+UeNMlCndUgV}czO*6$ z2lqJfKJTnBDV(|y6N$&nVZ>(liQdZ!rr{zj74gBi#0c# zl`nmNx-dN8!wEe%pQeN=Vt`H5LY1@Xf`p31!t`)Vdw@T9nJN|qxI!UotMAV;O78Q2k@cM* z{L4Oe`poysm6?4<9?z>gm>6R$89s~Ef8NXs6lOm$SlF@ufey&YnAp$Mxoc|}hXj-Y z9eTe#G*;HJtw}Yd&2T6j`Crot3pdW96%;NiQzcv%tPeDU8avpZ%m|2a0>t3BFv7gA zLVOG7{)zE1mRvP%xP2O~XP{|TukMgB_#b*@bw*Ad+VqEB(kI&ya}{QZC`g`Jw%FQG z@08lh7KX}t%C=jSx6P=yizHNfPkK#QMK1kuqbIf7fp|x}rn*R##6Jmq<_)PN_B@L` zgNd3hnr<}#-9 zr`=F7Ps5br^?*ISV z7zFKy!7K*0fWVBukmfO!!@GGDX_gJ5Gu3L+{52q&bQgEiq*?ECsex1*TvsEo9%3zf zjcha~TOurXF>5&X3R|Ibsqn@y$?-4$bF|~DanW=}tlT@wS#fLxgSq$|WE>3eLldhd zgQ6Uwx*fc0aaR17&Z^UkbK+2t(~G;t@ji2UacAzEe#G}QQSyQnY}TiEi)B&m;!g3O zF3yY(TzqbPz~I%39q~?-(kXsE&z+oA+~3C{oE%ViG@P;DlWnnM@UG%e+56~c(GEv2 z{4=Vyl{ZTR%4SoOq^nBQZO_>2Qg5=k@mr-mM(hDFR1AVn#K%fPdhB)*{0=b%fDn<57?iVGWA zm5rmq-M^&~X$9M`u@0^-?XG2k$nbO3u?CHE4%mh!OLXTVG^PlP`((ZQLRXE`4AsHt z!RzoOx^xji%#f(l7x=cK4HJ#J$5cvpM!2Z#5gcd-_BcwX;Sqe+Z+zxUkPYtfMQ-!q*FmT{y9pfZVHH{WhFodpJb@Me;{Ca^A~6M@ ziwv75+@}(avNqtS$mw6z67S$CXr?~2Wm756WBY=I?e`Y!DXyFeOMtD$T+HE{u)~)l zi8kjUGO*oZpMlql`^C>&d;zOa3`M)7-;4Q89?d0i#FZq98B{A4BSZ)igC+_EUa zpX4sm2q`d;yIH6FK>==*`BsN6AL-=pCUaB+8Kkw!0`v`)oLffzPm5Ik-|Ljox+1*T zgmdTetmF&gf$Ogo$rQOznfoi9m_wq74vE~GNstpB526MqG6ic8F^KJ%QRXB5^BDq= zdcxB(xL;Cays)Y$YXgDK!sF7t{ggq-0MyVkE|kL@Z@&$|Oh1hy_tC( zacicPdJDJBe8^*KcH5e9^JH@IaML6m8mORt+H3?rLXA!<0CZ-)WV#$UpjAxLZQR$x zgL&j3HS`zI>-f3M!6t^5@7!mdsy@8MySihiH1flA;uj<`!^mKX+yN?Sgm0NTMEe_G zuwTSSj(-0c@7AEtq^9-%sT_$X27i6v-DtM+~n*Sl7AXHS6_W>4HKKBnE5>{`CgZ3N_jIMvsV zuIzp-X2QwRd&qa?h|dVf^XLWLFH#`pIt)9Akj$I?S`MDuy47O|)O@0r#L0VD0+-W< zMDA8Bp82p%e>fo@-0H(e>O+?mv|U|0hH_%qzFvbL*5FHi&eEzP`^_?f;oOb@$N$26 zi~jzOe1C`cd-eB(yuSiq2YJZh;ae(<b$^(w6a+k{koPF+Qc{qoM1|G0Ql^X`R2h}qq8Sjw2XnXtBUVdN^eMM1;l?s>8 z=j-ES;(mtb%b^)-WHFEW$eF8q;raS38c7!bkQjhh7tEJaD7bKZD;z8>g*Qzv&E+q8 zq}i?6@hsXJ<+dl$za`bc(3UTb{!f9prZ>dmG5^izEzxos&H|9MnL%~gyei&I3DH39kFbuI>NGnMM=SWYL zDfWi42I8+P>p9E{l{*I5iPEbeU^#OCFi;QIkNLHy*jVzUOR^Q)Ru|hg+7jl+6%%-M zzH8$yB6g+mRn8AY-t`nje1({0K$W?QU0CNa#zZK>nAyRLXP)>HF>0};mG)SSdF2@* z5A0{0O5|j0{vMua@<#^xa_1*kUWxuT7?7{kG!}6a%jEDltR7$))}Rixk93*KurM-= z;LFrICiF+;%f*F#Y_YlN#7^gyubo@sCC#q`_h?6(U`9=p1xwzIe&R&w!l zSHHM3oE>tSYpW+tq~d)g5vtbFru|N=CTlqPL(7PiM8%y;$25`;(iHcp7Xa6v)Kj z=tFCpW>V0T69hR*Dpr^Euu2N5lvHUhW65ggrkJy(uB^IEIi!}KQhJfWD26}wN-3(b zR_MVeWJzIkc`+)x((WyF&PtUM`yEHf|LU|jBTfhbjs}Ya2QY8{S0~neyM*j``r-^& zP3dhlRZ|<}Dk((AR~dGn zBAB~AIG9j&@QN&6_A5n}{LC!>+#DP!z~;>86wj4_emU+0hH#`Dnb`%HNy`Uw zDdchTDNe79hjs?4Dce+xxs4@#-R5KYO$`4n>7Hr^LH@%bb-nw8-94s1xP8Lam$NX4 zagRM5ySq342uJ7H-upkVxfyC;)_MzeBky?1e~@?c&in(@^JE3?8oZf1Qix3=4jsgc zl2NgeH4wwFJ?;Lr0$XAnUR`25l>4U}4kY+JZ|{vN!XELthJW7}eQ~a} zs_3l*Kz)NUDQP96j45wlsmr)0R$}~|e=P_2w^F{mapekC`aKPN;a|(Q{9B>()aft( zCC|G5lE*`=^0H^#<;$fiPkBTd;k2!xu~hcm{t{#A!Grwy?t9*j@o<8-UmPkirhR7c z_Pr#>1t`h`{h4}#2l?Jiiyo51R1ru1kBh)Z1uWw`*fB&ezrW@v#K;MDm7kKP8i6&4 zoMM0 z-nQBJZrXEp8n&}dXQ$Pg_3e{TpvYF19rm+x8dRuu^8hi0OO*Lo>XCt=YDTyG^#z-n>56!DhXumv-X4v_rb> zm~E4}jcQnAhc3VWglY|IzBIq7#O#4po$*dR%kT30m#Ht267%}>6b-Vh|JJQ@PVktg zCvv4bD>}G8)Gw6#dtt3Y7jwIu;3Hk0(;U-~O)ysGVRSHDipxBZh^|EyO+xfjuJK2A zZUK?{`enV5Cay}tL%v1@IJhSIx&`+;;NtJJt1ptT>btmIeRr-=9Ne3neJ1PcF7@4E zm2Z_B?`eOFp=7bWXcuJ=9W_s$7W-816UW&qohH~h=|d)(na=8MZWn6&6C z&~SBYa(DFp*Ks$TPvfv;sgMvpUar1n#d{ikiv&veTGB@@vbV729URCoDp+n%7};iR3>*HxLgLz5PkuaHi& zcJ7#zGyq)=i4?d;fpdP0CRAFmjT(RdYg7&LPPKnQ!|x6aP%{zT!H~+7uRVvUd^7kvwG`TZl{F^NO3>Z5`};ENTGbVTz_@$pw$x18iOna87l zzChYk)?e!UR>sUc%n-j)Bd0kT(vg^)bhoyn;r?Vho_@bgJNjAe=q}BEFS(x~SA!4V zyUiB-?j8m!*iMQ3`e**!uj<84ofLQYyf4nf_K7AeTdAfvc#LGD@~RBTy!ow!@sqFI zm5UC>63Uv_!_gI3w+MoGfs3ANmH3K`DswzQZodEB9m>vUH!Sq#bFV5|!~wr2)IFb> zUkc8pg|GTI6{RJ(0ou_Bx=0E%WoZ{3(OO1BkW*wsH+~^Jg~jH z9{O0i#UP@fjIL(zyhHhH*g(u|S z^C?5CaPF%fLOu2;u`IfQ_vmU!h8Wphrzc>43C#lubQ9nBmyC`#|DII6{j7SsOFPdc zPqLlwN=CH~55Jq7E+*$F11XdA4Z51x=QK>yiJPd^`H7|zSelT|&`e1c;iZTae*Kdo zWKRApMTjTCR{V-~wpu@4moP9@LSwZmfqY13Y9ga0RynsxIsK)ah0(R(q4YjS=RbgA zQ+J}#A|{`<5)+=B#0DJEt2gG+H~a8zPxOfOvgK`^$g)4q>W2oi_-BDH(T5SK779(? z5z)kak6;DsAx{#Iv$|zLuNBZSx)BxP(?%98r#h9YXnv(XkXO%`$o3YBusE=0;u>tFa`wf-ODAzG`m1x1O(ENK0)Y`WL4 zXfq1~1kspF0q=>+LhjIy26^0F;ds<+N`RQg;an4 zFL8wx)06PoN@)Q5ln4r0(KnemcSxRo*Tp6S5KJ&_(T=Ll(!Y^;AepWCW3hliu@F6M z#TR$@!ThO0k9sDzP`7y~dNXZ<+7P`9fe)Gi{S*R{Cj?{wH%e>0CS)c0N*|Vw5Ewz2 z2^wKO5(O>nj;{0*1`L{2By_4s<1bHxWY}VA*bYa($X3KEm+a7?=yjAS#YwOf+W#QM zB|E>Ps?Bo$8`*_CyiE4kCjeXfZD*CA;BU;x#-2zy3m^b(`WwpZB`r*rnXgtwYCtDQ zqtt-9q})2mn_SNgN<}7Ua1vf9wHW(Z{pd~xsq}WKG&f1FqK~50k^c17{rO|6kk|gM z3Q_AZ`UTS`gR-$RwH_ujU4J+Q`jfV3_pSx{hJgMJ(6iQ~4)rKpXObCSKl4L2+teR4(FgY9k&7 z$&_`woW$r;s-m)Ad*PA?h|`i~(MPSir-OES31U>%pd1)k>v&tB3D@DUoN5Is|E5uw zmFs14IX_{KZ{@Mt?mDawv%x}K*-gFS_bra_MD!VMK7hcvvKRcv2IyuR$oiCps_DsnR@x{)=8nVM66Bjhwkum zszs?S<^k$*hk`26!z$_-y-inK(LgW3XjwQc!S}?9(Oem`(;QhBS6a;zau0G$pm}4C-QmMG{%^frOM8)!vuPTid>`tG;d z;CUgyf}#TjxGIU?G-Y)Pemna&>q4Wn!-7A}5pZm%8WQ+n;9p9?AO0vgoHThSgC|X2 zC-C1T;iJP?PObam3B5FKP8BhMB2r87cN8H_G^L2OfU=+c02;`&N{gwyPb%jx^dgR3 z&j7d52Lvw-|AdA=a946L#=-PbQ|x@;TbGfhywtzRriHvIaIr$C z{v-@72!l5K{rts(&`6?ApHNq3Mj+m8qJ`luZwn_G&K)M~r6mzgI~h+zKVaOYb8mNq zsjP)rR&>eATY=SMe3|fZN%`=?x0SpWuyV~Hm-6A)+I01lYJcFscsIh+gBZcHYPf^{ zAnX5e7B?b7nFRDWUz`pnB&Pj}@mzRQg3j`V(K|HA4U#NjK$2ft<%YK=$qhbzo+hy zL&+%SiMkaL7K#=&Se;j@R-BApL@Ttu;Zp{lcr8lFL4-NzYIHt!n@G>9(ymGZq2`{_ zPT^->qI@Bp7K`v&TOzYnMiQi`wM!@AERq?MBdYOLbuGH*992Ufp={=1)ehCE*b)v$ zTJf)d`j|i6nHA_;QmlIkwaLo6joRWLxW)YCZf4|$9DEw|benVY+@`p~eF%Q#S3})_ zu|sL{*dniagWGG~!Xmi)R)YB5<24_;&uh+{isi#Bcj&5ox4Fa*vJI}0S!taa-2;DeI`w#S4$rUbP|tVe z@%-1QdM+8{4$W`k5eE%L%ZRkyS%d~>=wxd}Ae zW^@R&%H6KaQk&vknvY z%$KbEf7kgp_EY(vYMXz(Oh5T+(#gN8rhWd~to-ktqw4?eFcrg^x6L26^7|$KAI{3( z%gR4p=Py#t7}B+EexH@UNb=utR{ov0>i%y*Zw8?*PN@1f9BtcwD}S2g|M6M*U$XMs zmO#(Kxy~zf|J&wY&$y}ngB#IZOWX8c*6$$eR|p{a zZy8|yj<r&_* z+aH?WzWt%Gy8Sq0RrQ6&>h_1m>h_1m>h_1m>h_1m>h_1m>h_1m>h_1m>h_1m>h_1m z>h_1`w{L%FtZF}ZELHm_nsqk?_HdMcAj=)Pc6c_?U7#yY6W7x<%*QE?Kbep6*7*qI z?T6z{vxf@sG1cFU1^Ek%(9HAX_DwdK@qIKq!yOW)F6)j-mLA;SJgBTImu-yT&jIn; zYT`R)TRM@reBK120HkG z{(cJ|Hw7Bz;?ANYelLJdS8&j84fk6MEhKPyMoI~ z!Z|HCdkU_PhRalN%9ugg*UN&-Ou=2K;W{WdA$J#LYcE~R0z;9OKq>;BKt6{?C=ln=Sd`@=s!;b$j0{PX86pH z;fmVKclefcV&Z_Gu{)697P`Z?*cH0QyhxA8H08}{DO=lCNFJSpEPK4FV2bN`6vu=?Ywc;=J* zmOd_up_l2s2R#Yv?gwrcxo)0}1Eug}f+l2w@5)JWk*YBpzKQ3p@97k-I0`|E5?1=4Zt2E^rnXypIdD z%;p*C_-}$rJYQ3pd5{;8+$YQUgff3|1Gb9hj-=x54==Z2GsygzxJSm5sDn&DNjO^;~VA4FHb8a|E&0@@-sEQM1JmzFP5Ks z;%~{%t?}37XMFq*@>3LlPJRZ(!}2pU{)GJWj6G&GBri72dKwUuTW#_+M+IGr{sXyP z(c$DDi@y`m?IslHc@7)vgYdt=1a{L18{4q`{-Z9 zzr|raU#fsmQJyz^=?qj4Vm4V(LGQz((*sS+mv{zbzGjHtW3qi-YQ8SdX1=EVOXh1F zElSPT2wvLE*S`oO;4}A#0f`9C*S*`uEK!zix9v zevwg-oo^Iy8f+BYnV)AA{4#%#c)~uM7=ND}66cAtKm;i@%-uyf6S_6eEeKv%XH;-3 zCM|NiZQLo18x=p6cXJ}WXfx#K(}@33M1@KKGYaff$mGi(DpV+A>6evEp4cqaDG#<@ z^G)fG3cSp-ASeTLDGQu8zkchh-tL{nhwl1uDvu8Rcpr}~&^(6r9v+YD$6I-f>c{as zeyJaec-*WXQ6$D{^&?us*vI;@Cy(#y$2=bYq8|tF_y_%%WA2EF8~vo7Gf}UGF!m*l z5jvMj-$EWa^@<)lDyZ)t(P6sA?iP&oTTiFY#`E0cM`Qwun0B13d`16L(=M!Ia=wjj zos&~;bh}BUV>RtYw>v~SR#R_uo6MwE2$s0b(M5zQMaj@)yJJ$X8t0w;AAr6oJ}f+9 ztOGn>@Q&d5FKAl|&nNQI2G7@wgT5!RJa>^`IYT6xnvP(%{5BtF9*3~-;X_5m?yenO zMD1zSQkl^$!{{~|VSF^g_~=2hRyE(L7Am7SIxBW3c`X9bs!#HdSce^((D4=gmi`n4 z&qR%^xl7cQz@qUY3r=x|=j22`;G(#q-=$Qkt4PXUBkpFSjlPEY^Qz28C@Iy?-|zxm z=NvtAuSfbQ%Xr|Q+H~-u?{x=z(ZP5?ty@_>T)}0hNY<33Z2DL112D+5lvLQ|SxTxr z|A;eFb$7n!*9h)nfEeY9Kk#dHD-DeChKlYX7?@GDI9ys7hi z24}Tf>B~|oCdV5xL@XY$A<6hohA0s|aTFZ5O5uQ?Rzg@u?CZd|UyMb|s?2n{oErD< zxfBqyDbOPFqPX9$rEq70YwNv)zT{2nFT>kvYtq^tOA*E-aCjg=bk7?92}!M>f5eki zB={5LxAZdb$7c=nuQ;@0t=%g4Q({!ZKgTBVCjZ4Ycys8O#+!yC;7zDK-cW(yXR_7)5qss(snnpIU+_fbdi+FS36FSP zY?t=_UE1&|UsG*(mlwgp<^BW{;6UJIZ3~`+^MG1x8i9CMZ=P5d?+WqklQvTCC@Eg^q61Op> zPX4TNeoRl(?kF)H#AZ>c@QrTHEQRM@+gGtBRuOV%X^^_VC|0dZus1*|D*CEcihdzH zWZjoZ`J^j&EkkZQgnZJ671CzBjiqY9(_;%L75-qddbP(M<&|pok^EM!qgX!1!jFtFxe8aB^;^`j5(^UYc3)mG&utzPh^b{DrM^EK|TfNrH8-z%o-{h^7M8LBM{O1l!G; zmM-9-%_ah3r?%o1JE)_6`fb~m)VHc-L zbGXI#Fn2-L1oq9vzbx)VM-n!>tf$wpjZB>+(*cpe#GCgJGBNMpj8gMH4c!~_K0c;| z(pU!uQS)!c5^GxDBO~*umz6#ChI%c+aU~Z~GnsFb=qAlZkl-Aa3Sul;hV3*2?>dN^ zIOakqp0xu3lr>U9ZbVMw=}FQY?T4 zu)sha4fbdf3>HDa?0|t278t0b!6qcZHfXR+z`zL$4AjwJmnOl)-wma4?_)eTVS#}< z8mvPS%&);Z0tQZ4V4#i$+l}&$E|gB9BpEC4!2$toG|0ym2+?HR4v)DOTmfm&0iecc zM2)d;q>qJK@wE)RgR8aU71BJRb790pdUVr1(LYRAMVyF~BS1-)D8 zebC-mi+p)v5TK~uN{5QtEm%%k>;jTB{RC=s2M7u?iHUH7-}m!T z?a=k%?p=NOI{KXO?bALJaXU-V`4W#Y1&7`HgwQJ=d-nCJ_<}lb0ihlHtgM6UB1Tgx zHGI{|g(Ss$q|Qh1o-`DvW2L|1VlYSf_TJ?~$A4S;%d&k^y`1l(9UVWw6B?dRJKW}t z0|=DuHXqL8)@5`tIvE(Fk5z*Rx0>&+E$T_}XtmI{aFU`BS^ z5r98NczPVwPheRd*@u(e=)r&)-A3){L&pclj)9p3q`;P=s+|Jeva!p%95!THaJ=@c8=VwBbgzX{N#TT$k6Xnh{6$+x`zo7dO@sCp8C2PbMr^-M#sC@~)yv{X%2?WjDN0e9`F z0qWPhBGeVXrbcjpY!%@#kUBdD{NVgR5<*!#RrJ^7e!RU{G^c0$+)b3Fzt z9Q>h!`phRqL?ZjxQceMzAy8s=rJz33P|$Y^3i>Wkc7b{^3H6SKg1lQ$kavN~6sT!Q zC{sg0-7P4nyFhgiC~p#KvWDv53D1VW!v+iA0)dYR)I~|C5kRrw-zH#8rv(OqS70LF zspj{vz&Zj3qFZ1Pcm*bk9tCz7)=x^y0t_N=fkEUI*twkY;M8&KQ!3Zfm3e)l!Z zpz)fZFMKhc@z7k8`Y3CBwF*8{l&Xe%4VAlc}l%{`)p{u%Qn z&|BrGD@e{5{)iEb%k&hm{vXK^K?JXrh*s9hx8yN}no&@bJPrveq**bJg8r_CYdxRP zuiq%uv>um$n{}`|v*#7uDhlrEB;0Kl z9DMZb)}s!O>GeL9uQLy^ri+7bjm9helG^0{3F5b8*GNzQ?1WBBlvqsoh#Jz zhIGRe%N4vuaHUoyOGP(i80LPpMo4~8C1*&o-7vS1jPGV6I8i0rB{|bD#WG7JU#pTc zCAouPzL_lKCn~vvBzH8-r;^DzD!HR1XU%?8wc-pio*#c=Bspf^r;_%Q1Y3230}qA- zOp#+9!iM1Jh&!?B{Au;?dNYXRMY4JJaw(Z3ELkIqk6^vxN6iOTl{yal%DYgBHL$1Fa9!-nBi6;{l5_Ylt}+L z!$1q(L3n~V)@dg3R^5U(H?$eeZ}#XGY)7LTJ@!Y*j+{SIXP>IGJDyQIW-pz+q;2*$ zt?VyK_V>sx{6wM7c2%S5_nW)qXUOGkvrVzG{ams=MmDaM$KGb)ko$+LRGWA2Rk^dV zH6i!W_536iDub-t7fSAH$?csiGi8t6NC{qJsl24eig{7-$l@IpzXEF_+w-~Uz=t2Q z8C4^(nIm8Y$Bf@VsC|wGq_9~#iv0VEN{N~_axSa=FtVPXH`Xu4bOTxWv!DRvm z5w_qiOu~H+POAY7T5uhJ>zIPOI0?62iGXZ~cUo|GfJ4YjmNz&FCtk``c~@C*GH|RV ztKOkWxH(C3W$8PQ=!q{ z*0w>T7^00VzAw;pM^B2OeJJyBo$D9hs9aCW(Klfc+va-D%Jmn?6_H#VsngilRxOte z*CkxNTa~bAhbrNUwk14lmGDa`VXm&XgU;3WF}2d(;ed~NPp=_!66uFoxh|7j9&$yG z?O?rxyUdBk6CX}xaL94^amhboAuNA%JuooQ&ReQk%-jz0nA?QeonjYV>N-Rgb-I}q zy3Ad;vJ9bV3T*R~Y`M1M6?arftOJFCFIeS5WP);LPDJJADZDD5mlXG5NkqleP8vX; z#N*cSwARxvw9;>c3bYZdTKQ{iN25LE`~dmruaMElFvqqXB)}s$z28Zg9Q3t>I?SFq ziN4;15}S>^Zro(MsVrhj7OIfwVON&KP1X9wU$Ze8^G~y%pl|#Mi&`lgRT;e~V>D%q zo7|oJYZ8q@?Sj3@z}(Lpq%h`9tgXP9OFAown)C4?rK?F%b`MnyzM#xoI~o5KSlysc z3SpR90}s4Rf=v$Qe*PFGl@ME!7I@4VJ>3Og;{8hwG0yjxQ?fkf&3NIMkr%6iKzSw; z&^_$3$3`$m9%HF`OOIX7o28!+U!R4a8Nr(!YPo~#qtH)mW*^05K{1%y*ocz)DmiaZ z`iX-)wAWAUBE>23{99mfk5ZaL!0tLlRE!WKI8vA)7)Z(0 zNpfA0%=IVDK<>X(;pHq%lWyLsh(hd_NvK&s8C9r4+{}vTF{O+=n(r=LZv<~wU*!`% z?3pkkkvO)y(LaigwO%S9+H~+L4aIy}P|TM=DMj_)6ci}fRYNgd78KJZP zjTIb0L5Y%*3jxlR8;#(AGi_SLsiGzj5jA*oh2!Nq)v2vj+dB2BRqGHCrzBv4s1QIA zaf+yL4;KZMLO>wzcddO+2E4S-^Zeg`Up^ml&)NI8hqKq(YpuQZkvq^t z%*z-ncBL>}_A)xXP-~8Gv)C8(Q+Ed{K*a$cU+-=dm)<;)4zz2%`>E&$>&>?J_jsp| zleh|vMIGU~>!=1g9bsBaC+Ci@wod*bQn>PCDpFK_zZfU1YiM7$^kHh2T_zc4x)n$c zGw*}nF__$cCAQ%Ze2rW-L*BZ~ucuTb9{epEA`yqr+^Q;PICF{OKq`S>UW5Zpl7V0CzoJYhB=xD#(*!GH))0^S%tF- zsztKvNzV}U#^a<_V)cg1&kR&DKebA=T5gk(9zWv}3ggE`onD-OaEVhN382AP>QikK zS1c|JohSWL*4-p}gzo7)Pa0-Nafu*3WH;cJ(%YtK?-AE3rqzb^44@mxxawYY$TqS z8|JmZRN~2=X61I)DJYCy@4>LH1*RhJb271o?U#8lWS$4ZxE7eoJhNsL*wY>iq36M{ ztp%n+?;g#KPnhMwka`{r(^_CE^`s9`xAIG+`iMLaf>kXL6?tP#y~<@WMKeMB+%p*h^l4%qXFGCRi)s5=DZ2_6P9brm8P6) zQ*nyhog^jBMuwCn&ie4mO(g}ptk^L4mye(kFz@U-~X-ajbx9>j~Mp-SkjlgiJwTd8#k zxynkdQgU^VMu+*I&-jH&o}T`m>UYnLIB&^p%P^+YY^!(!%RwL{vn>&8bhDhu#f;0< z`2!*aUt7^vq=A@}33D~<8|2wao7`=4EY|=zc=Gn&YxJk_OZe0Z`mUVuQSd_rhtyVd z=cYyz!gVU;VX9074ZxZf8J|1aS%UaxNV9{58`=jGJ#y!MgEd~WgHy4K(@Y35{OdS$EbB!PjC}0) zAlSlW6-N3OT+Ecy?VrJpC5i4QM^0xV&AM$Fukv|0@_B9ZE%LopGX`f^F|n!S6LV~t z2I3nhqT@<)BF@Czh-2rur>QkkMe+ER#2&e23HHcw>Z{tu@Q4msF$T`q=Sb~;dDFFP zJk~n#KDpdSU2Raf&z1^s zoviTSBx4Q&NQ_hu`FE-~`2v|Ufo|FTm9!6jDAJ~PMWa&R9VM+nE8}Q8L>b=QS4yC* zis=Q?1KjQShD7yzoa){_|H;wQoRwL9JM2Y=!%H;=Q@Vj_a4nOF;Orm7lx9A^8Ex`{ zc$dtK3^xy=N=mX9Mzi@SM|Iy%u+{dL%opMiCRqmPJmBG`925a1}yJ`FgaEl5O+IExyqkHer7YO8L5< zqUb`E2Gwb3C@AIY?IM1pqm4HxYVYNR?JX$fYnh$UdL3s_orZ>jQod%jrpZgzIZ>}p zLqkC+U(fdQYKGN7bs8E93ckMa*IL>e1_4jE4+{kWPv1C75wcQL&`YtZEMc4@+|9^vRCQ34{hTir^(e7VRh?p6aL^98H=O$;mY$TOi_vVMvLM3 zv&3c>#u0y>M>(v1vG+wJP4|g%wnld(T{wFMl~&S8q*nY`gX%y!gHqB-q@vhSDxcSZ zbOxoQlSm~U6BL5#Kstj`(n+MEMB{?$Kstj`(y2NYHu$YUbs(KVDd{AVdX-;CJ{`zr z5JI*JiJd@f2a=gsA=&v7JCs;PON&(k(R$6dM%Q7`uEo`|*^1pkBbx*=So)b%JT}b? zmTqO&EQ)f5IQ$a5Q}u=_uVCr6EAnt)g;g{4;G(MCjFnok)a24}9V*=@xI~W^syh#r zkZ?zveD{+%kVJ2tq{hDd1$Z%iQ^OEcUF7s85tiG>Sk>!ck`iZ22QzZF66}QW} zxHCu*@8aGdYJXlA-S=nnUdFp`(1p%tZiF)uyi+@z4<@kgrzf?nY}-&H`$O^&(`v_*^0|@xK6YbfJ|WB#6_$7jav8}?)$xVir}hBS$BuI_ z9S1yc)J|S_`8Oqr@?Zw%Xl}K;mgnc<3qGiO*!kX?og#C!2g7BVvpMRvwb@&L&@IGr z-}1Ap*{>jAFxaeEEl?8n$6npo3<+1kl3Tu?ORmPu;Z{@;0TurRcZPSkzP*j_Gsy9O|qn_&3 zWj*=scsE^D-&P-MUN`qhp})Vsyx=pdx`e{4nm%^oOsptzl!}jXmzq28umM$LCCU@Q z_$Zrf4nh!__o1SY8rcTbL7EwqO0$0`3ZDHE4>c=yJ4iEwQfU_VQLh_R2We(dD$RcF zqaHM<4${n^RGN+OQP&w%2We(dD$Ne|QR57%gG4hZHLzrBkP=0%1EuyIB%490f%Tq` zYQ?#0)trYy5+9}KpJWEVqPH~bAH?+=ZP-_>p!ek^9(;;fPbAY&BYzHjL**Kl@$aAK zNiE|~>H%UIFRR5e-hf-GjegQUa_9`MY^Q{u*o6rKl3l|M9AFl`6isWZ4d)P>%I9{wTmW9%~GEQy;DOoEsGUkOvmI z)W&ZzH#uSv3$d-z5!F3OVRcj7=A7*#w+n7o+=cUr2F!8Es1d@qHJDKzh;0};H41;sU zlTOYwFgNo_bZxrTKMj(%Rec#%vu>B;HhCY!J~k08(wtArL*QGlU$@DHQ*6ZcAlWuE z3>nX$8QGca^A#KXE=vkonK}oce=2Kpi;eDv;G+dw~Ss1hupjwQ~OcFdJAmOYGl2SE% zp$YFI;VcdMiyzJsO~H4SaMlLJ{cy3r2+x#o76;v6!pm?iS)_pX8OMy_4tb}^a~zkBKry@&2u8B+V*D+CqCrG zhn3uS5ig-?!ISD_)8I0|6MiM8r-wh-(C<=Wq_0*SC|xA>tyJ%cR|H)wUHL+If@nHN z0Sv$s-J`42_Y2b9ZL+wM9JO$%swwY$c@kDSlLwVRVW+l(1QN=r1o}PMC~1?*bKcCK zKUez{CD{dN)g>C+ag1OFTdGxODGJH=xIuN&sxtght$LAmK&SL~qFV(89baRo&-3_XfR+YR|tBM3u)H-ddj^hNAmul5N`lwoi z>ZDaAFV(8k6@?7{y`oC-gs%t*TQc)!W?5wBZ}c!`Szg3AW`BZ?_~6e%O}UyKl7#DF z2OfXIF?vj%FvkSG!~IOM_U$2ZV}YUDs@wd7J#ti_eOITl^6(Fgto((P6c28;G&1`_ z1X`l^@8tLe1ZlB}TxlYgzNRTh)R@SliS$iv{bje|*Jjy2+sxNj;%Gc4l6Yb&HJVVu z7R^~3Ws8r^9sv8;GZ`c#CK1EsuT}iWKii237C@HW6)s6UByUcvQUk~20F_ZNLIYVH zn`1(OLb&@&4ODg|+lkm?=1ukth2vv#stWI5c^tas@RImsNE4IEa`qUO6Iwn4O>v3SnwmkBU-Fx_ErE$2#xWt;j!#K|e)#CZXRWhYv*Pn5o5 z)ii|5ieoG+PqsF<$#a_Zcl+b<=E$3`Jb zyX~K_TZzM!stvi3f|sSOt=OG}HN>RVsGR=ViC?d7J1PGX-1o>WxdJuXTpRsj#PBMs z`i_%P>wN0|@>^t8FF&4aMLtaY zhQQ!L4~8pBU|kh;7Ff2z zPV`}N9*tEq12xJq&n@kq)$EsVjN|c>*NR((-r&qXK`tw!2aMO~GnmyM4~g1+ z<+U=5yVpk@XHb$06!K8azAEZ!AH}(VeAyYy=#Pg$9*W6VMUC-M%}5 zS4HLds09YaZ2ox2$-^nwzCQ1ySJ zLEzm*5rAr^7nBfGrcgH9M~yeAc6vbxL8RsRqAsAg#bDAM+QP(x6v{;%^>1sT^mt1T--QkkxV@#Jh4Mx75gzIQQ_u80V}Xy_ zC^CI-J>xzf)nHKRd&X~kl&EC#O5ZbVA2q|E()WxbeAGDxmA-fE?C*W!2?mwEhph5Z zSqAmfUNQnB((fgI^3btk2y{Py9xC6I9*y$m&*-sS21x~{et)#bgHLO8=YD~A(DaLU zebj9R)lM;yQlPYNJn5q@HmFX0Lr~f`Rs2qdp)HejBePf7^ z+Q9chwN8CQP}(>4_fd-ss#D((l=h9}&%Am)Vo;s>hM=@>)cdGPMWyK*&*8xaZTiMs z4<7p+p>DCHVZ5gFI8`&)vwsZj=W#`@sYUw!fs8W}`g`nczB_&Ya1ZxT?;2Ek&9Tr& zJ!w$s`^O)BRFy%c?;q2B)P)9>zJHwUqlOq%`u=gOkJ{g$()W*`k4nZ(P(3WzRwzBVZjozDq_LL7RH86UN zXSQ@Q(5igcKm*&0fp&op>tbMgG0;x(VIT8(ScQ8r(Dw6TFB#Zg479KMcwd?@u)P>) zulumc21dV0XP`ac!$uewgxbtS$)fIM%R&qDO|t$dT5meeAty=U?_04+gu44l8rADe zFR@`6IR;5R9WG+*QOrLzS-#L%t{GOfB4#y1Rea}*RaI5`umuL@^&1ZcWen_WANE@V z^E!?P!*n*VV|>`v2Iln~4~FS%U|oIKXan=Qjt9eZHZZwhTR-7&1M~Wh2g7tWu$O(< zHW~&Rd!5IFVLBVwoj$C|z`Wk$!7!Z->~bIWR|7Muew(Oz-AH1^n%RdS-ACJRum_JV zA=IsqG}3>xyIih0>?zL*eMx0&^j`G+K|bmTgGw*YzVrL~PW%M)_4M*g?uyZNTxC${ z<=GQH>Uo1oFVAlEQFj3BARC;;V!$;*B)KBHvSwFPPv(>&l zJB>j1YlzZLj}PU|*Y|BU@TCWOoqE1Tch>h}0jeE5%tzg8P@VL>pj6)<;G?cKs80G` zP?^#-Hy+@XIL4ql>3cz`zHjhRc?Q)<-wR6h{bN3A2j9D=z8940`x!p!eS_+x?**m$ z{v03mtU-0s_kvP=e}a#iqo_3c{!I=518q7;OHcE$vA+`Po+D{|eLq$+*t36RdK9c4 zU}}+G-+$KE_fem48sT31$GtwP#-P&okE?yu-3FDue~j@_R~l6M{*mXS ziVZ4#|JZS;FaHcGegAmhN43zvY4!byoXO|w`$s)=><|Low`9N?{r>lm z$v-_kCi$rA4Jti7PV-R_gGw*2dikiI8B}_DeCzXxoHxgJr>DnaAGL<>mHt6Pv~#~d za{sfBddZ;D(_^NOy3?T2)8jlJHN~KQDz6^>ww)gRJ#_320^OmK#IwJ|VQSWDY?SUa zmCbhc3^1-nLlQsmFu&{L}AkN00D(+xw5v+ny#~d)uv&xo=ms(Rb5+M)6lq(&)~1 zm3)=b_iZ0_nn9(f?_YdWFM~=?-4eRm7czXebk=~Dm{Jo^HDPm zDm{I_-q&l1^9(9Iec$v^gA|p9zLzIE(AV+cv9k$vceQRGA&jLGrvfXG<=~-ZvkD6dm=~>`;A9cK<(y+j`;7mf@?R3Wu^Or`g z)`(i|(xz4m4>r^u%CA+uj#W9LRzLqzN&WP9en&s0*zf46hoSPD#4D8_popKU)sql% zs#d3K^j_3zcOP}OL8Vu#>yTQS*RckbUai*psGvcmSF6AGQJ>R1@IrdETJED>F{t!v z^-Lf2TZ2lkRtNZ~YYZyATJ7Sa#v0U5)#@#*)A9}W_dJCjyMjQsmn2a+en=#7eU|u@ zbUoGx`nNTE8q{S@Jd9^T)`lKhRTzDytU`r8I{FCZ2LzWkC-E1k|^6Edx|1(wiylu11@buBMzN#&)BJDF)2=Dj=aw}^0# zr_ABTG3~9IVG-Si-h!*kpZ{K1#IY(LMLAWaeFFS*odB1e7Ho9*oSAR8J2}TqiF)$# zJX4^|XDfr61@UV4G21U&beMWP!XIpj7m9JP(;r5qpL+CAt9(@YsYeg>ypL+8 zaYYJ2%yt=r8%#^QLs86_rk{HBP`~m~>8Bn&)Xz82h%L|+e)X6n&H>^MaGUU~b} z3SQ!YqY8!-3%foc^UtwClC^Wc41AJv&z4mf zlUUdnh{R0{`~Kn@sdrS2Cd$1KPXXx{GJj1%NuQjc36GY9z%@&jN6M`h2TF>0jJv&+ z77RAJ#8a(t*{m15Wh39Cs~6sRke>4BXPWVqWSk6WjvpM@VL`}ZUfe4TW{hAyEtTs2 zqa)^V!5nNVctnQ^zM#WXB7i0x_#kXp==lMN@EkEB7C# z{6?vHfJV7PaC+#?l5mt$0%i-ldt+7(Q6nnT4s5Twv2R92|FC$j>(*v+_J8D{tcFnE zfHg27)UbNa?fo>rjiKCbbS2vf<*69yA>2?ih}Bt)?>5WKojPL=Wr(ZGY`$rh_^Avj zzGr!soM#c1wc@2+6t;y=QCNe4VQ_db=I#V$mWsUR!yYv-EDjIG#J0f9QjsTpSfzns zb$T#nwgqOEirnhM&NeXQfd^x1TVQ6X$V4A@jDcZvcrbhw0y9fR2K%tC28Pw)!5CNw zEK9$1Umy0#=h`5c9UhF?ZGoAkB44W8lEoP>8yFgieP!EdI`w()uwom9n(SfHTty@a z8Dgslb!U;r5ZZ|N>okv?h#qdd9KX4&(%eZ2s@Er&5^y5P;l^HNn2lJjIe*~8jx#VM zxg2in!I+IOuxEW((7><~*eB2JikN7J|dQZtk?SJUOM;RC0;wXq4~{}#OX5B zgD&UOJkz&xF4Neld!hNKIbMSeGqAnTyvB$1G_bwU{4O81ffm?1&8PUVg$A}4numPY z!v?k&njhlBDhzBdH2=Z(r<`eEd!hNeKI~`%`zg&YUDJW)5BPo;n^5`X{eqS`If3mqkdppqkd+heu_l>yl&LbYpQ;#3Nz&kIR+Xt8!cq# z@tNPTK8~IOlgnrRVU>R7ufFm>vwn>KnNQutXWk_79eT_-h{e`T(_>^qlh~lwDJh}Y z@fz#*7;lOaDY-oFco4!%*?Bp=q- zz`P#g!H|*$R^Y?_xmv%J9>emij&ruh!DVeyva1J=^&!-)BaO|rTRZzZj){P^hr_vQ zWjv+1$yxB8A)$2&YO_-HIU4Ps)4yBxj@PY&NZ&J*v7FERI{m`HJR*58h-6^%eAsCQ z<`Kz*K_mma+lL)!U>=b?7(_C#D}2~SzKmn@JtBE9h-6?Reb`$D<`Kz*K_mk^)Q3G{ zU>=b?7(_C#Elf9<@xOt2MDkz|$-v(8VWkEJk#>i5Ju3DaJEa@Ar{x2mN;KdD9zHge zQ1?(0brKVAAamQq#1LNolVajxUrhYbh>3?iG4ZJ^$wf@?*B28@2(qgG;rUd{SE!gM zWKFJ7tTzny#Y9ycF>#K>@1e3EhvC``XJ2~#L~`w|N@sXgVyUd?`O~#JtGo%7ua|3e zp5^o*Qyr^K&wqCZ)p<+fJy%j)n;U7X9BM>n-|}l!bCj>|G`!#BcPaUq37YCt{m=W8 z)-_3WI_a>eLKJ0P>+lzQ!gL_ePD>AUX zi02o5*ue(27x6sThkd_NMc`h<^RIo_I|jBF@%(ci_PBxVMLZwm!)`XPy@=<{_$l>E z&oi)}isuA`Y7@^3Ja}w6q3#i+*^_0KKqg<2cQv*wioCp+@UYS2_Z>5T7wyoqG`FhI z&NSRw#IIF7ojMC|Y*?zS|KcY;Z)6wxth#kJys<>$4Xd`<%e%Xh6NW^wQUmkD>AV5ky)n! zamHNig?YWf4> za}~~j_$@-+sifhAfI8WtJX<7fdRDDN@`%UdwSk6JD`C|?1`Mm-&#zTo%8NG}GyGlU z*5DeSTNh0AnahsBTz!eRYQEDVyQ4VO8@hg(1fC|d;Ii>UoFwSgXW&=0_ZAaPJvk_r zm4OkbQ7*I5dnj5)(?OhSANQDtLynE_+J?h|F}RC;T&0IYkd5bnMK3>07=s()<4Qdo zl59K&EP6O>7=!DsIP9wd9u849o&y#=97c@6eT6NqQYFK~A1yU%g z`)WfD(FAx)pCZ&9Pb$$ltT*&Je^ud=t!QWDiZfQmPY?0N$cG@2QzMrM~;u<7NRwTs=!dwotmK3F=D4O%~ z6iLy1x>W8ZNnzD!ke}i)NwNHGO>wxXqn7ckrnpT~w0n28jNeEKS$<6!8}F1_8Mp3C zO;IW-_HgSCmlS7h(-aFxkvv~|tiK!}lM1tt{i%A*}9=yu$>qigqHPgkj zAoU=LPZa)`X!C<7Yds<2Q>I5RP%i&Z@V{lWCFDe}`s zE%M0^gr~xJ5r<=fhE8oO_UkH&eMK;d!s-si_R?aLoH4&AW!@*ueSsw#d$z$${J3VA zHBz3;8YW*r23me%*6wXUegg%F-G{I+mUi{k+J+ZOI2(h_2YtY?_QtSXc#PkMx$-d^ z8>DK|3zzK8!|^=Z4gY=piha9OryZ=G)t+6t@<&rYM7USKJGH?VNH|w+Ncr*L(6;*h zWq@D5%3G;lMC-Sn`n6DpQV0qcMassq@l#iQadt(mEEhMf4AW|yh2pz0_GT>?cBoav zDaylmM>tg#=9^lr;$jSH^(e;$ST)OGfziiv`l3^3Jb$0xLd9Mbh>n)O_ZrTtk=C#1 zI4V}p2`yrV*?}D#sb+8ctZIgMS?olJ>NShXyLg|hhLPfB@rO^rr};uUzz%7&k>2p> zda5TEAXOE{B%J-Brg|Av&k*(JZA2XhJ!2t!D5ilYw?^PtF~q`RrynTPFe8-s!(2%KbqZz9Uz)H;%Z^+W9=K^J#BX zn@!%GoKMw#Nuq z+z|XP^4OC$4-n>_zl9WX8dr7`;*%Z9m93IRj|8IHzen(i!V_n=@#Y+(WnVd2m?N>ZQ-`x^ybc#ECqg%m z@g19&?$PM8k8CUKRh% z|Aycf2|iKy%iGmH%0r}irbEQDOTIcuK59M->cm^_?a-0? zhqp-PJubcun#yi-xc_L#KzZ{aZ8At#=6PMLts#9A?OH8#loZ<0w)0!^7%8nvETVYu z$@loupLh7u!wzn1$)O&Z-=D^pu6a}O)4&^!xEQ{Yej|6@kkKWQ(dZ5teS)O+=?^~( zzr-b@drU^h3%+9$Z*1=euX*^31pfG3CxMeTxwSxt5?hqwLVdYO#2Q>8ufYP@1Ym)jrV}G7zQmZUn zGDr%2#7ov@zy;?D{zoY-9?aVFqaSUj&V%r`H0mi8eDv@)^xM`%fAVc*TFj|?tKH#J z+T+_b^~0owh0<{G;hM?!-~VeaUO~M35qatPB62=+@9EPxyG9T7JJ&I1RnOX(6jqM! z!!_o)dN+I-QaciV>TY0>A&bf-Q6%|*T(;uC6$w&V}gEMbN0}kN)MHYL=N3Sb!z6+hJCyZ(8 zWF?Jw>183OktJxQJ`NBq<>92orJ!U9&+C+&I3}P(~iPkR>i{Y}!<6lg0J4OWLSm8W}=J<9lQojk_iG4-qtQ-5|K`36+kV zshQm9;0lmywzYS>`z}5J*4c>%`w@QiGRD0B!%d}D&zmRlFm967vt%j{6Q)`{@2{e8p8p`fR?j~Q-|_kv<-eX!JjSaX|E>H? zc4E?T7=S-7fsHYr2d$nl;XZzZQTbVIeuTA?>sW4d(coHhID8c$(!Hmn!jcP)6?u5? zw<2S_VR?)fVTf(e6lu7lL0aG=+u0!Flw(z@>p^$PQ?Hkfwmx~xRJi_a(6n*re6DJd zd;L85GlBgs1N1zZgW4}J8le<8ABob0vkZ%h$-D*<>9s{im`GfsUL+1MiPX!A%;~u2 z;}G>C@p?(5UQr~UYSo-iFZLpFbxEXNO!SV4#QEt(;@^@;y^iQv6N$^yi^QoVk$MTy zJth)Irx%GQOCq^?=*CLQ!?o!};JT6sE*rY>G9t{`RZT>jv#XkASjO2^^%eUWAm^&x z$oYZ62j5a&J8CAHK#$SOxLSpdHrDcp$3Esn9{pAfS+anu5t{7M`@jyD#kxA5k#2h>xID+3($xuI*- zj(e=x@9WpD2$%J`HxgJO2h$&f`!$=Z61XZW=WfcI{*K%>GHa2LwS(YhNi+t0apK0i zM-Sf0jjUN_f0f+tzMH$&sUl5-D{6!-cY}F1>4dXa;VU)kQ4i#vZ{)b%@wb~*5fKjE z4sow$bo&9;>=tGdsMFj?U~TJK_PZoP3|2TV{~>ls;d6C=#rMiO*{FMFm~}v!W)W#P zS&|j_t6Q6C=0S_JnG@o`O7woRQd`@VlSbOlZ<6!Nw{|+e+|>WSB(MK@{Y#vwa)U;e zyNFU~Hq(q+;};|(nuL2=+$S}*sHH>nZwcaROxnK7wl#Lyig3IaTBOwEHjT(1Le{lK zEu@}oHPi+|R?ngq_fpNLv_(pCxPH5IbJ!_juX_tATihazr4AG-0Ii1H>lKcp$Xn1w zmeZG4d)pdPyFER4e=S8)xw{dh;W+QV3vU}HAzmhO@SBu5upPRxBUEaj=p6S|FPx)! zwI*H;k4x}2_ENOCztcylk$WePw)KX#f@zx^SI)97 zp+;^9ITOV>U0pdJ92%8#%=aGjnLtyLSNVKumYz0)Jp|XZo|T?1mO*gDy9kh)v(nSW zr3tmg&oHR;bXn-5@(n6IUH<5!c0+7ROh=a+Z_?5}F^F_@x$y!;n8TFP(&ffe74Z;x zq^AoWj5fN=nIfEL{It<}E}XWrqB{_~v&45?cFz6in+@m!=_+HjQhSi%BEK02nkuI! z$50>D)u8?jN#v5ie@~Km2K8@9B8QWb*S{gjRR;AhND?-Pe?gL?4I*7v@kkN`k)9-* zb--%6${aaE$s-BtZ|DQ`>EdlX^_)Td8=i6u z>fdzpGK2azJXL5=|AwayGN^ySQ~zXQ4c`10Jhjpw{sm9{14MeBdYIEZeDOPH7BG*e z!U6Oj^HpJPQARzloTMt+J+wp66cd!yA*j*>{gX_E_JiArxmL!nF?R9+qmFtkP<7ONpPGo#-x#fQop{Lcf4-uT-(97VlfB4u zhz!R=Q^QV?HY68}$oVJX_}Nn;)$unk^(ub{q+aH4R_Zza=A{10-`vz+!ttJ|N5b)Ys?aB?`w1JCx{JS+ zDTmrja<4%L@i0*>V;)M~i%f{^jyDfQZrD5wa*NDEo_nf!7~q~@9-A{jKN%?Lo0-ZvJxpLzz50$Rmc#EB0wY^IPR|Xy6KFE93_NBvRv; zOmz2AJUGgLkG@igbBN!ytfA7B6qgo5j63){F;&gqQuikPw6ksZdh<}E z=dBYp$eml_RMM$#Fk754r9t zedwt-4tvbw)|<#-?knb@(tVx><1mr4icuw@bHmO*8NmCORnOYk!ssuOcrCvP@{7;# zF@7U>1MlWn55nJ$#~|4w2IcT8#B3&IBZ;~Bn0w}Mjfk^DFBMs498CC>BI3r|mR$3s zaVhm7g}9VRAQ}7?&1c77%U{epSB_ZKzs!+!sT>@PV=5WjBpgJKDb8mMA(t_U8%v%B z$yPxRs9{3-He%abinmGV?7PgCV-m^@9Ar>XKZ zMV^Y}sYr^c@`}lm;7S>#^~#sO7w6~5&#&_H(*z6;+a2(mesNwMotx9PmQ9x za;&?!eJLZ_vX3?USg727O7!4biJcvxc*g#Jiv-q)KcaegGgYwTnOP}D_1rZGTWF9R zB26uGlH6N|Xy7T52)=3Rl%=zz87Zy@H0eY+x~K^raC`EKXMn2ME*Xb?18VKJim0Zb?r-r)_u4SQM}w!h?oh>^?^r;eN8!lu%RFzomk@9L{h z4M0!GtxqzTf#IO|xp<4XpXd2VptjZA&olq}bJdM|Q|I=xSIWnQd3eXg6=>3x!$)AsJS;a^zU3TuBsYqYgt3D-jnbH8F3BTtp? z8hv_AS;Bo!Uxw$qi@f+;cY*hm<38^_Ww}p!PXpYCy{A0)Uhip;JI8yP=-%QzO>)b< zrz!50-qTc9uI!UK*zS4WQ>h#Ao{HR&Jc;-o<|eS!MJ!jrn=ZF6YjCA2*O3WefP1y~ zl;{3ZpEC2^3%sCQSFVc_nC*`Co=RQ0EJMO3x`Vx^N$%0!(-ikG?`f)gp!byHW_wRr zZY##Rq#fkS2tl5T+!Rmqe?wnzH&JVh(uE z4ZqQe_>LdxW0W8|EF!8hBB~NeDNksmi0D5gfjkYcow=UUMD$B=r39lsnKP58A^}KK z$qU+&Kk|fDWyVaN(5e(7Pm|;ctwq-Igtp{Wp0pn5SCSdOPubjj+_d-`>fBl#e0tP~ zsFkDHsTyvtIE0h*|KZx3I=h{!rD1-1s(JArua;?4_hq%@psR3AZpY?PW9a`8h26uw zYQYm~o_R!s=iqXw<^L1LbH&9e9I4f!G97tK`Biyqz<;?!h z%sUcMWaodsX6;R9OCnnuu~eS^7qZs9Pc@3yTAE*bYw7F1B4VDDS}EnX*Qryx{jaOF z3!ijbPt;u6t2OC=(^Q?R)!uH(5Onwdo@R0^a zbeE}u^oXb_+N(A7|CegDx7)v{*07G%Qe1nrpvQkmCu#!>lNPL$GE3b*;cZSvP}u%p z*bR#}DAD8jVwU>lh|!T4dR#ZLqY5j&-`JWwM25YI9>Z=TTGoyd-NQuhkF}Njk&)xO zgKMkal<`?cd60{HiZUkPgk1`7OR1FeVHz8QfuT{N* zTFQEu-)n8pm6ouinE1#dyI`>uTSGWs|GN2lW?C2Jc3fW)ADPQ|;G45ph7f;3zc^9C zcs!=fQP5D1iVmx;n#f62O+dgdV;g1>*K!@8FQFYdky zEMn`#B04tfe)uM?t7^NiPFgw3Ywt}FCo^B#nV?8KGoQwF2a|qp?Ry*rNc-mVo3?$Q z!w&hMwQmCFJ2|JiTf%Xf5W--0tu`yLnBqka4R zg7*C--n)k2X-hh^@A16s*}h6%ZDP+)^51D+J3f{Puw)KbBoDLWm*v?GZ2oAK@RKtU zZxD+dFXM+U7eAkv=>zQewSyw@u|<*iS#~6TerY6r*~Ccv@=1~SwNoPT=~E-|TPyAO z<-;z!p!JJ$WyMk@Z8fWP2RTk3X_qy^$oKX9rq$VH&FedIa_r;s<0nUdY_$>&u*tK2 z%xIl?a@CJLtl2m64t4-ot7c)_I5>G|Hrom^71p9-el_9`P_Ea&062e3hCr& zx>CGXz87ytci`ca1qJqe!SnA{mS@;jxZcerl$Bl_Cbhpl@!f8wKIQNvb(SQzy3*%l zahmO{o&PS+c&NBX8DPd6Rs4~QW9b9p3d9tbKY8+Jko+l3nxaE}>R&eahmt?)~Opk<&FJmB~!gLL5Xwx{EI1Y2!qmIQL+1?JGYczX;b@=S7@l zx_B{o{A0498u`Vt8boR>i{DmM{18rL(p&?8@`d+?e^ak6rgX}n+`4bu@|a0$8Dv90BY(3ReJRIt6@lpkl1?VQBT zz=2d>JN{C>kd{if>4sDl=<1!;{ib z|G*_C6{wQ>a7lG#`FKP3_4Db38G}~{so@O>4-$H3=1TxsWC#yXZiW?%)mEO)!Yo-u zmK%CS;@;>|B{eEMmQ`t~W2FEU)dgnkQSq=HeJy`AxQvQ>Qa{_0s^|WUtZ+e7`GH$U zcFQYg4aj0ENPFD4eoN}BhT#3LiX@n|NQknKKE~?S+VR6)c|?AWUm!mPsT;Cd z55$$4mHGh@oCPIW(puIawC_)+b7}vi)>`hfQZv*|v7;$uq9iIS;-jHP=+M3bHA6aD>B$j-8s5V(rI16@z6Za?}mjUB~9xvA4@3@to+6Zsi|G zcXX-v947wrz0{J<@iEgvnrg+Y9cO=C{;LW$`jrkSj`v8QaUumvrY*2%A(g5!!q(W8 zPVec2rk*O1X@HMuGFFr2g}YA8!MYfX--jh@18isL2|Ut`PSlX1L3U%Xl4QcEgbvim z9^(nI1Ke?FKvCw5IpetM0_yG7xF8_RoD z4a=yoV1&_ zAhj$K51vd5PC$k@Kky-k^TOV`R8LgyMedW-nO@JV2MaL^R+S&jLHBmS_VTr`OT{|j z*)PCxJn0&F<~E}t|I{|8p_b>96k&N7jr6v(juTuWKit@9JAIpMr^k!DUbL`n6)~+f zgDFV;T)x&>nf&%@`P_!^z;DYZ$>&}~8CTM=lPCX%h{ViptOQw@>`sX^ij;MQEG~7v z6*?^gGO8hSNa47|%pn1G3fPGWf#fTMUPO~z!i*xlOu9?xQWwpfk-Pv#2x$j4dOStX z-juujmh))jMQwI=DmVKjYNF8ozJ7SLqtFgdy~kFDpN!a z=4s59H>Haw@1e*yZTvGDOt`NB~1*oYrKqtbP}4GKk=R-K>29-5Mclb$&K#LEFTx$ zy-)cS(cRfrb%O9&ySp(3X~nuKJKKc3Apvx0D;RCrz>)NlxU2;kcFY^1_s}C=bn4*n ztR+bCj5kP-F<;WMdmR-|cRCXkA23msi(VqWdx4l9SBlW2gS;u|WCGd?S`4KNFGwv7 zX(pJba>7(w9m)@Y%@2zX&+h`4WmY`BZFTDLH-souQVUGoPX&{rJ5q5SG!nc-t6$!a zdhbi@d`~hrHg1qsd=9L8F;AMsQq4tIU)W_^-IEBP;QSDVj?s;!oX{sD>OmDb&g#K$ zBYZ;{2-r|YMV>ad-@c6aI<&gBwy=P+=1pldYIS8s)zT_m2ElQDE0Xsjt1i62H0;5% zzRW-kmG{)oZ*OHQm=tEF9ZQk*vsyDYx3*4az}_OQiV-n0KP$OH=X`kD_PH~xZLF{; zcVXxpHFB|Moh@q1%-T3dh?0<%1hO%z$DuD6qqYu*%QyhfB@?-=2W~srIS;?EO%*eRlQm+CS%O98T zpX@?*zFgH}`M5Wel%`yzd$wHiNsb^bDJNc-dKW%(Z-tE|SE}c<&Od_EFjMR0!+ONF zR%Flb>xI~5JCcuzo5BC8`DJZiBGVumE~|WYa;_iB3gO>f49{)rtg72Ua_qo*5%e$d z>?@WS&+*_H&j-*@<=2L1?QFF$n`WGmn0Zvjs~L1|+IiMm3A6`(ICyLF>C25yb{er& zeE2xoW0a^8uD1tnXVl(e?>Bw3o#vv2A< zxOVUgjGkz7Uio8@__!?cx9+Nw6!8gpESL+=YL*77e!Jov`d7u#6j>5`+lu`S2(@?) zaUH@SD=Ax1GVs2pCTQ+{BdKStm1H1}?<(%iGd7cOv^6iYG{iX(C1tgdg1YN#QZNtM z)s{aKDR`&64;h#LjU*S!SR!8BRO((xR?#G<`UJ-i7H#P_?LdtPHxf%zajKpa_E4zm zwT!8V;Ie7WQk!rYI|VXp!v)n^qwBkcqB{<}<*nFOE0zVMOo2?!Ur0FV|g3Q$Xqod3>S}(fvS5O7wnD2Iq-0@*23(SuELtHfis@kH|)LhM-cdX*M))@pIV(wlp3vF4qh z=V3Jl9|sPWf`*wrQ~OU2&1$Z-_}fw|pN5+(&)!xqEK;89@d{&ZyKVzckPS3S(=-8% z;wZN3cG-5S;Qeo4J_c`YxDa^c`ZZRfB;s_mX8a>N9MG3MPPco%N^^%mi2C_ue4 z0V?yrYaGlkDdPJ@oG`s%zp#@HP4*3+PG_>J<%VUuag@q^yHPYdw$nnZ`U}FP!%7FG zYf4wSQ?{Yn+eYQdr&!e^c(ZDH52SB$b`fXQ@D7pZ^gf6X7#R+pevnnuBTG8(LvX{j z^8y)j=5{Hi5b1F8$zF4)&DluC{Ihy?wR#d0?{OA*#yVE@k5aC~x5YWYY(Lw%fG6IZ zgWVHEW6N^I=i%Sbx!wREt7vPZVXCn()%m-f2Kb34t-2MKIso-YdzYQxBCE9xPc27c z$wBUAZ`%XkvEx^57HJuE;i(eCQzdx_tb)bDQzg09U%nHTD(Pz;Y{$j+ytjtR&iX={ z#x6Km7;#=jp7Y)0I=5T&ixE}ZPn>=VCT#cCjjg=G<<`9JXTnZ(#Rc^@=KwCDr4=d> z%1w0z^)oH@%FS8_GtJuV@zUr#`>&?`MVZ=1X@MMVQ|H1>xDyJNShqh)3_a?sUCxq_ z^Dez16#c5-*3o(Wtl0CCDBhmQW9^yX@^zo#)hX%go+tXOCRp@W*{fPnjI=LiFY}Q! z7zX$}LT%>*#(l~9Uy@zy8>{*#5+v_sHL)t;^~LP7WO(?(0681#Sa%=k>xsf!NSJ)@ z7wDB|)7GxK5`mSXA9Sv{HIMoxhBocm*y?d3vUQ9c8T61&Z#ThLZ0z=GwFkSf{(S5~POVT=pB*!e8c4yezUme5XJB)20i(c1?G(X% zo(^Ory7!TNzJDjgY1(Z4qogkq6PrWaZt5$-tkm&pPCR%q`=F7%8qDo3GmZ z8f2L2e@49g2s+T`I-tW3nw32CGGUC~6F@Ua&N(BVd4!m;jFwvtuJ|Ukv@!S+<1Xk3 ziYzGUG2Y#AVi+~*Gf^4tZ-vs)!oLwm#r`aB@x%6)j*Lscd^kp!RsB23B=I*fUFM6G z0e4~R6(r5RJW^jHsmXN(eTw|qeJ&0HB*G;`ye@PZykan}fwzq(z+UOPVz@sJux(Qoji1P>vHz_x{IEjfoB#T!HM-5BrenQ&#?w!qZra~*~X zgKYbF)|UzoEF?_ookyn5VFl9RP0io3Vq>UgTZLZXs1k7u#|wJ_dP9q!wNQSN2T0wV z<99OJ<^yL@FlBOn2!GV!WxzP9o&rew-;^vwqC|)Nto*tZHr!!lq;O@diT7y)&ua9< zVKF%8XnBV}p-n!IVTP>q!eEX(`=))ENeWVfTZCQTto9rf>I=rS3hf}%lGh4d6H(K0 z$A9t<>Pc4r#45MLEAVb$yYyNMcg%{9p0z zUP!vo`H@87#RP{qN+VLX39C3!vTupA(fDxS@n!fw%`^?OofH?l3ev}C;LjhK6>F_H z(=MnlA7RH&W1u2 zY!_+FTqc0jQhDciD6YB5)2?3}Kcg?l%O^2M>#XXNgp=Ykax@A7m4zr^vnH{qmg3mr zir$g<8Qd3xjk6j)-_9Fpk%N6B53Booxpa{*a37X~^8*IBp!+yr-Vhw>2pBG0OR z3+}YzTo z%lGHo7R&fd2q9L;6J&x%D$#rW){U*(R`*|gMeV?KSM5`mJk)w4 zvkM)nqrhh7wvyf2t8n8} z$qeSf%HE0o7_h1z7E)sFTF-If!wgKNR&lRew}+`(Vz`%4>u7rUcC4&FOHab&vSy2P zC@EXbuyw3eGq<07iMRu@czd{?7+;~P?Pa5#H6iOkn(Tpv#ZIsM(HKR)pzW3yAKNRR z0Yvt#6GkV_4hS;z$^#&Y63VWSKfCoH&n4?T|`Mw{%YHRq1Q44V-$v znJF)qNKeNA)Lko89O_m52+z^Fz?>eN8PSHeE(%oa3nTWk?tGdEhM_lPkFNgMiajT9 zW$)OH^~k?g8fd9KaETe_MiS@r%o!~L;Sk}mANR5D>d6C8rruk_i8FKTf!}*0;>0<9 zdWlVR+j_~5CLSS8xR#eh_d^XUV=B`^*2ops$kpy*fhBtMqHd8yI8P4ept9kDw`Jf` zNN7O6FT`|bfaKw>)yt&&xT7c;<01M**XZ^@`H9i(UCKwv&{6grNh4L!NF(GSPs%@% z&{u*K^{V_y4e}7y?Xo_iy(v=%NkoyPkUdAQ(Citn${%eG(=we~#g$Vva-UeUM5Y5Wf(T2S=3kAJH?4ntw%|33uo8Q-z>k| zaNVDq7Y#o9H=1GrRl(8^6s!(eCAAR5uGc~RxWHT$Do&ll2(2O~nhMYtSFVqKDVFF6 zXM6OWyina&-LO|f*`GKix$&EGaSW_nyY0ik4(HsywsV3VKNmajjI8Jv&Do3RjLfp; zU6O~TX3|io9lbd#V{)pW+4u87#^&CHPpwuGZ^?K>`>xk<&`18}76j7Bxc z5C5m|$g9KRZ8t1~2WptOzPnwwDU-IooA0r1uj8*BZ45X&oR;Mq>XKcuo1FT(4c<>? zb`uvVY-{R|EztWD7BY1b1BqTSa&1kF4A>9h0_a}E{h)G`?${>g?2&nyMX-2uMTRsC z>so{oKeXWThY-5XB@uMV5=ZMOyX^aTZ~MPw95-`YDM^P+MTAGc%|xt6%9d^&o7b;m zI#Z2#VQ*}CrAN6igW*)Uvm^BfGprh&$M-O-8ZG}BR|U6;{f=#sm%e3m+Q2;yonbrI zWa%3ZwB7MTl1!)kiP8}T{nV{>@`)SHC_=Ij3G1hysbKY*_AZQq~ ztC{)AhA}&-{rC2<=jY5BvrD!T;VoeFEkLK9sabpA=3_JS%a3&G^(>H3L*@baUovkg z4LKuszWEsR3^k1W5p8$gE(TM99f_L)bI#kvIi=n0S-;Mc{=qVWU808;*GdVs=p$Sn z>`%q3_5*#0@t(UDzF^XXJnGg5Q}d*4Wdp%A8RMMeHo33kbu$hBB2V`G-R!vI->ovo z)jqDZ3mUE25P{Fxg+55NVzsW&0ALXVlFX+ozZMPdTj2@&H=(MAgnksMAO<|r1R2V&^mz__9$e)Z?2C9!WRDnrrTU2nO9zx}MczN7j) zbz{GpJZ)u7M(k6b!qL}07tzWvVktkxTmt(xBDaoQ8cW0R`x+&Z+{$x82nO7B-TCdy zFXQ0)t_=FRTeI&65^|P;vZ@_4WE6fSkFP=e;jQJ@z+iKN z&+(F+|D6bYnSv~z5pgEvaJ~+fY`&d{$rai%@KYB-sBv^(5d(IQX4sWCwG>&zkQWbr z`2>U2i2>)ZH9WWnz;=A?3JOj3ACGpL!(xm~in0@>c@5-1+0a__;qin9+#5}TKS_cY zNMNRSlQoneuJiHIDx9`0(aX<9RemcTC+FK@W+_{67=)Zfh`T=FvQ_cJE}#ODvdxhA z!&28lm60$k2`?mH$t*}_h(hrP^sfD;gFm4ANaMf3fzFjVi^K7o5ko8Ofk_5LnP(=7 zPtB22?&`kH3{_R`VrUe}+F8CIIhA@6h+q{#IPf`8>4qUJl?vL~_<Kv4WS=1Mq4$Lc8MD&6nNicv52$l zbjg9tiH9y*=+rBwZf!92Ax)L~w9N^2K2EUdcvhR#6NG2gxWUA;YL`v#;9A|RJ{5al zBTE388#rsTeY$P@U$*+cmWcn$7N4rf+PEz~Re54-Fk{`j{{oNr9=y|}J(2i#r4_JeGz-)hvBN3t(o?Bk9%6P!miwCR~57_mLq)OYosl9z~YMU!{ z6|Pi>N=|KV+z9?##Mr&5jnWU%R%aXKu(b#UI+TUNoLY&EwI${ z?XsyIcmVf$qiG<|y`I3m9v=@Y%rLAlBQLtXU%_@^g&D#Mjlv2ugcamTrZnS+#r`C$ zuwKMsq@W+Hz_4y4?)ApWb(^|H*N-TwYCUoKMT|Fhx^TmK{Go5t7l&8E4$FN1`V5Gu zV2!~DC$3=W%ps}4$zwj}DotJRDYVjMY{@CdIHJU(@nspZF@ zPx|uhPZC94Yf5*GcAARWk1slXUB9g(Mc%(6>EazS(gBOf$gP%0=lj7pkn0C-pf4}q z_7UTQhRppla6jJC-#KsRE83UG{3tUerSxUovVkSVb4qu)!yve`T!ZVr2&TSbEl6q0 zWT$dBk|W?sG2DT*i=Iu(2R?M)BOrYxD{{qaojT#Cu`>Ean9fa#%=G=tXL&wv{2FrR zI%c}es?hHuvYAfUn|fg~Vez*_%FgO8fsYZ~A#ANzAmYR4uMkeMGR7 z1uz>+0Ow%ry%;zK77wrm%s$-~U?ywzE7GSKJs1JvHh?~Bi@cC* zc=G0vvDVi`xd5F>7_MD+Mz@ksrLuaL(8c3%%fQq=%K)rbq6<*wftGi@d3@9U_SOY_Zb!oeJib1qd_s&XvDDpsTN;7J-< zkV9J4jPm@J8^Ztirf@ZS^2#f?9W7y%kbFc@i?(% z*=Db?Acx~4ChLxmy!j`Z(~{izyL}fLZP4fEnp4u$k}WoFi4UUeOLz{O!FRN}VDO`& zpI*uT;?iZH6fq~jREcW`l4XlJMBLacBWyhl)VK_?@msll55>L)Ds=A|z{vC)HW+w@ zST=APK0m_~o|SacXpNYu+Va*(DGSe^q^uj$v2Gk!){Tea){PJK{DXSYCeYD?i6;LY zSHKpF1K$=2OIlnhFz+M9xM9k@u1(wIDcYzllT2lzIYykYQAY_9+M`b4#-PI9@USxa z%T9tAw%J6gK*xrB;~IFC()Y~Cl{;L5fZ-k!f#BcAw|&gD3&j~JEmPvMMTx^((T2t{ z^G0vc=7mmIxMYxM1~H)XFvaC5Y7Mp}m1xUjNI{QFOul$ZY$nJEKSd?a;;Afb8vcg) z`#CuXkJ$IksneJloESd*MEbuL&zP?MWz=+2rAJ#5kw5E6KD#7>QH9q8#cHWb8AFY%yyzxaFyPb}4ziI0G;6e54V_iLoEJrwcO3&BbP zQ$4bEBtiKgppAmONl873P8q|7!3@d8*jz5~?DC*gXgC4$8NKX?_ALl)B)DrSQ2PMp zMUvxo>Nv@OSVyL48MixhsW!mb0;z;^dmWA5G3zU}JWC25KBC>e_lS1u!6RD6RnPJ@ z_m`F3Vexxw7yp04^U-V6^EnU9;X&#{(u7;f`{0N+XUbeUHRt`xQZ27h{%oyuX?Z7( zlxnv&@V57eOS^R|7o!(S1#a!ucjVP>n&_tekL262*UKxOwoBnCS92QVYMcD&j2GW+7t-b&Qnh@6$Dh=)Rqj5NPa5Oj%~>nM+?y!Aj)wPBZM!^e=E9=t z54c%kLW=>nJZIo@-s3qyxmC)j_l;7BVcoi!Hyhb-CfZXQ{^>Oc>^$E@$<4u@>$GK2 zrdZ(CvPX7%Z@jU=aKQg3}*cdX}U^z*#* z405+F;xmCNpJ${#qpG5lF6Os&K7-mo*)38tzfvsqUc0qn57|YB#qS&A<(l~An>npw zIuTMU18-vN!oQt}Sd*^y;@;sY+EVo+7|0~-*B_CT2B@JbfsL#y zg3^KXHeB4{pGrapRLx7ZM^OSMDJ-OL*JLpZ)LhPjs6O!)e>q%NUi0u#kpXFY*t+jp zB)-UNh*rs3P^-oMuuZG^LKcvi@(=W_q@<)yR!jswxN0h$@?V$ugsjH!#x;#nQd}sy zKUAtNo;}OKk_RW36n1H~=g|fOmo)*$qi*IjL{Bkpo<4E+!5`2 ztw$ugN*>dJ`Aj8pa#in=#qJ7MI~aMeXJS>$$}7=s$2|ny`RnDV;cgs|x`_JHe!pqK ze^qL?q~??p+3{i@;Hppb0+c0?68U!NSXD*-X0+CHEvCP>TZDkxBmRp;pm^^PCzdzt zJ6Fh$wyJBg-Gk^tx~k?c`o4l_M(ToFrPH@JM90c2VExNRSM_n}uJ+4FL5yU`W%dW6 zB@%`79Q1mOKQ);T6X1-T6ugb7mSFLs6Db3DMpmD2($$5R;)JnirCrTa_DrUJIme30 zWc@c}SO$Bg*NR1d%T2+SXgg5qMpKX!z=bL?$q_0RT#V2-AQqgzH8qP)L?tVvPLzcF zgEewANwID6=RF;}MK%TB<^$Fz^OC`Ag6ky5ahjPn42tikFH9GY_)8J~@>!)ezNcyg z*QwX2_qR4i9jdd3KC|n%9U7J~cFQgDapO7%H^pOBNtQ7SuTq=US*gu#snl*3g0+!n zYX#C=(}6iGv^fntV{P63ex-K#2M=ZX&(-53AF4b?4FhtMk-9=PF#OD2LQm02AN)}y!}<&r*VvnRWsUHL z<~psR=G&Z5*g^!HsB$`S^%Q@_BlVX9ZSl1%h~eLdSN2iaXM+baY&Xq6y)P)^A1Mka zOv~=LY1#FrAUCf1##+-ywHUIAZZY=O-$m`V_1tJNf6T|S9yjYDG*`Io*&YT{oz`m! zejjGP`hcDzANjCq1B`jA9k7CUQkqwC)Q1qNnvrx-SJpvonYanK>XrRE{FmGb!Zo6{ zCy>dLAEA?YPo{EIU5j}MA7dQ1m1A7c1Vt0(^5_`WthuVKU*3%Vgo>vG-kelGmE)V4 z)bXD14G!O^L?te~+w2-tRnfKFN%es@+F&$B*}2TrNv*8|`>Rat&Yan9^J`Nj@4M6&oDhOVPi}Z;*;fWcs-^#XRf#Z28ru7_cbxpd0S?#uRt#mK0z@zl=tYLiAX8jQT zq~OqvQv;8TjWK$6Zp?3af+rom>-d}Ozbe2n0pk;+^J=A?R-?I4wV%gmX#X;4A7(P} z$S`2?MHFut(RwC6v7QnoW1w)nuUpTD|DEKFq6AEuBG67!mCF$i6Yv@*>5w3URwGb` zN6wXK6Z3{is2SJuM4^aqe;?gWgMuQj^Hd)E_*(gGLRUbl-I-W#Nq1fJK3p*Sr|Hc#qZIH}WJ&&7)ek+K zet`}pMlh(FsJiQMe2fJoRf1fneI(8W4Q`q zI9?0#58zx?m8e=*0hlD0a$1saXHk)$7_HpkkhEzqjCMetn(ns+4j7uyhN84=@I9}9 zvJ<+f)mcJ^!5All7Z0CcPo7reW?KoonW+Y<)p%u-Vb79?9;VJ?ylZCBprE$`03JNh zuo+=rankDX^h+X9{!byl`Djv`{OL$Yql7WJLhWN>n^j7SL_mm5 zjF12)$Z9I|vQA3$&?0P%gxrN@BD1^k#Ybc54VC19-A*S>;6`oJOj!~T%b5gW&JtZl zo~ye-2JXKFU53z22}|ZcfbT=(jJJ<9Wccq!KjW=<4~a;{$|3)#n#5Y*$D??Ue?;&T z!uc9Wy%`IBnM0T>VHa!j@YjzHp)vFD+X+G@kK_D{c=MYdsW+lNv-ZeHvB$b|GZ`6} z;$yFUXg0IR;IrMpDwBC+d_0fZ9ze(GJ)Wmq>Pb@uo&86F3?r@pj0@{}ey=_10BB9? z&ZgPMJG!LAlz&U9V7`EFF2?$*G3a1Rj;%}fU+S&+p#E#rX@6R3e>(q;Ci9zp{f&>p z+N*LkNN?#fF&t*gEa|dTNq5PXP?H;w-qCIPP63&m2{N@M%uHU6yyHos6=K@I5Fd6K zlvzzJ^<=Q)B^%d4yCZMDV~;^1q1gi29wjWNqB{|hLk!HCaeQO;6v>AzX2|}4ND{1h z2e8O_A~&NXv4 zfVj@^jr)VU5BYDzd#k%U=KsDOtqUcn0IaI$qN}=_R7gxF0Szi3Muo;G!l9)G_Bnl- zo{C;OTn2W}jtbXOiMZ=ZMBF9lPINex+L~9_YMD0+H(3I6Bw&i57N(8f*B4NU4X39! z#^+k%Y@#FxVdhm3#cAbjZ#nym?_^{MiFVj=e?YeQzrF?zbx3>=X)&!%ZcLU>4N)0ujtND)Z5f{~@3dJK< z>{yllaZjLFK|E&b`9wijCL&q{KsQkmwkZyzd0gmcb+(S$I3ioSg)5FRIi{?Fi&mqSw1`PNv8PKv*y=&!F4lzW4QE41=YyhT}7ot z)>IIMvVS)8MK|7IDIB#YXB`-4qg47p>@c4vnl6Oq?|dKQxWoU6Jr3VCNt3?c9xsU) z=(eg}v@{jn3EE}O@2m9B@ezDI9=cYsm?(Mrqc9a?mkf4sin?G(n(`JNP_z$sPcIt1 z(MCH^2-?|T9Jx2i=w+y0WAmDBYB%NdNLi!%i9e?pR3e{~YbFsgdxQX;w24sJPh|4zv#HUB?L50W6$_Q2 zS1>8-DSap=y7;%^F!W+KIfv%(=reZI(R9sd2-|WQ5GVo2W z{f#PGuti0B@Wt$#pm@Z!(U5L@DqRqSJ2?R|Ko$oOS);QtN9{m|*!#Bj#ri+33C^2m!Rv-rBUx>WU z{@mK756K7=*FVIk{%b<1A5jJw<1z^?&9TS8imIogB)D`wXIqbtza{lQDJ&bhD-@7! z{gMAOe5qtBw=PgNJR|ia^>zi*b1~xMLZC_wqZD3}nYo_ue5Vaq0v8_1&3=OyssSf` zjmS`FEW_Ljse>F5K7fs?JwE&8>~L8p;LRZ{aA9`148_Fc zs*GT4uy3^a2-_-+wTzIf>aod9!+Q&nTZACT? zp>~|`c&RL0{5r3Vlw9*&DFJr;gRepT_NtCwbo0%BqID-QoR z>Vt7Gw3v@Jt6n*q%z3I)!fn`{iki2a(an!U+yl-om0{#uO6uV^b6=5P;~%*%t6w}U z?Mp&1u{gEVn!u+iI!FV|4vf&7e z?~qwYuOC1Ef%_}QFSuJb(u}T3Hxi*lC=)JCa&~cpc}ej2 zkSdEqs8-7NVm&arT$sVaQ^aer!D~p`l}p0u0mph*{syf`dYR{KjHAQ{y?&abw7usC%$aOtgRsZW)%_-aWEw@bnpyS3Ukd1mhs0z>fDZcgNb zx*0rjt&(c%2Xo1HiW5?w?$>Ior8=+*sh@NYHe#875Uhdma@Gr7R;c!&YR#JM3LbyK ze-ZtpF5g8YGnjBznF6d9o^U zixRn5#D%Vh;vA(hb*5a)Lgo1!xqi~Vo-5bS+1K~T^~?74eDfjj9h8(=6DCsT9B4r7 z*Sx?aM|0EyhO;_WkHb-Xi%>>aX|ZcIdK{&QnX{dqilvLtMoBISW2?PmUW4M)!}&x3*>eBW6QU5E zB$}>OLOt?1z-(QHJk=|vC(a z|5Pqq)iOgR5bwKYvm?J1;O?e3Ht^RvS8XH0o3#?$GqR}FcafV*zDzS3_@EPwxfCqH zJ&eD;cDO*r0k+#>gai+7;z0rDKDLwbpi$Mw-1aiJb~lziE`7kmK)%1wRWH>kW@vRa zS2mkNH9kiZ*DPpi`9j4MiAH1@MMBG@0{BBTUMyrIOK>byTBsM5=J~ShwhtlZ;yas{ zq}2>kul-Jn5D?sqKYV_(YL5jNn>|x+Db1lev}2`e+W1w|#xJBnJ$K4)sR;A!TqLxB z_?%u6w4;y!42e^UGr2W|F+(xP+jT!-_m96?$+da4yc)9BypxSx59L|oWydLGQLvjP z`cEL>A#<2rkl1e7&dk+{>il@VY`J4XwK95SB@$xA$NY&D>YxynTOXREs6Ki#RhS>M zi0Dgn2k+>=f2ggwRA)x;jVrh@X5Pg+b^Is~0H`UU>CtSymfdgq>^@-A;+1_Zo-+W- zp?=VQO*ld^ZkNtf5GF~IIfp)2&3804-DLhyw0A1843j`K(DTwt=(hRRX8>qqSCr8pek7QJ6?st*YKWql6NOehUTO~iMNWbh#W7^(~{e-`=2I0PX;aXIlo z2$!61@Ur^-hdPQ@PBVybuZL@LJJl~_U9=f8>xwGqVOTGoq)&)H$u_HUcvrnvx;4^(!u&=i=ai0>l2n^EEA_jrrU2Xb9;(&;rUfOv&94|gK-T(Azj~T5Pfg(VSh-%mSf3j@xtdq!ew~q)XIuR(WfvPUpjhbaQU~l(=M5-D7QC~|?LWIwZN=He;*FkO-RiT; zeN}bK&n_0P?zEwP#UQNEl$7FEfozo;ZH5BMl$7m`ZIe%j36zBpx*$Ou!A|jcLW?%t zxh;=kuAB2WlxVBLdX-wuTd{kUFe|fhiaBtT+xP^`kb774N%`?;Gv4sy8OPAym6uQ$j zr#;efup`p3VcY)gTeY8w5r@MW`Rj%^o(U<-lck83IM{QSR?|yevU}D&57X>|sE*d> zMT#E(q!1Be3@^O6X=~3w|E7miUX-E9a>?nh{-=DV)du+6@ks6r_+cU00Vx-LIyY|= zzofYANIm~XE7q}rV>O_D+6s5>jKIe9N^0^_(~ok!J5i4EI|Fk@isHtMsV9ZMV2SP| z+ue?6`-YB&j`iE3+dCe5$N%>BcKNSVRF#B2xK=anBv1WK-~IK=ICj!_B;W>kf-g9X$uI;9kq#X1InWZ&*{F>3Rnj6sYkogVS z@sE`z<@jcx*Uk)lkprWZLqJ9C6Y0!C4Lr=FTu5yLzLKQz(f^PFh?n8iFE3FYdHC!6 z(21zpi7R|`pKT3$z~Z`q2!_*7x9pM?h5jdNBhWlNl=v6kg`b z`?zU`MI@;tot*1Y(kTM!#)h7Y5#Wqwcfp6SAQi`~f{wR4I@>?l(bTb_qqAd!wNV!x z%^`=Udl&97gHXi$LYy%2n}f|0O6snG&qSf)-|8)D@y+SjK!2GLV&fZ5Tx=)7l|E+U z-kNN*lb>Xqu>+douDc~B7@ry3n^RXtE;E2v{G0XzF~L*H65lloG~5Il&dT*#MVPSe zL^uCP?w!^P9Su99+VccYm2R%t;y;IFuryWT6=yb=I4*}^CHEm?vai6#;BB|t80-x% za%=-_Ib$=IqZLPu+z}mev@W}SgSRN+`!BE2V>Q{>%UZAo+m~KrT|KC=R3C?)1Syjk z0#C*J-h90M8?`6iItLYUe#?~b?ZvWEeHVDpyzu6c5v7C#CYKtUT;WmqrTM+qAbchT zc^q#K#6(AuKTk06l75`>GUObweK^fu5CSSume`B9wXyRqE;CX5InZG#^mNe$g`S06 z#L-juE|A);#j9#bRG`&nP)-p~;ND{1e@r;sW7-qRJdSGoN#Lr4Z>es0DI%?^Ui3HZ zf0br^Ve1uUM|Zg1U|}b@-W)6#4cW{Qo+COR>fEv3O72+i3hp1(KI}gHLORyF8RE?7 zJ-lPyh8eT*TKp_Ua=`LGiQ3Xa3r?b0>2l?-S3(eu?n~Tg2}Tq2qlX_p>C$Gbhg~W< zRTT+cgRvoaC`Es7ugXMu1QaDHNSmiyoP~$#^BR*jJbx|7YE-3I@4)P8lCFEE&?O=3 z)?Db6b=YmJFGWkUO3EVEb$3W+hxbmnSVh+NLgmn_(v;futT_{=Yp`*xP{JT;z)Ea) zaEczyE&k1tS2qWLJp%l;>e>zMiM~HLnZ9=~e%=*q7~-mr(XMON-S3P}S~)~OWtb=< zirN=Erw&d`F+L=u?Y)DJUgINUJ|lhggtd!qr>bu2McWq?fu`)163WuhlN_EDQAW0+ z#s|&`rv!*nbVRHpM4U;EyA(eyBa&cnKUZSZr*?M z!bBhJ8R9!9oNjRGSPxi3!wa?`1a}`M*o0vF0zG^)6a1dFFij`dJM{{zB^_Auf2{{<;GH( zsc_2Ga1c+}y$;DSpXYKkyWZgQrKR~tUBUG^;98|tvza~^JvOOdC5lM-r$~LX(NJ(a zzX7#+bQguFUe)Q=+?}qXlS}Rm#!fzRH$D$}4m{3X`D@vHGTD{=G@%j$$^sqY4oyAD zj)yZD0!+moZ+?#;Bj^+9hENC(6YQzge;Np=Mf zIILe698)MnAWgxR?!%yp!lGuuB1`t9=fu%ug}Z2{_QdsQD_yuy)^Y&r4PDlKIx+ac zgX~VbPurauP^;DG?o0OM zE54>A*fOqeMsG>o67prWYfpT{^p-lBWeX;p`)iTzwp4+*n=^tR6S5~%*X7vc79|)o z%2o8C_9FCFTh1SwLZg@)T%IL=K$XV@%&4R+#u-l^669C+BxruProS}5F@ z-Bj`N&-Ta6Td3dKp|I-^9;K&4Kw+1bz^()Uz_R~!%y!G8Jgj<9e~71O$AWy;;1YBl z!)287tiQm|4TkrZ!QeMo;9YQt+?eUFtRqY=MoG>eKe2@N<$IO6M zQw`9Fe@%iL_7ok|YIk$*WkHLS)5*0PJ}uLm-{1;<;w&BVNvW~3R4YB{%70fnR%)E2 zUs}*jZ9;zPu9a%-nYo&of#37}>VM@5t#&nkYU-l%Suf2~1R?f=5RHNmjjQQLQYkj& z{1Y}#aHwUa!N;QAkx% zjr#74x~N0NaN&WZ&X$#FJD20Ymz=BY5Pehjcb1@y57TMAU*zzQvKM|9Pwj=D1EfSq zspbo2E{7gZAS+wBq~I4hHz60JQWx&6L`lRohh8ov|+3D6r z0Dq27i^zuN0NBb5On@&$R)X*1@XO^>9Uf9I!`!4y8taEw-DZ)jYbw5XP08|thl2wT zJI4C)6U>h z$8pKLHIygi#!)NmsQ~@Jt8Sr$Ig$(|+q}oJ$sw#Zx7I(k)l(henQhqQP7JA{AIZ5S z+@@D58WU~r8Uy2^9sX&JrSKpb8p{MlS<@hnefgNZOv=MZ4q2oN-&A@b>subLm% zMct5Lq=oXe*2Xwa1OZ5N)SG=)6k9Hh3Xf{Z-x6tfXkUUobzjf$J45u;G@gvvRWn6=k0tG?7h%8 z7HetUQ!-G}nF5+6GA2N?JB7n(Q$~u7V6HWSLdLiFLIM6olpkv4X|>X_w)!T*R$&W$ z=Ncq*-5K1gX{*;Wor6eWj4UDswq7z^trg64Yo)uw)7J!#U!yIH!QB$~_L~+_+@?RS zI}XQo$;3=BCO#Q0q!H=QB(WZ6$Zj%MGzz+`U08ZFLMpkjc`PdY0JKr`3WdVilt>-A zN-hS4iq_zRp#1-$FTk?V!@WwZo~wu7jN57RJ}k#HHz1u zJ9id>ywbZw8>k1sbC7Z!qAV#0-cln-NgOo{#N38coo6atnTtT?R8p_HbJsbex5;<( zcdkeL*OH^xb5FXZjCv8C6|cBz5m#<)3VBpFI_>m&MuP`N78PJhaF<4C?H$r_DSwG%cHjlVtI`He>2+!DFHx>F z_7$~8c_e8^>a!G+fk}0;+o&nShbC@{?_(9Den!=7eVdQIuj&R^sz0h}3qB*FhI^XE z3)#RGj7%u48%%0oI_~d4>-6AI(nws>bSb3<}-f*aYJt7#6aPL^)pM>5BsS( z&b0SFU79HorK+uK(rO+;Kgoaw=zLDAZ-6{fDD~yo^=;c{*T*W9XHuUaL$hT4GbkNz|MkzL*dV3-&Os2QjYxWvGrZwL{-Y5@DJzW?14GW+v7DkqbKo@ zktXcU*&F?-mtdg^%?4}r_F=w#t25#^yfsSjsb(6(bAEIqjTa8VX_OgqK=g%C0>m1(U<1efb8KxjK zs<7syF%B%)sGj%Ec66hQq;_tuYqmQkGj_(7P9eX>(2>g&GF_R zCb(>2L|pTQm0VU!0e8_CA_42#ORO)EeM=HZn1kp$3c(l=D~GE@9k2Yk@Z2Ry{?WYT5RlXRc}}9AV6k4bPAg~KwM3sH=6)av!1T^y zp>DKYYKXf?*MAS#ZXA>ga}Kp&0jiBiFDTTa88fLO>fyTtl@dzHv}LO^$wg|j~E_5)B#`PwU<0O_Um^s_A{kG0wvP$l zDKSTubOxRaKR{4~EA8AF+?9iG&DR|M!HU;6S_|W27&gJ5$;e58Bc>wz~-r zbEJKK3**0e@+*yJn?smWwxR2!m2B%0F(ZxLCd7qCDUfa%R7`ju$*x}Dqf)$(4bF(5 z>+mm!Ot;8x61oL%HNYuFTz^F1f&sF7B@K#p@LzR?u_>nZl^piF-9x4EQrV)?=^Gh& z)(Vu_Lk3K?w4O^(tzGeWzz&|MF)6>Af}Lty{}sK2UWh$1gKQa^wt~|nsFtlniIfe- zheRMR1vm}S$t1;&EgiDKcb+?(5|$2=AUn3yhut^Q1b+;x;zAS7_ML1UQ1|P7d*s)_ z^QR+LJ5CRI+Xx|(1`3VFj>tAdtV*fhH(`6bywO%{s3gP5Qs0H!+bhQ=1*)UHlWAsH z?_@(0TWL0hGH{Z}Yr?*}Ua6di`_o&}q%-op^@;p#A66+xauC3vHvDaqa?NT6DJw5K zIDQewOT6g~r!J2ih*iged|5RDXL7cKnl+LgBxRAu5z#{nk)>OrZxQ^`=f9?hUVDY& z(KS*THVS%jz*(@xWSt;B;<+J5afla~c(@093DvgLn*+`PRRp98JxJo~>wq3TUpOQD zXi`orRvf#So7;K#5x=u|m?RGg>RCA7{Ohx_-iV3;OCvNNv(5`Y8sMv7&(f-07zmYm zS#`qb3htfU&@(u=DL`htlDaBKU7AXuYjql34L#|>*3LSdZ2Jp!PNq$5@Xd9rdPwE~HL;Jl#xb^5)JyrEZ>q9RmwTG>>Df2#!?;Qejgu zw+RzLJyM_U*s15YdkpT#J!vhMoH_Ua$%s^u{5zzGytn@7L1SHgK(=#NtLS%yrTcY zr!rAoz81gKjhftguFbX+AW-#MX}>A@Ay3%Ik694&7Kr|S2kCRteB)Fe=6~{1Tb@?b zh0Ng~{ltHQqbV4g`=d6PGsIa058#Q%{5r$>Jy)@%Rs zyb*~1!>y{-uHiarR?cy|wMWkL_+qS;<*o!ElwYzwY((FuZVJS>nC z)o{*}flD?ea9>rz9!yD+MVn>RC$`EQVr0=-alFnxb`|rGJf;G-eIN|S9=hK8x;#T2 zw~w>l_*{ybEj)8IyGO;6EOa_OucY~gN}By*8H07$Q=b5rzB&OeP6VAEPEVFp2xC|c zNBn~+>$FVyOfDVP7x)U=SmrD8hQGt?3Urvzl)*LYecvoa;(Df$nT5_bxW{bp6yZ4V zOoM#tuG!#!uW!1o9-v0p9`1<7Q3QM$x#)w?JxK-~ygQ6`q|Rm;r}EHdHJ)%jklC$B zyf6I^dTfJz?I-cmW;UfkNA>@MuwDV26w!GQXzbYi6Ab4U))gr8#^C4j+b-s}?PJ~=oL3n_JZD-^u4vAbi+bA2v z_3_||;R`)@^rf-fM;;EIxM<{|8Md?uC!%1akxjK zfN+n*jodvFM;rG@_T-+X?iPuP5YodF{%rOSwMX`6L}bEM@=pYJQ$G!oay@@D`ID@j z+UjB1Wklu>$@n)uE{KTe5)hwgqmjfB@I!XWf0r^`TbDGan$sv@?F;`5xGXh3R1VbF z7>&du`&<~1e8X$EEZQCZn^c3fzVjxVN5!?eA2U4G&I^8szx4*7R*u+iU_hgK^55dj2qh<=DvJCuaL2~)c_z#ZfE$#u zL0l^*-;8VJtLL+B!o^q0b>&EgCQf#1gzK}HWju(=X}<7Fdp+Mw>0(N=FPS2Z;XZve zw_al$$GBwk9dD+xGgQ!x`!a+Aq>!RtWYskF)o3R_<`DV@QB=sS4x>;fF<1wMZ;&n; zgY7G_*3&^&w({H7gony!oN&j3h1a@CdL1sfy&ZSnOSN*zW)9$amt zuHmH$1Pi5pK1&|@a_p&3*au&tfSU0mHum_2Hi4#`sYz*Zy$25thO!n>3Y`y&njWgY z{3q|}%bmP1Z>2Ax)Th6){_D=H9~^~;vupmmKLrLb7&TVF498H%PxI6gsPe<}o2R45?eQ3&dczfkoSMvz|My`^AUC%Xh^Ck^Id$ODTw`6Z zXAoJyDdG+PUHAkC<_amgOfYyQwlSmW`(3ME;`Gm@6lU=@=E?e zN>Y$a|K8m;Ho&bfwO)RLt!#Ft%#VblbQO)xjZiH}Pp4h`Bw?>t+g?LCTm*_!GSB>M5X@99w)T7p%Fd7!Wxf z*q8~hC64H(Y_9oV&Lh4pBY0|%?;3oLjFeo3SZ7lb43waakRqR39eXJeO6uTC)mI4a^wfGvp{Ed}zsW|fLf1oOkY1mz zhwsl&v!GJ5vlwp45E^?i-R5<^ee|-NV{&>olo?(W--pbX2Gar@%YtkbU8w>_IUH2Q zM@mN?mNTV|7V{>xeX>uAd;d~rj4;+7^Ew_T1ae_DTyK7Z{ws&w9xejK?IjFLq$8l2 z$wnpgGa-kIbUyIN^csm%`hhnzQLTbN@r(AiN3|MBnvc~BQLE>awrnHXB4qfX{C`sh ze{MscF_ntE5)OfkFJTXe{@`Kpk7Y-wFyh^zAsKyt1_)m87gHI(zA&d~F2%Nz9H!#(+c@A0* zsSk94#gMaVhM~)amam#jTXLdQal2gMxI+R>wiZX16wg!A{Sj%$(IPP@!)hh2fP}qN zRc=fs?n;-?g>m$h>$&ng4`EaH828Wg7|Q~H9EssYsxCL~pHpu9@E)GN!c!3z|46+q zVzT%le~5}IV5~iqkQM0(P0K3}&+g=i7Ui-iFONDs5VLey2SG**g43x%*{IPN!Dtf2F*Ca zs8$FkV+Z6_WZZ_pmZ5@MM7UWQx}rtd=8IU`Ww=ieqh^j~mlMG7st{RA(EfD&h`9*a zo+ApZ;Vps3cq{*)-$XG*eCeSl|03Q@XKn6g;K+m_h2VrrFp|oJLT!huhUhJV}JZGgmUA9>%*6RUGmG+{7~p8DHsky z`nq#)aTY3r5B7&~4t`%n>b0e!%CT;Z^I_9NgV&}?cTOFr*CdMqf zEhZ2(VFfYOf;`JX6)auO78%Umh5^QV-;P5P%{bsZAh&=M>YpQyM*TpE{ukVbxe4F5 z&}Gk4DwO)9`cx=3wH8L*&2)RO3f$m`8oX{$PA${HRT=`Pyf|NhY@Wy70>3D5VL zE0lq3wYSR^6aKnlv+GS^Q)a&#Iy{(Wtw8SxXvLkR|wH>ka{D=G(cB&k8Vs8v0{!;i*vbw z8<9A#!MEA+J^R;^B92W<%8-WJ$U#0S5my(AOKj zuh1G(z=7xHW4s|ZoXsN|96u`<=4U2QQ->B5!tG_^8}}c+;ru<{=M45HFWK_B^==$! zGx%D)9=!7 zUzF3{*#tMKWFQEUS}96FB;3E!JH7frr}zSs8>MOyp-ys&^D#5TsF5drh>{TEP1y0c zlw5rrRvO*lLQFV|?hwAB?k`dWJQADV8bLeGe^Pma$_<#$Z1eY`Y7obK^HnEkReZhNhKD`PkI{o19-Oo}$#)r)CfK>OsD%K~aB(5;%%PN4 zX`HNYAtc^?y-=Um0y41Qk{AFxu2hhE3dMwOT)Nr(7;Sh$JQf8TYNCGOE4Vh`G4NE} zXZ})lk#O;cd}dxu3+8tKCtAwSsF;e{_0W^j1_x}Pqn?CHu=zLnO>?m-m%3fr3m5-V zep*sYDP!J6(^B^=sXKTeAjj5=nob=A;|*W-M+!@jH*D}E#RgL-J7Ivb{zE>!NLA4t z`#^4Hz`Zl%XGMq$54&$VO$D2rdQpe3Ko4QZYxff1GRWo(Yd`ab$R8&CNJ5Q?nJ zO{4D}SyQdn@9FD)q;B&q>LgQKI*QS;>s57?Z=rZ}Zw49=ldby$=^olRelw zU4b7?!O`Zb5vmuz5~0hg1`h@vnTCg3r{*8N3M!N&R8&%?q!k>CLM90z2K#zNeo%yw zA!mff8>W1aIq(Bg)CpA`FOpp)j9#!OgEP2zq;>>yiaGrgT%ns&*aI|voyhBHYJ2cU zT?SbyKXY}z?+Si82rGPmW}`RoX=!LUbAPFVwVXY~!9&%Z^434p6P}i%8@11I<2IT- z;Uy{denQa2rop)JdI+|VZ39~%>+3KBx4(nDvN%2o|g{Gzak(x{VPA;9amk+&@ z&3&5F7DR)sX-YiyRCFP__4mbk#?>+{Q_2eH#=%%XVlJU7S*(2|#zlq(zd$2hL8Iu# z3BIjtg43M#;Hx+BK|u5g3sayqoNI1$m}^ldQ)Y(qk6gt3uS)%I16HQS|2yfh(TLp* z&5!@L^mi9?l;V5V>bS`rDoeq?7c{pUL*3*G-8#V?8aY-<%NfN&jEm()tGSRGp;xuy z&?X*f=eUkFrr2p6xC;2Dc!DdR~N{ z$UQ_qJOu%#+MZ!NSt8ZDcvmu{0}P#>;*uj@|HK38lp^wvXts1*y3+kaiKmq=1$e0Z zyEuCMSfkUI7P=u5Wk$ZFf>FoCX|>nTm(cV~MWCuBRD5aG7SdxDM2zW~R%=UHrc_Mh z0`(Gl2&NQsJcS;9C`HX?_lMPc1H21vN(1Y()YH3@;tQxOJkf_~M!MjC(-SgexSsIq z@4P}3i+jt%@JI_d)UH_#)VRi5bj&wZHQYSIiKX|smMV6NT1osz(?SPN z_l{7D)|hIqS!fvMR+ zzbUPUCgq9?ic@{|_-d94oj7cUz7sDsEi{NV`dNJCFO`!-VoUwojpjH7iA_ym zeO*b^5d(oQDeTpI_zP|!EvCV`=8f`)omI^Ic>Kj=s3&?kVc)CNK zyR30o)yFX7Y7I82HP+`0fr}KS3pl zS}h;ITZOX%f8UQ}c*y+STf&+k9NF^1Lixft1e!W2XRdw_1?@V_IMdB5s>B5{g8;nA;QCD6n7 zVeZBNA`9$%J5&mNM7a1Vu`zrhlH8v7WOv0$hGFx#A*hX{L7~*U zxCSy`#Hj%#mMT>4$KI`qTBv(#lcbzVX5Q8j729mI@WCW4^>bx==Zw9pe*2gGF_>-o+-`y# zjMP-(5}bWF^&=U9uDzc1(zk$wP#761F+#>6ION!FxvSqwA>o%5b+Q%Vs2hHyzKHmS z#@ZO~>|oD+-?z!eSHFjDqofd}-&X(C+&MS4A&^}yqjZ%!} z*7@;r=0Cwld?nCw|Cy^e++DYz_*ZM>RKl>1vk{8ro_u;8%ET6ZVhl-;Am}w)rFn5u z+K1++L9*!CHWnOHaIRWWRw(GKx2&U69E5O!mP7aAI&w-McW(w~x?L?fv~|Z3PDUa7 z-W9SX?m$TP@4;t{Vm;P2aND;?$ByB907pxEbsQ6s@Lcq$DZcCYn~FE;5jug|AX^Oh zq%Ocr>DbS!!M^N;B;xxLw7Q?{h1FleZ{APw6V|(^lf?G9*;lP1cV?)5H#Oo9<{nHZ9rV@6uLGOQ{?i zTUv?u_DN`3x{wt%V)Uylz0kzLvgVv#$1!uy4uB%tnsR`%tHf*%%4Opwp&(#J9|CgH zro=@A8{uwtYLEVaXOOfMqD=N`F75Y+7j#CO)4qg{E=!G#FoZ0674FdJpa?87YfRWWplhnZzWkzmqul4QkZ9Cw&$j`$6S-RPo^e`Z{BA95>Sv4b(=&LYbt^Xl32Sa|_2CQ#(+9dqo4< zYh7TEL1h!RGsCVCKDfX1&;g~Nr!?U`;$kA^^iWj>eU6R&2i`?I?)!J<`#+rZ9^Z^3 z5XOg(;lnj{c9P??&o}C!Yh5xJXh6;q319W)Zw|y(vC~n*C8sx_ zkViBNBp?snnPJBZR`&)d`@lsmm3_CmSK=}r$l#aOU7Xm2+z{LWDbw_P#L;$7(I(EL zhoQ2+TR@VKiH@kaB1x7(j!rdpu-}^1)Z&)BKrykB^p}62%{UU+Jvp!;K!_5jNDa0d zTrk`fXpOk*QXF-&91iPxSD(*G-{8Nn3v9sJ*GO#MdTfC`Q{NfZCR*IOt<)I}R)>@g9ME#Nj4Z-AM zk}PI;i;ns#Xv8_SIpvxpPpp{-3olo*DQXuImeC$PJ{-$h#~iSN{ohb{iq18bI0m_Pq{~h%9{o@tQ zjf^?ZV|?fVCyg)dgMOa?OK__jS;J;1)K8Wa#7LVh7-LY9)KB8ue z?>;@&P_yO1sPSRRu^m6bMR z_Kk^U)qF{Rl^;c%FWMK&TEsJ%lyj`x71Sy1HSVs5S%~05-O8w7+pb!5M1B_6D}QXJ z@@K#aY3?eZ-in__hL%xUuZPpZW`Q@ycA&TyE z8fgnB$ZBHA8S^d&Oec$c;IE4>`n4L}-G|la zcJQNzXUA5LQ=@y9MpapHQv;WpV_6%I+x?K^w!qQQEoA%d@{sLB%?MuwyhRNQ)3Dkv zh}&g871e}VhF~zRnOBSVuU3Wzxo5~5vU4$l_5sU9R9P3XQ_ET*$1!UKC4Z+iT&`rv zc#MlVT5iB{Q(#G~_XPf9ZU0C#A%_1I-I)Cv2vG;HUx{UnbBN9R$93YJf3-Js_mhMT zyezJg#vS#rO}-hiEGJ`(V_htkmCPMjr`7zHmCj6C1-O4XW!3X5vRRS^YkVL7S7Z!0 zmdF?s9YdivZ1S);LjA2^X`6gdUUX7hmc<(w#OdKlS0Wz$|)@=R~}kJ9s%+w`rE+cSF{nei-gCzSTLRe{!{K^S!L`WdgzWi zxJ<34js_XsK)6CjRS}Oj+bSck{4b& zm9szS!PJ(NiTypWenzX%5iEB5&7tru-jKh|`Y+ocX}>W)r~A^9dbN@|+vpfeR;|NG z-#WZ!z&eyl#R|CFT%kVpx6yUj%{yA7@1k&!*QyDz1wBIvc_Y7yR-%32JiL5Xm4 z-o*0X#BrKKT&rdMd$p<1617*hLu1%~&5OX|;No@;dje*iU<<43O4`bytvi|uK=H@E zkcnU1$>f@`tR>tfAZPz3;KObRbK!-X&_myYZ{Oy-D3#J9u?bx-=P)6?ZH2)YiD#%y zSEz^x6fhzs#Wi%FiUN;h;hXnuJ=W;qfI{S`6Qr=Zz`8~uiR4B|hLS7+SkR)Sqn-G&&)<{JSLtf(eA^G2=cOh<;}SGP|A2deqLO$f46oMX?D7uh@Xkh47W!yI@?r7?8H-hZ9kAzEz~n=mkXMR~$C3wby0ehuIO zI8zQ-H%jZo&dv1yIO0V^Z`?r!#FU|MQ0zxjh@Kx8uBs+U!EYb;?cQ(6cC;o5Hx#nq!NG&j_cC^TZ<2Uoan)PZHxA+;uUv z`o=j3V{!$0cP_k{+egMFH|&*@&WCjKtm}bU>N6rFsmM2OP;ggT!>)51_6;Vh*JRg_ zUe}OKE|F+PB>9WW4Wznq_{1ji(rC3M(46RRSp4xCk{fmn9zuS#P1bqwCxaSxr4M=6 zW%M#W`unoic)Q%#N3vzGhz`mLVdw_W{kd?{7r$V%mgMzJa`=%Lc9$C`qlaWH zir?0a@&HZ<=mlhZ;+?ik@Cq8v34%q37a(Yswgo0RBa4Sdh4Ij8f303`^IbxkwFQ~- z+Uw|KS)?YdS*k@B%iBSB)M>SnU=Ea%K$QFqUers2%Gq;EU-5<(L5CK@18;K0K9UK> zbPNrh9SEGLejq*Me^TDYX1|8YiY+fZaU2QM)U$Z;^C_-y9|#5*$O9KCM^}L-Wc+~) z1=zSp14IOpwOg7O5Qj=%R?DyNOXbFM=9l*21i^NApaVn%l^eSfbMuE&=>GxVf2BSUw;CUErS>qSQvObARmFQPs67=0`Uo})a#GiOR*($F5RC@((gR zX8=)n-CUhYZu#1f$F7BPQ`K%I1ycK@WLgC|Y8>RDa|9 zyKz*#Ereu=aWUCnEI%p!`{1}gcC8lO%_{k0R-qc<=m4lho+lXjSRs?N%Mj4fkr*xd zQ?8g2bkL!#VzW4&p#O%7hv9^E!n2a6)Xf@Zd5~z>GRT@$wcEPf{^;rt;~ypc&*jU* zDf#r^fQQr6!&$44fyAv@rbhK8mNi;-gap4KAkagTqpz@&CT2_=yx!9z_T9IL)WRTJmkqiJlkb7pp!u*V>CAGA6zW!azRF5L!@r@$-44WYPnj| zY#or%(r_rfSTs!wvPuH)c9zsFK3O;WR9$(mVy>-=5#1;ABG6!-o8Co(6gX8kySJ`9 zKA3Rn$%Ih26E_?|ngRM9@hw#HA)6`ydW#aL0f=1@@8J_#)n!UQ{|3VN~}dMI^jR46kU3F262VEdi4Cm{&KA8T?Oks^@*4^PXCTaJyt&H4P_1|kbO7| zz}w#Z_q;>iD>pWj=Wi_^vei4L$vfsfFYZB8QD<=e!tsThtwL%2jP?-^nwo& zV0OIfTRQW}b^1iQG8& z6G(z_uopz>M`}S-K6%!9I5cqm#MeWYy&nFA&~e6k7zX#~HDEIoX@CbGK(9DC2>V2J zOiVZ0Pq)ztFX@nQ#$R>o$Q7Ht;n9yjdmv_fc{)FbBH$csA*2%|Y_9+UfHPaU_G%;N z!e8c^7s-IyxyUh=-&{Jc_hE>KtKrajrP_*pQ;9#UaMig-V7gK@oKiK&#>y*qg+t!q z0Hxmbs(0`4&UIhQ52P|}#WAU2fs{h9qExI^75eXZ1q-MkWdwL}lFW%GtG`_O%jZz0 zHfhVQhdn@Z+N1fN0i>T`3I%>ZM=cvXZ_-r2V!L; zM4sZVyM1`CXkm&rFZeD`+*8n#rVK~?OSiOAgBZb9SYPrjvtiktS}+avM&4P(2mH5gMOZ)^45-;NOKGMb&-6!!DMX zvkw`(H~c*@Tj_6Hf9s=#AFlf`N2y-*0pf#4XmANkQ6@>{8c#}WU-u^-_Tb=TW=&E7 z&uf&~Dm6B^@*7L%oj7y0DuMOTQ#gDhSwxtvRxJous%EQFW@~6~{2dVGo%F??twun& zMP}<}DHT(tWVR^udc1<0WwwSw$(gODlb-71GF=3EYsrg zX<5ydwqpGmGv?0ULTgOeuBQ*g$c;bhJJafJAKdGSwPN#Ia4)LUS>JI?sUta!1drpO zYrzvl#14cBZi`R?>Dht{C2BJ~>;)=e!frfc!m@Vkh)>w2Sl0A?GFw@1^T;c@Djr>9 zKdM)cm{uO;@<>QSVjs|!Ybsvf*bq2=&I6YcWgE^6gfrV3_NU+1_yglzPCrH8ibk+F zTl%mfrL58@?N!WI%@&llEj8buO{uPeZLS$%(@xtM)3(f_HMy3%9LooYId!Z);;;h0m*of?aMewS_)v}j>>+1 zCN%ojTU?)X)E&CUZFG0 z@J7dDS#@?(38m9%J4S*Y+wH-uK^D*mYdW-c+BG91Gw;i8$dJ&?uOD7pD}DZ*}06y0sK?Le%tCV$q}d2 z`G$Q4yMe2c(N^`Tb$Q~eWgFxxB@h1(<>SoBL7O=l#^jyBoXocd05U%A)8W}CnUvV$ z{mEAVc_z7sxch!eh|$;9{)(|z)7h2VYqD#6#5Gk_V#@BX&#I=ij4 z!lRwNUG%}T4^KigI1s<2F&kg{XHT5}6n^zLdGN8bhIivvHJKQnmVoDlv^Nl6{$Js_ z`0NHdg^f95jEVLV@cfHf`u+O9|0j5kIJ+(1SF|+{U;5yAEe-w~@O&wB7Caqa)nsCP zeenGAx_=Lzmz~|713!D~ z&KllbU)7|HPZ{E8wv_Uo!!DH$cfrt-I{zNUomlr6UAdFf1IA$vg|>CN=#JJ$>dN=j zm40gLj!NU&r6Y(NqDDt~bY5UXXWi^Qb>*MdmF|tJj%*E6pIeZBPu=WK>&o}mmF~0k zU?FmDHFLHpULT(S%iO!bM^#;m|Cx|L0>KkBqo^oBQHigT3Q80t6K3E{ok4uyqXp|v zZG7BXEtvtdA`>RjoI9SDwsK2*>uq{_+j4)m_QqBoqCzHU67UrQVgw5TEiw#hfJ(x{ z%>TRgo>wT|-rLXrem*~1bLQ;V*=s-6UTf|32=^BoKi*LAM(`YQ)`|}z2p`P68H=`r zbN>5?aII_9EzH1sM#aR6zSgfc%k9>$x1S_mO6T9(CHeIy=cmR)-)Gex5ZN;pcZiVG zzv7%~(|EGki@VzBz6o+|>0Qh1GXF;Bc*kt=+jl0sV>aAimkg`MMkz7GYq&eb%EaMa zs~hN9%uNwuCP;68{SGV_T0PcbSLpB{t{`DAcevK`!5j}BcYPIGc=VI_9>)o5Pj3q1~d7MN;v=5>0@qs0N&y9{q;Wh%`s%an@%+S(a{VNp4feJC4IOpN zcZZJV8uiywrn*gCkr24X&i~QVTuWQ^CWUBZ77t+>wXTExs@$Xiw^~)PDg>)C+tE*_ z!h@h)Z9XMe+WBsI80H2o0W-YsSJvUK)pO9q7N{Eie|+Bkg?1F{MY(prv7P`Y|GC>+ zd!qSz1Wn|OiW#)UYFLv&4efsW>l!r_odIgttx!X|3u{JkvMpk6 z{`D-DB{60vdK4Ntw0ThC06B0mtdPSiN#uZ_Z70a#V-i1L>s&JbKw{>-qyE|J*x^ci z=xWN1-{iAL6$)b5EO;S_yeb7Ryy3HN5xhVw^!Hu0QNasX_Bi6BT}^rMb5urcR4{|2 zY8#vQAXgK(!Iu5YwwB#3li;(K$qolM*s{Xh4fS8=;R^LR=1=D@=pngQW%3nzsL|v9 z0PnQ(C=Z$Lq?U@U776%4?fh6oZIBbj>g}0r;eIjC@nxR|Y__OeFtW-u*oc*kx_^-mA%T_7TlHD+CwJ&VzDkKUPe=w>mP9nx`{+qZ0f`9taonBm3tc!YKn&=DOhNo?vf4u@XGv#F z-Lzm-x#O2{;*PqDjn=$x>gnXyzSc~!wD?(w!mNJ-_e(J?qSgEV-(kuG`NwSg+xx{| zu`Rh@wsM#bt4SZG|62#?>=3irAOq;L{7cy*p5+bxpUKI2y*fEX)Xlu~fFab@xI+(q zAMb399M(f-Yp^Gjpf+{|%LVI#0jqMvVznxV^Z2q=saH`jWZKJi(SC9(%!Bkn$FZ4x zpi~1y1y3Jqo@RBX$wfCuvr+dwz+j;@hOQrPJoP>=tSWUbr2B8J%<8xR4F~E7)|j?k z03=E<9ebYS0X@I{N$I)s79RBcJq03LxleE99-rYkrcOLjh(vboQh++I;Ze7P<8X6k z_^f5}`Iw5HZrehrkSAZx6}j=jMG{-0zLOZXTq4CA4xBv;vHH$E@xcF;S7rW1SUJPT@{JPglH5e*|n{+Cw2F|*5K%-n1y zTC3X}bi=xntG@3RSGT!FI&xSJH=Pr|N1wbW&&wVN)6~${*UNgar`)fHs;!MkM3PRV z@kvr&X_9HZ;e|f8`j2cNC`15gxRddq*^U1&UQqN!17s%33H}u+HQV?(8Gcx~l=WMG zmh!h#-fw?PoYVHzH7^{Cat8|EqC+-&h3LgxC;5&O@i(&g&B>v_7*}ngnUM-k^`YT` zA%Gd}&f{C{r8zlw$Al*5R9)oo+CelUX))CtQrVmv?Xlb(yf!F?X-wiJseq2!FjvIS zrP}NHIQm+V8$26xN*Z2~hgU>n^@OpM&n43M*(iT;d!b%+ez3dz$ch4dyddb-rHTV3 zT%|-m#{6pXb-3`t>9Mi;_JS3qlHMxa3{M`U(z}e+k8&rj`fmB#k-ooKZ3W*3<*$Ko zg|_l@)=b7xM{rHz)Jg5qn8i*5){xX(JVUIBwdGSYlF!_DXbPw3pk& zMPGKRGWs~hd>;2jrZzc3i;KC?ZkSfAK7*?lQOnP2bAvBZL(q)rr-y=OIp%M&O^RWX zz!Z7%Fx>B85pE`M{(HS2R}9#MaB;>`fthxpzmwE&`4_FE=t|5U8UGQj1j{M!6(vYJ zzvVG7leJY*%t|e;HE|OlicYq!ZPd?U+FCvDIb25ZV57{_h#EgvcAh3&lNIx9=e?09 zbZP$S8)P*?4cokGt@)eLA_@#?a>Sg1dLoM$YRR8Coe!(8($AQ9BS>#Q^i9q(R^5og zYG+`cQuw)FjUW>I$Tx8sjj8lip~WNcz;a|7BXfxv8DvIo0GNr#7t$sR7#ys0Qv{OU z5kry>i(dV8ZvFfPrS|-xhnL%!koY; zJwex~F~x|%o>(XC52hROGct(}Na7F@fwuv5%anpmtLL-S$fA+y`HbP~rj5%f4({ww zQU&fyV9XfDye0>M31#xshsLA;iT~fM?*0}2FzL1HMb+)VIqrsg3tFcYf|q2mnVAKQ z+J+zU$Ad!Ib$DDkJw({F!e9W$<}4^g=w|p3TVr@+fpl!*4|&uzb3`5VMy86=u2L5Z z{xbQd72|c9olK+FUDQfVx?r0}^qSzasC;?aWhn?ft#+O?i_(>ye;Jj~xK$&eR=8fG zAgx0{CC$jGmRzAjSfNXkE3{E-8_UXEv=ml(1&ux0tX61K!dcxZA2RCW>iC(s0scbD z>FznrWbRuk7efj~h^j71rB#v~p~Z-&3Ai4katbc&z+>VECo?0)su=~L#VnN@>zbP! z!RfM^ZMvZzn0W1)%QY%zV=QI{k*6v>yl%ai3b$#H_9!u^1pV0(cSyXCo9vKs|pV_%0 zgFqG~o6y@1{F9!YWD~(}w0d@>mbf5~T`chw@{lFps4+(VyX(}{w3F1FjXY%0pOqSa zhNy@yrUsjxlv&J`=`%hv_VOz|-pQ?dwn7D|5$_IU23K!ParcnjLJIp>sG+k?Q94t* z?>AW$QIdBxOfPV?PA`NGLQ5Vsp>z|e`H?y2AZI_Zc62LRdxcr8-+?-OfeQ@e)!`iw zcFjO_7O~)8Ss9$NKdF}f%bw^irTT+?07|CVN?v9JtxyXD`?{lC-ic-z$rbrxbUA8rav^M=1DHNwwQMk!>k;s;52M);5X5?6Au z?XV4g`@0U+c$;VI6=Y;J5quSOZDaMf$CmgBT)Je7l(yc2dGtm`jTJRhDA!$Jp~&p5 zDC{=vd!G<BVT7Wym80c-eRux?%4#5N{^Bl_!Ev-O!<0B^tH6g!BHlKFaT*{701kNXpBf9Uqdq zpVUuC{X|mb&yIMtvGq0ndntKMkX6N=fBm^yE6ElGWc7PgU{q{jgr{@ zDL>jp65k##E{bl6)rEec8j!uEgt0t6hn=0wokx0of9_lyd0AV;}Mf zsV>H%k=ZK}w?G&g_3RSi1lzsxC4>O6S4e=8&WCp2yw8Pi1G#ljoAf@}q@G5%{ix$4 zeM)N=pL{z&RL*`^0++t>J^B@|fwiHp5ckW~t{#-?Z}86KZkC=%75WnN(2vG4Px~NG zvm0-9*6Y=-b;`bwaG6)4n3D*UP%HHfSE7~Ad=wu{=UrB7wfnkYyUX}dE2^pk@xz8w z(PL;&A7{1PSb}sLhmXGnXrnmSDE?ZpQRZ)khH3Ie?k$!`XIwNH^}p1kw8lfI;)uT; zO9`V+q$_m48Jm;%m;w5`W@KK0*YUY>MUkN78`ApfuY!C3jEz%}s6+E|#R|t>cO;RY z@n-(B7s{d7d4HU1*)6~}+C)OX^)H6z#I>q_X? zEZQ;l7}M_op+&2%((0U!O!xXXyUaz^*ZEbRw5s$4Wy}+-zJH5cM*=ckm z4zOl#Ws!HpN2mI3&u&s-L&R(~K1Z*%7Flih0K>cm2(7uSn0sZtt+4OV%PqrCS0~;G zh#frIX{qIQ0CJ61No2|G`v*W{ag0#hVAe2UjyZQl+1#yeNBpw69n~&e5{Z6k71lm_ zePuPuMoO)(tuEH0`?`m>8b5+T^*1u>%kiXE9RKA>=Xp|IfPESankH6mE)X`#iA_DM z5PL2~)}7BOq)s&veu@36*ywsASlQWmmHY=cAZ*$+JYRgPBVKXR`uZ-$5H}UmVv=f? zoxF*Ol?vu{bKwizc+PuKQt-=z3h`=uYzOWaff`xGiI=M zM*WNYFjn7`D>7w~R@nb2tJMC3EYdM=+yAK6Xp35-o65P29g%2>)lnxiKfcI=1&{}> zc|>;=c4pzof%sx=CB>!l_Qa1KLh7Y0f`;-f1QN~EtX%LxyiidZm$Bq@$+eV}v!53A zg03^ji*2PT8H;!xe}y?6Y=pU$#h8iiFP0y6(WR(VcN}SP1kN{B_dIyytv8h(s6F{= zd-D3SzM}CBt^~@_f;Wyi0<)@@N~wNT>N5#FHg$%b7b1L+D)?aA&(5a$J|o=SPjXos zW(xSic&wjq^ox3EtI{^yH^Nu3JGd&ID{iVp!jskS+o5gZNfpaX=ZyMq3OpjEPYW{8 zw#*p+*~9OH+CsBhsVa&c>Jwb)$O=r;lgafb^jK?D z(i2ZZ!3#AAqcTkSe5uG<5@t;x4YpN_k|i6oH-~IrH)#Z*>d6wDE+pS)dxk=_;S{$7$9j;R9+`KS*H zrN_6Aj6e9_?9VTnGX0VIQW?Z~s`<+5UVC-+>|*8Cnd#Mwl9!x7CTY!It#9T5<43IC z-+`mSy#OZ^vI_TDk%5SDZG)$y)w7wMFKf4-6A&cmm%H}ETnb?x*@5tOv(<8>vtW~8 zg}j3Hxbo0(vMgX)s*~BWfGe_kH&&#L*_-s#>uErLPu*8vyvj$;V;_W$bih|i0edYlkEhd7>^i7x0Z1J%77yOAt<2!$7OODDzi zGCZ>Iicw?rOyQ9?3Xi<#mtV#s|5)XGIgiZ6b&^M(DLnFSS`{8S_IL5feQ6$frtrwp znDEGdXJcs|d8Y8l(wM;gcQ%&hk!K2zER6||{C75%=8@}Wz6K)_dqI_d$^5ACUxhU4s+=|5auxSs`lRF$PyG8*s$Ip=+ZtD;HACeyhjMfg90C^AT_Jma~d%}FOzX(*3eK*e0 zU+X}MK-`DI1>STC0w%Pb2$W(flSionS11aUM~Bv2hVVk%jRkLveMNO8ySOn52YNSa>T}QTg3f}gV?nHZOm*4PoD9>ee|3PviR>t z^1ldFkpB=MzTV+l4TxV9E~rcw@%cG5UONHT7;eGw^r~~1NtwtC1d>XxW4l*F)&{l~ z$Xb9bA&|8IS^s!kNaL|M30bS_$a}7WU7pfjp!$IST3kokn7U0INa%lokNKgePB=in zwcVT86u`E0)k3E2n;qffg$o|`YoLreXiqMhv!>2?TFyA~?NR^ivPaz|uo-p2IZ*5Y z4WCTm7lp>tc2>zbb2W(f`t3Vp9xro+7>UpqLu#j7t|gfup;_d5k{T($&1b7PijAh`;Ga7n;d-EE4-I-XJ#$x z0g3fNzVz%n7Z<9iz4YY}p44h7-DGV>Ew-+6t+dURow61wz@Va7`NT(&1@mJ<&f<8lf7VaxE!gXw5 zgra$v$@?lc2H)Tkz+aCN18wRa`p|_9jD_dGSIIj*2TnkxRq?Qdf1{yZd-9s;R>^OL zW$`+W;*6{avrBJ9zt5Q7>l1%p5~o}b$#-RN?4o~Cib`4msH9$x%|aQQ4%1#JV*}l4 zC&xw&%-El*fr0EBXx~56E*k8u0BwFuBaF}VNYOep5ZF6{o%Hx@)Z@e0T*ufn`;aw@ z!<%N2S7}Jl@nL)}KVwE@LW$qe!|=rXj@RLH&>ClWE-w-6p+=`O$W2QdW3ER>^-+yX zyU(#p99^oBflQQ<8Og}JG~LQuFC*u59A{)k4;Y!|*aeJ?5VJ?bXM1n;QXKsSMw|8m zzP2emm8IDmIAG$I&z_a=R%~NH55?a#?Ul0T);97LNKyPA{a=CokNUj}B_UbW=}kL# z1G4hh{uM3UaU@IFMEw6fBUK!m=wJywLV@U46j&z(@Xx67y2u-%^PbM+%^@$jb=4!a zpSTa?1V9bT2>)EB*g6i)?2Ud#w8I~$esMrwW7>~l{$28N7CpfU%0~GKRlG=tSR*J#T!;)-Ulw&==c(;qXUKxe?OSKN_aRx@P9 zU1B_av9#uX`2?Padf(r&50iN|44wfJE}vcWGP|b7EQ5F6V0yV^L!tyWy}7ps)bq;!$8T~erlJ$#?PVta74 zgqavyy)+VdxsT8U3LMuK{Df@z)Lr7UU)8R*oZK9=?4G<03KQFk>=H~6zky=|4_s45W~C3Ac(q@1Z{X;w>K>rvej-bd!I1>?Zk)c7 ztckqncGbbkNi<(69h4kXpfG1CgBaDJq%=ypW>2|`4guNsf5EVhp+>?P|BVdvl#6wS zM>0mMj82`=#5btnmW&Hj#!FQ=_OCWdM< zCmRVzWX9aJZ@5m1wT^RJ2zbzi6fR(BM&5=|SjQM{qFCCX~yU z%?r3587<@vDxNcnV@D7tGtW<>|1EeD|NYT~^Z)!>W-R~f0}_2Y@rnV7*N~W=Dg9%> zd_mldQ}9FvtMl(>WF4>*e1(|dQ;hm=@UD1(f8Yn+O1xHQWd2Cgcoq8l;MB6W*ETZp zWrvLQov<;{J$bb)O}F47^xjVM!OkCV^nZ_Y+l+oT)r=my)N#yrZwpM#O-A@G8Z)>nsoY$xe&22F#KjuJ47S^{U+emNw|qR^ zSREL`Nxztx|H3=w^}t27$HXxJ;55|`z30A~d&)QB*TML4)NPO5=t{g6(-NDb!)i|B z{As@vKLHiDS|{eW!5DTVLuSd(*c5hZ?Xk)#Bd2C^?XkwE962&oYovA8EAr|ws=7l5 z^W%5d9#g()B=Rq$H7KhLi@zxG%N?;)xUY1H+Kyy{Xz;-e_F>1Wre zTq*8)MP7AoArvnb9-cCyFEv-YD!PpCH}V;jCf9h4_02x(9sIjshGETp6RfktEbB5W z`mkp@i08{*6T@p|#dO^4#VSnDgX^WYSOf#_YdEB?vpNU{-1`@fAee`rQZjG+v5siC(C2sg-|uHZ$nYZs#yyHx$NhHO)mO3ra*m0mYdnT zTl`rOX4hkV2&&!kAuEo{3Ouih0BajQPjKgBy$|bo%dCAbaD&XYFGa^EhP*V#>X0e# z_Br-ZJ6%^aWVtNbCfBnPr7q%sGZ9=v{rD5E#2c>ghf}p8I25ALe=Hm~*JNAv%cW7h zL@)DKykmshXy5Pngu`2|N}xRUBPH{W`NDKGLm*?TNR3bn!%%W9a550VRl4h`&(rnf z*JsJ+XYV_V9|hfeQ7g(4X9(JzuCeQTD15CO#rG15`Rc(L)+b}36VUxhdJ z^5R;vn6LYdSD}4-rn(8BwtFi3)(ryjqZ+hjH^NDC3%an&9%ZkC?v#&V*sSHgifu;y z!94lO2BzI-?WCM(DGn&RoLSLo)NiC5cT$bwjM-Dxx<)V(gwk>*5&V*`@X>Pf!Dfw) z1h0XP`YuI+aBo-mIM_&h$C=R&^L&x~_J8M_kqKxc;jrpsK}arRwQnT2*ntpNZfRy? zl6QG7z9xI$2ONZ2?cOb)peS$ zp=hzeRr^H}X?4_`3nzVF&2_{c34a0FLee!EjgK~U|4KQ9kFMp1Mo7);6+T)oZ(Q&v zCgjKOB2(j|=Joe6_OA8vrZNY`U1TbBbRIu6K5AaC(9wE%Q>BK)&y`XN9W}34*l4}H zsZ99rWe+g8h^>{OTx2#^kXyK}Xz-8OfWo`g=Pv6=G+Un6eA=GNw4S@0^4_xd{r1=q z@Q7UBg#2S(!+i{7LL>C44puM_AHiRK73s7fBpg)>+W7-OU_qNV-r8b8aEW_ zmOb1uwfio6c#YRaYd-OoSDno*{t8HQf4gQMNK?A`xPvs7{MI4cV)jz5YgYK}qM>F) z*{}H=8-17g*MLyZ#ifsVnJv(pj`vJn@NO@p$Doxmg1)kC=4D)uI(9;j!_?rY_p^D# zz9{*sAEIW7c+c!_2LVq=m}NpHw2*IvOG#FqByqpr=fRc!>oIZRt(O@fpc{e@PONO` zT0=%Yig#cm9OguW7W6xIU|IanOq+kq7I;6dr1I9wm6YRSpFMUxD9>$wZTyS|-$V&w zfJ;n&+57X?`7T?u1_re62D@m8zl_szEnk5b zS??`7NCV)irRE^CdErI5lc#rU{Ekj&zaN=p$C;rn({VV9|6)9@@>L|}72+7|Tz^H! zyx_EkTPL!L)aS^ld8mJr7gyuxuP_K5@o#|OQgfrUS-46r>mwH2SeR<^GHLTqr$%r% zVR*QGnRk!)S)0q5mpkuvj{T5!8rQbqYkupJ_-s{om$)!4JC?53ZASBzw8kenRcxA-bPonoy#8u7eV?Sixu?bF)V8fYSm zFZS8PPy9q04RXh>@S?u1YHO6lDLMK~7=!F4d5T=g@j%8UI-^uFH2dV#8JFpd(U}@2 zGyA;9H)*cB{%p1iTapI{~buLa$X7XC?c!mnRThb!s8?n ziwilku2S#snUUMX#=)qY%)9AmF_!q`2R`1G%;AUI@@$15 zkX>g!xUtG#?DxJBnstWz46?cOz!tnz1^i)6ML#Pw+(#wAYN7>fxYSaHc-E_bfxZxy zdqlk$Qt>EYtMCw`F&^XeW0HQD`f-PT2xg#&=!l@fB?}{m*Dl@6oBHvJe*8{9ey$(S z=*JWK@ooK>qaQvV*sSg20j|iw_BQzo7J1=V(|%Q~x)RQ|f0bF;TTSAn=xH$?WJ%F@ zS?^B9=}7W5;e0M#^094JPcK$KJ?U0{NFFbZC`>2VW_dB zP*B;LKR&zd;(f!e9AU0OqALFu`)o6pLh;M8@PRAxwG&8uy}jMYRL^l)H=jTT)62Fk zG@gpmI_Rj9FCi5{Z1blg641W;0A#vS`au|ZGrBhyzqBWex>|~RQQeBhIl(vh$GlPA zT)os4`FfxFMzp&$^PLA(5azO|`d)N5IS|vSPM8mFms61hC~ivhA&ld{4gJACfCWmq zKEa0fHUNrE<&QevGWfW>S?6CZ`J?#*CpX!DAQ8!1<3Os~B@kqTG*p9R)cvObYZoc7 zOh-(>Vj%(;c-p9g_-0%5aN6a<_?l}oLt2&V9fR9*cjQ}J<0bg(gx2q6{GxppCSuL~ zfteB43FOm&$VwJky)=N&UP_t0z40N*@|NpF#D#6wfMPGEie*}p5!j(oS_;}u#t^_Wbkr?bY z?DJ?icHa;j)x*c^2uxxj2sZ}p9mQGhCbkCC-ePr#9&-3-Q4M-aE2aB*hD8Ta#ng?- z0xI7Dt-LhVsxU#Z(`eO?Lc&X_C1Z}kePgmV^1bWbMEI4Hn{Pg5odyA23h5A1Z!`1c zRbn8d^1;F?rAVhte$0BZh((J0M_7YW)Mifvf9GeNA@dxAGybKK$^Vopnk-|H0#>c) z2!1Gd7RBK3@o`4oR~R_!ndg)lYGOkc7|-|yv#*Wy8bjjH{h=^s`ZD5wE zzmkvQ9X|`d%0x_bN1n|;KxKF2=lN;{;`r24u|2S7-YB)t&Ud{mD;uInZMQkGCwU8? zP1310oeK{%;SaBGA_{M3RpjT(1mfN;$(>g<;^)hxV^xv5WwP6PJE}(1Et6g7w{Mnx zhm0_|k*n`6wec>=G*C52*JSgxx*a>z?(3JkkO`S3 zAa^j^X^_+U0s?Qj!0BVG-4#DqaGQ4JiNK%doy%r4>fj65S74WtB+xtJvjcyo>6lH9 zbvOy>j%p=uoE~}cIavib*GvLDeZ-4ul>+c{x00g(eoh1Y4FMP_Xs|s6@8wwyOdq6c z0&trP?m*B@pUm}iOJ@ksvR@U@p-p*U7U3?98O<<1fZQqz+#aPU)8zW#9yn0Wn4b3+ zx>8l~^Ydh${q{GK@N(q*O2Lcva0cEx1m2$54+Y*0z>7YD+$D^5%dOOl&&h@XUb(6@ z*6z*80Q}-}Cj{VaRSZE2;7VpsAa14jPLSpmSuLCduoQI{pp=<`Sk{D5caBUY47e-Q zl564@2hJaXGOK$hxB4P%L{hS(27Yyr{5eq;92Q>5N z@KKq4Z^hx@CRy&-n+Gn>s_q`7>&fhUvS;6I=?t0uVtOLD&(#lCm@vZQrDq7L7_&8= zhLWjzJYqs5Gx1+Z4T{hSS>!>uzo_OMIi26;z|iWYF%)+>9%8TaK)PeDVV(*wk zs$_CKc_Qa~B2VVsh)%%Q>zs~1K__Wj$xvL;kWIl(2N-L7InWz$Y zth+8&*3t~z>>lQSbS>Yq}zlBH)@qyC9|W*;ZSZiu<` z2{D{iklZLHCj_2NU^bU~D^RoRFvA@j%(yA)K_wifXn>wdA1}dly*tj{Shq3oX9VbIL>cuzmC>yD+<010x~MO; zwaDU@=rUaJTwxL=9GZimCq|+I4lodN_2*rKDB>E{OmfoheMUCM`|+DzC`a%7Y**`$ zaxW3>xPfpaOSmZU!gza{14mvTK2gN?YKBZ}DEbQGLKnKuT)r<#_$qphu(&329m$(Y z$L^;W6kKo_L8Rr9ASJ>_5tcX0FH14s5U1b)%+8GUca21LIF4&`EjsrlMdwIHe2Cp1Oo&9nd?_W7 zkbsv$QR7$u9TXHc{8n7BA#RFr2EMEn2_AS91`KavlK2jZEuc;D#jhn8F2jwx>Y3+| z(X2LQaJk!hUIZ6z>$wv=v?L>kC5j|MG(32e>c@EfsMHS;2$ClPPacn|2NJb5&r$}R zfnGLFHTvrY=s&!DJ;Q@?OZ7vjMc$h9qgg*X^rKrpdh{bl`b1B7Ak--3p_{Mo;3tlE zJJ!Jeh zKT5Gl0*3vZbWt%g3eS9nT??FROlE<@6_hR%IPAIuN!zK|^;_ceVAr2!4ASg+ z`n=EZ>jE=exXdT~x_lpgeX{DtsrhxO0KYCJPvX}lDZ{VNqg(LnlBniE?(`K5W<*Vs zqAsy!GNvba_KMR0Q}OJTO1yL@{Q3lH!>@n9Ls65QN6n*huJye4#0-K)EhqLYXWBt3 ziYb7J6~wOrm+gOQe*G)u8)HaDF(WX0cb?r$GmBnAHEa#{KQO6K1m9X7TbV0I+((K~ zJBeFY(;_mD%ACkmk?%naOjrej{#|RBLJ{_a_3G^g&8}l$n##wsi?Hi8kO5L-!gnox zhBrV4989z8&kM_Rks`^U|05HAoGP0vWRa5Q*FP;4&DIm}>qWp`Wj*t2Suy(ZXE{q{ z9B-OE`$!A6Bzk#~VoSelY)(&Z22`3KXW57e<4NGFy&~Y#KX+t^J8~oRXq=S8fLsF- zSE8GfU{2=$ugGTv*0JTCYCQk8e1`cx2DGD?Pv(1>^joNNRxgOZgEybOa;aSH+s_F` z!ak_4HZ5Z5Raos^Uu4QOsHdcGr5CGFD(!O z!a)8|s%)B)BF=kb3>xtY13St$0+D)C*t5w|zA>wPFs6)4?|Vr^3eJ=ri2Tzn$uOg~ z9PL>$&$m)C&kNIa!J<;>BrGaP!h?Rh5a_t4e*w;AS(h{>990jaE3ubBd*?}k6yL;p zzb^8M^CP}q@rqM3!Z(Y2^Ad)_sN=?mZGiOQy!C>NaX{t>-Vytrz^cYOfE=qQ{-pTC zzy1%HGq_=^Wns8_vGnUS*6zu1!(S^9pIv!CK`D!y@Y@IydxM*dRmZ^p3PBV#O3cP(vnkEpZsspjAmxdVWQacc{pbgz9V?4+T7ghi~qiFDet5j zUirv%Fp2dI6pbC=D{hGytDr|d{K_)H8d>W(1-uYee+~S$AnUnDJ`!L(C+iM+B?Wo2 zqgRR5km9G|{yEYmM8eDaqpBZu57LED6y2X9td5=&r0uJCL$p=&Jp@BBPS;q2e?7k) zbet^DzYO}I4)P89K(BX^=liX9UB*w^T%lcfOU;ZQ$sGBv^)jlSvy-${iriW$>pJ0V ze}Xlm$t-Wh=g?QUpAaneOL!4KX7h-+#>txUTb~D~VgN`~pS_R_Ym~6|@z_7nbeg^r zKH>9ZevC^wB@NEPA8Cq=GBQ8^b9yZGWp#)0-=)cR0?L=rWU><3bSYx&cSw2kfQRV4 zqQ_*sPfd?uS^A!9(mRVvV;6BW2s{k-8mV`7b286(W++*ckQFUzGM>4c-$JoX8c4CV zr!Lmya^-S~BdLgW9YaN-A`3DE8$Y2{vI(}|i4ZM)eoy$xU(stRYK8li481moaXpz{(;~#|tEK@1 zaiIc6=$n|OK<0czgec&r*BknG11OhtmH%hpPu?%hVdlAC($pIFOKRgotr>NNeF>}t zvMII!qcB{7Bnv%0AA5;Y!7G{nufU5+L@yMYqS+pRrO2Y$Vi%C3cLE~IX2TX8`s7kq z*qi%*XT-77qN-Sn@78N#UD(f@T_(z%RXj zFe(XDDw~@`OK4#~(zw1rynja0-I4Q83+4N$o>jaH8P>zNO3=jNzYnnTMADUTPNRet z&LstNO8E8bOg*j9HLcZsjbl7A=v-6*tj{y;El7*utUHR4z=^;oTLL%m<6GjjMx8h^ zkxmIjnTF=Cj@=^}_VBJp(vqx%^H&RGOozXgNz?W(I{EobGAB;L8C1zr{&JC$Z~cJW zq=f@GLnVWDP39($4Q@ zfT|*SO({A}%kf1m9XWoRbu=Z%e?m<4-&ZbY(CfvnW{6QIfvHi?c#b9_c@3EAWPj-Q z;0yJkk7Y?GsX!t(s(XUJYTpQ7PGkBTOXU~c|6?OHV@2|j@W&@qUiDH>1UGv(ViuEy_6_Zrj90s^_y zb$;P0LOdSvtJJ8!O8=@f>P>zTaNTH_D@k~JrnHJ%{Q9N1YY?R>rSmn7yJQh@V!rL1 zs(yDV509BK8F;?_KQlh!5OBcws6nZVgOdgTNan~E1m0=T)1wX z`x*RWa>e25h!U}%sba%tK9ojG3Fp~@cWmdiq-A5Jp(Ll#jgtQ-oa<;%rwRTca7Uy1 zlv2?&En9T=FgKKt={2XLorvaeut%wkh#`LU8d>_u^FK6s$oj=shMpLbSig8AkN)+G z&*bsN`o&I>0|a;BAi=;X2tGW}&cgGR#I{u}dU|LKrcC%ZAMss*Sbf54RJGhFYN+Uw z!^WU7b;x-78Ci7b<31fyKZtCvT!=x=Jd2{!As1#bu7YTAaA@*b%})#x6(Vbyi0?(Y z^?c!BPfz#vto4gAyWAASnF+bULS;~J(RYDpRnb{>8y60@{3ldLV$U)tR(rU6G}qg{ zv#<;&Wcblt^RF^i1ImL)_`Pks1Hj%&yaQ;ITF8xE!4#> z=>R;XS!r=Cp#xIL9k3b69|a&H~irY+TOJK1!5 zig#pIyS23YX4(q`HmF2I-_z%{I=p3l@E5+aXibSAGR%Sc^J=bDu3?{LM{=iCFmJC+ z{16GKJ_Lc~&8#|Ze{mxFOXfg~iDP9X;h{Ak71RNHqT2YZ85K;t&J6j6c%6CVysxO| zXW8;BJk$@txOERU7DL2K4W3m`?Q>PUtET;~{#jgqro6FkeUnX;XI4ame^72ejYp&6 z|1+v0amC(ZmAEBpCSGgk51I#$I2U|f_vaVtIiNq7q!pbdCbzr!a;3^Laxa`gX91ep4N)y908=;7DT-jA1yf&6kOU|~Y*vBY?b z2nSotG3e;-FF^4GcNowroxF|bBjVDc{)g;y(dQ6d?{S^&Xw_wk-;JBNiwN+})E9U3J@6c>NWxjokKMx-w>5)$UeAXfD zyf430JDsW>S~F@o2U9ZMDeZ1n?Y=>eH&b%QMydU-uFbDqr>gy~s?F}Kc~AXf0Cuo1 zwvw_H-^V+S((YFEhhcey?MY9JM|SeWy1a&ND42|ztuj_PRj%14KMqq9oAj*=_>O}- zQ6S$RLQmy{Q6GlRBIPe^^lh@8w^ie+sMBBZu~GLQ9QHT{QSxIMku&AbUASv{goZzp zX`)A;Vdq}+u6%cEdXAVm83rRx|75ZN-`I-t;77O17q-h6cKUJKRk6d1;*$N1(qLok zdZ8>{awPu|nd<~A&yBKpB(GU6+Ixi;5bM^#W?`Q>hIn1a9f9j_h&<6=ARJ8Z7BdW2OKZUHn&K_n6 z&s(CNf*iB=^Zz!!jypC8fXDs{z$82a^)JY=`+ikXL_xhXZfvr?(nu%-OVWEpatPFM&yz#t^uk>IvlRns&jH;76%8WRN4Tm ze51Oo0dJ?;ji0C1pF-c5h`;A8!==wg?iYu8E4pfKL)D|etk`9QpP(7M-%Or7ZPMht zc^$zky@{y5;wZ+wIC?$mGdvr`ErxY8S#w@1(Py&cjiR%U=90QRiT{fZGF0BFq%~k| z1sM>=OH=YloQ)`sj^jK=0qw5j{hHb6bdOX0IRH{k^`~fo>JLJVcCn-~+{fro3r(;t zlQrqj+1dS(I46l#_1*X{eAaef#XhbO_;31A_Kd#_2l4mt1@VID;I|l-n-x2arzH_x zm=19kgZy){@|3urIAqm1IdUCo+S3viMwe*a^$jw@Ld}Y+J8tHX+|KQY<#8^U_6>>T zbR3bH(D!GZ@e8xYOXrj8vp52_`|+@$ycgcU#F$LXA~{@op%+oQVKc%OGe`TRajV@| zhQ&t*rHt@iQt&c>Uf$>i>JG{*O!b zze7Nf{$H&6Uz6$oeEL7(9A);`<1cIHfXwtCTS)G6JCgn1=C`)_9XnAH6+qIxQ2obF zlIw}h;+VK>voah09Xkj!%kZ8-oV zNV!WKrtu$rKI1>wjjNt0$(1+tYmodx?4qbCAq)cN`W$=ESycOv>R(j_w0>d_AqxD) z^v?m*Y-=hNQX87spa7}}ymS|j6v;;rHPosPip=z@i?Bln- zuCb5x^}D@oxh!+8cpfV7;*#2LJq|Xj!W~J~IFd>K`gpJP_#`k>rA*I2ccsV}$KA~s zi&T{M(f_+wcF6GK-;~`apTtj(N^&-mr1W_V{k|ggp14P4|s8f_I6XbF;J!?K(0{hqr8rvcYQqIw!b$TUuH$~ z3PK!S$*PmO^*tniX4WE)7jS zfBoVss4_^ZoGVqDjb|27<&T310b@N1IWh|xAbzgkuEBqF#B=|M{)1WIZZL}*?iis^ zx@l>rJsBcG&fA3ZH^@-32Nc>u2itQJ7}*U$S5nv6t-O&pQx*>rf1d?&`K7bH>NEGr!^EbAm(V zbx!OJUhxRWv4gFBU5in7gh{|NjD`QI^$*A%=@rG|Zc?qTaJvJiC*gymqOn}lcJ;S< z_7OeLvzNS`(N9a*BNKf4QKp=5CSk8*l2#nvYb4+I%X?AgJudGBnfC+oo|k$5B>W*& zOU`JR{V4&g7FD;ohkrCD*y_j|@_|EJY>he3NBr4}Rh1-%n+z7rFwv$sVAO@Z-} za!G7|GH+h2JNYXR+r}^Lmri2R;MgR*o|Giio9|bi^$k&=vCe;?wkf1^%}xdVPJ#Y| z4D?sukcNKONziwn1pV%lpx<*6^dF|7|ESgTX9fLs1^ovC{YP{T`)SO~BK{A&)@d&c z1&ILe1!mg}jx-doaeLb^qp0D=;o^*AV5}fnp{6~ZMS0LHk0KC2humBvwfGmp(~?=y zX8cogX?Bn@CGUgB)B)F=e`1WX(Vtp>cm^4djE+JM>wQt@>BydMm zN!##@Vs80NVw-Q?m)VZGKNauIFOo|XYg58`6+K4Iu;4U~qxm>-AZeT=2|&8Um~5C- ze@+e0LAnbJC&TmpgcLlLbosxi|H7&3e|TQ1e$Ibg|GTHIfBY+{`pw?}je-j}i0s>x z@X9PZ6y);U)dM**o-@KUsx~VMfx}qS2UU|M4>syhoWn=;%NHd)^knjpd#RG zlD|W;xyx_g29@7^Qu~z0(PMUmXphyYRHwO=~UN@-OP5(fMD8JKdPR3VcbhpgPI$MPa zAXaZh%e=F!&F->jc()-*Wmvnn0vURW+9MhMoBS5O7&`*RxH(N!O~OAGMkc}i@$Y2; ziz`e04`AOBA{SuaPo2LsgcbdKY#&@bUyIB+t;bhRbggaPvYp<-os!U}5@2_Bc?);> z#}Hn(-(S%hXoECdaH#}Z+!%2B@utPcPvhg!;3o>;IK4!DEXyg}@SonU$rr9czr(%& ztN(%&;i;`{3FkLRVpNjrt(5)8CKDf>oH9xdo4*;~p2S6i%wu zYd<=8dc?P6WHJqUyNBX~q+HR!a=B8jU_iN<4tK=;hddV_byYyU&Um{jGT|SidxxO{KsjWL_cm( zLxC4D)1Jqk9e$Sr-u=VUWM`G$oqby#0K8C~N#m+`UM^`r1W*N3vYY_=LJCmQu%4=N zL;^p|1K0}quo*2?k&@czo?+!jDq1RyXIp(ES|fQc0QXwL{z7N=k6us|x%Gv-=zgaN zNpR>RaJw&bzX04(vv;%U*c`anUDn3s2p6MV^XD8$EOl8u9Q(lATG5|`m;D923~;(y zaAW+Fljna{3G?sF%>OXve^;@d|H}u?Yrf2D$$)u1<@`IO97CYij$SAKqxruOYJ&MM z`=8B!NA7|D!Tihqx@A^4QCgG7%@?su!->T;g(_r$gbJ)pXfox`42*R&8Y{p>%5!I^ zn90j|Fs8Qief6H-$pZ%LCI^Oy#jZ((u%H8MA7B0$-Ma z^S)+}8VTzTE*F(6X+2;xaZbHjTV;|17V*jmaApI(kw&aFC zUL5@xNZZPe8V#3IP9QxdC4qDl?^fSM-E62S-M<0eWl>)H<@J1S@)+nTzkgevoYLQE zLjc>HQ*HF;KQeiL!d{(|IGCvIfBdS?6Jju2o9J8Ygf5@rwS4+M}<$rv0 zny^Bxqn#rgFO5DZO|LaxQ4jrowXkw*E~R!FRJfp`m>Akyqku2$~~sPr`6M!(=hueZn)tdWuA;-=u@S} zruINc`Uu?4JJ}hJHL+ZRgav?6{ zP?DcYcK9exj7lJmq^hg;bEzAZx~*jTA3QL+K7JE5E}{m(*ThR(_~?Dcl08WJvud&=lFzp$Mm&Vh7yaOAnZq3L0A+G7e%?Tn^gpNr-11JyPA)htk%($?+?avzwl6&S&C$#pH|fDeS*0T55)1W!KL)pzWCZSLK)3WgU%) zzG_mwMI{;jmqeH#jjLuhN($4FNm(r^K%PnYwWP2nGATcnl)>34wURO~qWrhI!zR#e1Rdr4MQ#1<75(e3C=w8Zn(05Vo`QHKU47{!Z8 zH4zD<|Bf%j0YI7CIz$jnt1BHt^N*jzQ<6!15H(t}Uy)eP1jWJVgK7rN)?w~6qN{OD#)ADZ`56~WJJA+WGzQ~>;{HIj_1gPWH@Qt`HMrbMEt_6 zdLPZz^|A{sqL4m_x!dVaIJ>@*jrXFirs4 z;;i8B0A=C_GJ=Dd$XP0+6ePq&2U&h8a5L*q#m}rgAmUyXBmR8x+#rz!p*wad&-M)X z@J=pL>j!8dUS7S_@A$$OQE%ziJq_p* zKxD4L9W%BA=5^ZfLY*Ic54mNm8eG>*Lk$ZtBfb%B2mcx@3hz(qbBd=08pO4_?&0Pd_M)eqd#Q2Fi-yGxFg`~8UjBksrNE+0fl2EZ4^#IyM*Zs)@C|wx z5`Gu=oaum>w$v_8#?0|F!j*pOdHw`{=dC?a%LVdTS&uKu@iq}1w}w6|sw4G_>f zF?%_ozv2X2;a)|_cL`9)Wf>Z*6C35u*xIFw?2BD0p8yTN$}=b8d3H*OCvHYLm|d>| zSI!jCMKzXON5T{lVz^!vdchn1Q%>v>(wJ>DAke~~O{DV4uKVmo?_nW*K75~1-$r>t z4TW+7CjLEie^^zroam7d3GZ=4H{ynRg@S)CIAZc(g;g38&i%B(X<0Au$}MX}FcgfY zj)BxN4uYgJ%Q(5jjQWZ%SbaCj)SSab3;G`teY(BoJZ9%g?1HAzgZP=UUP+Y#F|Z9J zm5S(V=Z~DG79#Nqi0uYnNJlt=@G7bI86(K)CL1y9bR#U}(JJYSa$*cp+>bZ$g!9+b zP48v-q4|lY{QDDYOKBl-(aQr%==^E<@Eapl{yz`QPw_XQ#RZNaTF5gB8@Q#^H#7+?;^-Wi#wA4gpP!45CcRBym10=K+J|`5ZKlNO3m2Q;-8Q$O$>|bk#HBf6KW5 zo?v5l@az)KjORYstan^e+gS=n4VMP(=5Ib{ejzQ|Q|gcu zbMEY(DyTERN_Bqr;iL?{hBC}|7X9EOET17+hB-AAB<^j9OEH;sC+GQl{zekD&I%J~MyYSizD-9`fVM}Ei8%zV#}x2FnF ztMF`cCscM&`$j)%ESNxjqwZWX6f&t})L;-Mj~{B($-S`fLU{1{G|A9 z@gW)<8@#WkE{1}4n)Y`wN7%vFSNI&gS@hz}hahFikDcXAG;3pfTV@l_l* z>Ic&}x=lmWBc7{b)lbU8b{UkG!bf^(_2BIG6@2KQU@P{ptXN+8Yh`W}$w;!k*?M}8 zB6dMgDXdglqIMpa%7@uaS!f5Y$XI276fP8vh)4;(U8htk<%kJCFdeKx2&RRV86>Or zgWRD?i2Hq~L3{!fhro4^q=>R6ew>Kw_|`gfHv)Tg$BrRo0Y^V7Lh>5hMh7*FsrHmg z$YDYVN2VA5I}qgtr^q8O_#H6O2d;I(+bITb-~XM>#FVxA?7VT)3|94t}qTjUR6) zcq4eG+}MYkQRotS8hxtCP&n2#D6M4fJ~OLB&bvN*nL~#ohgrxs<$gPI8YH4UeB9C=sFJfIDpYwZoG+W0?ERM?sj7pp&^cUlNFef(sjBabo>`j-V=M7 z#DOKfwa0s;WGN;8!jIsb(D5Ij6!k-Xhd%5M9d8U=78CRm+VCjRI_LS~k9%-?6>3Gx zslRC6P#0=Wgz@||cyH)<^P;-|0W~Lr6V9o~O?7jTNf!sjhC+4_3)P@>?t+O@di*I$ zuU~u)spvhaHU=fzSZ{p4js1xptHW1@ej{Y~Z3W8Ir9gbE5f%*XCj^d_1OdNmLoz_n zhAe#%RIgDaA=C%amd$c>bo;#J?Oqft&)(!SUftv+MAA!(fzq3dm&E-~CG$uWQsS-t zx`ognEXE_zN)i};4|nvPKI7k7CL+QZ=CPW+g?QuMKh=YZaqkxQnC)nlq6kj(lHC(b z!3q59m?3eb3wseeZ1xr+HtEFL11d{dsdC)^$KL(NNj3ie<3DXbY>B2?*|gr%-s#t&%1r4et1LuV90Mp zs@?yvXKwkcNPQPZ+xK@Dsz1tjYfCj6 z>bwW`s-*f`Tyyo(n(80tw(uvdL&>+WXiJNVTvO5b~?`h;8GSCSW~n~LgN zW=__BytHu66t!<$kg1MOy?gkJ^*?8$$V1vczW)FIW&N*K?% zxjb5yz6j1y|L6A+(c4i^*QrBa-)}XO4`2M9|K2_#-KDK;V>{0WA?`=@`floLc71=f zgZh6@FIzoYmWkKPYOnr}%Cps@W%YL+ElYowsQ#u4jz3vhOZETETw6U_mKr9VN#{99 z{b%o_On-X*$4ed6qh+;o9;HV8E96IO?%RYLt{j*Df?L?Y7 zb^Urrq4Z5BuH9QsrN&_8+}}hRbDtj-d@@%JcT^Y&BQTrMm5{#sQ~> zh|IS&s>vJ|5gbQ}ZZcoys$VpPFHD>l%L(U5T#q5P6Jd_`4h=2q6eaA9mFuyBy`l2l z6yBH?7C?;~DiY=bstO>r9)NEpww-4%hjNs?B`{(bekvwKDm;$oVIcEv*;N zeQ3R}VVrzbTI&sII}Nv;1m=7dR0;Kdw=Y-R^poC(y8l;>64(2np4zJYQ6HBN<=OhF zC696)r1KOH7U`(I*3)UopQz_NnOGrpMV(LC)%dzxp2y+-mGayVPhh>`XW34EQ?LGD zUyqgbosSdaq&H(YFZ*!aVbyn>oGSh587OTqU)tyo|JqYBB z8(1W-{~xbAMdGbK(k79ImuL1L(^|Mrcw&U~#|5aTuCeUrsa$Ux_RT6@`%mcC^N>gX zdZ4q^*LPw6D1?8kT0PF3jd9^>xE>GnzQV50Eqd(mVm~nTo7R7wY@hHG(m%F})svYY z=#2gm{`*mt=S&eC2WEzOooPe=%k@?i^DoP^ofH8iil_zX{fd2@Iu5!kzvl$oiM+yj zw5&Ik>*IhusZ94NyI=LY?l1Q1>&Y`xUAL;2{Ezs!8uvS=@YX6gJB2q;*LnK*=H;f< z<9(Ft>j{qc)f0baJ$`dNdDg2sQ}x?yc!N&1TDoPK{j6B^j~*G=KUAjAODl1mr#?q= zrajH1AA*m`{$<8LvwsAp^mF3soA1MX6IWIu?-WBA4llxMJ6TZB&nSEqmJP(X#x`qk6xp`avH99G|7)yD5Kmi0wq`ul1z9o7>qR z`2E9~YX8yaMfL&pxc(SARs03@xc)VU|4--LAidu*+r_k@+uh@?ant(h83#*M{d)iB z>yd@3p57^Zem$=L;Dx>)zm)BJ72YPwuo)pn&PBG0l33lot^RjW|Jn6@0=*xy>ksVp zn9!uVtsZ4t>vlBOkA01rr_V_KfUO?YnEY}_r)`5acD3z1Phfry{4})Zp&f;`6z!d8 z=b)XBb}`y_(XK(e1?|shGhUH8iqMWlI}L3)+K14_M@yYg;rZ)mV`$f+-Ga7qqQw7# z=gn}Rz;lgwCZ6{~dp6qh(T+iTGumlr??rp=`I1L(b3Hw;{_EqH&%frp%;%%0)p3yO zJW}6z`JH;=lWLjgssEh+|JM1pp&FNToxZlVdX#Gk-M-jB?mMveRGun+wemdmx)(aw z`sL0wiEcY6*W(gQSyCbvsV|*W)Yu>B^2x;d}1#J>TRp z^B=KHeYN<0%s&awognql49^>* zJ%Q%`h1az(K2!2fL;jA&O+vJX@w(=ie-O_*QG6Pnw?b>9J*lrON54nalkUSD^?w`g z=M2=SrZMWjK2Nag*R@vv&pF3dkN^2h?uI6^|D|$0Cb3_o;!`cxRXQc2U$~)KN z`uxgy&aG#;L+kNE<*E8Xd#d`2>hbgH@$>7+uRT@%3zVnof9 zMpm?euJSzGL)v(EX=9jgog&YDXhUDg^Cadc(8f)Cj?DKglQx3qzJ+rCgX?Jkh~a)o zee?Y@^jW~NB8cPjak5P2Con&Rw)@Gp^EwkhR~;vM|2U8*uCJ~1v{H>1x*ro4+4`w- zZq#j96{xTMW?_7^HL6L!PG9G&$MuxHhSJkr$I5nMzgM|F58s3PF(&>pRgcbNCR3-m zKCt^qzs2&T^)8b29 zSkqIL`mgI{*YBTG`CIk)F)Deg_$KxERMk&<`v&#|yju zJUo@x*5g}I59irdkL%wXuirm#yuRhZ7Z$-h|T(EY}FUaZGos>heq<1g3a zuhiqO*5l1o{i*ulIOVDO!3X~Z$5U^WS5L>HAK07M<2t|YAC5o19&b^P-=aJ_MIL=z z=y8?vPf@OGW*?_q@3-tl$~&d-$;wjIKcyZotH*Dz$EVigchuvnlPres|a~-pxa*Rzs_^=1-5$p&sa6Ci5$P|^Xu_P>+xGvr|IiP&ZAv#ug;g*>QT0l zZuR|T-OpvH$JVH(i2ASVWS^zXjE(BczbCc2&J^e>T#L|^;q=^OQ5uNV7|@P8H9>MOZ-soQocSdZ=OW0dQ0 zl|7(*xboNXZS^SEoVwNT-*g^!-ETeAe>3s<>>&lem3%OM6AO)aQFlo=4HzVLX3C+QQqU4SXQ2XC9uP%gyneS)7`Ucv_>-&)xT^W;m6!>^{E7$vRmPAnh&5p6E7k2aOof2_1I%#UDyD#!Nvd%tTh%L_j)`Mgg` zYhnC}pCt2-o+MuVgIxDdnk>)H*(J|!?I_PZr^@;zj+f^)^2V^8VmJ;p0$B>$4ue>>)5yF}N@_KKFvc1YhN{bS`zz6idr!&4y7eTdtiC3zw@ zO1y87%uixJNc58D;fo~ib?qennB7uuXg0R{ENR21N_+_Wi3jtOXfK#6%Zc10@m{on zBl5b$A6Q;C`r|2Cuh9MSx@o7#@4Y*R zU+jH}kF1im#+LYUjDu6N<@tqQOFbj7JRin^XU%wdujG%mmN+{@TIXO>5B40HKW?1l zYkZxwqi&Y=I;_|9HuC%#EGMu<>Us?Gk7EBkS||Cpf9GD#suSe(*{HkjCV77AwbJgp zOxmMp_oD5B{otiysq>v%BrbyYzv1I#yO{M!Ag*;#;_PB+OVFNMBG11YBW<{kyxxQF zL)(vj_M=~-_`VrGj)x#xKfZt2hwT zZD&ZEI6+$9iPFZ$@Ac3X-}9U?W5DAy?&Oo z-@w&hJacxbyUU~FeZqq=WQt#FqB4&&12|y7l-R=XpFgpUd>X=RY>i-`;e2eY}PA zZx^&P(8eap{KN~=RxXw{igxFD@;r&QYLPrQo`6R&9>sC~_k1qLU2?6ov8~d2Hc9LI zNm_HCC-Sj8Pu5Bs>nhg?ar~r-AJ->AT;C-7qE0-I<9Pt*buX@Cf@q`Wx(3&AW*qt7 z+R#I?9F9wF`sdaCKjy;K+bm~NKj7w?%=;$O{^OOdFU{*+sGg{|1OKlkli%bq&+P{~ z{`2*re?Ix|*Z=K-|MtLtd*Hu4@ZTQzZx8&p2madw|Mz>qT#uQSuP^-@-7lUCz_T&Z`Sw3Q%x`7{d}rnUa_Z}1^V&4?#Xnke zA^Z>ezxSoBQ>mrm0=X3T4{o{b)=AgelgHk2>-d{)wEOfLcxo@Nozu5p-spY<`+Eo2 zeZ77A_w@GZ*=Jxkt7!aHI(pMJgi z_VRW^i+MxOzoeTzuvcC$*>Lr&k=}-lti6Bn>}8*-np1R^{yZdAd~4-t>XQ!hdjrNJ zq5dqOf%@bzf%j*6d3w^HKQ&O9(%;B-o|^}s`a1N9T7=6#^~9Oo9tkG0JEMB^>g2hI)BJeJw-jqA_tQmyav%5|L){C))e zxw@WmRbfv356CAX-=84S-Z7&`09GLH?7}fvMvYZN+CI|LyR&{x!gA zGDq1Fxc!#ozs8wsSuZz{Jb{(sSHLG6BOa@8$NvGhUl)G>@fB)A=z0R_vfPK^E!FyI zw^5J&992(`IP0BeO&Hio0FTch-jC&)@n;V_05_j07OD>fb^Z|fbMOdx+Oc{;X;#f3 z_i{7fb>v-@>-@3jWqqqr=W@j7o#xK72JwksB>p69mle%rxqgaYtK7-I*xk=#)rZ8+ zdMy#xo-vD&=}k^8$B2Z$!L5 zD)DB&ozhC;Cs6!c9@#*M?-g-b(bIK|HEaf^r_L}6sM2D$q7vh&v{1L?4$H;o! zC*jt$8ImV(y!dK(0v>NDeja>~8i(|9gU5-7;me%yDb0%0a%v4@2p(clfeFS1M2(=9ywO} zQ-42*o-T4e{7$pd2fO=ita6>lzg(6(1j{|y8F1390*ddeT*pUNV7(;0^%Fb}pACP> z`CvZHDxo~@!b{25!Do@zDc8#lzbDI`i~P^o`inFxLh)7bCFGyNH;{j=-09EvCBOcC zf_i$kqj>B$@%h5mznyMW+lBHhQ?B!PK9G3*b2oarv$J?`jrfP~^Ro5aG%NQE_jU=u zi^y+PuJgw}lsuF5%hhy77yX!KRZ{##%5}W&BZ)WX&6Ay{Y1UGT?+dql?t0EquJhPm zNS@=dKX+8Snd8{ct8^J^I^^trX;voXX`UnT;abUK#<4Gz>p6K8zX$P2#GCb9-c92D z6u%Z;LjH|%ryo9(<(lLDweI3U_%%AMnr8ISk7?Et%JZmlohO0#**Z*3<8$?+8fPee znsOZ|5{vspOl_f_7(TniPyqkI91P0Q@^mvz5l!e_mRuT zIB8Z9c|yfIb#9XU>M(SsB%&eqdo{lufcO1%C)K0VFtFCJ;)9uI$3uIH4~ zavKbgcrW_XoJY1P*K=YNpM-BEZF0^) z|I<#F{GPMj>vcYS1^G3~b)Gn`D<04X zaFVd_W%F|i7 z&J)4)s&iUVk<$>LNAVAu_#?7hbvfru`j>(0OvMzx4?ds#m~$mQPJR-+`A~O1^i;0v zjHStT-{LIQvSuT`km8?!7n3i6Pa=O0`NP<+Mj(IIP^mLa@x9?o$j^drCcgxpQRrT; z@yhjjMKKPT?YIu{c@+O0;_c?AI2DdVomUo0o-o|JPx%6F<9)|)#9uf}*2_=%$12zL zSa@Gkg7|L`AEfyG@CbQRwIFA|!uw3Patw{>b6+u>fgdfVkp1Js7ldHis5 zzIz-VXeD{BL;QYt9KIOWZ7mGg#Pkbe=e{YYT zeuVqBiMK~R*IXodtj*$|BmNtB;A?UH^M87}(OFKKwUFwZVf-?8|33z=BYzRTwAda0 zF1+M&w|}l&Z!dee^M=UUE9F@IM(Qur{!H=1;0MXCglCU(=f4>~jr<;X)iv(;C*bL$ z-TpFs