From 6c7b1592a84d5ceff8181c885ab1b8a7fca078b1 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 30 Apr 2024 15:48:15 +1000 Subject: [PATCH 01/47] refactor to support surgical linker builds add preprocessed host for surgical linking refactor to build artefacts for both legacy and surgical linking update build for preprocessing update build script add a glue script refactor host into crates try adding linker=legacy fix build.roc extensions add build platform binary step to CI stage the changes for surgical linker --- .github/workflows/ci.yml | 11 +- .gitignore | 6 + platform/Cargo.lock => Cargo.lock | 394 ++++++++++++++++----- Cargo.toml | 13 + build.roc | 115 ++++++ ci/all_tests.sh | 6 +- ci/rust_http_server/Cargo.toml | 2 + {platform => crates/roc_host}/Cargo.toml | 21 +- {platform => crates/roc_host}/src/lib.rs | 0 crates/roc_host_bin/Cargo.toml | 15 + {platform => crates/roc_host_bin}/build.rs | 4 +- crates/roc_host_bin/src/main.rs | 3 + crates/roc_host_lib/Cargo.toml | 14 + crates/roc_host_lib/src/lib.rs | 4 + crates/roc_std/src/lib.rs | 4 - crates/roc_std/src/roc_dict.rs | 4 +- flake.nix | 1 + glue.roc | 10 + platform/host.c | 8 - platform/libapp.roc | 14 + platform/rust-toolchain.toml | 10 - platform/src/main.rs | 22 -- 22 files changed, 516 insertions(+), 165 deletions(-) rename platform/Cargo.lock => Cargo.lock (67%) create mode 100644 Cargo.toml create mode 100644 build.roc rename {platform => crates/roc_host}/Cargo.toml (65%) rename {platform => crates/roc_host}/src/lib.rs (100%) create mode 100644 crates/roc_host_bin/Cargo.toml rename {platform => crates/roc_host_bin}/build.rs (75%) create mode 100644 crates/roc_host_bin/src/main.rs create mode 100644 crates/roc_host_lib/Cargo.toml create mode 100644 crates/roc_host_lib/src/lib.rs create mode 100644 glue.roc delete mode 100644 platform/host.c create mode 100644 platform/libapp.roc delete mode 100644 platform/rust-toolchain.toml delete mode 100644 platform/src/main.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5193fead..d874d8c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -on: +on: pull_request: workflow_dispatch: @@ -8,7 +8,6 @@ concurrency: cancel-in-progress: true jobs: - build-and-test-native: runs-on: ${{ matrix.operating-system }} strategy: @@ -24,7 +23,7 @@ jobs: continue-on-error: true run: | curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-TESTING.tar.gz - + - name: There are no TESTING releases, checking regular releases instead if: steps.try_fetching_testing_release.outcome == 'failure' run: | @@ -49,6 +48,9 @@ jobs: - run: expect -v + - name: Build platform binary + run: ./roc_nightly/roc ./build.roc + - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh @@ -58,6 +60,3 @@ jobs: # Workaround for https://github.com/roc-lang/roc/issues/6688 - name: Check if crash occurred run: grep -zqv "crashed" all_tests_output.log - -# TODO clippy, rustfmt, roc fmt check - diff --git a/.gitignore b/.gitignore index 427538f1..83f97883 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,9 @@ all_tests_output.log platform/*.a ci/file-testBROKEN + +# glue generated files +crates/roc_std + +# build script artifacts +build diff --git a/platform/Cargo.lock b/Cargo.lock similarity index 67% rename from platform/Cargo.lock rename to Cargo.lock index 7694fb5e..1a571ae6 100644 --- a/platform/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "arrayvec" version = "0.7.4" @@ -25,9 +34,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -52,27 +61,21 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cc" -version = "1.0.86" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" [[package]] name = "cfg-if" @@ -102,7 +105,7 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "bitflags 2.4.2", + "bitflags", "crossterm_winapi", "libc", "mio", @@ -121,6 +124,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + [[package]] name = "fnv" version = "1.0.7" @@ -162,9 +181,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -181,20 +200,14 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" name = "host" version = "0.0.1" dependencies = [ - "backtrace", - "crossterm", - "hyper", - "hyper-rustls", - "libc", - "roc_std", - "tokio", + "roc_host", ] [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -214,9 +227,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -264,9 +277,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libc" @@ -276,9 +289,9 @@ checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -286,30 +299,30 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", @@ -340,9 +353,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -350,22 +363,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -373,15 +386,112 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger", + "log", + "rand", +] + +[[package]] +name = "quickcheck_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags 1.3.2", + "bitflags", ] +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "ring" version = "0.17.8" @@ -397,25 +507,51 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "roc_host" +version = "0.0.1" +dependencies = [ + "backtrace", + "crossterm", + "hyper", + "hyper-rustls", + "libc", + "roc_std", + "tokio", +] + +[[package]] +name = "roc_host_bin" +version = "0.0.1" +dependencies = [ + "roc_host", +] + [[package]] name = "roc_std" version = "0.0.1" dependencies = [ "arrayvec", + "libc", + "pretty_assertions", + "quickcheck", + "quickcheck_macros", + "serde", + "serde_json", "static_assertions", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "ring", "rustls-webpki", @@ -453,6 +589,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "schannel" version = "0.1.23" @@ -480,11 +622,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.9.2" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -493,14 +635,45 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", ] +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "signal-hook" version = "0.3.17" @@ -524,18 +697,18 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -549,9 +722,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -569,6 +742,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[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.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tokio" version = "1.31.0" @@ -579,7 +774,7 @@ dependencies = [ "libc", "mio", "pin-project-lite", - "socket2 0.5.6", + "socket2 0.5.7", "windows-sys 0.48.0", ] @@ -624,6 +819,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + [[package]] name = "untrusted" version = "0.9.0" @@ -682,7 +883,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.5", ] [[package]] @@ -702,17 +903,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -723,9 +925,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -735,9 +937,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -747,9 +949,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -759,9 +967,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -771,9 +979,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -783,9 +991,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -795,6 +1003,12 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "yansi" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..1630c9d6 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +resolver = "2" +members = [ + "crates/roc_host", + "crates/roc_host_lib", + "crates/roc_host_bin", + "crates/roc_std", +] + +[profile.release] +lto = true +strip = "debuginfo" +codegen-units = 1 diff --git a/build.roc b/build.roc new file mode 100644 index 00000000..39dfbe3a --- /dev/null +++ b/build.roc @@ -0,0 +1,115 @@ +app [main] { + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/cf_TpThUd4e69C7WzHxCbgsagnDmk3xlb_HmEKXTICw.tar.br", + weaver: "https://github.com/smores56/weaver/releases/download/0.2.0/BBDPvzgGrYp-AhIDw0qmwxT0pWZIQP_7KOrUrZfp_xw.tar.br", +} + +import cli.Task exposing [Task] +import cli.Cmd +import cli.Stdout +import cli.Env +import cli.Arg +import weaver.Opt +import weaver.Cli + +RocTarget : [ + MacosArm64, + MacosX64, + LinuxArm64, + LinuxX64, + WindowsArm64, + WindowsX64, +] + +main = + + cliParser = + Cli.weave { + release: <- Opt.flag { short: "r", help: "Release build" }, + } + |> Cli.finish { + name: "basic-webserver", + version: "", + authors: ["Luke Boswell "], + description: "This build script generates the binaries and packages the platform for distribution.", + } + |> Cli.assertValid + + when Cli.parseOrDisplayMessage cliParser (Arg.list!) is + Ok args -> run args + Err message -> Task.err (Exit 1 message) + +run = \{ release } -> + + printInfoLine! "generating glue for builtins" + Cmd.exec "roc" ["glue", "glue.roc", "crates/", "platform/main.roc"] + |> Task.mapErr! ErrGeneratingGlue + + printInfoLine! "getting the native target" + target = Env.platform |> Task.await! getNativeTarget + + printInfoLine! "building the app stub shared library for surgical linker" + appStubBuildPath = "platform/libapp.$(appStubExt target)" + printInfoLine! "roc build the app stub shared library at $(appStubBuildPath)" + Cmd.exec "roc" ["build", "--lib", "platform/libapp.roc"] + |> Task.mapErr! ErrBuildingAppStub + + (cargoBuildArgs, message) = + if release then + (["build", "--release"], "building roc host binaries in release mode") + else + (["build"], "building roc host binaries in debug mode") + + printInfoLine! message + Cmd.exec "cargo" cargoBuildArgs + |> Task.mapErr! ErrBuildingRocHostBinaries + + # move the prebuilt binary to the platform directory + prebuiltLegacyBinaryBuildPath = + if release then + "target/release/libhost.a" + else + "target/debug/libhost.a" + + prebuiltLegacyBinaryPath = "platform/$(prebuiltBinaryName target)" + printInfoLine! "moving the prebuilt binary from $(prebuiltLegacyBinaryBuildPath) to $(prebuiltLegacyBinaryPath)" + Cmd.exec "cp" [prebuiltLegacyBinaryBuildPath, prebuiltLegacyBinaryPath] + |> Task.mapErr! ErrMovingPrebuiltLegacyBinary + + #SURGICAL LINKER IS NOT YET SUPPORTED need to merge https://github.com/roc-lang/roc/pull/6808 + #prebuiltSurgicalBinaryBuildPath = + # if release then + # "target/release/host" + # else + # "target/debug/host" + #Cmd.exec "roc" ["preprocess-host", prebuiltSurgicalBinaryBuildPath, "platform/main.roc", "platform/libapp.$(appStubExt target)"] + #|> Task.mapErr! ErrPreprocessingSurgicalBinary + +getNativeTarget : _ -> Task RocTarget _ +getNativeTarget =\{os, arch} -> + when (os, arch) is + (MACOS, AARCH64) -> Task.ok MacosArm64 + (MACOS, X64) -> Task.ok MacosX64 + (LINUX, AARCH64) -> Task.ok LinuxArm64 + (LINUX, X64) -> Task.ok LinuxX64 + _ -> Task.err (UnsupportedNative os arch) + +appStubExt : RocTarget -> Str +appStubExt = \target -> + when target is + MacosX64 | MacosArm64 -> "dylib" + LinuxArm64 | LinuxX64-> "so" + WindowsX64| WindowsArm64 -> "dll" + +prebuiltBinaryName : RocTarget -> Str +prebuiltBinaryName = \target -> + when target is + MacosArm64 -> "macos-arm64.a" + MacosX64 -> "macos-x64" + LinuxArm64 -> "linux-arm64.a" + LinuxX64 -> "linux-x64.a" + WindowsArm64 -> "windows-arm64.lib" + WindowsX64 -> "windows-x64.lib" + +printInfoLine : Str -> Task {} _ +printInfoLine = \msg -> + Stdout.line! "\u(001b)[34mROC BUILD INFO:\u(001b)[0m $(msg)" diff --git a/ci/all_tests.sh b/ci/all_tests.sh index b6c770fd..7c2f141a 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -5,7 +5,7 @@ set -exo pipefail if [ -z "${EXAMPLES_DIR}" ]; then echo "ERROR: The EXAMPLES_DIR environment variable is not set." >&2 - + exit 1 fi @@ -35,7 +35,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build $roc_file $ROC_BUILD_FLAGS + $ROC build --linker=legacy $roc_file $ROC_BUILD_FLAGS done # prep for next step @@ -88,7 +88,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do $absolute_roc dev $base_file $ROC_BUILD_FLAGS cd .. else - $ROC dev $roc_file $ROC_BUILD_FLAGS + $ROC dev --linker=legacy $roc_file $ROC_BUILD_FLAGS fi done diff --git a/ci/rust_http_server/Cargo.toml b/ci/rust_http_server/Cargo.toml index f39ffedb..9416b372 100644 --- a/ci/rust_http_server/Cargo.toml +++ b/ci/rust_http_server/Cargo.toml @@ -8,3 +8,5 @@ edition = "2021" [dependencies] hyper = { version = "=0.14.27", features = ["full"]} tokio = { version = "=1.31.0", features = ["full"]} + +[workspace] diff --git a/platform/Cargo.toml b/crates/roc_host/Cargo.toml similarity index 65% rename from platform/Cargo.toml rename to crates/roc_host/Cargo.toml index 1a07bfa2..e5e12da4 100644 --- a/platform/Cargo.toml +++ b/crates/roc_host/Cargo.toml @@ -1,33 +1,20 @@ [package] -name = "host" +name = "roc_host" version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" -links = "app" - -[profile.release] -lto = true -strip = "debuginfo" -codegen-units = 1 - [lib] -name = "host" +name = "roc_host" path = "src/lib.rs" -crate-type = ["staticlib", "lib"] - -[[bin]] -name = "host" -path = "src/main.rs" +crate-type = ["lib"] [dependencies] -roc_std = { path = "../crates/roc_std" } +roc_std = { path = "../roc_std" } libc = "=0.2.150" backtrace = "=0.3.69" hyper = { version = "=0.14.27", default-features = false, features = ["http1", "client"] } hyper-rustls = { version = "=0.24.2", default-features = false, features = ["http1", "tls12", "native-tokio"]} tokio = { version = "=1.31.0", default-features = false} crossterm = "=0.27.0" - -[workspace] diff --git a/platform/src/lib.rs b/crates/roc_host/src/lib.rs similarity index 100% rename from platform/src/lib.rs rename to crates/roc_host/src/lib.rs diff --git a/crates/roc_host_bin/Cargo.toml b/crates/roc_host_bin/Cargo.toml new file mode 100644 index 00000000..2b336dcd --- /dev/null +++ b/crates/roc_host_bin/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "roc_host_bin" +version = "0.0.1" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +edition = "2021" + +links = "app" + +[[bin]] +name = "host" +path = "src/main.rs" + +[dependencies] +roc_host = { path = "../roc_host" } diff --git a/platform/build.rs b/crates/roc_host_bin/build.rs similarity index 75% rename from platform/build.rs rename to crates/roc_host_bin/build.rs index 47763b34..5af62787 100644 --- a/platform/build.rs +++ b/crates/roc_host_bin/build.rs @@ -1,9 +1,9 @@ fn main() { + println!("cargo:rustc-link-search=platform/"); + #[cfg(not(windows))] println!("cargo:rustc-link-lib=dylib=app"); #[cfg(windows)] println!("cargo:rustc-link-lib=dylib=libapp"); - - println!("cargo:rustc-link-search=."); } diff --git a/crates/roc_host_bin/src/main.rs b/crates/roc_host_bin/src/main.rs new file mode 100644 index 00000000..69ff4189 --- /dev/null +++ b/crates/roc_host_bin/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(roc_host::rust_main()); +} diff --git a/crates/roc_host_lib/Cargo.toml b/crates/roc_host_lib/Cargo.toml new file mode 100644 index 00000000..4eb86d63 --- /dev/null +++ b/crates/roc_host_lib/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "host" +version = "0.0.1" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +edition = "2021" + +[lib] +name = "host" +path = "src/lib.rs" +crate-type = ["staticlib"] + +[dependencies] +roc_host = { path = "../roc_host" } diff --git a/crates/roc_host_lib/src/lib.rs b/crates/roc_host_lib/src/lib.rs new file mode 100644 index 00000000..debb8563 --- /dev/null +++ b/crates/roc_host_lib/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn main() { + roc_host::rust_main(); +} diff --git a/crates/roc_std/src/lib.rs b/crates/roc_std/src/lib.rs index 677c4f63..30cdcdbb 100644 --- a/crates/roc_std/src/lib.rs +++ b/crates/roc_std/src/lib.rs @@ -377,10 +377,6 @@ impl RocDec { } } - pub fn from_str_to_i128_unsafe(val: &str) -> i128 { - Self::from_str(val).unwrap().as_i128() - } - /// This is private because RocDec being an i128 is an implementation detail #[inline(always)] fn as_i128(&self) -> i128 { diff --git a/crates/roc_std/src/roc_dict.rs b/crates/roc_std/src/roc_dict.rs index 918c9558..e46c3a45 100644 --- a/crates/roc_std/src/roc_dict.rs +++ b/crates/roc_std/src/roc_dict.rs @@ -108,9 +108,7 @@ impl Debug for RocDict { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("RocDict ")?; - f.debug_map() - .entries(self.iter().map(|(k, v)| (k, v))) - .finish() + f.debug_map().entries(self.iter()).finish() } } diff --git a/flake.nix b/flake.nix index d41396d0..33cf2ea1 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,7 @@ darwinInputs = with pkgs; lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ + Security ]); sharedInputs = (with pkgs; [ diff --git a/glue.roc b/glue.roc new file mode 100644 index 00000000..668ab7a2 --- /dev/null +++ b/glue.roc @@ -0,0 +1,10 @@ +app [makeGlue] { + pf: platform "https://github.com/lukewilliamboswell/roc/releases/download/test/olBfrjtI-HycorWJMxdy7Dl2pcbbBoJy4mnSrDtRrlI.tar.br", + glue: "https://github.com/lukewilliamboswell/roc-glue-code-gen/releases/download/0.1.0/NprKi63CKBinQjoke2ttsOTHmjmsrmsILzRgzlds02c.tar.br", +} + +import glue.Rust + +# generate the std lib builtins from the Rust glue code package + +makeGlue = \_ -> Ok Rust.builtins diff --git a/platform/host.c b/platform/host.c deleted file mode 100644 index 8d42ed4b..00000000 --- a/platform/host.c +++ /dev/null @@ -1,8 +0,0 @@ -#include - -extern int32_t rust_main(); - -int main() { - int32_t result = rust_main(); - return (int)result; -} diff --git a/platform/libapp.roc b/platform/libapp.roc new file mode 100644 index 00000000..fd4182dd --- /dev/null +++ b/platform/libapp.roc @@ -0,0 +1,14 @@ +app "stub" + packages { pf: "main.roc" } + imports [pf.Task.{ Task }] + provides [main] to pf + +# Throw an error here so we can easily confirm the host +# executable built correctly just by running it. +# +# e.g. +# ``` +# $ ./target/debug/host +# Program exited early with error: JustAStub +# ``` +main = Task.err (JustAStub) diff --git a/platform/rust-toolchain.toml b/platform/rust-toolchain.toml deleted file mode 100644 index 04fe0f33..00000000 --- a/platform/rust-toolchain.toml +++ /dev/null @@ -1,10 +0,0 @@ -[toolchain] -# How to update version: -# 1. update `channel = "RUST_VERSION"` -# 2. update the nightly version: -# a) Find the latest nightly release that matches RUST_VERSION here: https://github.com/oxalica/rust-overlay/tree/master/manifests/nightly/2024 -# b) update `channel = "nightly-OLD_DATE"` below - -channel = "1.79.0" # check ^^^ when changing this -# -# channel = "nightly-2024-04-28" # 1.79.0 nightly to be able to use unstable features diff --git a/platform/src/main.rs b/platform/src/main.rs deleted file mode 100644 index e064d1b0..00000000 --- a/platform/src/main.rs +++ /dev/null @@ -1,22 +0,0 @@ -use core::alloc::Layout; - -fn main() { - host::init(); - let size = unsafe { host::roc_main_size() } as usize; - let layout = Layout::array::(size).unwrap(); - - unsafe { - let buffer = std::alloc::alloc(layout); - - host::roc_main(buffer); - - let out = host::call_the_closure(buffer); - - // TODO: deallocation currently causes a segfault (probably because layout doesn't match main's size). - // investigate why this is and then re-enable this, rather than letting the system clean up the memory. - // - // std::alloc::dealloc(buffer, layout); - - std::process::exit(out); - } -} From 48930ce9e81abdfdd98291316621fd21602536c2 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 09:46:31 +1000 Subject: [PATCH 02/47] chore: cargo clippy and fmt --- crates/roc_host/src/lib.rs | 72 +++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 40 deletions(-) diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index 332fd2c1..85a6a623 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -4,7 +4,6 @@ use core::alloc::Layout; use core::ffi::c_void; use core::mem::MaybeUninit; use roc_std::{RocDict, RocList, RocResult, RocStr}; -use tokio::runtime::Runtime; use std::borrow::{Borrow, Cow}; use std::cell::RefCell; use std::collections::HashMap; @@ -16,6 +15,7 @@ use std::path::Path; use std::rc::Rc; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use tokio::runtime::Runtime; trait CustomBuffered: BufRead + Read + Seek {} @@ -26,14 +26,14 @@ type CustomReader = Rc>>; type ReaderMap = HashMap; thread_local! { - static READERS: RefCell = RefCell::new(HashMap::new()); - static TCP_STREAMS: RefCell>> = RefCell::new(HashMap::new()); - static TOKIO_RUNTIME: Runtime = tokio::runtime::Builder::new_current_thread() - .enable_io() - .enable_time() - .build() - .unwrap(); - } + static READERS: RefCell = RefCell::new(HashMap::new()); + static TCP_STREAMS: RefCell>> = RefCell::new(HashMap::new()); + static TOKIO_RUNTIME: Runtime = tokio::runtime::Builder::new_current_thread() + .enable_io() + .enable_time() + .build() + .unwrap(); +} static READER_INDEX: AtomicU64 = AtomicU64::new(42); static TCP_STREAM_INDEX: AtomicU64 = AtomicU64::new(0); @@ -348,7 +348,7 @@ pub unsafe fn call_the_closure(closure_data_ptr: *const u8) -> i32 { call_Fx( // This flags pointer will never get dereferenced MaybeUninit::uninit().as_ptr(), - closure_data_ptr as *const u8, + closure_data_ptr, &mut out, ); @@ -789,7 +789,10 @@ impl InternalResponse { fn bad_request(error: &str) -> InternalResponse { InternalResponse { variant: "BadRequest".into(), - metadata: Metadata { statusText: RocStr::from(error), ..Metadata::empty() }, + metadata: Metadata { + statusText: RocStr::from(error), + ..Metadata::empty() + }, body: RocList::empty(), } } @@ -819,7 +822,7 @@ impl InternalResponse { } fn network_error() -> InternalResponse { - InternalResponse { + InternalResponse { variant: "NetworkError".into(), metadata: Metadata::empty(), body: RocList::empty(), @@ -829,7 +832,7 @@ impl InternalResponse { #[no_mangle] pub extern "C" fn roc_fx_sendRequest(roc_request: &Request) -> InternalResponse { - let method = parse_http_method(&roc_request.method.as_str()); + let method = parse_http_method(roc_request.method.as_str()); let mut req_builder = hyper::Request::builder() .method(method) .uri(roc_request.url.as_str()); @@ -858,13 +861,13 @@ pub extern "C" fn roc_fx_sendRequest(roc_request: &Request) -> InternalResponse let time_limit = Duration::from_millis(roc_request.timeoutMs); TOKIO_RUNTIME.with(|rt| { - rt.block_on(async { tokio::time::timeout(time_limit, send_request(request, &roc_request.url)).await }) - .unwrap_or_else(|_err| InternalResponse::timeout()) + rt.block_on(async { + tokio::time::timeout(time_limit, send_request(request, &roc_request.url)).await + }) + .unwrap_or_else(|_err| InternalResponse::timeout()) }) } else { - TOKIO_RUNTIME.with(|rt| { - rt.block_on(send_request(request, &roc_request.url)) - }) + TOKIO_RUNTIME.with(|rt| rt.block_on(send_request(request, &roc_request.url))) } } @@ -879,7 +882,7 @@ fn parse_http_method(method: &str) -> hyper::Method { "Post" => hyper::Method::POST, "Put" => hyper::Method::PUT, "Trace" => hyper::Method::TRACE, - _other => unreachable!("Should only pass known HTTP methods from Roc side") + _other => unreachable!("Should only pass known HTTP methods from Roc side"), } } @@ -901,11 +904,9 @@ async fn send_request(request: hyper::Request, url: &str) -> InternalRes let status = response.status(); let status_str = status.canonical_reason().unwrap_or_else(|| status.as_str()); - let headers_iter = response.headers().iter().map(|(name, value)| { - Header { - key: RocStr::from(name.as_str()), - value: RocStr::from(value.to_str().unwrap_or_default()), - } + let headers_iter = response.headers().iter().map(|(name, value)| Header { + key: RocStr::from(name.as_str()), + value: RocStr::from(value.to_str().unwrap_or_default()), }); let metadata = Metadata { @@ -919,9 +920,9 @@ async fn send_request(request: hyper::Request, url: &str) -> InternalRes let body: RocList = RocList::from_iter(bytes); if status.is_success() { - return InternalResponse::good_status(metadata, body); + InternalResponse::good_status(metadata, body) } else { - return InternalResponse::bad_status(metadata, body); + InternalResponse::bad_status(metadata, body) } } Err(err) => { @@ -945,7 +946,7 @@ fn toRocWriteError(err: std::io::Error) -> RocStr { ErrorKind::PermissionDenied => "ErrorKind::PermissionDenied".into(), ErrorKind::TimedOut => "ErrorKind::TimedOut".into(), ErrorKind::WriteZero => "ErrorKind::WriteZero".into(), - _ => RocStr::from(RocStr::from(format!("{:?}", err).as_str())), + _ => format!("{:?}", err).as_str().into(), } } @@ -956,7 +957,7 @@ fn toRocReadError(err: std::io::Error) -> RocStr { ErrorKind::OutOfMemory => "ErrorKind::OutOfMemory".into(), ErrorKind::PermissionDenied => "ErrorKind::PermissionDenied".into(), ErrorKind::TimedOut => "ErrorKind::TimedOut".into(), - _ => RocStr::from(RocStr::from(format!("{:?}", err).as_str())), + _ => format!("{:?}", err).as_str().into(), } } @@ -969,10 +970,7 @@ fn toRocGetMetadataError(err: std::io::Error) -> RocList { } #[no_mangle] -pub extern "C" fn roc_fx_tcpConnect( - host: &RocStr, - port: u16, -) -> RocResult { +pub extern "C" fn roc_fx_tcpConnect(host: &RocStr, port: u16) -> RocResult { let stream = match TcpStream::connect((host.as_str(), port)) { Ok(stream) => stream, Err(err) => return RocResult::err(to_tcp_connect_err(err)), @@ -1050,10 +1048,7 @@ pub extern "C" fn roc_fx_tcpReadExactly( } #[no_mangle] -pub extern "C" fn roc_fx_tcpReadUntil( - stream_id: u64, - byte: u8, -) -> RocResult, RocStr> { +pub extern "C" fn roc_fx_tcpReadUntil(stream_id: u64, byte: u8) -> RocResult, RocStr> { TCP_STREAMS.with(|tcp_streams_local| { let mut streams_mut = tcp_streams_local.borrow_mut(); let Some(stream) = streams_mut.get_mut(&stream_id) else { @@ -1069,10 +1064,7 @@ pub extern "C" fn roc_fx_tcpReadUntil( } #[no_mangle] -pub extern "C" fn roc_fx_tcpWrite( - stream_id: u64, - msg: &RocList, -) -> RocResult<(), RocStr> { +pub extern "C" fn roc_fx_tcpWrite(stream_id: u64, msg: &RocList) -> RocResult<(), RocStr> { TCP_STREAMS.with(|tcp_streams_local| { let mut streams_mut = tcp_streams_local.borrow_mut(); let Some(stream) = streams_mut.get_mut(&stream_id) else { From cb26c57921d6752591c6776060b5d61f3fd2198c Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 09:51:41 +1000 Subject: [PATCH 03/47] restore flake --- flake.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/flake.nix b/flake.nix index 33cf2ea1..d41396d0 100644 --- a/flake.nix +++ b/flake.nix @@ -38,7 +38,6 @@ darwinInputs = with pkgs; lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ - Security ]); sharedInputs = (with pkgs; [ From 2b84a72600b79961a12b11e52e234ea32cadb66d Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 10:09:36 +1000 Subject: [PATCH 04/47] fix: restore rust-toolchain.toml --- flake.nix | 1 + platform/rust-toolchain.toml | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 platform/rust-toolchain.toml diff --git a/flake.nix b/flake.nix index d41396d0..33cf2ea1 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,7 @@ darwinInputs = with pkgs; lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ + Security ]); sharedInputs = (with pkgs; [ diff --git a/platform/rust-toolchain.toml b/platform/rust-toolchain.toml new file mode 100644 index 00000000..04fe0f33 --- /dev/null +++ b/platform/rust-toolchain.toml @@ -0,0 +1,10 @@ +[toolchain] +# How to update version: +# 1. update `channel = "RUST_VERSION"` +# 2. update the nightly version: +# a) Find the latest nightly release that matches RUST_VERSION here: https://github.com/oxalica/rust-overlay/tree/master/manifests/nightly/2024 +# b) update `channel = "nightly-OLD_DATE"` below + +channel = "1.79.0" # check ^^^ when changing this +# +# channel = "nightly-2024-04-28" # 1.79.0 nightly to be able to use unstable features From 24f4d2173ae515c84a16ea2fd2c9418d323fbb93 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 10:25:59 +1000 Subject: [PATCH 05/47] fix: add --prebuilt-platform flag to CI --- ci/all_tests.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 7c2f141a..0b313e70 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -35,7 +35,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build --linker=legacy $roc_file $ROC_BUILD_FLAGS + $ROC build --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS done # prep for next step @@ -88,7 +88,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do $absolute_roc dev $base_file $ROC_BUILD_FLAGS cd .. else - $ROC dev --linker=legacy $roc_file $ROC_BUILD_FLAGS + $ROC dev --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS fi done From 3996094102c3ec9fc7b052fb0f90693ea5012d4f Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 10:43:22 +1000 Subject: [PATCH 06/47] fix: add build step to nix CI --- .github/workflows/ci_nix.yml | 79 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index 333f594b..e036b84d 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -1,44 +1,45 @@ -on: - pull_request: - workflow_dispatch: +on: + pull_request: + workflow_dispatch: # this cancels workflows currently in progress if you start a new one concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - build-and-test-nix: - strategy: - fail-fast: false - matrix: - # macos-12 uses x86-64 machine, macos-14 uses aarch64 - os: [ macos-12, macos-14, ubuntu-22.04 ] - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - # install nix - - uses: cachix/install-nix-action@v23 - with: - nix_path: nixpkgs=channel:nixos-unstable - - - uses: cachix/cachix-action@v12 - with: - name: enigmaticsunrise - authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' - - - name: print architecture - run: uname -m - - - name: Run all tests - run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' - - - name: Run all tests and capture output to check for crash later - run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh 2>&1 | tee all_tests_output.log' - - # Workaround for https://github.com/roc-lang/roc/issues/6688 - - name: Check if crash occurred - run: grep -qv "crashed" all_tests_output.log - - + build-and-test-nix: + strategy: + fail-fast: false + matrix: + # macos-12 uses x86-64 machine, macos-14 uses aarch64 + os: [macos-12, macos-14, ubuntu-22.04] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + # install nix + - uses: cachix/install-nix-action@v23 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - uses: cachix/cachix-action@v12 + with: + name: enigmaticsunrise + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + + - name: print architecture + run: uname -m + + - name: Build platform binary + run: roc ./build.roc + + - name: Run all tests + run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' + + - name: Run all tests and capture output to check for crash later + run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh 2>&1 | tee all_tests_output.log' + + # Workaround for https://github.com/roc-lang/roc/issues/6688 + - name: Check if crash occurred + run: grep -qv "crashed" all_tests_output.log From e749cda6e81f295b04688283ebceb85c2cfd633c Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 11:52:20 +1000 Subject: [PATCH 07/47] feat: add --release to build script --- .github/workflows/test_latest_release.yml | 3 +-- build.roc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test_latest_release.yml b/.github/workflows/test_latest_release.yml index a36a59a1..c7ba152e 100644 --- a/.github/workflows/test_latest_release.yml +++ b/.github/workflows/test_latest_release.yml @@ -7,7 +7,6 @@ concurrency: cancel-in-progress: true jobs: - test-latest-release: runs-on: [ubuntu-20.04] steps: @@ -26,6 +25,6 @@ jobs: - name: Use ./ci/test_latest_release.sh of the latest git main run: mv -f ./temp/test_latest_release.sh ./ci/ - + - name: Run all tests with latest roc release + latest basic-cli release run: EXAMPLES_DIR=./examples/ ./ci/test_latest_release.sh diff --git a/build.roc b/build.roc index 39dfbe3a..7062e8dc 100644 --- a/build.roc +++ b/build.roc @@ -24,7 +24,7 @@ main = cliParser = Cli.weave { - release: <- Opt.flag { short: "r", help: "Release build" }, + release: <- Opt.flag { short: "r", long: "release", help: "Release build" }, } |> Cli.finish { name: "basic-webserver", From d2a434df5082d975e6494137dda99f9bd1c47f1d Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 12:32:57 +1000 Subject: [PATCH 08/47] chore: cleanup build.roc script --- build.roc | 107 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/build.roc b/build.roc index 7062e8dc..4f730b92 100644 --- a/build.roc +++ b/build.roc @@ -40,49 +40,58 @@ main = run = \{ release } -> - printInfoLine! "generating glue for builtins" - Cmd.exec "roc" ["glue", "glue.roc", "crates/", "platform/main.roc"] - |> Task.mapErr! ErrGeneratingGlue + info! "Generating glue for builtins ..." + "roc" + |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] + |> Task.mapErr! ErrGeneratingGlue - printInfoLine! "getting the native target" - target = Env.platform |> Task.await! getNativeTarget + info! "Getting the native target ..." + target = + Env.platform + |> Task.await! getNativeTarget - printInfoLine! "building the app stub shared library for surgical linker" - appStubBuildPath = "platform/libapp.$(appStubExt target)" - printInfoLine! "roc build the app stub shared library at $(appStubBuildPath)" - Cmd.exec "roc" ["build", "--lib", "platform/libapp.roc"] - |> Task.mapErr! ErrBuildingAppStub + stubPath = "platform/libapp.$(stubExt target)" - (cargoBuildArgs, message) = - if release then - (["build", "--release"], "building roc host binaries in release mode") - else - (["build"], "building roc host binaries in debug mode") - - printInfoLine! message - Cmd.exec "cargo" cargoBuildArgs - |> Task.mapErr! ErrBuildingRocHostBinaries + info! "Building stubbed app shared library ..." + "roc" + |> Cmd.exec ["build", "--lib", "platform/libapp.roc", "--output", stubPath] + |> Task.mapErr! ErrBuildingAppStub - # move the prebuilt binary to the platform directory - prebuiltLegacyBinaryBuildPath = + (cargoBuildArgs, message) = if release then - "target/release/libhost.a" + (["build", "--release"], "Building host in RELEASE mode ...") else - "target/debug/libhost.a" - - prebuiltLegacyBinaryPath = "platform/$(prebuiltBinaryName target)" - printInfoLine! "moving the prebuilt binary from $(prebuiltLegacyBinaryBuildPath) to $(prebuiltLegacyBinaryPath)" - Cmd.exec "cp" [prebuiltLegacyBinaryBuildPath, prebuiltLegacyBinaryPath] - |> Task.mapErr! ErrMovingPrebuiltLegacyBinary - - #SURGICAL LINKER IS NOT YET SUPPORTED need to merge https://github.com/roc-lang/roc/pull/6808 - #prebuiltSurgicalBinaryBuildPath = - # if release then - # "target/release/host" - # else - # "target/debug/host" - #Cmd.exec "roc" ["preprocess-host", prebuiltSurgicalBinaryBuildPath, "platform/main.roc", "platform/libapp.$(appStubExt target)"] - #|> Task.mapErr! ErrPreprocessingSurgicalBinary + (["build"], "Building host in DEBUG mode ...") + + info! message + "cargo" + |> Cmd.exec cargoBuildArgs + |> Task.mapErr! ErrBuildingHostBinaries + + hostBuildPath = if release then "target/release/libhost.a" else "target/debug/libhost.a" + hostDestPath = "platform/$(prebuiltStaticLibrary target)" + + info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." + "cp" + |> Cmd.exec [hostBuildPath, hostDestPath] + |> Task.mapErr! ErrMovingPrebuiltLegacyBinary + + # TODO remove this, just a temporary workaround to see if this makes CI happy + # if so we know that linux requires an object `.o` file for some reason... + prebuiltObjectPath = "platform/$(prebuiltObject target)" + info! "Moving the prebuilt binary from $(hostBuildPath) to $(prebuiltObjectPath) ..." + "cp" + |> Cmd.exec [hostBuildPath, prebuiltObjectPath] + |> Task.mapErr! ErrMovingPrebuiltLegacyObject + + # SURGICAL LINKER IS NOT YET SUPPORTED need to merge https://github.com/roc-lang/roc/pull/6808 + #info! "Preprocessing surgical host ..." + #surgicalBuildPath = if release then "target/release/host" else "target/debug/host" + #"roc" + # |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubPath] + # |> Task.mapErr! ErrPreprocessingSurgicalBinary + + info! "Successfully completed building platform binaries." getNativeTarget : _ -> Task RocTarget _ getNativeTarget =\{os, arch} -> @@ -93,15 +102,25 @@ getNativeTarget =\{os, arch} -> (LINUX, X64) -> Task.ok LinuxX64 _ -> Task.err (UnsupportedNative os arch) -appStubExt : RocTarget -> Str -appStubExt = \target -> +stubExt : RocTarget -> Str +stubExt = \target -> when target is MacosX64 | MacosArm64 -> "dylib" LinuxArm64 | LinuxX64-> "so" WindowsX64| WindowsArm64 -> "dll" -prebuiltBinaryName : RocTarget -> Str -prebuiltBinaryName = \target -> +prebuiltStaticLibrary : RocTarget -> Str +prebuiltStaticLibrary = \target -> + when target is + MacosArm64 -> "macos-arm64.a" + MacosX64 -> "macos-x64" + LinuxArm64 -> "linux-arm64.a" + LinuxX64 -> "linux-x64.a" + WindowsArm64 -> "windows-arm64.lib" + WindowsX64 -> "windows-x64.lib" + +prebuiltObject : RocTarget -> Str +prebuiltObject = \target -> when target is MacosArm64 -> "macos-arm64.a" MacosX64 -> "macos-x64" @@ -110,6 +129,6 @@ prebuiltBinaryName = \target -> WindowsArm64 -> "windows-arm64.lib" WindowsX64 -> "windows-x64.lib" -printInfoLine : Str -> Task {} _ -printInfoLine = \msg -> - Stdout.line! "\u(001b)[34mROC BUILD INFO:\u(001b)[0m $(msg)" +info : Str -> Task {} _ +info = \msg -> + Stdout.line! "\u(001b)[34mINFO:\u(001b)[0m $(msg)" From af350398ba253e51ffd0dfd8f7ceb90259b4fb6f Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 12:59:48 +1000 Subject: [PATCH 09/47] try print pwd --- .github/workflows/ci_nix.yml | 2 +- build.roc | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index e036b84d..af8d464e 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -32,7 +32,7 @@ jobs: run: uname -m - name: Build platform binary - run: roc ./build.roc + run: nix develop -c sh -c 'roc ./build.roc' - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' diff --git a/build.roc b/build.roc index 4f730b92..e21e079b 100644 --- a/build.roc +++ b/build.roc @@ -40,6 +40,11 @@ main = run = \{ release } -> + info! "TODO: REMOVE getting cwd ..." + "pwd" + |> Cmd.exec [] + |> Task.mapErr! ErrGettingWorkingDirectory + info! "Generating glue for builtins ..." "roc" |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] From c1f4198b095b788c231136a8af0f016106031573 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 14:40:14 +1000 Subject: [PATCH 10/47] fix: missing file extension on macos-x64.a library --- build.roc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.roc b/build.roc index e21e079b..4bc9fd82 100644 --- a/build.roc +++ b/build.roc @@ -118,7 +118,7 @@ prebuiltStaticLibrary : RocTarget -> Str prebuiltStaticLibrary = \target -> when target is MacosArm64 -> "macos-arm64.a" - MacosX64 -> "macos-x64" + MacosX64 -> "macos-x64.a" LinuxArm64 -> "linux-arm64.a" LinuxX64 -> "linux-x64.a" WindowsArm64 -> "windows-arm64.lib" @@ -128,7 +128,7 @@ prebuiltObject : RocTarget -> Str prebuiltObject = \target -> when target is MacosArm64 -> "macos-arm64.a" - MacosX64 -> "macos-x64" + MacosX64 -> "macos-x64.a" LinuxArm64 -> "linux-arm64.a" LinuxX64 -> "linux-x64.a" WindowsArm64 -> "windows-arm64.lib" From 2cf4da50b74d69b04b563a0550a422c32b6f9cfb Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 15:49:20 +1000 Subject: [PATCH 11/47] feat: improve workspace and path manage for build scripts --- build.roc | 27 ++++++++++++++++----------- crates/roc_host_bin/build.rs | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/build.roc b/build.roc index 4bc9fd82..b79f1e79 100644 --- a/build.roc +++ b/build.roc @@ -7,6 +7,7 @@ import cli.Task exposing [Task] import cli.Cmd import cli.Stdout import cli.Env +import cli.File import cli.Arg import weaver.Opt import weaver.Cli @@ -25,6 +26,7 @@ main = cliParser = Cli.weave { release: <- Opt.flag { short: "r", long: "release", help: "Release build" }, + path: <- Opt.maybeStr { short: "p", long: "path", help: "Path to the workspace root"} } |> Cli.finish { name: "basic-webserver", @@ -38,16 +40,19 @@ main = Ok args -> run args Err message -> Task.err (Exit 1 message) -run = \{ release } -> +run = \{ release, path } -> - info! "TODO: REMOVE getting cwd ..." - "pwd" - |> Cmd.exec [] - |> Task.mapErr! ErrGettingWorkingDirectory + root = path |> Result.withDefault "" + + info! "Checking working directory ..." + "$(root)flake.nix" + |> File.isFile + |> Task.await \exists -> if exists then Task.ok {} else Task.err (ErrInvalidWorkingDir root) + |> Task.mapErr! \err -> ErrWorkingDirectory err root info! "Generating glue for builtins ..." "roc" - |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] + |> Cmd.exec ["glue", "$(root)glue.roc", "$(root)crates/", "$(root)platform/main.roc"] |> Task.mapErr! ErrGeneratingGlue info! "Getting the native target ..." @@ -55,11 +60,11 @@ run = \{ release } -> Env.platform |> Task.await! getNativeTarget - stubPath = "platform/libapp.$(stubExt target)" + stubPath = "$(root)platform/libapp.$(stubExt target)" info! "Building stubbed app shared library ..." "roc" - |> Cmd.exec ["build", "--lib", "platform/libapp.roc", "--output", stubPath] + |> Cmd.exec ["build", "--lib", "$(root)platform/libapp.roc", "--output", stubPath] |> Task.mapErr! ErrBuildingAppStub (cargoBuildArgs, message) = @@ -73,8 +78,8 @@ run = \{ release } -> |> Cmd.exec cargoBuildArgs |> Task.mapErr! ErrBuildingHostBinaries - hostBuildPath = if release then "target/release/libhost.a" else "target/debug/libhost.a" - hostDestPath = "platform/$(prebuiltStaticLibrary target)" + hostBuildPath = if release then "$(root)target/release/libhost.a" else "$(root)target/debug/libhost.a" + hostDestPath = "$(root)platform/$(prebuiltStaticLibrary target)" info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." "cp" @@ -83,7 +88,7 @@ run = \{ release } -> # TODO remove this, just a temporary workaround to see if this makes CI happy # if so we know that linux requires an object `.o` file for some reason... - prebuiltObjectPath = "platform/$(prebuiltObject target)" + prebuiltObjectPath = "$(root)platform/$(prebuiltObject target)" info! "Moving the prebuilt binary from $(hostBuildPath) to $(prebuiltObjectPath) ..." "cp" |> Cmd.exec [hostBuildPath, prebuiltObjectPath] diff --git a/crates/roc_host_bin/build.rs b/crates/roc_host_bin/build.rs index 5af62787..9cbe9816 100644 --- a/crates/roc_host_bin/build.rs +++ b/crates/roc_host_bin/build.rs @@ -1,5 +1,10 @@ +/// Link the stubbed app shared library file with the roc_host_bin exectuable fn main() { - println!("cargo:rustc-link-search=platform/"); + /// The path to the platform directory within the workspace + /// where the libapp.so file is generated by the build.roc script + let platform_path = workspace_dir().join("platform"); + + println!("cargo:rustc-link-search={}", platform_path.display()); #[cfg(not(windows))] println!("cargo:rustc-link-lib=dylib=app"); @@ -7,3 +12,16 @@ fn main() { #[cfg(windows)] println!("cargo:rustc-link-lib=dylib=libapp"); } + +/// Gets the path to the workspace root. +fn workspace_dir() -> std::path::PathBuf { + let output = std::process::Command::new(env!("CARGO")) + .arg("locate-project") + .arg("--workspace") + .arg("--message-format=plain") + .output() + .unwrap() + .stdout; + let cargo_path = std::path::Path::new(std::str::from_utf8(&output).unwrap().trim()); + cargo_path.parent().unwrap().to_path_buf() +} From 13ef211602ada775490d17dc3c563adca2966a63 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 15:53:25 +1000 Subject: [PATCH 12/47] try: ls -al on ./ --- .github/workflows/ci.yml | 4 ++-- .github/workflows/ci_nix.yml | 2 +- build.roc | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d874d8c6..ad00c314 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: Does init() in platform/src/lib.rs contain all roc_fx functions? (Imperfect check) run: cat platform/src/lib.rs | grep -oP 'roc_fx_[^(\s]*' | sort | uniq -u | grep -q . && exit 1 || exit 0 - + - id: try_fetching_testing_release continue-on-error: true run: | @@ -49,7 +49,7 @@ jobs: - run: expect -v - name: Build platform binary - run: ./roc_nightly/roc ./build.roc + run: ./roc_nightly/roc ./build.roc -p ./ - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index af8d464e..4a71b6a1 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -32,7 +32,7 @@ jobs: run: uname -m - name: Build platform binary - run: nix develop -c sh -c 'roc ./build.roc' + run: nix develop -c sh -c 'roc ./build.roc -p ./' - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' diff --git a/build.roc b/build.roc index b79f1e79..28d427b7 100644 --- a/build.roc +++ b/build.roc @@ -50,6 +50,11 @@ run = \{ release, path } -> |> Task.await \exists -> if exists then Task.ok {} else Task.err (ErrInvalidWorkingDir root) |> Task.mapErr! \err -> ErrWorkingDirectory err root + info! "Listing working directory ..." + "ls" + |> Cmd.exec ["-la", "$(root)"] + |> Task.mapErr! ErrListingWorkingDir + info! "Generating glue for builtins ..." "roc" |> Cmd.exec ["glue", "$(root)glue.roc", "$(root)crates/", "$(root)platform/main.roc"] From 0dfa57a4075f9d235d0e9f71ad3628fa59ed56f6 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 17:02:27 +1000 Subject: [PATCH 13/47] try: moving rust_platform.toml --- Cargo.toml | 2 +- crates/roc_host/Cargo.toml | 1 - crates/roc_host/src/lib.rs | 4 ---- crates/roc_host_bin/build.rs | 4 ++-- flake.nix | 2 +- platform/rust-toolchain.toml => rust-toolchain.toml | 0 6 files changed, 4 insertions(+), 9 deletions(-) rename platform/rust-toolchain.toml => rust-toolchain.toml (100%) diff --git a/Cargo.toml b/Cargo.toml index 1630c9d6..bbeff199 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [workspace] resolver = "2" members = [ + "crates/roc_std", "crates/roc_host", "crates/roc_host_lib", "crates/roc_host_bin", - "crates/roc_std", ] [profile.release] diff --git a/crates/roc_host/Cargo.toml b/crates/roc_host/Cargo.toml index e5e12da4..1e2293ef 100644 --- a/crates/roc_host/Cargo.toml +++ b/crates/roc_host/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" [lib] name = "roc_host" path = "src/lib.rs" -crate-type = ["lib"] [dependencies] roc_std = { path = "../roc_std" } diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index 85a6a623..62c5d6c7 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -50,10 +50,6 @@ extern "C" { #[link_name = "roc__mainForHost_0_caller"] fn call_Fx(flags: *const u8, closure_data: *const u8, output: *mut RocResult<(), i32>); - - #[allow(dead_code)] - #[link_name = "roc__mainForHost_0_size"] - fn size_Fx() -> i64; } /// # Safety diff --git a/crates/roc_host_bin/build.rs b/crates/roc_host_bin/build.rs index 9cbe9816..e59f87f3 100644 --- a/crates/roc_host_bin/build.rs +++ b/crates/roc_host_bin/build.rs @@ -1,7 +1,7 @@ /// Link the stubbed app shared library file with the roc_host_bin exectuable fn main() { - /// The path to the platform directory within the workspace - /// where the libapp.so file is generated by the build.roc script + // The path to the platform directory within the workspace + // where the libapp.so file is generated by the build.roc script let platform_path = workspace_dir().join("platform"); println!("cargo:rustc-link-search={}", platform_path.display()); diff --git a/flake.nix b/flake.nix index 33cf2ea1..27cb3198 100644 --- a/flake.nix +++ b/flake.nix @@ -28,7 +28,7 @@ # get current working directory cwd = builtins.toString ./.; rust = - pkgs.rust-bin.fromRustupToolchainFile "${cwd}/platform/rust-toolchain.toml"; + pkgs.rust-bin.fromRustupToolchainFile "${toString ./rust-toolchain.toml}"; linuxInputs = with pkgs; lib.optionals stdenv.isLinux [ diff --git a/platform/rust-toolchain.toml b/rust-toolchain.toml similarity index 100% rename from platform/rust-toolchain.toml rename to rust-toolchain.toml From 244fb6261a6ba82e50aeeb2ba51a5865fda2df9c Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 17:21:09 +1000 Subject: [PATCH 14/47] try: building in release mode --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_nix.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad00c314..042f8add 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - run: expect -v - name: Build platform binary - run: ./roc_nightly/roc ./build.roc -p ./ + run: ./roc_nightly/roc ./build.roc --release -path ./ - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index 4a71b6a1..3ee551fa 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -32,7 +32,7 @@ jobs: run: uname -m - name: Build platform binary - run: nix develop -c sh -c 'roc ./build.roc -p ./' + run: nix develop -c sh -c 'roc ./build.roc --release -path ./' - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' From d76f49d25cbd84e6ef9db95fb35609fd69a6f3c6 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 17:22:46 +1000 Subject: [PATCH 15/47] fix: incorrect --path arg to build script --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_nix.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 042f8add..f8443f3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - run: expect -v - name: Build platform binary - run: ./roc_nightly/roc ./build.roc --release -path ./ + run: ./roc_nightly/roc ./build.roc --release --path ./ - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index 3ee551fa..d3518ad7 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -32,7 +32,7 @@ jobs: run: uname -m - name: Build platform binary - run: nix develop -c sh -c 'roc ./build.roc --release -path ./' + run: nix develop -c sh -c 'roc ./build.roc --release --path ./' - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' From ed9afc46677d10dee2ddb7100fe2d02dc5d867e2 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 17:25:32 +1000 Subject: [PATCH 16/47] remove unused glue script --- glue.sh | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 glue.sh diff --git a/glue.sh b/glue.sh deleted file mode 100644 index 3877ebb8..00000000 --- a/glue.sh +++ /dev/null @@ -1,2 +0,0 @@ - -roc glue ../roc/crates/glue/src/RustGlue.roc crates/ platform/main-glue.roc \ No newline at end of file From e819d570bcf01c6cc965d35f5fc76495af95c669 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 19:27:33 +1000 Subject: [PATCH 17/47] fix: path.roc being called incorectly --- ci/all_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 0b313e70..cd663603 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -85,7 +85,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do if [ "$base_file" == "path.roc" ]; then absolute_roc=$(which $ROC | xargs realpath) cd $EXAMPLES_DIR - $absolute_roc dev $base_file $ROC_BUILD_FLAGS + $absolute_roc dev --linker=legacy --prebuilt-platform $base_file $ROC_BUILD_FLAGS cd .. else $ROC dev --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS From 1e3ab8f6500f45dcf283a596d8976a61c243d2e3 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 3 Jul 2024 11:43:12 +0200 Subject: [PATCH 18/47] ls -R --- build.roc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.roc b/build.roc index 28d427b7..0c687e7a 100644 --- a/build.roc +++ b/build.roc @@ -52,7 +52,7 @@ run = \{ release, path } -> info! "Listing working directory ..." "ls" - |> Cmd.exec ["-la", "$(root)"] + |> Cmd.exec ["-R", "$(root)"] |> Task.mapErr! ErrListingWorkingDir info! "Generating glue for builtins ..." From 245ebd7bc589b1ce2e752852e9109d056a8c4a61 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 19:50:00 +1000 Subject: [PATCH 19/47] feat: pass argument to roc cli into build script --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_nix.yml | 2 +- build.roc | 11 ++++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8443f3a..fa95a291 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - run: expect -v - name: Build platform binary - run: ./roc_nightly/roc ./build.roc --release --path ./ + run: ./roc_nightly/roc ./build.roc --release --path ./ --roc ./roc_nightly/roc - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index d3518ad7..e5e6a2de 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -32,7 +32,7 @@ jobs: run: uname -m - name: Build platform binary - run: nix develop -c sh -c 'roc ./build.roc --release --path ./' + run: nix develop -c sh -c 'roc ./build.roc --release --path ./ --roc roc' - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' diff --git a/build.roc b/build.roc index 0c687e7a..e3651878 100644 --- a/build.roc +++ b/build.roc @@ -26,7 +26,8 @@ main = cliParser = Cli.weave { release: <- Opt.flag { short: "r", long: "release", help: "Release build" }, - path: <- Opt.maybeStr { short: "p", long: "path", help: "Path to the workspace root"} + path: <- Opt.maybeStr { short: "p", long: "path", help: "Path to the workspace root"}, + roc: <- Opt.str { short: "d", long: "roc", help: "Path to the roc binary"}, } |> Cli.finish { name: "basic-webserver", @@ -40,7 +41,7 @@ main = Ok args -> run args Err message -> Task.err (Exit 1 message) -run = \{ release, path } -> +run = \{ release, path, roc } -> root = path |> Result.withDefault "" @@ -56,7 +57,7 @@ run = \{ release, path } -> |> Task.mapErr! ErrListingWorkingDir info! "Generating glue for builtins ..." - "roc" + roc |> Cmd.exec ["glue", "$(root)glue.roc", "$(root)crates/", "$(root)platform/main.roc"] |> Task.mapErr! ErrGeneratingGlue @@ -68,7 +69,7 @@ run = \{ release, path } -> stubPath = "$(root)platform/libapp.$(stubExt target)" info! "Building stubbed app shared library ..." - "roc" + roc |> Cmd.exec ["build", "--lib", "$(root)platform/libapp.roc", "--output", stubPath] |> Task.mapErr! ErrBuildingAppStub @@ -102,7 +103,7 @@ run = \{ release, path } -> # SURGICAL LINKER IS NOT YET SUPPORTED need to merge https://github.com/roc-lang/roc/pull/6808 #info! "Preprocessing surgical host ..." #surgicalBuildPath = if release then "target/release/host" else "target/debug/host" - #"roc" + #roc # |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubPath] # |> Task.mapErr! ErrPreprocessingSurgicalBinary From 614f2d5165e500d013f1272e702887e499f65799 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 20:01:52 +1000 Subject: [PATCH 20/47] chore: cleanup CI debugging things --- .github/workflows/ci.yml | 2 +- .github/workflows/ci_nix.yml | 2 +- build.roc | 76 +++++++++++------------------------- 3 files changed, 24 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa95a291..2c7f3272 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - run: expect -v - name: Build platform binary - run: ./roc_nightly/roc ./build.roc --release --path ./ --roc ./roc_nightly/roc + run: ./roc_nightly/roc ./build.roc --release --cli ./roc_nightly/roc - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index e5e6a2de..88827bf0 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -32,7 +32,7 @@ jobs: run: uname -m - name: Build platform binary - run: nix develop -c sh -c 'roc ./build.roc --release --path ./ --roc roc' + run: nix develop -c sh -c 'roc ./build.roc --release' - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' diff --git a/build.roc b/build.roc index e3651878..e3aded56 100644 --- a/build.roc +++ b/build.roc @@ -7,27 +7,16 @@ import cli.Task exposing [Task] import cli.Cmd import cli.Stdout import cli.Env -import cli.File import cli.Arg import weaver.Opt import weaver.Cli -RocTarget : [ - MacosArm64, - MacosX64, - LinuxArm64, - LinuxX64, - WindowsArm64, - WindowsX64, -] - main = cliParser = Cli.weave { release: <- Opt.flag { short: "r", long: "release", help: "Release build" }, - path: <- Opt.maybeStr { short: "p", long: "path", help: "Path to the workspace root"}, - roc: <- Opt.str { short: "d", long: "roc", help: "Path to the roc binary"}, + maybeRoc: <- Opt.maybeStr { short: "c", long: "cli", help: "Path to the roc cli"}, } |> Cli.finish { name: "basic-webserver", @@ -41,24 +30,13 @@ main = Ok args -> run args Err message -> Task.err (Exit 1 message) -run = \{ release, path, roc } -> - - root = path |> Result.withDefault "" +run = \{ release, maybeRoc } -> - info! "Checking working directory ..." - "$(root)flake.nix" - |> File.isFile - |> Task.await \exists -> if exists then Task.ok {} else Task.err (ErrInvalidWorkingDir root) - |> Task.mapErr! \err -> ErrWorkingDirectory err root - - info! "Listing working directory ..." - "ls" - |> Cmd.exec ["-R", "$(root)"] - |> Task.mapErr! ErrListingWorkingDir + roc = maybeRoc |> Result.withDefault "roc" info! "Generating glue for builtins ..." roc - |> Cmd.exec ["glue", "$(root)glue.roc", "$(root)crates/", "$(root)platform/main.roc"] + |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] |> Task.mapErr! ErrGeneratingGlue info! "Getting the native target ..." @@ -66,11 +44,11 @@ run = \{ release, path, roc } -> Env.platform |> Task.await! getNativeTarget - stubPath = "$(root)platform/libapp.$(stubExt target)" + stubPath = "platform/libapp.$(stubExt target)" info! "Building stubbed app shared library ..." roc - |> Cmd.exec ["build", "--lib", "$(root)platform/libapp.roc", "--output", stubPath] + |> Cmd.exec ["build", "--lib", "platform/libapp.roc", "--output", stubPath] |> Task.mapErr! ErrBuildingAppStub (cargoBuildArgs, message) = @@ -84,31 +62,31 @@ run = \{ release, path, roc } -> |> Cmd.exec cargoBuildArgs |> Task.mapErr! ErrBuildingHostBinaries - hostBuildPath = if release then "$(root)target/release/libhost.a" else "$(root)target/debug/libhost.a" - hostDestPath = "$(root)platform/$(prebuiltStaticLibrary target)" + hostBuildPath = if release then "target/release/libhost.a" else "target/debug/libhost.a" + hostDestPath = "platform/$(prebuiltStaticLibrary target)" info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." "cp" |> Cmd.exec [hostBuildPath, hostDestPath] |> Task.mapErr! ErrMovingPrebuiltLegacyBinary - # TODO remove this, just a temporary workaround to see if this makes CI happy - # if so we know that linux requires an object `.o` file for some reason... - prebuiltObjectPath = "$(root)platform/$(prebuiltObject target)" - info! "Moving the prebuilt binary from $(hostBuildPath) to $(prebuiltObjectPath) ..." - "cp" - |> Cmd.exec [hostBuildPath, prebuiltObjectPath] - |> Task.mapErr! ErrMovingPrebuiltLegacyObject - - # SURGICAL LINKER IS NOT YET SUPPORTED need to merge https://github.com/roc-lang/roc/pull/6808 - #info! "Preprocessing surgical host ..." - #surgicalBuildPath = if release then "target/release/host" else "target/debug/host" - #roc - # |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubPath] - # |> Task.mapErr! ErrPreprocessingSurgicalBinary + info! "Preprocessing surgical host ..." + surgicalBuildPath = if release then "target/release/host" else "target/debug/host" + roc + |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubPath] + |> Task.mapErr! ErrPreprocessingSurgicalBinary info! "Successfully completed building platform binaries." +RocTarget : [ + MacosArm64, + MacosX64, + LinuxArm64, + LinuxX64, + WindowsArm64, + WindowsX64, +] + getNativeTarget : _ -> Task RocTarget _ getNativeTarget =\{os, arch} -> when (os, arch) is @@ -135,16 +113,6 @@ prebuiltStaticLibrary = \target -> WindowsArm64 -> "windows-arm64.lib" WindowsX64 -> "windows-x64.lib" -prebuiltObject : RocTarget -> Str -prebuiltObject = \target -> - when target is - MacosArm64 -> "macos-arm64.a" - MacosX64 -> "macos-x64.a" - LinuxArm64 -> "linux-arm64.a" - LinuxX64 -> "linux-x64.a" - WindowsArm64 -> "windows-arm64.lib" - WindowsX64 -> "windows-x64.lib" - info : Str -> Task {} _ info = \msg -> Stdout.line! "\u(001b)[34mINFO:\u(001b)[0m $(msg)" From f8c8d0ae66731d3dea6b73485616e4bb1152aba7 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 3 Jul 2024 20:13:50 +1000 Subject: [PATCH 21/47] chore: update flake to latest nightly --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index c2c3d660..2358380e 100644 --- a/flake.lock +++ b/flake.lock @@ -102,11 +102,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1719834518, - "narHash": "sha256-5gkZjzHe5exZHq9VNzVAyJ1uOx7WPSVvWAuo8r5mmg0=", + "lastModified": 1719966224, + "narHash": "sha256-808HOv+WTv/QhTlkC0eu/KS0vV0652+8XdR0ySOrRUI=", "owner": "roc-lang", "repo": "roc", - "rev": "05ab0183805907c3042e9f946a08b793ea75c038", + "rev": "f69d39dffce472fba35681dbc8b920b3d9bf7319", "type": "github" }, "original": { @@ -158,11 +158,11 @@ ] }, "locked": { - "lastModified": 1719800573, - "narHash": "sha256-9DLgG4T6l7cc4pJNOCcXGUwHsFfUp8KLsiwed65MdHk=", + "lastModified": 1719973106, + "narHash": "sha256-IGCdN/m7DfwUfxZjFnlTiTtpwSHCb01P/LWavAKD2jw=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "648b25dd9c3acd255dc50c1eb3ca8b987856f675", + "rev": "fb733500aead50880b9b301f34a0061bf997d6f2", "type": "github" }, "original": { From 0a28ce93643161d366d086671bb936ed71708fc7 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Wed, 3 Jul 2024 20:23:09 +0200 Subject: [PATCH 22/47] small improvements --- .github/workflows/ci.yml | 3 --- .github/workflows/ci_nix.yml | 3 --- build.roc | 52 ++++++++++++++++++++---------------- ci/all_tests.sh | 3 +++ 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c7f3272..d5c8050a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,9 +48,6 @@ jobs: - run: expect -v - - name: Build platform binary - run: ./roc_nightly/roc ./build.roc --release --cli ./roc_nightly/roc - - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh diff --git a/.github/workflows/ci_nix.yml b/.github/workflows/ci_nix.yml index 88827bf0..b303ccf3 100644 --- a/.github/workflows/ci_nix.yml +++ b/.github/workflows/ci_nix.yml @@ -31,9 +31,6 @@ jobs: - name: print architecture run: uname -m - - name: Build platform binary - run: nix develop -c sh -c 'roc ./build.roc --release' - - name: Run all tests run: nix develop -c sh -c 'export ROC=roc && export EXAMPLES_DIR=./examples/ && ./ci/all_tests.sh' diff --git a/build.roc b/build.roc index e3aded56..f76bfcfc 100644 --- a/build.roc +++ b/build.roc @@ -1,6 +1,5 @@ app [main] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/cf_TpThUd4e69C7WzHxCbgsagnDmk3xlb_HmEKXTICw.tar.br", - weaver: "https://github.com/smores56/weaver/releases/download/0.2.0/BBDPvzgGrYp-AhIDw0qmwxT0pWZIQP_7KOrUrZfp_xw.tar.br", + cli: platform "TODO use updated basic-cli 0.12.0 (requires changes from github.com/roc-lang/basic-cli/pull/224)", } import cli.Task exposing [Task] @@ -8,29 +7,35 @@ import cli.Cmd import cli.Stdout import cli.Env import cli.Arg -import weaver.Opt -import weaver.Cli - +import cli.Arg.Opt as Opt +import cli.Arg.Cli as Cli + +## Builds the basic-cli [platform](https://www.roc-lang.org/platforms). +## +## run with: roc ./build.roc --release +## +main : Task {} _ main = cliParser = - Cli.weave { - release: <- Opt.flag { short: "r", long: "release", help: "Release build" }, - maybeRoc: <- Opt.maybeStr { short: "c", long: "cli", help: "Path to the roc cli"}, + Cli.build { + releaseMode: <- Opt.flag { short: "r", long: "release", help: "Release build. Passes `--release` to `cargo build`." }, + maybeRoc: <- Opt.maybeStr { short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path."}, } |> Cli.finish { - name: "basic-webserver", + name: "basic-cli-builder", version: "", authors: ["Luke Boswell "], - description: "This build script generates the binaries and packages the platform for distribution.", + description: "Generates all files needed by Roc to use this basic-cli platform.", } |> Cli.assertValid when Cli.parseOrDisplayMessage cliParser (Arg.list!) is Ok args -> run args - Err message -> Task.err (Exit 1 message) + Err errMsg -> Task.err (Exit 1 errMsg) -run = \{ release, maybeRoc } -> +run : { releaseMode : Bool, maybeRoc : Result Str err} -> Task {} _ +run = \{ releaseMode, maybeRoc } -> roc = maybeRoc |> Result.withDefault "roc" @@ -39,31 +44,32 @@ run = \{ release, maybeRoc } -> |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] |> Task.mapErr! ErrGeneratingGlue + # target is MacosArm64, LinuxX64,... info! "Getting the native target ..." target = Env.platform |> Task.await! getNativeTarget - stubPath = "platform/libapp.$(stubExt target)" + stubPath = "platform/libapp.$(stubFileExtension target)" info! "Building stubbed app shared library ..." roc |> Cmd.exec ["build", "--lib", "platform/libapp.roc", "--output", stubPath] |> Task.mapErr! ErrBuildingAppStub - (cargoBuildArgs, message) = - if release then + (cargoBuildArgs, infoMessage) = + if releaseMode then (["build", "--release"], "Building host in RELEASE mode ...") else (["build"], "Building host in DEBUG mode ...") - info! message + info! infoMessage "cargo" |> Cmd.exec cargoBuildArgs |> Task.mapErr! ErrBuildingHostBinaries - hostBuildPath = if release then "target/release/libhost.a" else "target/debug/libhost.a" - hostDestPath = "platform/$(prebuiltStaticLibrary target)" + hostBuildPath = if releaseMode then "target/release/libhost.a" else "target/debug/libhost.a" + hostDestPath = "platform/$(prebuiltStaticLibFile target)" info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." "cp" @@ -71,7 +77,7 @@ run = \{ release, maybeRoc } -> |> Task.mapErr! ErrMovingPrebuiltLegacyBinary info! "Preprocessing surgical host ..." - surgicalBuildPath = if release then "target/release/host" else "target/debug/host" + surgicalBuildPath = if releaseMode then "target/release/host" else "target/debug/host" roc |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubPath] |> Task.mapErr! ErrPreprocessingSurgicalBinary @@ -96,15 +102,15 @@ getNativeTarget =\{os, arch} -> (LINUX, X64) -> Task.ok LinuxX64 _ -> Task.err (UnsupportedNative os arch) -stubExt : RocTarget -> Str -stubExt = \target -> +stubFileExtension : RocTarget -> Str +stubFileExtension = \target -> when target is MacosX64 | MacosArm64 -> "dylib" LinuxArm64 | LinuxX64-> "so" WindowsX64| WindowsArm64 -> "dll" -prebuiltStaticLibrary : RocTarget -> Str -prebuiltStaticLibrary = \target -> +prebuiltStaticLibFile : RocTarget -> Str +prebuiltStaticLibFile = \target -> when target is MacosArm64 -> "macos-arm64.a" MacosX64 -> "macos-x64.a" diff --git a/ci/all_tests.sh b/ci/all_tests.sh index cd663603..dc6aa2bb 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -19,6 +19,9 @@ if [ -z "${ROC}" ]; then exit 1 fi +# build the basic-cli platform +$ROC ./build.roc --release --roc $ROC + # roc check for roc_file in $EXAMPLES_DIR*.roc; do $ROC check $roc_file From 6bcdd66a63b02a486d31ef3ac7ba23dce8082266 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Thu, 4 Jul 2024 14:41:28 +1000 Subject: [PATCH 23/47] add build steps diagram --- 20240704-basic-cli-build-steps.png | Bin 0 -> 227504 bytes README.md | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 20240704-basic-cli-build-steps.png diff --git a/20240704-basic-cli-build-steps.png b/20240704-basic-cli-build-steps.png new file mode 100644 index 0000000000000000000000000000000000000000..43a023b0dc06405b28b248cca0aef40ea79e619f GIT binary patch literal 227504 zcmeEug6Gs7ICLloNH<7#mvqB#@Ls*X zzx%w;U+}_*bB38cd-h&?<#(+;fl?B}7-$4&FfcF}q9TGaFfhoTFfa(OP~d}X|VtFmE|*by&mAbBl?OAhwTZ2Kn4Sg!UyxO!|*u-OwoNLBdmX2`J;WAKMWk}_P=lbrwI-} z3@q0(MI+q*(hYW+68wJ~2{s(cAnF%z=6`A93DZaLzt086%Lkj!QvyYv!1sThFAOY# z;rM^KibClF182)$Hca!sQ4E+g8DAyR|3c4ul8`+^z)pMQ9V7JY9|HZWIcx&kf4K^W z`pgq18M}xT?LV&CUw5Jm7X6p2*di#f2pc|{+0y@M-T!_zpQk>?f8dH=Bje)-=1PqK z3gQ1Rix0w0nM`zEH@ce>i_YOAmm9LG4D_Vxo`Pa?b7RGm#OUM!7t>yBcu z$L)o|&E?5jJh#Ihzc1S4Ga)XV^W`w!+uN&sZ$$L9t|)5a#6ELzBdAHA$+$m}wMe;k zd&ThaM6t?xj%=gj!3Qj!^U{{vsWPn(Akp0cyAGWpGeMnxdIic$x^7jQu5%Odu*sm$ z=Ma_3G1qu{U=Cg@l$OR9*MTHYIIaaB<+$CO<8%b(g;SC#BbgX%*rxea$Ms|fu+X`P zXRMrDu0-;9v5Lp>kZ@$dSz){cvPJWSe!fh0KhM>U9|oa(iK^3TcZ_@6$@avVFo!`u z(Vc0~DaX9)vVz5Eo^%kzG9dYLiCV*6)0w&&Mc1V=9lzVW+gZCh@qiQ@JkkS8P&Gg* zoMQoEW}~h$t+tuQ?r7Rd?RK=jRB9PIVw#aU8rY_a(bP^F?mCR1D!#!qXc_H1OWU4~%qlwXEgn3#2YPFWo>zwHht%%BP~- za)gRmkm#rD+EK0l_7-)?;j$J2j zYJ-&qlG%@}1V+)XBzbRaz2Fcdoxd7AnfVq$fv34gAZ6?gaE&@RqxJj9ASDEgdGiG* z!u530z~ge0T1~Aus@d(Tz9&gZKLMmrLJ|5(d%Q@Az&?b4?bs&yx`!2Ky7yJwN^T#@ zzg@(1z8Q)$m$}169r^Tfl=gzfV$WX&pnN>((ND9G~L+OG%JD2H0|lW|P<~+l4($#k_9y zblSoL=(d-G|p(d6|(ORq@(Bv7B!cxxgjjYcD~G zKYa1k&o^^Z>)(!-sB!NY;t`Ziz|G`Sr@G2;K`YI2xZb*Nr;B~#p-IDM#@W_j>FX+u^2kLt^8be<57|Mm-1NKIZu8_ zX9^k3zkBBmx`Pgf8LF@L#3@t~w0tElJOLCNlUlu;zxyo)@tpm%*}IRAW26Cnree`F zcCAMnK+R#vA4s_YmZeZI&*fw*+l|5wbu@r4*=}5ELfxf!pUAl7 zY|e!stlKVLPzEGB<9>Z0+-@>&J0i}YQhi)Vv!|}I*mrl9c}NE-*uYV>YR8MAgB;Gb zPC2virRNwcO@_qyWWD`>)Jg0xBTAi|)x_0y*(qZ-zeDquhW zq3O|R5Z_`$RO5MLE!9|=Kd_~+&2G9sq2bXqeIYxs)XOr!N}8CDRGLMkeGXWoEuOR< zxmruDcbi+)kMy24*e~&=2PxwyYZ7=~%2cDRIy{cOJlRgQpE9ZsW#?yEDPqeP=#%DE zl{Xh6m-l94q=4=cP7gw&msGFa%m1x1umci5e>shGnGx5`4(c{@p45w*45k!8l#|Qn zKiL{%L4K;!8F~VJCaM{U-}jb3Ci)e3^iYe(-F8VsKbSI>(|0IF}!(o1VPDMDkV`$0Rf!HtAwcAX}$etGd5wZ zZL>yu?|;wISuEk>;pYiHGTD&jn5^O;vh z8^hl4t6ZZ}Y-`jhj^q||jp+sd8yxssjGg9oV?D7ma>zg*%J`U;?#hi8!TKM2C zEeoaR>N(82)sVD(7wH|8JXlZlAi3Om%YlKRZVuR|v91cha6z+ij0Wj2b{GZX|FP0kI}< zNnFdflne9(PS%O0#A?%w4HWpWWqE;#9>naf6n!@HwV@OB)_9p7b;xaf>Vx_ScWbY3 z;NoyK3fm|}rVWp+h)flP`UI^J5{WFE3UAOxLdQOzf{>@Z-k&V)7TZ#91NFlsrh^VC zq_S1d)Y&vtqJi9RFV?f&{qzcvDbeUp#teMzrZvB+hDk=7w1TxcaEDCA7+FESj&uRv zM-8Y-XcbD5d>6%}-4=cETTi!Hq@&B%@CtZL!kyEWbma-l;C%2N-%Od5){!!{AA;U1 zCMSG&uo|H7;)*sm38#Q(I|SB+KeN_O!!5Ri!DtMc=|F+YL;4s>A}jjow86%HhK6!* zTPr4iARz)liLj1D+{pKd*2Dy$-~f|?Y=F!NUXu6TW^6vqEXts{?VrNBA=V8C>J#Cj;3GqIkxB$s183|n1Z>ddEXTea!Q``q1@AA*qn9tH3IE>_o_b>VpnoAku;(?<_KlgL46DgE@rOjBx z8m@stleJ?Z8LC9qQ8T45>hsS=<##GqbQEsK6f{IRV+0Ewb@K~lSj1xK^JRgLy5nK7 zegeEA={!oiBWx3 z6;rGUc5AEu7mvBSj;8P?%6}9L_7k)&v9onjNdmw#PdAr{BD3yw~24daE}Dv3HWrUp_{qZW~1(9y2>=>{N}#K4a>XoNE)@ z*sPN1NIC6N2X?}ujSl@v^0JSROX~2 zw6~ElF+c;8z5=QDdkytJf6xBmDmRFkBrW zz%w)|OYnWRE(FFX>13oK!CTU;>wTYCUSw9DAvjxF9!<^HsbeTt+YX)!I&wQ2ZL3SQ zcrq=Akc}C$Auoz_T+WKwFYH|bn&`KnljfGFwlTmHDcL=FUk~9@L$tl3#l-d5-rw6W zzL*b+jP)$^)Na=Y^PsN?kE`3nwvdO4UJz%G$AUKsr>j7& zk2?6WV8D1X?)!0>AgYJki4x{i@et~K#mRB2LMkL9ETuvbY>T)xl|4Z#8bx<8u}#)h zo5Rz9<0f_i)zrOfg0%@SfAvLy$33gKko?QUQ?u!6wv$QaBb}od{V(0gTJNK+_>Cm1 zg!A$X``)Heugey1HX<3!72J)GO&ajXq(mp&;EV zfqAK&BOtchi=(+Jv-gSe*7r?lj>3P$LA%}aKrgjSupY+-eyFrxJR#rK#&>*6in~Qg zZGI5(L_p(4Ho{bP9yhzN@bQ+uc8%aJpS6vR{6d{xtQ1j=?=@)f`^ARz7l?wI-feSw zCyB%Y=Faryl@By#ye-WaZP3|sQM-`AC2&3f&Sf_uP`ms_wjv~u0QE}8gfjwf*qoq{ zJYS7l>m{9;FSiM5^o<0S?G%B$t<46bH#_C3(GUpTUCm&-6Z~>^?;z5bp+VLvGf%NR zgM_RuH5Bk~rQhy>pX&^`R0U>`6m#ObpVwiGwa}odp(g0h>p8n z=E<%`?&3}v~zh-kP{LPiSA z7IUwA`j$+R_lmOZBUm$&1RV zIyj>(J-CX+E&1$99kAW!IXG5$P0hYASUDalI_(AfHH4q{%K7y|>ognpJN0cd)Y3el)v0~JxX0A~U6vYRf56`zB<`9C=GA{zGrtRwiVoI1); zcsQjSSb6}9_qq%Zd@7T&agL*^NMXcrEu{g?LFufj*;F2kH357^_k~#x2k>FMEyyhk zhptPYfXmJ)LzYbh^(OxiOXSDn`~o2y*8IW6_^o1D*f*mN@&$U_qm@2Y=!3CZe0`VJ z=_kwphz5_7;Mz8G-J{E#_xJk$GM^5pA~sv2qCx1IeQ_vme8vgsg_xKjzDI z{D&W#khTL6e0r7^!_5?g?_Vu{% z&^Q>s#2+%=z!DscX_g1*Ypa^lw^N=13K7YN>q|LZ96x~o1Qb)%7K1yLH?RzHw)5;b zu%wt24?Wc>nWF)PE-K=wB45CWRx9I+Zh#U1!vwD145fs}nzg;f*(=EZ;|k+VV(uLtfGBtQRLr{FN0#BC_)Rk4@$+2Jr}@05oT! zNNMDCpVWDst&_tBXf$?J$?9@STzXfeDw)L~bW~+zgz7yqiQ_k6QB75o?$|wlIh8PW z*>`E6M;~LZ{M==#*fKx|kF>K8eNDt|A_7W%Hr=f)5ivn(VL6Y^QK9Kuh~90O+`Z87 zjTmf)D}oe^SGIVQv>uG+LasmUp{Jzg(x->(hA2^T!yBT)F5aGrKQ zgYlxI{LBD?;3KN$xB9Xm5W$kCEi0kQuwEMng^rr+c-1Vs`9CNVi>6sTTSA_@Ts@cs zho%dD#(Mq3lO0KJ&aYgjlg`LAjn-Eagv%8kz`3wY8cQqN!CRzKQ)2IPB*wp6mZ6oG z7=u7YQ&^fD84)0QvCFN37KaD!#VADV`7*5c4fE@+@`>Ej=hY+*GgexuM4w=aXJ}zp zNB2eY>u1wPU3*w`(nli2W#1<))jWrC{gC_IfB7`t?8jrH?HOE@nQ|TBT<-0MAIWo| zYAN!e4@bh%5w^t>*}Hh96sX3Fsy54bizAjIPL5YE)>Gq_ii9Yyww60|=7%j$RJ$>g z)6XbXyY;O`cznDn_Xhp43}CeUDLHOx<44W6sY7T?U&vI&d|U=R9Qh36_82iY``qKo zqN*3q(+UUuwmyg-g993FMBwc!(Yf&*f-HWj;umlY4!h1J19Q~*>$Y3UMY=}Zz7gcG z8`%LU$Uv&u3B|GpJO+hPD6m|7088NsV@4yR_5Ra~FK4kn_@b|6rj+Jot5>5iqC2e& zova}f_*`~*pF5<)XGW7=U0SP&1da&b(1DH@zI=dwOpb(6G->n43M1zO0^Z5jdI*A& z*=#5)=&@m3*4i0`Pf+|$RAiaW?*=C&URGI0(E^BCZML3_yR4R(M?&l_$LI+88$3PI z@HK&C9omj(W5Wro-9<*mAkc-YI`mOIuIC-~DM1Kf*t-woL~KxBEMorz^LX5M+gEw_o!0X; zBQn%1nn9>u^h&Qhmhu(}6w@=_4K$xuWD#f`j)>8zK0t!QepQCRZ=uxX`a#@5K0n!% zro@&M2ZNtX42KL+c#E-6PHhv+SXwxC%&~K5L;LNE9N{{B)8-ds(yE|*HaKu9QyCqi z*L;G^873inFH;2hc&0E`%h$*OAj-P}(hjeNu4oXwh$t1HhC@py6B-jr^BRY#wxpmy zX61`K$Wio50DmzW$+@7ah?(b0T$mKTu!qOAcbrgj$amn5es(xTJH+%-^d&>oAz^TP ziF|RwDhJBWs^M4+PkTiz4bHgaOH-bFW?W-4EJBG_i#}y`Y%df_-lGF47WC~*gbii( zJvo0&;@(aTQ*+Vpv@BJ;b4GXW=0H>j3T_X7zmFirX~HC4n1MjAY`rH%sOeWQz?H43 zwN55FE4fs}pDIczJ-4Fi8Nya$g6U zGkPf#iU?aInbJXTXWM7pvmjaQ6n*V|p??XIB?5bq%GKo~mpk32ot(LMLHlPpYLQZx zTO(K+t_u=3E{nI^Iv17fZGOqL8+uPLxV&KyB9r*OtH=+}X+DBwfka_^1U<~m5J%B{ z11HEQ+>irieWo|!B$6AY$!aoQlx=LM>-R}m=$y9JQKUZtyBQ8ma;0W<$bW~JTM=t~SWS#HTOERGlgwjeA=+S$Itf^AQZ)igH zR0QenG}o0pk9hq!io)KGgazZsexsI5c|Gv@C|JI9pR{W{3hB&LC>nr9Xx;ozj{Qe# zEHtQ|ab9j@!lxueRA1WqR8!SyBu!j&uVfu82RD_Yvu%?QZr1F=K6T1T zbKv_nNDH88J_xOI6_KY%AWxfI2?93VA5##J%}TG+yx4vgu~ETu!p90zoqXun-!Oq( zjcjcvBNx0`z{iX5xcB`g(q2?uLM^iE*VBRkKQSrvS1=hgfXNMtkxZ2*ixW z5GPZ>WmOd8efB|FzFIZ#0~%y}6v&w%7lH(at8HCdC^f~7ixf&zvP5Zfani(#Y|Vp6 zpdu?(@974O==}j?eHQ@!S2LVrsul6u2cDG#$i2z7+@*(jeio&AUc^@FWerAeUHPA)+#4 z*Sazttme_G+=H^C0U9K=1k^*G~bNz-^U_zv2k*BtaaDS8YiM2nFIyme! z;^{AYwkZ`aV9VKjeJJ*EWTIGrmkivulXTMW#nUf=j@HLt(cDl`Z?#Eo>|LVdwhcQS zCCRgic_SE1%?VZ2{(!FlZ~_Z`lzfV#&q-}j_erF-mro??iYsmSEeyf z(5cvIJ@YB(0n z|603blu_n8-V;z6S^(KlSZF&=XjpW``u*;8kO?Mef`r<&q(Q$ zxW)XbS>II71%`~@R9}8{K+dlZX5^SD!8uCeJV@-)2vM!HzSxTCxt(fia9wSqlPj4j z>U#$%m|!M-DnqL7o)s3nJ6(Ny(dq19yj3gRaCbGmyb~G+d0mtM86u^N>I_Z#v5H@) zK(A7>HUa007FQ^@`YDQ#gSW-4U$w56LDSGNlZWKB$6A%0iM+*B?OP1_QrZ20DZA~| znO7Fg*RboKwQ!wbB{A<~N+L_RTZZjVQHhO?cgX}Y!5oSl=TG+M*hijtFl{g-A=>C~ zafGtYt2!Nun3O1Q=ar|rnQm1Q6v-D>vuy`|-@nMeFS~jqhD!1OejgnBG(JH3xXI51Zl}>8UcX5fMmN&hHC|oqp$XyZy}V;f{yj@!sqYR~N=I zvP(X-$&nzs7-}fxvA=^aZB}TKaJ!4H(LPz=fVk5I>U1OWK>FcultyhLotLG;$V?z5!8ZjzxVy%>u!@D*4)+eJP7OZps}#+ zj+Lx$TLFYqyQOA8)^0#@S9i<>CN2aS5b1yjm_+P7WV*{+3$!0{{d$NGzz*Z;x{*n6 zTa_kaOx2)L@1Am#V$dFBQuCzMh3xCtE}g!)SKHtLO|Q~)Gwmzs`e0VtGnuS08S4jn z4B>~{E%F-KV7zx_U~)OjY&*&};|t&PYPi>Uund94PDg9iEQxh^49arx-r17A&*5Uj z4tdah5gdl3+)+8`S~O5g(IR6uoZf{EZ_ zp@OQF?8Q_xvpG#?qmy8@t{$kF@?CI;WHLt>xgz}omEthyBfOp zq*wEQNTw;0jj$)HQU+h8(U^999gpCq3RY$yh=IF?pJ?9#r^&Iy@0Q``6|&{Gr%BnO z4z3Y3q;GYD7@mW_M>1*fKvFU?vn?!Xq*XPs+URr?9i+zF6VyKrXTOW$`?$b*q4xduWqPI0s8{Gr zx}WZ|F=xi?PHHe>361sHqg~gm0uWg3;){UZe64hzUNO}>zHMsd@{7x-s1GE01rri3 zq1LN%Y3*{)V@}eX!oe zM|K>GcZDIpEV(;7Eza3KkM0avt*`>7baY7=+HHUAxWodsu9^S zI(HWysWZ+(DdI4!&E zVwBgyd{tG^f^46NOB!vk!c(NZE{azM&cB?}K@`CiLb( zs^bXT%#QY5o3|b zzoX2*~4JB zal*-pY;FxFmw6$BgVGhpHsy!j2LyXGN8G>YRFl zAXpQ;@7`NX{pftxIWbl56yY(&F`(YqQd2*eKhkgJvX6ds8a{X>x;|E%A-x%m^7`TyfA7YeGwfE^ zvPH#t?|buldnur24||2LnpkuA-CBoja?kzvcJ34W!B_!J=D{g5KXedcptAtf@N!Pm zmnyWO=0p6_zHec_`A(MB4daH@fPjITZJ;cn5SG*3B4PdhCC9YP08f~@<2$Uot*=%C zVQv*AnNq5^FlEmGc6(6U)X5wSzafAYiqNWHnj@EmV2@pAv2sJ!oit! zH(vk9dmpmV3-Ng$PT!E)L~Wh6xFlT`-A(V?h#TbcfV|JUz6daw`TESp?lLh*=j;?G zPt_{x@Lq|KS7=>Wt+7^~_*^ZKaM;yeI)8jVo4U3rX6RtXb~+2}p*aeWh*SOAUmqAt;J- zfn@*~>XQ-Xa=Nn_uz}~V-RCzMq|S?Ztj$l zKQQjS*-D3M`Xuk%kP6i<1-gYyffYSDBI9xV^hYdkxkAo*B5e*qMpk~0u*U;afBglm zp!0FHM`pF#UD>fKvguEKDL~fE0J_8&7k{?b;BY*TPTEv&kZbD}%DKwguv(AfX2POq zaAz}^qM*1F73<bzV4(q&OZ_Sy`b))8xl2 zN7E3%ULi|PKm{Iej_5|)9h|Xj!vKS$h+n=m_=&52!$F`#qZz79?1s9LK+Slchdy0I zi@~~_5i3REo?zsdOJ7OkvU81EYi`40$*C83S3+yz@6kOOq5?Iy9iOa_G@fHVE_#DH zp08SWnw>PBKAj=u*P*n$u^{BF;dYsBvYV$v=+`~Mm5slK_L#9=YgT!(g>gEnv&}7f zJ98&JMok|pn|vt0gyW1+Iwy&{kQinD##|D-ty*`an9hwCn8Mw2ADDV&kz?P);@u!^ zKgT(n<-Xka1pvtlNXCFwh=h&bUDI9*z6K`GhGxs_J(p&JK)s3~s|$)RelQ3bkAR|+ ze*en*kcY~0ySOHlm|H%-K1NI}@o+OUfI5zunJ>#?zS&{U$sjHKr~Lw&>OV`HHy@aB zt0XjAmR}#^E{_PALDNO@#59ahQI+kz1BThY`iE^`J`>#ciVQCpHX37Ta^Hi zRi;tzUCWpHFP#o&5(j6k<9#0Wrw)7H8=#&8TiZ;2wQW-v5lTPpe&6K8C~omV=PMVNnvo=yJSK4rF8e`8+(%>8nKb0RsnBSTxG@brRfn(f+#z zATs`QUfBHA;??z*FuA$K=+xu(QM`!TSC<4k_8iW9wG>c-KxaQdeuh^yMS=TQ6@ zPUkLf(ijX1nab=Q1$yO-Xb=0_q9!=oV&^Z{gkq2TCnP@fE4d(r5?%&syd0IsG-;8l zONr6E44ihU!zFdbyy*)VIFXDPikr8N>)$e}+Gpa%Y4RlWzuy`c>BSdRQ$)j|Na*3} zu#fA(6kTZhsrr!|(@68v>GJhH_rvTj@F_~yBPkA&5XU_#7m`Qyk_7t~v=Z#^RPQi+ z?tr~qv;c2N#6Khv6}hj{t~hQWP$#!nec!6YlJ(#@8OCL9s(S*b&DwoEBcMb=fK^5G zXD6XosWz>%UX^%rBA4ynzwm5`_-D?IkIW5~=F;)=2ba_FkzBPi^;OK`9aFbbl}e^u zn_VPoWq?3)O7`YKQanX#(&><9M~6Whx7!-MkvT_>b+Yt2kpr9y^vAs#WrN2S9rdjV zC!r^WAVKG@7G@tbld<{zXz=Z|P7^2cS3MAiKo=`!p;Zc@43~Y3 znyZZNn7C!H?UHlz;~#U9Ekz8Eiov+fYai|l3CKiIvK)JY+&|b=23+kW1IAKTC5hYY z`pF5i%b^dCf<{5HN#ST-wm}eS^L68#uvOFkxX$)`_y$EUkxkBVG+5;?#`m{s5_JX-oS#~bhEQ;e)Ks~ug9*@-hv#nQ?Dnd z$%!u7m{W4DG2dG+kj-TDO^2k-BEf~(Sa+`T{6a=BUcdcZ_N;`V{rIBrIIVm|m5mgi zZBN2#wb^7*8z0F!5V9-R+8QDp$MSO2Kek@!y*N0#igc`PebVBaF>w>-(9krH7d9sw zTn$&H_72fx!pKs4xvXIl_EX&ngo%}-M+Jj$MvF4?`{v4 z+x^_&5`STQaf`5|F|$>VIIwB)U@KaI)X^Hd7|T-p3%@VQNHIe z6UXEM>k%n&2N9KETAOePZ_;12jyufIojmlHe>2msoHZS>h{M-%`}G50RKpK#1UjM% z<=W}EbT(Tr#$EXIVs#f>4_Er|2~?VF)+HQHOJ^J4&2mm(czAgiGd1zwH9MZ2becDf z=g*~LI(H##Y#hr>6W`v;1P+)iRz?1pu*fei_NO61;}|!2DdC1`IVk&H@7iMGrk;hV z_LU_a!`bylR0yJi<_jV~42Dq2_=MNnlztk7zjq4gio-F@%}=9#5hfYoLk)$GqL*Ei zQmC-GI=!fDE>$}FUOeYhPxvir1)T8L8k650o(b>=xn#!-+RuA=B87f(7Qczp6 z7U1A)=xbuyd)ft9=J|=t!r%{BoGWcc=+~5lbf#nJJ&}k z(Z!gXU7AhkE_HRj;Mt4d0_2DQHhT(_3vm7=)qhnzF>`o1jpPOc-swfRKbysLv*AJH zt**ZK<@o7FL$zef;O1|F!YL3r9T`@gMR@-)2y$73 z&UkN4HKeOgX9*6zOe3N_=GtzR$Og$hNLszm>3K?$4bMLBxMvnq<-NHf4vQy&@VvFM9 z8@n-v)7{jtLJOvbsi-%H`yg+pcYR-cOfNGWse#PwpAe6)s|r zy?nkRV_tK_`YiO;B^}6@I-dwytZW>tv{O$^mb)dcja8laf?*&YvbZTbnfQ~6wI>Y{_OhKp1^Nh2tuys)#CbJlAd0sF475) z+ER6!(5peJZ58!A*lRqkAp2K2!Nj!h_@1>*v0ILI?vEF_m;%vy>|NuJZ7qSM$U-`f zH^Umn&@re;&EOA%3mOKY_5%OXbG?Wij#MYPhn)};5-0#VXsit+Gn-dIH^#IPlP}11O#t}+-nooEHHA@f;!lYjH|=O{s>>IM!<kqK^&9Z+8lDCKLDe)z5 z7gKjzzrmV!jNyI|;>pvntS94>%>PWyaWf-zC7xxyxmI&ExViGK(9Oj*!j=AneXuzR zPumrUz>%!g=ZE*}8ZVAKE<1Xx!?CZsGhHrfwQBbzCgw82e|+DpQ;sO{=HBKnNG>ij zp%Sw?ovR-^Lr|U0m4R;Q>)ewT1slbsMs$n;)J|ynm$zjYPB^hY%SrZvmV0zr;LY>v z|eR$N7~sgAby)&hn`_%?q*xl${%RVxoH~`OV6<2wBXeYUE)z zg{m}h;2GY;kKCiQXOjK7u>4eTx{IanRyq#QYU)Un^uREPf3(wyjHgsPt z*3bqv0{)UZAxoWc@l?O~f%({NWifip@ttloI}*KmeUbN?T*)LPPiBlrH)-zD8=r^N z;qWQL4gchpL_~jSSn_zum7SOD)^>+~O7rq&T){+sDz$}WP2n;@^6if_tcII?^)WEs zn+xH3G;^2`m6Y5xeWRs>TdF2=kaT?!$YH)S)qO3Wp?{2(E$dW4gETzXP4Z_9sI||Y zU$2+#_#tF}kND=y+nw~Jexb-A#e-i#%HsP*%~+b%$o%=`)mxohj3=iddrkNnHkmkY z>b46*km)~7l{gZexsG9QPg?kSJiglREceQyh|45>P}VlW^Nnv`g~LL*NjtuyNXjsz&h{e6-Fn@#lDOOH zsZg z8UE3m=I4P(k?m7q?lq#NT{+9MR|j`$XOoGghML*kF&<{Uqx|oJ{4ftY<3~!3?Fv91 z)<5t&lZGirg{cl^kJ{MrT(oQ#X6AIL<5%CXES#pSJb0KEbq)9O^=~&P+!8KcBuqqj zbFwpGRnO3);yyeY#`y;0Oa5r~N7O0v%Q9O^OY`Jz!il>QBn!8l3&4r+H**>rZYP$Q zy0Q*F4SaK3#nM_YjpC*IJRG*>OgE*uLkKODvW4%#A8!)TWP)AolY$GeMRmn|0qMCU zg?B^l=KQs>kjx4pD3)fEV8Vr6%SF1%?#{*BD);#D$J17fZ6P4z6uyG+-RDIY6L#B& ze`M#C$gm|+URw!%M!J&aUqa;-{7mX1fItktUqJ(&wBBVqhj*Z{OsA`2HD<}E^K`eR zRQ+UjV==Ymq`)RT%z721C)@ELSRHVPkE!_3LXTHPO@2!!+0jFhLyig^xl{#7wL1MR zuv-JVrqCo3p4?J%4{P2+@CH6A1{W7;Kj1E*l83|Y8&Y3j@V?bFVmCs4Pt3bE9=c9@ z;T}ZMxDZ4#F>@nDpMNcDiiV7$`}!VcGq}!@8KZ!+{aLH^Yc(p!ymZGYWP0nKr8|uu z$-XxaT|FFa$Vs2sy1gRqBE{hPtF-Rx!~5llw>S@k7whSI&qr`9+hn17(34U2p*J2h zL2HmQdl?BL-+l9>`mryz2s_+UOBcy%TI7xoFvKwT3B14G>G91TAyPI>#H!`(WQ{oW)>yKa0^yF(rrA#Mz zcA`{15TQ>ZJZh7bBS)gU{7S5jO?2=v3e)vs2suQWoxi6rG;~!JZodARE8g5BU?{Dt}$p zg&!vQ?$cC(=?Bp?m|T%a#nOmLzuEdPzghd)eUgyM^*0G%5SYC^ZRg5lERgaB%$*}x zH$>ojP-u?-7%q%g?|UH0%A)b61M~MlDjs{m7xHk&O0#a1rB5ntqrD*f#X0wVXR!b; zd9g(T+x#)ggNGtWCzBzsfq`M5E+-N|{}=>WxET=i7)*-|eEm%nKAeYAmR5N%#WzUV zh@|1t1@nWmm~0~6X;|M@(`5g7npdwFFuWsmZlOPhhv`LL*LJOTxvG~+^!cgZYepbtH6pZ{AK=U1^?l={gX6M&fbiB}g({8dkLS_z zd9vCoEs!%K{yrIwh?@20qGM<_3?!EyFnC?3+m;lU)A>b2C(lK^jqe@eTZ``p3cvBJ zUpzw(P^nCj=9lUL*67Q?MrDW8&Wl86j*kd z2>&c64BTWA@Qx&Q4Vd?&zt0khz`e6Zz9S0ZzVj2;>Fn4YNxe2VY&feanbh_*V&!Ms z7>vj*M=$tuU(H{Ik+F?M@6mquqstA~BXrYfbJRa3D_;^{ZGBcfyUBgW_RJ`4q{dD8 z4@=<5ClBmLPllAz9|4tmf74|0!~JA?n|fj*@dBM6kJm zLT#O&d4ykG0gy2^0c?}i`ut=x;>aIT>&a&fpai*okN=r14BRG|Os)eX#(4xPK=9`Z z0Xi=l;1s{59F~8`?X`i>O{s^uv7xhe|8|VuijE9B5NP{XrT%X!B=PA7dX@l^4fAm@ z0-5O59|8ksk*^*;dD^x?yd z`2Ri&sP()^LIQJFPyZ*wH^br${M|JFlSZw;i^VYEeaZir#si8n)1y5;jjqSA$=BYF zFl0Z`*W^^a@29W?dXr^zzzPu`eH;dE3GxPK7z%OxH9vq>sDB1#Ev_!~J>=gC^3fJD zQ}czHaORD*82DshYS!1W7FbD{et*>Oe+l;guQv&Hy@1DuE{5NNiiH-r_wUlByWo1G zz_W@og7IspfSgDnYz2+mLjch1U$ZZ$Lh+m(qYCM>i~-Bm_-ND(0sGa>s;;%HrQ#J} zbGC(-r$2j)k70(4U5ZgZ&Rd7?th)FGG%o+`8YA!MC5TcGOp77m;LrB5)#C-kDL$q!)&D@ z4?hhauNQ$5JPd06`lNN}(#yRt9Mla+vwx`#$q2M~Tck;QklEuQ=<=Y|O6;5KENB7f zaFy7p?EC&ck;QRO?J+y-2l5j^4N%Kkb^lqI_TiTEuMvG!hab?XCEwHW8qFATFP0`V z%Dji2s2Hom7~!`B;_JT`8Oa>Fpf|WCo*x|agn*ggy;}YP@S+eI(<%M3Hu4B2BJE|H zIhamqbF74l!aUpRJC&hjdm;6Kwi*oWF;W%>iLLysBzB;qRO2hTc%}-hWcRAjSlSr;w3!XxpRH z8Kgd7WdnSKfAd{}QO}3deDNeGP&9HWC>swa6je(S8x(2)RGPkUWhe^@?R2Kh z@n6gPKjK4|eg@$x&~CR0CggQ43+{`ha~fouGT~^_@9+=9WfjAv23D&hu$U5S9S0Pz z0dkXykG)a4UiWNH2lH5TDoQeIz^);Y!?^s$%SpL~oVK%0=M zs^em~T*TuJfHEh-_g*q+q}Y#2Y#0Or{3cESXNQ_gXcs_-0gzD)<}2owsFjncmS~yP z13V`H7sCf1NSF^6q~nABF}S4~TlRmOFcM&o0%i7EO5O3N?Si1kKa}U057fISNnEfR zgJX^g$Pn7J8|+ON8qNV8q11N(UBTdaH?h~=c>WlGvMPSt1;Fi?ZP$8?(>-c{elMox zvnX`RTjN2M1#l|QP`bd9sfy*5^?dc4_X%IW-CW}dbq zig#&V+UyAEAke4W4?Lz?k%dCgJcY$Nw)?6Ul{9 zEx`MOA9}=py%r6yn%w*hVJc#-_D6YTr(HcRgYjoPD(DDo(`h_@%Uvqm}{#$Z+po;Q@(p5jP0;k+&-vP2@Gada1%#SC7ap8e!Zt6?9 z^g(HeDUX{o)1{XCI0nrkW>JHw67A7G0NY!7GGmH~$P1h71?1KV41 z)fO`f5)Mt8txd`FaPr@B*_?GVT+4~8A-U4v-EEMQmH4^@1Y0cr4HR!z1@h$ zll2vb{gOckfT;w&%ApRRp8yzHp1?=SyCYcvAHuwD_c;s;uQrmcV~X2jrKI*}DswCM zHBU?cQiJi&bdhT}01ivaO}ojtT)~*eBY=*W-@WczM6n8e7qEv(TMJMRc>>%uc%dK4 zv6hQ4aZ5^mrV890b*Rlsq(nr8(bUb&s#<+z0^KRRn5;A&irdfuSXwB#MtTNG`N;u^ zUu}pp{AH!TW~xK=O6c|1FnC#LlzQ{D*gL0#TeG|s zJr$qBN~_9b1f5c{%4|Z?W~{Gg4@~ReulxF?rie1bdC4aW!>l+HMh8uG7OjORijp`n z^vyAV(*;0n*I&fetpbK$ZqaxftX!Z}5AZ(l-)xcNo6UBA1*U11S_0fc}aZK#{BFr8IXMC1!j+2C&csqMxt*Z zT>x}=3|N3hk$orX^BDn3%^=Qfmd)Pi?pP_+bHY8j;M3;IMSStIqGI?QNgl85ajK~s zhPM@1w?&z-V6)pcJ1|!_mRU0Yz9Y`3o*t3?^{s|z9k0_t4!DNNgOCXR8Yo*P14~ne8`W61iTu-v1*5{VV~1}#RH=+rsL~5xBVRj;j+E8 za%SO?g}BIo&FpnVtOu=Z@kn4BuNo~4-3A$#z^L#0+1VkLN-&1+ESnS>aJXl`m z6RMj7i3XH5IEh;Yov(Qc{&IGJ>!Ap2Jwiw?x$_u$nCl)l`SgC!A7RJO=+`S>Pymr> z@U9hY!H!a~2AjfQ2b#cqs=}x-LZ4(srihoUu+-QK6QOGw*UJM!n)kGX>6T zk?%CltIem9QrrB0IPD(iWrefw=&6nF2)f{*MV}Vr*eEFd<+T9?6n_UH0dDW|1q)cAqHZNJ^wRqLgUX zG7@UaC@aopj@+?Y986|uL&jdkcM+tlq*u_wtrft)cKs?j{fhXWRvily5XdNL@dz+g zvJZzSjmZv{JM5}#ZcJ5Ej6`aPm)Zi|LsNj)87-U{ucvNxn)TeEm$0gn z>>602U}&$arc@B~i#PV0WpTLXuY&z)u}{1vY2ZFhcjG5l3xIU3k+_SLF}TLh#*DR1mA+HvvLMkl1^U3PBnL1f4zzJlyo|tO>x+E@;OF<-+C6U!bOWko zq|<7m-r`V7#*`TWUfR^L3n%fQz!3SR>#sWWwYJzwA5`cxU=x(wI5R4AhCc!D9bC30xwt4ZrZ7+j-6sBe%fA($+fHsnL%IE z;aTzJg=;lvzmI*2(EX_GVdiQNfWp+@*X!)EAM``!I<}+>te<{Cbv^h(-H^VtTTs)i z)t^P>@%n5|_D<&|{k{C7R?x>|?`QYN)0a0*XCOkJT1_l@S5xsv#2i$@apMU0q2Cy@ zNn(H=JK@B)^jrW3*nIfslLTgcVKor2X(gM&Ig(nSTB-w(r=@5EeKCNLxZP%}n!N_$ zG_C+TNuK-5AhJ(zW`O_E1wGuDXABd1o{hACzL-zUVuvXJ3?7?h?$@@RnZA<~7eR5n z6lWIM=*fFK6NMhcHkFDZ0jTG)iNyzZzWpj`j^tdW8nc_Cf7)#zq$PO)vt?asPdh-AfMH`uVOn_J*Kvd;juQ^{81y-U61vXvCT zW4+MQiMY!8=ER)1ab7hY%h*!da<2S5--+1OdJSI%z47?sNcGV9z*X0yrh#sX5p;HN ziZy9T`TL%%*fWS(xoit@QA?l?_w*KsQ~-*~%3mVw+C-=t|_|TLD%}jsVG6S}r#LP(l?y zr{3Fb4DiAM;h?sJn%``S$Lg>MnnOUJ?9bgPfX{&wAkJHOg)p2cG~6e4y?aja9(P-LW8r)q^%4R5_w8X1Jsj3^0Gganc>ybJ zad}|s@LI1gBb}<{qQkDXMW?#`MTz^~S)?_}((PuUE}!y+8#x?T7^m0b9onV)#;y-5 zb@Rijuj&S`t>q)_dO^eY1F!XPhPexxg{hiGhv8=8ZQYy-<@r}(gRxtUvX`DEa!W}u zIUB?J$yED`Er(;K*7OAT^FWK@1!DqexL`^3u0_B2`j0)!Kg}Wzu!}45B6_6R&8eAm zOAFvEy%7z$aJxL}X9Dd_SsyOt_tih)-9aM&Tj*@&4z2%em3B~1Y4gP_5>wMMfsDZY z+1>SNvR!Z&z|Dxs1+YlA2)Iy^NzrkR#;*BoGp>r^L?^f&A7R z0xF5!vH(_b@6C7{_TZA+A>Y!9fGUoXW=q3y5E?3(d!&Twd%k|X(DTZc@giT?}W{b z92P84e7~=K6UQL0lY6##9I3o}20EXZo!H?XvNi@>iDfp*!~RNX(H#@_)u_q>1$Vk! zuKWt5XfPJ-V%3WJA^(xfbre?W>9V}Fdhu1Lsep_l7Eg8E&n7DD*jG9#0hGZpW(!yC zn~xklsk8S}2QHw!>*xyG`i}5YkBSFViUXw_7GhSmjt@8KlR+c3m`In9Lwg(=^BiBd2aY^YxUoth07TD=dhzxNJs3oDilkHSO-vH4e{R=?E$QaK&&X-8=3sZl&lyi z3-rd}XaoQR2m#d?S;qi}m#Klst0_MuY!$I^fPhc)y*-ffSU2vogHi!TSu-+LqXD_h zZ?OOiuJb+y4TNilKMGj-5t~$cz7#zKs1&@Tn^sqhuEe~!J!q7@eM76H6)^f!*ZsH? zD0lP$5p$-i#c+nt&x(mGu@b>On*9i3fkm{WrvdCvF5Et{%bQ*2MqLzKfBEsNk|-g( z4DKi18vl7R+=l#Ub$IJFnqS(g9)KcxXGM4jAKZ3y$!c?IbE}RuyNnKVImGpr~Xl$C1*})uF`-^_)v8g z;QuZa)9rRPYJ^M5PW9!spr~O;%WB2#ZBx}!`aHl8@+$(Xd8#PyNO=wMU5cl80O_f+ zV%O112b46;To>yQFOWhd3)Z9Fo^4kG3J|aBIg_eUYn7V*UEL3n%oE`7rJxL$3{z4l z{~+3_a=AaJ%0O5Du2uSH9j2y~fTi(z=?}s_j}^&>t5q}}N`%`d4F4NNd^m<2O`&;2 zV@GLIN14@0eW02Ii-Kpr=(1TqZ5*`f^K}!ziz#liiA4}ub})+^&$f{0G`sThWK+*6 zSI+4F9bp2U!WrU=WjmE8Qg>y}hf=ndvgW#Zf-A%N=1?7D5j+Mz-tJ#G4XZwi3YOll za^yFI>$NLo`fv#~%1ytpa#$^5AY=;Qp>a{X%M;n7%pK>k>@5ZLc#W^=Yu{*n+83=I zFZ4`Fa$smWZQYb1W|GhTxMx|SR(UqHq{{6@NpWnaqe)H(-s5#1$3Kl9s6`rn~g_@IQPa-RDtfatGITN zR-3ab5dh3T(b@+0Oo9X0kp~-qq=;j|J{mSFrN2bwncq1+jT1O3A=dc@&<$n5T478t6T;OFUJiTm0x}xY+ zMhXr7vu_$GB?ING1js@NRa$(TTJ-+PCd0W6fm#ctG!)9%8ZM%9-EdSo8-H|lt*M7e zL4EfC<5cJHQ9-(1{{q>h)8dC$?Kf);(%Ck2WOIgV;+Fm9&1+yb+Qa_-7beu!oR)mc z9Zx&rj*w#K&p%gH(5*eJ+=T~v}A50dChKU)n}NA*&F2)>(c;u-ExX36)eLF zm9wfUJ&ERR7G!)`H4$ucfWr0jcVr46ABcKGFv%d7H$Vh1`b5nV(L}5=&y;9PzuM9l zo3=&#Q;~v5m^~*Z-@ZxSVwe6>mw96lbU@c%`v}Ba2S7j}t@vWtZgDO;o9qae!(&_- zP5UR}QvGA4ff+k8XI+PE7i!CWeKRhtKi_>=h0Yb0fV1=4)Q(-h;)HNNR?j4$%DLda zGRKz2;nYIa&A#jI=wvtmZ$EW#5m))rv$UPj*y&L>p5Ld^;JfF{Y9zQsZjOO=#i6y0 zum+ShF#t1W=)_yNtF6k5Ga1l6j_z#RHdrFb{(@YFAw9U*TLEe8+ISSdML@mr`quBM zEkcFt>-oX;(`Nb!%=1Exq_r_lxsLvLrgTuIZh=2(8;5c}`v+4k($>CWf{@(nyx=u! zo`Gi~qXiYBxi#d5@iLaN;t#!!6J%l0wtp)GkVVHN&A?_2UJjt*c$$SWWH4q#wu9aaTWV1D1X6&>jzUyzz7D zx%Fwypfxh#)xh#QZG)u&9DEh;hs_M;YlIN2S?ZQjom!?G2fQv(jj?aj5>lEK9^J#2n8>-T4=L;@2*N+=9 z%}0}Qow06iCQk7=*5B6JpGV0B;7G;jtortckAq%LrK0C4FzdFNGd3O1D_&X|^SLZS zFOhD7M3j4H1w2ptQ$0*(`m7ka30MuC^S(&d>`(6;Dg&!e_}5$VJ?+U4?ShN`c12GH z1rbs~PuBX=_d;f)9rzqo)Z)84I9Ylv{-xMj&TTDYn#0p=lp)&-)iE(o_J^$D;H;)e z+Sp=(9RM?$_|uT%sYn%~%Air{>0rVjKrknu*`g%sRJR2>zBNAGWB}?9tJ*3Rv=bVj7x7GpA~6%Cs17j<3?GO^t*`qa{R&$7eb0lOA(5w53U`b<0l(Yx&6cxn(= z?qr_)bq|oQY~bwO&!0Cs9-e5*-E1&DDmLsA*%Wyd0LkopW|Z%M`kOI<^*uYhYMU-y zuSW;<^bnO|ZGC>kq=R#{+C!s=+J88kbb#6GpM4v^@^pr*E}Uq-nd?%7Wpk{R=btD|Dg1Cr0kyLZUL$zy2RXq0h+be&1(njv!h2p zxWi7?dpUsY6;!0PHBZ5(J9nUBPJt>iGKu}B`Kme6I`04|0kAcHZ@YdpKICo9DrjI# zS#$%A6+(x9?uw-B`T`3g_8TVFi`WlB7T(kHUX9bwmFS6SX-DO=;YX#mnlVTyphw+? zKWFGh0+{*6Hc-hL@YD6VC3daAm zu(FxS7q$7!S`ZkTZyB5f8%GXMcUXsUQ%CliqKULZFlU_8At|yO~ypfw@Lf9TdTjisv}g zE!}}ea0ahM95g9=iPZ2vF4N7_&xB0f)9?npI`%qLBh}O&FC9DTkM~42pBCPJ)9PvX zvoZby;{kUAia{y0Rx)Uhbx`7aSmF#w@fAdaX0lGSzd)tl%;q<{@$>$xzJ4Z&jGEfo z^xL~yj3rkR?h=|yEHP?3j6^+L=dz= z^+S;;-`u4ls_#O!=X9RW>VvzN_WFb|y)Qb!(!j&{mt4?~SAj|TXFJ1>b2A_r+~Xpn zv8oYPUFR+3P~rRMBRgBm*?W_DR$D)vrbv_m_eKv_Hi8H}F4~ zM?FXRCF!#A*z+lRJTWt~0@3cFWeGvi*0C|g^%crLrzau2b#e=NOxmg;@iMoWiYk3^ zk9@4SJ<;JsPailmC_+X;s*i~V{tT^PADd>EX%~;|&J;Ia)%tCYVYXneXd;p^HTL~I zij}BGXhNMyibP=hAZI%Bu)y@f#KQ8-T5Hun72OnB^jNez-+l5Vn&QrO1saOMi>tE% zqz?t3B5Fg~a=C`a8cSB#hWqQ8kna6T=Lx;8=}d>Ie3IT~z&?UYKkFVEJ;*F~xUhnR zkRzbQy?=cMBE3T@>7qWP1R|?3k0%iPE&(%Gh{mLHl!MRz{EFXX^z_%Q z^YG(ekxgV}W$noOoqxaozpq>S5SXE6`<9-~^Z%v4e=G8D7YV`7U`!Mv*PH$!jo($| zNjU3(%rvj@z2~TZ8{O|V;E!v?7a7kiX)99V|F0nwr3j*M`40CTlGXk;os;jE$5@%v zPA}@6{vj%6W5@w-_RU6s2mQY!@%xXhpP$D1*_ue?f4rYGB(C~4V1kZ#rn#IO+)N#N zdIy7~8gw`^(kfn2bMOGR!x>oCG17*!vACKWYkNr z+}hh(c0Q}6E0DioT31swuKfbi8eU2)2A-!P>P^X6wBu-3`Rf~hn~6!8<*8}`K@V6z z5#x(P?uv<7n@^9xUs6%EBAZ}9ZJhnPAN6oH(S1hlGp(d8id-=?sY7J=9EP?0~aWrX9~jXl9Ia}OTO zmhL1YulvO_s|RusDtYgkK4M6#21x`!UliuGLjUbC-p~c{&%!C)?WbdQ!h8y&pCPEB zK}>qrq`3_OY=i%Mu?ohb>%rQ`{@nQR?*o-)vcx#hq5;Rlv(pQt8(fc*{AqBmBUj?Stfbg#cOnzC zmtl(e@}-r)-I4&0s%WQ9xOAY6tv%uyniau3bcjEjMdpmItF3M2)PYv@sHsE}L zqA%Z%4%F_K^(BiDf?Gh~u^NVnapBAyp_-1}4ag%rI=%^MA3l7VRRzm1QcC9(H{CVW zVuK$n?`0(~y>2<&Yk&6N!tr1A{cy^pr%U$rxH!o-=6BuuaK>dgme`+LLv(l9&4!er z<#jcnD#@nqIOn>&6yM^^{fbSfH z=LXqFGk?*Fr_OXOl;^{$!P;|u0^a7s?FcH`31i}js2F2tR;S~~`&*+P($@4bigi>?ps4*z`>X81ij zQ*?&Ati$fcVlO84M@k)y?Tt4-w)sQf%^Dm!SkE*~3mgzX1B+};eyk{d8) zZ14Lqq3yG^FHCs!^=xOs^1}}$FM*prozsVw6uZd~auLGnobSAOE|$0yt$+b~uq)Z} z-yy3cazQ!`A!r5dQB|h)jAk ze$TWl6^dMd73$h2y~E+PRqYl@jIznm4;rQv%sQWWUHNeZN$bLFiHVEP^n5a>ENk@} z2_*-z8MJ1T=Y!iy?6g$7*!jn;`u3X2O7oezL2M?Eh&2;=8mLirMBTI9H+jz4VS_Ev zZoc=++7SzLm!A5!ZgBHs#!5he98Pu@22Jua0q9emRN>s$>`*3W-UVLKp_in^4K)X( zdnaB?wt895f4*Le-bQk*+9mJ)Ffyd8#`)3JT4?)6XBK7#B|)*6%7=|`)kjPAZ?V#4 zlaAcxkPvapc?eFCZh!0JKQGA91rI8f($}jvJwNHixBWzyXyMeBV}BLK6)m7rF!ar| z{cCT9?0c=4D*fd18-p1%m%-F4RwAKfbIe!R_x#ZQ)p>XsPt(VXcXg@S^^ zr@ig@-T-l)U942H8f8Tyt@b8ti(__dLCP^2b~NsGsn2z>sx*%v!2R4}Np>3l;_kjD znfx++{>v(c;cn?+(c;krk$V^cvkEtzb(Q(-apDN;5t~QR1?>>Zj&Gpyho2=Xp7nTK zB0@TCKJ|^00ySi(V)EOud)f36_0<-LW@|e2ukhoRmy`c~-~YPE@O@^cyNui#W$rgo z2kpep9Ew9&c|A?k@RMs-o5KaYA7~%VAMuuO#(;l8`r~{a{_hJj}m)wuBUKkP}1C z7$?zlI?C@9N+x`ob3f63&dtvD`EWAJ&GxkqkG=}^2kMbpU6k7KkoLK83oo0if6hb@ zM@R?0;ENuMlKT#&%P3Rg(E%4u%!1HOT42Q5M;WfK)pG5GnHhJU!IsNFPd{!y3I)kP zWZ`7Gdfk4f;I8F$+G`nYh#@1)7WPc)(|8q6-~F$A>328m9Rx4v;b=?4*d4mI)K?l6 zoBE3SxXyt+<4jycJ&9cLH8f!cQ|X=aSU<*wZ|zn=Oid=zW2HHpjI>t8F*a9(d}#Lg zkJps}`~psW7aflh=eVv;pY~xH@Tw1H3)*w>@F;2fld>HHG8`2f@;=lsl$~E?s|bme z^bJW#Q3Iik6zEH6`o9~MfK5lV zOpR-6Znh*qSf*a4Hd6g-oa}>$5f~m4WpIZ%TW+s1?)`>7Kr1{brlzkB(@x0st{E!3 zn1vZXT=4F$(@(R7?`{B!sdv&6jzdb*6mvF)79!JP)NmELlL3xBcrtDOrsQgC=~yJq zWGuT`Dcu1jTUWGo5?nLoR?Fj7SQwUD!k_5yv!Q^Mi6QA3j7dm~2XflKOK}`J8^@Jz zC8?p9VCov?`m1`iqgJCq&KXBOF_q<)up0;Ak3yS)7>!lnFZ3Jt)R)2ERl?@Dxj7Nt zCMI(hsH%QUX%C$#p`3j>PvG9E*KdA@_?WiJ6GKQ~HRv5`ngim!7_oyhtflrB$SOi1 zyHDhzbP&ys_NRilYf4c@T6!unlZABtCNx-p8ugOEk z0#=-bpbBeCiykrw8U(%IVR@p_C;)T zeB4uZy1vLGCi7e7`CBNj0sjUbIdU;p^C8CZI!rOLJN|7Tc|5E+(Y3@785Y`)%DvdSQ;@|LP>p3ZJzh!am!PF)Vu*Q$ zMp`wD-(B|aUPO?`2k@#3TJtOw!M5p3R~tD)o^ApZdB;DURLl>HI~rGy;vN*aFHNSp zJ0?zDe^zH1qXiq>4>yPF4v$9;ZR4owbFk!7qq?2UVd?696qcM{Hs!mu$5ERr4R3Dl zI6e(POXnjoc3%y;jD^WaB}jdTigP?G`l_ zj5PqE9UNWMsg$Z=j|J)RG*G z5elUvvrpQED@31uGkZ#cG#0hO{$1Dd=QAWF1-VUQ zBr=YdjUFFr+PA%vD~vCWr>nv?d99gXbZ2~Oa-IWaHmQ2W(CB|3bf45R_&{Wn|5Ex< z=F6ua#J1uKT9RiUI5s~d4xPu5QpI{AC-Q!nedN1V4=4l6d9Fuo3Ahe-NG;yxie^oY z=HnG6DbAos%oKntu*?oa&_EaW=3XRv>dV4a4UMjPBYzg^W_0mr+KvbJbOoGmqzGha zQb)IDN)DS61*Cye+?lw+>{enW)xh@XPEAxEW*|wMEFS;h{dYL7Wv9y~RaD=R7WFIQ z$4k}CxCKJOlx$+taS_+W%TrCdu0<}P(K!D-F%fK^P>Ewd#?D~SUi8)d!{;Ji7l{sG zgy{;LFuz4Ef9YR(-$ho&*3fQ@for}k31+pu=#EYC=>QaGAf+|^kk@+S1>WnXMF**z z2V5H?uGsa5_IS*g4YpUt9paA@3^fDm{2TF9Yls*FL z|6jHHyCzc*<{h1-*l4t(T;CK@X`a=P30nl8qZXlN(duis!2~4(1mGwMi6T|#Jwz!x zccr-oAQ$_(yzdv84nQ15o-nCHI!?+w96Vdi$1=Ng%EK zw&EJ5ClL6Wfh6zZ=G4QE9g3}{gz>6#<3VmK*j%Ajp$-wa{~kobE1wl@&1M!eZ}^gt zwad{;yTLbd{-ThR???nFc{ph6uXg*S$+U*@xA@Zf`lwm#YfGuMLtRt4M*a?9)saHx!&#VkBHoszA-ijHA| zbA*NE;jTs^E@vE2=}tlrG`zr_(}{&n#ZQc>-wf8Qg`Irg_4z^uqTvHa;Xu)*tqdGW z5{o^TdiftO`j70zTLMAQD*V=+8gujR3VD_BS2JMjsDCf!jXS(9Z2oC5>|_8{J{gOv4=UK>cMYNy(No)uGjPL- z)t8nWN@>z_Ata9IhI8B=;muA1P1Qt4DuUEWsnO1k-OFSH+6X&#rcRC>?OxH-H>E{+ zu4vpvrM`5>!U+9klJTEM}#ND=_r|@@MZ1K;i79NeGB6GYz zT*Y|XlAz@AvY#9a54KP^-h*}e%WnZks~jXL1pob+i_cc8WV#9p#aNxJB zr6ea(CYMoKc)u-Gin!8J|FG3>gSf(*&F_p`#U@I*O_pn(<0zPGG$c11;^t4gLQm`2 z4eFzseGu-sz^Npy>Ak$lDT6SmUw2EVaG_t z&32;9ZJJC9_)ePD?@B&5^km+!Vby(s{)7K80&=F1;${!`*X0TxUG7{ioz$Ux>}98$ z5h#iULtHM`*Dx@)(mlg;M&XAeO_^unt3h*(dPNEzankMHclU?M5gY}URUq`K78ap= ze!6&bWe_;z@2*kwmdSa7ygp~zBU&o&|pIU&_rEuvle zqBs=mi(+27+fr9oQrPK}vU*P~4DQcM5hWs#^h!lUgFe=3Zu<{D=sl&HXkhJ1@)NOd&8e2% zU2Q#&qRpsP-*!4TF#^s#9fVv}f*|o#IF={mq1L7ebIAlWD_6JH&1=}%n>E?GreQf$ z-)e^^cHGJ&fwV4)LRVG~f>+em8^c~uXMNapc0)x)!yl{68-UljT$;RC$VpyRl#)>@ z9DsedIH~d;N%Uc&bC;cf9~U~P8>Bpn@puur(Q>o@sgVa|Jcdkeqxu?B)xfEVdI za==G4D46$Yx5rGcJL=7k+n1ftnMEKyF}Mwh0>RBDzPuhwL8-^r2(0tuB4iNgWpa>? zR^e$P$<&XIZ*je5H;_Cd9BM9K-B3g58a<_&U`@r&oyx#3cvaxrHrU^-Zx;HM(S6#b zs)fYhKwPB^@vPzolQpnkGebNX`2Fs4d!U{CD*wIZX$m#o#Kjkkn{!{!72T2r%5HwP zy2gQIor=?*szcSyb?i-Pra2Fb%f$ZVMR%<=Ei?pced}6CyT0<+*JUB9FH1peBFJZF zB*aWH%ieIu86Qu>6)AHPQ5H$S_u#u3;Ljc`^bA_0!&zcy034w6_m| z@Kbp03h%r$MQgZy+^*I68m%5C-z)tBSM%;leMpU6nH*4uVbn*BAIh09=GN>v*t;Jb z6iZs`f4AU8sjbw7HA1z@1w*J8j!sq9RCO6*zVD}Evsr9y({CJe=(~N$Q4FKAnh9kH zG2;`t>Ps1Qm?n%@LS@9&tJX8h2nqK@*{cYw%6y=W{cf~)2k*`s*L}t7;v5ax)l3uv zJ%aLQ*^$pay*j_v?b*exMKwA*{RkWPR;EJ%AtQ-)6oC%6dFhADp9z7uV6=C0X`!2! zgJpWmL@uH=-^C<>a0J(LJ=m&?#xkqVHvCw59v2l&;w`9mD=ihS<*C2fJa1@Z3g*M~ zs5QgaFu|`vf?w8Y;o1oA9((kBS#-NV3@3X_oKhJ;i@`bc+%ehTM~8z>rd6k5*F-oe z&Hy$NE;U&-rZnbjlFf*C?vcl%b$)apGnbC)&nQ2i!)og|(DV4%89n_>6fh2El3Qg1 zgxjLmPGL3A6cMl8Yj&aco^$=D8SNb{1o0HS!0f%0Zrxps!*wh9NEpa&fql>{lF|W* zjNdQ+WRWt`y{GsX#wJshFM1<}#Ft)fw|zU6q%ks5^q#a8p>@I0o0CZ8#mCIi$bL&j zcwcih=AscdvM&t#=7R}Gb;tpu#XlQR4A9}vj$_7vvyWV}ZAjUL;D?X&0-tBZav!er z;LNC-ri3{99?9%rNV zMT}dfBl6IwH(^PF&#IH5boM;XgA8HvDRUP48(;HiE+MR}?+?u`9dUYR{^ygg4vnpY;o||8sz%{kv)Y zPWpU#pOHFzJT(&;Lc_6ee?Q!{yAJt?mfKji=^KWkb>hV75@a@=xtp@lmxRMZsN8P% zo877C1B}?BPQ<)GzUy$Ss|NJ=v;D5-)2aQD8Ws-I!p|L#_4rw9#r6Zbp|`sxg>+EXT>eIu(<*}w{`Yz z#nwF;R6DpR%_SuiTX%PN2?+^w9J+~#i2!uNV!qA>z%uUbslA>bb~E){t*EFN9UFTQ z9}*JM=+>*7yn$_+572{SAR!|1^75vnrb@9Xt%&OA=-Aqhz`5=3?|Znr7kn~IPDx2I zpDJN985XQJS+~xaG>w%S{!aiMJyOShrEaxta!a&suMe2PNg$b^rb`DdkLvbn=9_D93H;d?v`hLtK8ciLt}G55 zP(%vRQlY6OdHj5RTC7@%yC-c!kLF9!7Odf2-r@0tK;uEmsYk%3Kytmw{*8!nOz_>2 zRWUVc(cXxqEdw5f90N29TDMkeRXg)JE`(cz$^P=D3PYrwJm5`sN%hRFH`%J{%|ND_ zjBC`UTzCnjSp{nksemnjL|?V1IJ!(Q=uNKD?z!RK-?z< zK!pP!>guWm`^*kv4&B-%&szXkpjK<8tHn|`mh!VRj0+2?ak^8XeRHnQHSp*L&_}x?$R+4Y(f9yKYL}R$U zCgyNwZ%O-RSeLz*bW~7rjATFE6XoRGJx^9Xzo95){(ARvP01yxjHM^oYIvcux1$rG z4f`dgj_j+x+J>aBC->hyu1*}BQu(W>3qG|5sg}ltZQNICPWK&tbFLZ{NroN>6BKfl zX}`QxP)%pyWaeQqK9sjaCei`>tPokpR#G=cK0_GSgUq{#uG*5*FA*m0VG!5$0&jXo zKfWwzQv{!`i}UmS*=o8)XYB^H)$0@h7@}2gODX;hN9J^6hq~Dne%FfwkGD7t zYv%1ARV%$r=y2We!NGoPWwx7Igw)C(I*R07`d?C$#xd}l@Y3BG^6TbL6SwN_K11Fn zW6im~vEEwCFtjLr8KzU0d-bI}fXtvKtxl~ogSN5_NK#x}-U>i#$;nNd^tl1G|8z0Q z_e1XcwJ3vM%r7k$a0naN8I7Lg-e_t80DII&U~G~P975SaeIE%I_FN`~ z(`T=LFqtC@vlM}>0720cKzuYhVH>u1Q^0KX&5r;K2!ShBR#pLM#9}rHeFH`#2F3#k z5XXc9p?OK414P!BLLQv5+Q#Apo?ZN>7px2u@>SxDrmPOZ@b|5^7$08`)s-HmP(BuX zesurIY|VkaqJ<@|K+Mk1W^miv!(SYXIZY*0y%CE0#$ZHaU5!U`&Zb$auU$temzUMsCwiQ9i1NpSYbEFJO^w-y1n(eg|x+GHOKc_rZ0kb$@g_pM6NG9qB z`;N%~ytl$)GwS31VzaNZ%~E{)0Z{t|gL=isc3*^ow5B&Akmcp&0D37XFp$%JYZy2b zE}+rWUuXvrVN*Ytieg8j@&*}xad8oV<~A|P!QM*0DQ-LdMDj;1NAUb9o+Tm`BoC!N z-1B7TKDbN`Ktc-nEQ}J2?SC$2R29ff&T|u5rdY)m!mFY!I@s4T1Vb4|z zozdK_9>jHXaiHJ%2+!qsJsW%VaebP$5@m5Y6KRA+Jnx8{|L*#;u*l&A*+;!OvK69I zk4?#Z=SU88zooGWmp;M;&l%U}+;vAlYpfEFPy5~HwVdwgmxMF}D(?Qx_G&~>!uQ`D zD=+OG&DNY8`hwf(Q@u`ac+stPmE4(4x4E4EXhx(WU7jzBQ_Rx^Uw``$dlGvyWr{c) z<$sNXnL+2q-ILLj* zu#!-Gdc=F;Ebc5A4BFVG0^pV9-VSjos8ph9eI&thu`3fQvkMd8{);~;`PBe12tnxNKoni{$h^lJ&7(;ePlJ9 zl*dcwscorc7=PkLN`$u7&igMY->GW#Ii8fw*=|y6ClpiD^ zu+?rx4YZ)lS_|PqkU%wP<7y*Y`)8!Y#Zh$uuv~f8OLaE3sEm$|j?2R(G=X3tgQ7`V zg8KS;sdz@w06>=H2Hc#SI6L|P-+!dw{`Pi$5=Q*HaDwagcwN1W_EssTX6V&{MApaK zrN<*egff19ew>i#Em%~7JT4ViWF5>-F#rkX4>hk+tO0{SM2RY=w+0+!7RTD%-EF`` z!~1z^rqWm*iHwFOPrcG;c&Vek{UZm?^!Z}5n|=z9lgyQk8i6DMe4|7(72q1{$~rHD zyNU=3O;;UBSP63k{^pieeG!gY7t3JjJn$AgS&8w>*k3W%7GhKRZJJ7_5V%qgcZmL`s2^ z9&&&e>=CzUk7>!)aM5F(Mw^{>nqH#{KJ&8#;5vZg+JYV0bSu3Kr~4ALwY8U=S5XFg zm5F-g9vkI{sw#SyiQi-Hx4om3E7=6-WUkc3YS@AUmcw~3rVTtjxrb^LECE~e$M&c4 z`(;1k$966^12?DVyRbK|Kc#R*bUfSeLDp(l*7;|~BM=7iW(Ll+lNDYa&vZ>Y0;Of# z&iW}|aVY1iwoV5&3-zp`8SFqKZiICpnnLP-0%0#ZOP6^ED4jq$gEYC|;4`4SUj6h# zD>woAGqF&Z#YP0FI@k@wc}NnIOU-q^^YLf&_&DnOz*KM1X5xi&Kr5F}GXiQSArhw( z7z`FbZ{}ky6tb+hHv$?el?LJ@Y;R?@j!npH-Gp$AEyMNoq6mKkFZs3D+c3v!qSD#^ zu^TXSc5((xCpCaP$20N|E)2YNps)Jq))LNm7~0?Zif1Ig4cDZy z3-Ix!$^^|#sB{osC@^Lr-+s|=^<*ZQ&V!7_9KSsL?h<80$-3-MpJfg56R-jr5W$4> zyQVni)K;6ek3<2EfnVxGDs{Yen1-#-ZDt4O<}_i`-o0&gJ&ro&mL_V(rp%F}q@?va zd$VbWmMcAe>|lbjsZF%xMb7=O(znx?c1M_{k$s;>q)pyBYGA&-WfDSRMEGu`dOn&$aS?{yx+}!-uOjUss<%(+{pq@>!ydEElOHi%({t z!UgSoQs(zw+Gc;8Azl9d_D}fYRzokE)niba`#dj)TturfF1yzicfJq8+Iu(J`(kf4 z5wcGwY$v3X-*&b<6)0+ks#4)mdR>4m75u#11GY#WjhO!&?8B)=#3`(@NoB#)(DH`l zm=8rod9q;|?^EAOz(wrkc3 zeX~ou8cIP#KtO_`QH9F49iB9}T$J%>wB1|geTklU&xEBs>E|@=cVX5iC{YxGykj?9G5e7k+qi%y0 z>#k@;E7-dxB{x^t@6z6zY&q-tCqBv3y3epd#x#=lYx!`)VBi}ajmLZ3w|kZJZS3U7um@Ye`vNYlPU2mwXk5%>nbZ)9uVJ_Ydii|; zGu+AM`jOhi#P`0TFMUI&(yqSlrifHd1|#IT6OTWmSPh7GXoJhi6TN91ufFT8p<2HV z(!dTW%$eBn6fXR}$iJsB-FW3$b|L<8eqleA{Z{ycu(a%g+#is%f?OA9VS=EkJsAX@ znezLhZ>vX!7$v)^#oO&Xt$qRcx`75AUSf{H9h${hr8(4*hpX$06pMV}^}0)0$gmc# z`x}o)MKCWF{fu;j7F#U{wb&!jx=g%A!k4C2CMhUtq$Jl@&Qp5&(`0RN$ytnesZ=== zjU*RrZ-Tx(c{I6f_BG9n)y9PQYS?+Kxt_Vix~PabT+H(t#dqtm*iKZBYhjCc1sAz~ zM;IjjGRmu!{-dTOr^K^tp*P6Qk2zjHgU@4aaZ0^|YRT1HiFq8eT_bnx%^Va(UTzG= zFq@m3$C8Q|mQV09U=c=eFft-JkqC~W|6tK?%G-YzQQc~!Bq<&cjvTi}i>{Z16K_VM zS|o)m)A7rx^ImhjEcU0Oh{Uxc(?kpGo$*>(tjhb-dDvs+yP1_71aiV+4|4+H+#}IK zR^?|0e?m|y6$5C{m7D1ACGNzGDZuAdsuA3)L+0Y6+@DX?-jE}0La&k!s6ISYomg(Y zGxG2k+_;lwNB(K7<~wx+3imDd<{O~W>N{gq*gN!6HZK|4^{X3&@O+2w%<(smiV2p( zkUi$6iK~26@DYq~y=`B^tNKLp<_qhc>4MKs_+DV3uN0njzEKG`Y_Q&2RFip8s_Ub3 z0i6M1a4|Y&Ar&e10=tk%0gf8mm1C>dC%jaA5(p-+iy)qfM@R+R%xr}Hgf_VXG;SIG zI(-8RQK`O?U&X%wXTJ+wbrDj|)ZCovg}+6GDsGs2OroLxsT4i2=>tgkk<>nD!@nq~ z-GaJ=+{6g03R^_|(g;YqI|x5?WG4o1al^bYY?nI%`l!xYRZY|ChKTg&F610#xn*qN zXX>PtH@wVPhkp#M_H)HHG`J@Bw(bC-22-TcOEQLt70e+Z*6l8e5)G8JBnZOcQd9{oc;SGE`}dINih9OC`FOn+g0nakHXrK9 z(OEu;?g{ESO~0?+MWT6`|5QmYOfo-cGq|JiI3?1~mY}@%MP42dup)^aYR@(|v)UKP z|DB;IbpJOarJ)X@+6nb(O_eWliaCE>-kMX9Mo~TNSYHwQj3ZB81f*$xz6F=K#?nzq1;-^ z#Ckz7g(NLqTIc-Ngh)hq>9mz9n`Gsi;9p3ySF=f0 z4OClXUR6l6UR^NzBEuJ>MPQZdD!SM_`A5NQe!7;`9~U6{D-X}(<~eh)z_BzK8q_`R zuw^hvM^7)lVY*%U{pCqGL4QqDR;NbFvqrM8KqRA9^A<=kyt?f}i}zon77@zZ>yiIk z%(o+3F*aK5l$@?}PiwA$HC>`a&`1$I3+werU|GJI_7&Qz8^{^kV$%)gw`Le<@5+xdoF`P>Nt%m6g$i%Gi~KCMKdU zsOv1wYsWBD_z#A`B0ndyp9x4)Dh@udB!6GV>0&{u_??b@#D>+djc&gb8V2TNCugEt zW=2Nj2oT29AD!h(xzlC%O(i#d$oEz!hdVD4!kKewkd} z+Nsk8_)iuZNBwnJ^B#LM7$kvzp@lW#kXZ>i$GTtKw`O7s9s^E5W~M?DycC;F`Rj`K zaXG(RFvsJ24#DlU$d4bzslksVZjNuDgj$*|km)&|d;V$bt7Fw%IeWHNiQS~d42Ml~ zXa8zzFPoNVC3wPqN&nu|U3ABv3=XE=oL9|l(4X2lD#A8VjaUVN-OK?YDJg3<3=9n2 z2Xc-`F28a?-b!SI)HQ8BpC+Q440qKX3-2gdvUG5eVvnrCXqMW>MdRWq`s1pbz&5uI zhlukTu(GnwEcR#9-Q*|#QfblJaXd36?81XyB1KuO4&UiYz9%7+8&==<&!bpAxr+H`G-9 zhQmlnY(KIoYb*MbvCYbMtzXhGK=AK7EBuUek9c-v8yhVz59o2!h=j839|TT6n&a1f zN`d6uFs^dR7i8=;ef5@Z0J%hMM7`Xe*IAiM@)u^*=q6qsJCW)849Ry*4tr9cDE7ET z6=cNpbkKC&SX<5pxcs`!mNJsmqT9|u0&KF?_|q3jN;Sow%sEC-U0HeJ#QANyCCAZR z{j@rN5(G2r1^lF9R+`|6vdN=R$&@=YIi*_3LVH)(#Yi zWbe~RbwsJX?l@P&ba_D4f=4Mf1s!Sq|7a`*t=|)J=&z5Mj7^%xQ2+9~_qdgU0Meoq3Ti5(`_NdGSsGWK z{2Iq+9CY-Ry}itL@1ml39G6Nxd^Iq;w2~)X9&B@{2r46Z2Ni^c8>xBdb zIdgC>GTf&&Hq2)*#qOakG$zLrEs!y=K1N2uXP1@QGbcElXAHy<(n9Y5NhM0-!AaiL zLm(~nr0rQw7?T)|M#@q_nnEkvbMrjF?xsgY7;{qhwFI&jH+{s;`?ln&M2k~OvNUzm zvW@yQE~1+ka>j+>6Vt`=r*2fF77$2*5kLSG5+_ij(~!w7Bo=@;fY15!HyR=8={lFs zdX@cfuWcfhUtQWpctD_J*m?3t zVY|@=DV3@&6+dQJa7Z<(F(wC9zUX8VM1*vY=L%Jf;>>dOJ>1_~U?6AT(X`Shu=m0p zeQ&6UmQkQFI0r(6>3bZ}D#}^hRX`f&@Oz`orqQSUBuW`^oscR8{xnf{eCY)Immf+U zUH~1P%HLOG>9#hd6F_J*ZrCPTzR*eWb)xqh3V}S_&$WAD=RGQxSCs5J3+DWUo5Dr& zaog-4^ae+*q!;3>96J)L;|Z1qCkM=uXJ#})AGxSqj^o`9C@EV@`?$l|pIQ)i$ zE}iL~hD)K5uKZ=>+kJGAcy)>9?I#se^%5nu0G90z&I-5ZLY7qT0xuV=bk}X>YshCr zvcpS!eiqI>FqEXIyb3f(mtM}S4huDECfYOF-;1SXEI^n*(BP`|Kq+f8(m~auPZ@c~ zIIM|U8JmCYSUGBsLx6N9>-hkV)1<5fs(|ZJ*kt#xEfcH%VQXF-%u9VaC5hhAwes6s*c(B@ zeRA331l6WnZ=IiszByaX&9M4i=;3ySsM&1+FI4i>Z9gSgiTw;T_@Jq$$s z#qVL6+ZrbZyjs4oi{DEaRQ$E8Es19@C(DhefnOh0fA8>NuV;jT3>3<+&D}QQBP4T^W{7g}A_(CX!ceUDC3Ebg#WHH71V zKluu%#L?*Hd$Z_$R;b$sx?@1Si{{Sz%GR?q77mg#$ZifI!s_Af+SD>7LxtqgnoUp0 zWv@BaH02=g+Hr=%!6H*78%~CG4V?Y-*Mt&$CaJ{*jCjTWg6MLEhz2@7d?H0<>hzns zPAzdi9GvPY`z0?F!9q+t(~w&&eEw9A5FMioas%_&>{D+UWXHyrUccJSH(&hA<;aV@D zAa5jqWGq;W5$n_{*O2b6YM?4b>xbAA$u2>Jw=Gmq3&ClD9YxC z76e8zJkzHL(B{RsE0BswA@1((-k|)p&~)Co5HN1Ss?vdo+~_ zUYswRc2C|oYK&Q?jDTj|aJ`-R&Pe$ws6~e0_I-6(sM6yptQ>s#f6fQlE;)Ef zhd6zYYp*=fs#ANLzxzce2V$b^MeSiYC(4BNFKHmXdZLq!j67Rc)I83^720GAhdRhVU@ZlPl zObXll$O8j&g+d0%?(g+BSp1?`y-=|ES?kauzg<#@pm%zECE1BGS&z!HE#YY7Bu+}%Y0Z9Dj(q6KDhlq9w3gS}B$QUt$SJoZl>B5o28nVVz= z%a%Vo5a!xMH6)fhRZ8)JGHK8(=I>uQYXjebA_E}^tU<$mC@Bi#*rB!MzBU*1#LItp zcpe9R4)(pNiFyhLY`Gy40^>L+<)|es585;m-&$=;BGmIA3+~$GC(NwN*-q-xROMCJ zPQRB@K_7prrU#$BRTfTaj#lBA$mT1==RzgXZ}Vo~&={iunVczX5pqvIa;Z$^9<0B<<|_f(32jpDdhY1sfd@eZgFf&%8l%Jos}aW}#)?h6*f zWaez?SRhF;%>?x=$kV81@qeeDy9QaHd>P;QC&b|^?`Da9b) zgY1(*sQ%yHpA%uDXp`t2smt1SkMD2>|80wV_FVh!N!sUP5x;6a!aw+5l{$o`A9Is) zQypxLR1Vc_9IS52DSjUlGuvG_mUCQcRmS|^;-H|F4a^!Mw+v6ehauXal;G*jcS{US z+^%>zIy;NA9iAV_afa_vHt{^nCvUXi90F53H5G0$lxb?UCxVjxm3lzh`?-jkist&0 zL7D}fOHSacG^Of+WH<&FORsBCh`kGuPehSf8T0VGxhz}a=KU8qQZgyLCTK(po*q-p zaaQ}Hw2?wGpdA)%zx0;JNF^f4HX81kw=tQoc)*iRcPd9L5g#TRRE-$+hLl>}3qjd5 z3=E7672KvSQRkq*xUZDQP3x#_q`ex$s@-OlRZ$BYhiTy_BgfjP**y01LB5m2)>9D5 znu$ws1PjA6PP6ryrz7t?@LymO1xF4b2Q3xKpbak7cDA+(%t-M8(p z1m@sz(FRJ@6(uhnWnd`l9T=vOw8Zc_y+}vmBUQaL(%|39~^gT|O z3&C?Bujuy9dSIn#X&HOnIU8LttPJi*!fZ2YRf{r+kH1i3%2yTNtw2vqNx`ODqzgx) zN336K}SGjkuX4UsCEIxnm5WiPiqHMEKWq>Z5q#{>?TB#Yt z?|nihy6OX!tJc)qoXY1$y^zM&dF?JMC)XYD-lU17a@f$<3nELAZU-Qaku;NG|H%H*EW zn!+Ib06|!d-(DX+senXZTdCqxlU}c&N^nIjdY!TO#RA1oLhu-pUrMo+tHY&YM88E_ z6+7aXwW7xV(*gL?3;UA{YC@mYo}o@8Xa`Y;UN4wW7FVu`x-6B)SAE+A^ z*eIUPtyRIcu9~YV5M^tCq;V6Z^$Aw-LT7o*IEx#SQaTphk?1Z`Zh%fVCoK&YEuOl! z`3(qQzmPlq+Md7*=#RxObU?lNpA+{_URM5IbTJKyG5o=GXGG|_xb89~iL0ezx4nYY zo~OC4y)I;0`L7a)=*zCck2l_RqXDYdWedZ?^%cp0G@PQ?YHRDF62Nk+R1*OkJUBS` z-LVxVHRlyG-8>44?rtxB0609=iNBT{i2l6}K=q$sEzJ2}J?Xpz+tMZmum}hKJUTG@ zy0h?ab>AB>QuT~i3lF7%Zr1hVLbURl;b z!*S$|1lGM0BjKFgu62U)v!+DH#C)?xc(wdmBtAytGvn;`)>zg=7SA#0spj2ON=p8{ zjeqje@*L4X)2%q=&oUy-Y6&+72m90aae)$notSk9si^_D zn~90Z$(WY4we{7}k5^~)X{YXgJM-E+5H!6ySNGdTz`2(Pi<&qFo<(E5>?C3s9h_|d zf`GVYiz{f-w8~Zn0StTFtas6vW?R+ z5$K%xD$skC*2DX_$?CuEyuk!MXQ?b|hZ7(4E|n`Atl<|SLWZ3G9AXTTd8LRljj%R^ z6ZA60P6?H`5W4sw9*fv{D9y)e;r%NTzb?~WBU%cjzsK?WAN=>kA|-pj z9jge635t9^e2rPt&DR;9Jy8X#U*b{SJe`$!ZO}`;VWnVtQe^3y13>|+;e0UIvNDj$ zk@w}`G)qJ0{*Q83!@ZxcDDX925q1I${y6G z`FQP5MoCzNtLM5x{hnYx!3<<81cu+{`tsQrm8)N6`Oc76K4OArDIMqxHv1@=`Qvwo1Pgdr)ryxcgX8!{6ur?^jJpvRi%s?r(mz@rGaPtRl#iJ84^*u8fz3*WP(D5_W!E6|fj+T8 z_rB#(M?p4^*|r7Zq#W5RWA&hF$U*)8mdwhd!2`(-;`0N%WzkG5M04{R_djg&*4QT4buP$`48? z;O|qUGIob_{IU0aev!_OV)Z5Y@VNlbDbI~=whA5~;I$0?O~L=YGT{9U{D!`g+;0}~ zRJ{@c)=*>5SA`#x$M^g-Tkr}jSH*pLrE@z*i2(F- zt<;s`?#YB&J(1_WM*OLbg5I0-v(B_byXMUSdekW9`k~0kGotyTVbhwku>Yq78C{m> z)soR;k)okz8}Mk#JMrWlfOO)zul7He%s_(xpau;{_x@bE&Vkkpng~jWnDA!9P)-dtz4#LH<^T}4ML;#aL5sVisgBx(E6=2 z0HayzsxY@|SK1j$iI}RiC`~KcAuThE@ZXC+nl36P?KqsNKJ=P|S$24uv>5Q5I}$<# zxXxymNW{i4?ZJfLH{Di6U?WCHem)RiOd_>BBRvu1TbP zz3*-!UHxDJ+UIv9hZ{?RqOW;A|0kqIhtTsA_@?w__t8M3Kf8Gw@d=BoK98NJD3x+vpN)_Ip=pRh zrb%}-$O{qb5fb**$=;z+-1@hn_ zj);i!`b1|=2|4<+kFzKqhVG? zGc7J=)>LTM@&4j!{<3rHhM1ylI03LzJ~pKO-NeBJ5?wz>`kJK<53s(a3W(#NK6!ZQ zMtV^~VtU&DwHxVZ*xKwWw4_nc@#0FZhN=G10-)(k&oz)<{XqbGbZydpv^$NM)#A+D z@x9V#_=jR^>%c+M{p!%*_~DE7k^Lc?+E)lwLo;YT{bwbgG{2mkzEPMEu<}?9 zwDNOead#2|Wj~_PCBotWB|XB%?*z~Ru3nP^Ug`mJ@sWm4##@>XtuIg^&uo#?rka?l zCDCYy``r|_US|mw_7C>rf2>C35E@{hH;#A1*(k;hu1&rMzU_DWZR%ce}2Z`jR(4#0>azG)*N zA;v&kU)MIcIO=?NQ&GR_h&$9LF3y7e8)bu(zM;Xx!H6edUuv_z4psUoPGheI2V#>T z-+!@`QxwTqxXg|+4=t|D&_WP4@Vpaj-v%6HO5~N8L6J6&UmOG&pyb9v{byM)fm;^? z&7fb#3W|$)&4*!-_02yp`u_rF{z)l8T<79G$VfLh!pdfh2*BfSy2YVjH8;^ic&ss6 z8Q&HGZe(C^^K#(}FI6sLd*Z|PV+WfM)_=m@JWhyj@gDL5_O9at+a=};e$AzKZJda~ znXIDQps{GhSl%)}KmYxEYctL(PmZ@*nwpx9j@1v3Ga=Y!LVyCTeje z&tQU93|Hba=wgeCs7T)zBzT@#OhK35(|#M>UHwLY&d1N+(q#Sk*f_T=Xk%lu!}=N@ zv-aJxMYs$IfYcy+_#277SL|?J7M+g{A*FpgJ@xiCPA3_Y*t_;~5WwfV$if+(g$fWP zJ@{(kJWzAf;NSK`9}x-ZV@Z)w6K<#Z_SB|de6iIwgFuD-s9=j#Yb$@~?5``-6IbPt zVKJdKEUjwNCTEYKYD($!!W^Q5bd-$uq@oTB7;k{^~l&bO=J zzSgU6!P3Z(KdNJtzDN&$R% zXM6h!)Z{X(1C{hFo>r%E*wc1i9LycW4NL(o;cC04EvMWk#3vv*iG{!d;Gk(r(CB+S z1LR#0h?Xuui$nSYo=D%fpwEh#&^J!+ICkH)`h`Zof)#W3@>Dwta8K~WAQilrZVw>K z7Y~reVj!G5z1$(0J9&#B;o149Q8H<4@wzy`?ci&j%=z&=Z`0>SI9L#Fd)dvcOhM#y z_}}IBeI2-IA^er(pZD?Gq84f2=)G$MmD(a2spsgK+F;i34OJYmXbq+VL{ysW34jk!To4!w!IIR81@ zKvgLn706GFhD^=X-81|w8-Kl{;X?F54;6vT)U{|P3XjFi%nY>fc|kvtUj0Lcqs`d6 zM<9LAn&%@D|ybg$jpdm(LX1zaWk|*%HtyWp`l?#1mJjXk_M?nVOy$F1Gp9 zSz-y18A}Sce0Xu8*N1#u$bzja!TdJCG6K|iC^xSc8|++MTuhb5gmu5wVp@g$)s#Iv%Z`pd(d7s>;3@Qx3wc6q!*)^9!iJ!O>v z?e(>$;ib*2_ferlDv5!ooOD|C2Zj@g09c|bB=Q*l&C$~%mSPfF>%*6{|HK4A(Lr_* zWT_Drd9Orcy~}>R&yv>fA^HGdZufxaBt`X`Fc1u-0mGmK0`Go<(*65@%Y~YnnsS7* zDB4_JP)=6{^N3D*(6q*)TQrA8Mq0sOH!zRI!y|7w5;~GA7dvrR7RXEGK- zLW*O{zOt?*RK`)zD%wycv_%$`0`6Pg4WY}PM7XV@n5TAEXek0W9{XRK?K~xa%1XX7 zHs_>##G@9Nj4sD}uS_&|I}0=HielmcWk}2=8vnzE;jE5JAl|UU($4H_>npQZ2WL0c znavEow&SAf5sQi8=dwTgoGZ_M^hdr`{p8Um1Q!tjXd4wG|>~4>y$4<-e*D#kE z>%Js4HsJgcO?vHd+JX`>A=O6rFF*$(jPxPr~!Ub&Q?rJ48RH;ezsi) zK}bDr83Kl1D#GM2Tlq+ME-x5D1n|lD5Je>=T3XLFYpZDvae0ikI`08LXq6Ju+wjdE z9Baq#f@`=@c)Mp10N9H`DLoSu=Zy3e6&NEzE>|x9dWdE&dsiIK{Z6>PWYp-V_wNIM z2*;3LPi*;z%1)GGP3N14jNm8UdBXbbDEX7nzp3maZb<2e!k=$PHx-?PS*EKaLK|xu z^-L;5j%$*hXzV!B$W#}A#;&pYf1$De{y6*!gBHlA7*#%hn{hKT7qb1a?_(yHq4y*T zB+dLjti3c$xx&)kBzs?14@Dli z=1|J3gc1hAj0A&UiYrF8w9c&FYjeE6_k8Uw;k%-2qF20v$JQUtC%F+J z?6C7-ngH1p%xOg;Jr@qRsXwt_sNDoDGBKYW7$jV})j-hk1*KmAC7f`Z5Td;U)T})K zcp+Q=?D)fXq1NKL_tq%BITm2WxC|ze4}Y4@74qXQXOWbW`V#U=^2;U|eOe2?pmqYZ zsy6IF0`7-O#YZ-)D0;wbkob zdN%>I=uLUcMU9W)4Hpz`3SS`b1D0&N({ji3`^?N6Fs@BZRcet}(tno+j5c5cHw#?X z)1b`K-Z)n}y3sfrb}KQlF94gQS^=$bYH|m-FTsMmc_I3$&j(lfJ3vp_6ObdppsJ^L z(?u`6tMm3~So;k84n7UkxKQO&rn8ZgL!gm^Pt0|`e!ZahmF|%c%50>Fxmy&m4Sf+B zap}wB{qbw>EC(cE{(IeO{Fnj6O5y6;X) z@pGA=v>03OjPvqz{Q`s$FIQLbG{eAXQ+8#+s^AFG28$RXt%{;<@e?w%fS%j01F-TZgGtCVRf(oL(%m+JOM zG#~Y;-{P1`zDr6OCvL?iG14z@5_P^@BYSN=I~Wx=Q4mU424hA0r*p`p*e>-CSYr*Ve|EFh^{I2q7IAOh<%h!oSIQD%!eO;Nqm~zzjpxkKj;RC-{;Bp?ck9 z?6Ocx8(H}-NiX`e4(5l&?d8rC)K|a&>=KgOKsXw0@>qFDxSJ_3nCJ8{df{pga0QL# zLzutauFovmJcA^{t%{p)x+-5j3{TjWO=w6!M~dc{p;H<5CK%?4- zTv=^t(-C{Qs~+?CW_tJx$!th~MYNS)z+_fzuC}J=eA8mT>1LDxi^DZ=$=7<3`MxGf zR!>sGNN#8&?G+yS%H64mfaDLn>hC?!)-#kVna2(0Z*Wj?GVsJZO{&c5*qGKL`f!>p z2KQn5igO)X+$VyCTk`Dv9_)o&TrMXbqXd_{&jsJi>4XYkN?b+SM8Aw$oTR}ZgOm({ zM~9#=&JL1EcgD<%qpY3#8O|tbWo0EX_)JE&J(lKSD`M^0t|ByEvw+I+s_I26Jv8wk z|M>Vg-HCp&N+|i&9l$FC77m_H*B03Hc}Jgo;XnM&yXz-(a`tcngAuhORLoJ<4nWhs zxuL0v7rr(uEUYwG5SrNb{^mlP(`hV|D|}`H4A>JB5g)g6KRrJW_3x<^qc*W6{*HYg zIvxp&ei3@{91lx!3=HfZfw9J6`2y+ALe^(%hTZ@sXKBqC+X!>xz9<0VAy$>K?^T}T zG3!DX?*dRm7*pSV{%Tg#OAK&=o&0v&fFCgf%CV z{)L6W&lSH_@v$S?lHyZF0!;B4xSFLnp%NyM^^7qqD(BqE#u!=V`guQ18#62G0ACxh zBQW_Y0K~s-C|Nnl@)FHlMdn>iOu8bhtZ2$EY#92E&#~o%^rbSmmF%;#Gw9FS2)E7V z@a>kcvl@~awT8_3Bs7hwq}&ErHV5#~63M>0)scnYBG9dtbask-+=khp*#k4G{rv@P zmwx=n|GwtmU-%*$*88&w5saf`p-h5wIlko~m=p&B@~Y@m!G+DBkim9S7$UB0%e%^c zi`p|jG#9X>pytEf@$>fMB{Ot&GOK6b1D-BCh>!!W~H-y(Bgt^(~+I2Et!cn8AURh03WDr)51+ zo?4|c{O|?`A@Xs&vB1WU8|K0XICS(W(9#CaK-i<2B8hWj9i%mcXV#jUxZ*JRKY%L} zsD<1C1YzVud%)*Lm&_ALAQr$4K~!g>ym@7fvg(l-M1JoKK>&#^sTLW6UWYD$Vu5H1 zC$56Q84+X=Nl;rC6d4;2pM1X(f|ghHQLpi+y7lM{2J~}^c;(MAXL24aF1KZ6Wh(D6 zq~OytG+}7-8O5Td7U7ITchFv96d+S{xMXD9L>*}tBER7>ryM*=EWy}7y2mi^JpLJ1 z7)0;Jm6p(lgzlcn;}oyj1)WJVna`RiuCcv^@^(uns8YS3ztb(6bbyt9zkk$!!s0x}L}_7|+Ak;wfN zB}7`<8LPi24v^D^zzXN1d(I}*+q4BuC*WW?-hY-P*VYoi3D+|G_pQt>KLA<45 zMX9S?&4(QKEP@b2=Sgm^J2-@ZfZ#pPV5&Cd4PQrXCsA;=z+W{x!Us&p0qe72F1y+# zCdSCE>bu`-9ib8-C3w6j=&`X`XySuLKASjg&mgiUKS)8DV9DTmvB^&GDxU;Fmq3_$ zh410f>Tg52A#J~% z1EX7|eglOSs0E+=yqm?SrSD%6%G!v$DU~^wiy$$qGoU{--sG7mWm_sj?=c2nTUCg! z*;>aR5fcimXu(vmz$XL@b0EsISlMR6XlPD$&XF6R7})P;G!imKCWTH83CrpQ^W2ap ztK-%gUliOG_6BAr)F$*o&X7Gh0-N@vqLI zJ0PACMDs!O?zrs0!$7~lLX4~mM;=o=h1{SDg*C(K5Hsj=*1nCWMhM;;&MIRmb$-c- zo8nFcDZA>uK-5|j_1=4*sD;*iZE{k@S|L$P6`_xaJh)Pzg=`nXSRCZ#C1~|pvcFV1 zYVbbxQ&OaIy}ggZ`%Z2v!56lKR)&{Mok)RB$ZheR@nd}=_ZF&y9iaM)2E(B#pjaiH zQIL{htl59j3H8*Av5JiRi| z4;)VUb7E>T*dnzlWJNif(PAsi{%qX?OB{2N^y_bN44W+#)3PjJrj}AkjnXDz#W`vl zL@}f@{ji^*TPE2_aUy;<|At2bv$_j|%05oF!~^!Y9=flHI6%O<6xn?I5{bfm>YVanY0x}MZ!$Q2o2agcDp2x5~8P$9U+T?IK#ENFjC_0re zEG-G+_B5&eTic!U(yg+HaBaG?Rt}>PUT+(mk5+r7&NhuWDi#E|eB?8XQf5e{+-k=v z!YFB0L8?c4!v_Sc zVp!HjRtt-O7Lc@@rYC_;WSiJR@J=F6vJTB$E{*6KfGDRwX=fVmjCao)eqN)1*0=F< zv(spzB7$5@W5dKc4UvTmf`#|N<(5d{sl_aW-Hp-_ViaY@5f%(G4AIsIy%BH5^~6gx zA(}?}7LJ4VG_H`)s_5&uFL4sWX*ocVsRl0lePH@3qZmo-61ptem{BAN=*n!qZaBDTH&E zSEgVxSA|1v3CBhKW0z_1UqOo@arlu*2%Vd*?xdx-EFdo9iBS+QjA*(On@Db2#niKs z#O7mumBB>b5?o7iiC>-i_QPwLIVWD{ih3%k4<@FL004$48b^cr4GRRAbuELnWS<@r6seDOr z4mZGS+*jE#$6VULtriHXJNWwYi_fCVM>>NkLhKIXu8rgtFDL~q7cjHb>=Z0ScSwcR zM&LVBHP_<2q3gwSCE_7*Ya`%=9}t`C+nc!<^k2My#`=~hBte&3dpVh#s0n$4s@H^; zfUd$ilcdAZ>qYo!!V}?wSTjWHR<%Yy=rfChCuD{n3wwC?Hi~_`LYoAgg_sybcYzM| zBLXr00w%gl)COAs>px9 zLH1w}MGuMF^hE{VVfr(z!|dmNsx{N`sx2S~xsGS>3I-$z6+H9GaJP&$B@-n*ikco7 z7JEVX>6g^VhKEF4O8{1vc3td(jQN_L>oIMo$eXQWamgz=FSTl6H?;7^+HPZi(T}tpp zo0@%>+;&uNm)~D62sZ7drqmM!;F&C!CYHl`zTnylpM2>?J4pNHj>PD$k#PA$6hvFR zoS*xGJXJ{u?(HIhfC8^CpUs!oe%`nI8t_P^!(Wn<^t2-cX|6^YVF zFmBYnsmcoU_hr$%!c>@8c(5S|qVN(8(${?fjS-_8RtL8X_9VAK9NRPOzmBmiXuX!d?=^5 z_s0?Ek{jop?c)R}kKQf4`dY8Z9|RkluVHHWEa~Ml9i$?^U3AhV+E3Wz0%7L2 zYh|!|r??mHudRwZ!e&sgG@+^N9G1(kAJ*28RQnGvlHRk z&X&GvrE+`Z5e`gopVe0tr)qjzr%+J|jJ#s_6I@OXsf*mgo}nyY#6;yILDO$|b``jF`y+)bypzlyr3zszxP2}-xWg~Si~hA;oI2y$auiW zSCVhwGfs&G^bgxl;$GJwW^>3vTLWvA``|QWUVMo|Vsy!in2srFZZgPGi%f|~GHL!^ z>(gr9?s|y*U{hvZplPwphJuVM;X)BsC6Xfz?>;7$!%cj0^2l6w9Za1BH|CP^i9PHw z99b`6@X#P}LYMPyzE~Xf6*ZF}{008*x6=c-7>5_PgM|f>L7(q+m<0mLsURiuG~u(G zT-)m_vn^&pHH&a0r&ue7?1WPFD1kpWdzF5LN5?6odMEc7C(DZfxcWHX zhxp*iZtlk4|f+nWxLR)iUa&#{C? z0jLm;8JI5u5sm!ABi#<>+3gf@7Q7eG8IWHD;6g-+Q)9DN4N5}PfqHH842>%#*;hJj zI_sB-+n|IP%`2SJ-1Vh}?W6XCg=UXR%}m!4Q`*p)g{I08CYm9x4!R=+9~TzSHHL}b zDxW)N3dZ{pTWtvTA7NpySP3aCnD@vbBv`RBaZ=xP4Kun_l2@C&MGBiXD>~^_k3U=19I|PIyTDm%6UD{k5Rs<^{e3)(C!u1ZiJ~a8mFcPSHThacy&G0~ zI88y*R&({VPbhdZva38uoH8gJ33@0qEVV7R;dnB}C?GKv1AQ#H(YWE&oB}S)$Z4EJ zk79n1-rIxW(r)h2%#(4-B}OKBRy|L-x<2_Z<}eFz%GadV#L7SWIFbij!p~`q?JTqT zEv$xmIBhAtW|Wf2m}zwkzqZ2~UgxQlMSW#567h%B4zY-u>hPr z@xyu2_j^H)&ev;owvY6hT@&X^Z-`6Q7AzIkrJWQAzIc6tESmO%)7;HUhi1f&)}34W zK#e8nqxfEwGw% zM9ACO%eA?XV0LIewqFv=VM^|80IdRYNJr4Jstn!~(fO&?t53-}p>H=RjfjE1s|h5m zU}$x&NMGM!AYiR9=!q(rW9?hyQx{yKb4Dw`05!F6TPPIOqPb6!pGvn4K}{&oJgF{G z69buX)TA3$Z4Fan1VGtgp`k^aFq&x>Lo0hQtAro#ehE@?Kx-^@vUT4L z5(KS_6S*+h+fDqabdOD~Am*BnWg)X9SJwx88#LhCQpfr|!cNC{?r;;VF1F#6nLi=s zO7z8iYUcN5eZGxOP96jgM@-{w|R8a0~EokXV=~$wZF6`mnIleyUp)w&!BO;SA2?q`{Zta zgH8sq$VxEF5IC~Y{$SoY(4B8oDMf%>MXYV&9u}lGk z@vqeZ-l1%1KFA<%SY%<4Jh`vdPZh`UOaa)Jt<6x*?oO?*vhBXsu&sgY;9tb+=bS&D z>eAAf(ETA~lK)C*35)B;?yEI!S)sg$S2jt~#qtejd$}DqUn&J!(d2r6LiSr$ooz#s zA)!Dy=_(z-zQk~xiRCFM;u|v_!7vV_KS@Z`xFW%l&N~EIgZlyZ0&*&)j+bBc>iRqis7+`t?TvUs!QScrXD+Yup-OVhn^3rh~yk8XKjy%Yp(4 zjCQqTW)k{S>$UdF_-e9men_b4$fPj`8A!1jPE&FK#=D!YqQal8f|&+y`oaD4_YcDS z`v6x57{+TTeQP@|167m@fQ42djM3U$8^Rdw+x*^wh(oO8y`){=?jyF)_Iw~a0>{AF zsQZ!GN96;4EoIX?1QJIKGr+4f3jg-IHV~pCf_}N{2EaVEEd=)sI#X?gRe2>wRkBc( z;sI+mDgdfA1Z>h)#!$ zMxb-24;N7>)T|aJ6#m2d03`N0u0C>z&BA87{WP@CZiqsbjOb>UhER+eA^hC}ut4rQzcGbBDKE z!4WcbRpJFDxkZuid0gL;5b!pgjP$*_J#6F<@H}l7@Gf7m#ap9%$|}&tb9%g6Q9OGX z!RFd-f08-#IxCbalL>xWPx|h0y)Y29vsJ>!YRAP&SCCG4$*b=>ymU_3rfDtn;?T=u zy~1RBfuUiDO26DdUn`1;%5rTE*FK?=6&MmELp6d>#y;kRqguPRrPa~X0Sm-Sk8U!*q-RLzy z{_s~Zfge&Bl9@q3nm5@jE_ZPg%}6Xlsfr(G25#C5gsq30H|(jD(FB2(DF+O;N!K0$ z;G0i5lp&ftmDV`{iy8W+FRBl9C82o?atA{8M)?C!M`tQQ6C(T?2Uj^*B9-_VL^Kvf z5oHG!OoEd5jtD0knVIB3r9j{--BJKl6Coq9%QXUhGZ-pvju3k9qgwIYAMjdnh484I zMt$dwT{i_6Gs*ZyNebG*dSlu+&oqj%O z6w>@pqWjF##^mr!Fy~jmcx%wNL7KCbCM?n{cY*j$J=f-N3*FP@25;{|Ja!u}fmqoc zStelKc=dxRKZ@HA9bJR3yVxz!XhKAm6U!ng%ZNfZ%^;o4btD|tci%6>(>ks`tpDIY z>MKMj#N$BWhmN(m{=Rw9nhhQVz4B3D1Q-wHL;^|E8i)sd7>S0^L4S8Qtsq0h1mSD; za|hx!>+N*0CKM0KNMY7eDHysra}m2#LO7Us4=lUtr#!U4%lM02l-4iN`$PxS4ojiD zVlLGQfuAf9tniWaqc#OeuyZ1@4ABTANf2f>O6&6hz;aCS=WZ!apchMU<8l=Gkf>eC{(0jX^O! zI9{k~kTMlJmUpi0zuk$KYxhX8#D?=SLIjEi20?B>r3RQGS6p^K=LBaA@@CQ+ZBGkN zG6WPTyR}z5508g4-V-xbk1;egs8wU&7Af`&WY=MCacvqWmJT-vckQ zp{L(k_MU|pfT*Z$o|NsVm;BMm>U6=`{ED0c+sVRATqIT*dw=ij50+9LxrZqGslpa7 zCglPQ%$1E8F?XdN^vj~hJl)x7(9|7>;pG2Cnsn)0S(^x*#N_o4&^vl z0#ZRJ5L2z))bANbmbJvzr=SY@J1!n-_9&A80?#*jR?pr~6`9%L(F4ghVukPo1)(*t zA0E~e9z4G6zpD%->_N0LBtLWO)atCfs8Z|kP%%jzyh(4b?e^v5?7Mio)5W`4{zzZ+__mh=1!@pBWt4jEn!wXhoQhD_WTX?7qqBtU>VynpQ~zF7ktzCB_7Wb z5Bo3mwb>D8ZJK4L3)jai$zZz#>*n;hKK0+!iK(#LD+(E-Iw23$)^A$1ngmm{xY8?- zs3z{pYY~y*`wPE=?-3h#j7#0COy7XUF{mQbeHeef$jE(`O39;JDIuN}4LP@CiA$-n zLoKv#FG6%ZDvB{~g zw%BP!BY0`aQJS;ovWa`#h&l3%3CRIVsjTV*u2!zZOW^gY(bYK0LmdO7E7IVO}xm+1Cf;vpQNZv2pHR;4eFjlU3s6~xZHsbuNZWGqCIw1n@G zJDM0E zB>TF4cb;m~v}#ul)|QO+*GHY_FqQ>PO$dh=MK;Wv-y-0Lr;qX|K?;=?K0-Xc`czqL74h_Rz4w)dF9Dad?*z4+^G!wj}qGf@N|Zkw84 z&#)F8BR*ef{SfHPh^N;^`ku5SSA!sS6oBRs%UbCpG$6vy!1zE+ji5L1ojK|aQnePf z6ydwq{&?2S=KXZimk+^3B}{e&SP{f`u#=cX1Ml#A*LQ*!M%3M0I76 zk;r9#3P$XZQHT(cN1wHe2Y=M?eDSbi4@x(Z0Fpr>aEK+5m)A~@z}vxD?dJ3ew_U8t zrb7)whz!p(E-i;1-RShA!Jou@0Mb`*2Z?fUyh>O7xpdKQHG6CBi+Am876oWgjr3#! zNh`bC*A3RZM^6b34(>;>a4~f>xYNNT)MYl0t40hj(R*CbdZH&HqP&wS$*{{Cz|PZ) z!jP`A@O}?&(yH2YDo{jd4uy_U5|};%Q@TBxDZ*l0*XIG_a*A6f`4fiB2YQD-lx6N> zef(;ti<42pE&-9zit#0yN;)$slDgGB1|Ik$z;nwsK`wLl!;X7yaZZ;i-x%4y&paB* zVrEC>*jB)H>=S1qSl}e3Kol z1+QmTLej=?L!PZ`B9kX=o#pyenc?HjcjtgZyUSPqqbIcU7zUkya{NXI*LfLqPN@@B z0=S9PzY^M7a)2}kNN4Rg8%xp(+O~dzX?jJ{j)eWs?E>Vy-mogcV6&}F_B>q@y@%;Z z(7Z2=PVL7_TM+_Qy-d79CcKq81aoO3Rk}CsXB$vYoNMEmUxG1xvZel9P~NJL_6w}3 zczA=<&h(Z_atAdQbFh4XLCgT-9ZKO5obUg2kNx$ee_v{{672?)#`~ivv2n>o7JZGM z$&wBBB|iNP?6h-(OIy)d(c)laNMkrsbH;xKuSWTCSQ&GeKK=9m{^kGkeS%hSubRqNnybRfDeF#vl3pcWuS>+ z!B}9o-U1ywwXPB?dNPzAHM8EYB*`CjLIFY(8^5ZN>$Dr(R0o$*5NQ~WqDJq9TrYdCe|(6;*jV8@#!4`z;s$-d7;k-GLCF0&X9UWGi+ zeVVogH{3ByYWR4+ySq1imNa>MNDYD=&n}e1HbF&kNI?gcMBv;I|M?mJewzXh@U}LV zoZB=)AnI+9d=rHsryUC2ecqcmUB&v(lM8(lPr+e#Cl@qC6HjkSyd!y_J z+&%?lgg1*fyWPDp9X+j6t?zuA1wl-|sAinNt=@wgxAg*RGp7d>c;mc0_H=6=eu7!D z#2WngpJ)H)!J#0;$gEf;jPY~9SwjD8ViI{?j=#~lv99G9%vw~hp;B0WOq1Z-rL!h) z*>UUap60&X94PFzHr?4$;+#wG=V2 zo>`l{ZxCX9XLcvEX-EfppE*J%dh(BFBax6$F=ImaM2PyUeNn~Ak7guw+x&j_Uv;4p zAkOwKP{pvJYmJ=2?06n)9lO&EmAhv0Js}~sM76oTworIsI_xyF4-40ugm_b+9H2)( zQ6n{$j3044hXHBR;8Q>u16Bf#?eM=@;D4C2PMG&M@A#1(i(!Ao zJED7RZ8??glEUQzIBv#^`895=TLFim^zhF7VnUM6DDVsE=C`yWsDpQi};P_PI2 z3uv^rh}*`QsH+XZo%P+|s@>;*9Qd|FS%L$3@;+P3dzTk0<7)?-M+g3xmJ}*Vct%9& zs5?EzUtd*AK_~^G>CRb`{Z*3cn3e;RlwVyi^6?+tB??*;pkoi`bsK(pcC{#r<@7>u zx%bLVg+IT~N}RbNnqN30k4Ol1GmQ<^=XXu{R%%bI&?cV1&&U}M* zn$L&|SW~+ZB(t1PM0zPuN^$QF*}UAeGmULdhmeya1gSwW9}520y8{2jpYC1!%iQIj z$@dI;6sKdx_@P2-rW5feSUCP*m5oX0kVKhb0@-#f`F5o{n`{#*VL0>Iaic5Y*kmZuSoxHl8U8D^hz!fIVweWa!2_@G?Sa7}OxxILRJNMPN zy>hsoqOj6a^i>UN_SLq$ZQ&Fz)6kf8o5kC2Y&@06>5OSX9whmiVnsWce= z|Je8k()IlB?@y{E?(Oy{Tp??aQB{>Hs74?y4X8RpY%K?Jhc}rDdyFT~tFCS1{b~h! zG9?;KvLSGI_}Xd7#lPsA>Ayh^4i2q8@4k7e-nER+(0)H^(|UOD*S#BY*|ww{>eMWD zKOH2BwfBk_#5NT1ycC$B#$xWaRv;$qmW3tb zVkhq@$6Mw!RiBWMATVUavV?4j{WjSTsAN+!7cf}+b!IWaq`$8J+>9pHIyl1vCT0g% zH-`I$R(*gD({6}n5XKL0RB$WH9+{^QX}~i=CLU;#@~0RH)BeBb@vj%6B$7pYVAJ5% zcxvNW9#F+qDd{FK#S!KY{j^c_^ibVxc>!xj$B~jZLXXN)Fd3Rgo+2x$=9*yJcf#(*{Nyc+=jbG-le*80~6Jdo)t zV&S?ukP0xt+>1U|XoR~}50TDy zy$MGDCOh#CeAdO+tk-)w_Mfgxet@H7g;BTeAgUmKYmq_C*o*JGgJkp0_Ak1C8`!$# zVpYs#eW9+l#wlxen!+)o??po4YtGL?S&zfqUi-6s59ra8r5B9w=8h$LDMUWH8Xmid z8mXGA9*<1nML0zdPJ0rq2vEw#9?rRxF3gT1L3Qtttp>3(8r>Gl!_o7F|TPFCP@HceC~2Q6yo zO{f3U>U(p8j`G&MACK`1BsqT5&YdRKv=*0t^PEmDcDS51QDYGl{nia3`13p5<#rAR zz67JP_w7FBs);LK0*bYjKRjXxm=d@!4U_t}^6KJ4cWH?t2`T)KN^uE7kohiKCQ32d zi3u?oCr7z5Qg(J3OHt6tNh@|1Fs+`euP>a4t%ZH!28aB-CO`3jQV%&?zc7EsmmbEF z>+NAu&IM>v{vo|AiGSRSnlG6%_qS3oM{)IA+I_kBh45G#5@>PHe3RrARY_?g0o!6sF{nn|ot zkxz(%SaeefQ-4C~W=2=nxz+)NwHeL6MO8JRyJLdBCdc#mo zATc>db{uLXlm6{yBTsS3Q@hUCVfmot$2UWdPzm^-HTqqxEM?Lz%B<8sOkjZ}4g<6D zOO6i@k%+nYB^(@Q@T78h7N72jYOE+*r% z-1qqGB4v@r1jb~zjmNaKz#K7AByvI4SQA2myZhaLEz8v~#aM{9hDT5?)80*)^dId% zyJ)9XI2RE;7=f9!c%l`L^dP4p*iPdkhtOGqjkPJ5T(y zaR4`tEt7bc`=fI7ri<#g`c(U$bC3^ESCs|h{d^xfMl)K^M`nA((i@&cTAiM@m_S8;Ho`}a6+mi26dn3)vUyFkciUo z&pK{NPaADr59At@FlWAKMmLrifRUh%kNV&fl_4V}@ysubX$Di7O|`=@BU+B4ah~xt zsK-NRCvHif=r=8jIoUf*v=DnEPnutQ7T~q!q)!-^=-%8PoNVyilJj)m`6Sr-zz6mRWiNjvEjf3hwEhA@ehy&pGUuQ3;$oT1FBy5BBM^z2Y(UJ4f4C;^ujJ8NE*4SifN z7%U-dqs^HjQ3wD&o>~?$_QE>JEx`KxerpV4&er_z0N~Hwcz*$xwS8Gh4H(J1B|nov znf*Ym97%y>qFTe4Qk~$0rmb{99x@TbT2g^+u(1waJ$7OVL2z)ooh1_{tFIru@%SZE zC{#Lf`E`3UE<@M#BZp~D{tdyjp^CUpK~>dIFoIY_Dp!C0%i`NA2D$faePejrLAv(r zi#Ie^ghhj?S!9LZnbqnq5m!ewz>9p(zXkkXMJwCQG>mH1$f>1U1$g&SlhGidH; zwE0h!BTF)eaaOeno~#DI>;x@FCJrOYj2#6?jfL}2{GSq(Ol*)T<@bUlj?AJYh1x7y zREl)g)v*vdqV0zJUw)EkYwI6hR`hQWD6k3AZr_81AoJFkB#UU@jAp=@`6;h=>m9P= z$CH8U-!BE~flbAaBeL0p<6!bsf2krV`e*a`n2a!91&8J2aMnr@+<1#V3^(g-QrYWs zEK6&=E!0}2?TR|oH4%82H!~tLaVA^@Jm9X2yva{}^B3msD9()+o7=U__4qCbny+ao zDu@=z|2tCic@$|cZiAeX$+L3%LemK6axVgPP6ki^>c*<8-dx+fdHIOY$x1#XpYW@( z;R{Kzk7Q!x+C9>1OcN)ZtsmvFxx#=@pph+?|*4$*}`)`d(th%XmYRh2?bO)8!n787;QUb7n15xv=@lU zk}U-X>I(^h|3aonNeq_t&=0->Uaaw*b)n>HI^AUIpjRd)yb$ys9@j!hM_o_xQF(i8CIAeh5Nbw|xoMRqHy{d2*vgnR$M zn6!jsce4M^qHVFv2Tb(SosHaIBsCRm;8$b3V;YA*Nd?oR>2dtb5RO9-MsN-HbfK!S zyw|`*2Tdl%^3VxFMA`a9G*i#DMDa^$F z;i%mT@T;q+mG7Co&W0x3Y9G0q{O+e}h8lVWL!U`$QjL|%wZh6(j>A~gH6;=WuL>Da z?~3nh+vAe8AW;M@!Ra&(UYx%N}?w7N)alYAu)`X9U(7&ykxVrRX7 z^UWT@twv$NH`@z}U;8rLnwUr(i#NX~cDju>EY)UKaxY}!x7TD(pdElN2mq|d zMS_C=ep5m4e*3doV)0nVoO=swxN$)V@*yB|myo5!qDlYa7Bjtu1#_Jr1W5A}-E%WP1G9lKL!?$jZq_kmA6)&@Fq72&n5$qPijYif)P( zj*;?9CdvNQY{V}Nz!;Quu8IQz*M}I@hQ7egL4!6L?4^uXqawmlg{-+T5>B(R|LF~Q zd;mQH z#6LB>*0C^=)qJ>uW$7rVYSt=Qp77QDcQgq*X2aOIFPSN=n7<&WVl|1^u%P2CbJAE|+@vCjM>9U4;^8H_JkSm`56JTp;)Z zUbleI+X0qk1VY&5?I(0Hq{+_bFW&LGhFjBP^2i2Q#Zjy||G2)GAWJz_;P^$Qi-byj ztT@BoIO1u}y_2HV5NtL~si53ioXiX_82i+jK|NR#F)Cd-_3N)>hyR7#n+AAw?8r|% zPr?9rr2gFzNQK(JT`>@hRqRfA-eL0d(G_@*6k@Suwd)ephg#j@?Zos%4t#R}wA;eoeu_?URjOB)sBm8Ph zAK&d&dGV!R?ZG9;S|@zAPLL(Iox<2bvEIf(9f|mtmjDVG6Jwwyt)|w3|EdNY(6l+Y&_zK7BSA^Ek8MYq>6P{-Cf_^8r#*ODjD#*8Zk9A7IV^ zlqV-9CII?mX=#T`RVP(dRYylw=cfAl`-g`l@HLdXgxFY83JNjNNx!B*=WEl^|2Qf@ z6bCeg!{2ESseZ5gOecT}Lm?KKj>_AmPCUW1+OIUdBbt+Q(1YilZJe^I`PbUd zn2Zni3KHt-IV(v_#+Y;(_rT!1v5`^8u_<#hgMM%G^`s;))qrtQc{P$NnIN6c{Zaby z{vMdcns2D9b+QJuHDk!72K)Q>0p0{)!kTbuX%zF3K-J!9=UXu@MB}iBkMIs(-~Lf1P|5iA?UI z&wFJG;`Lc0iiAC!T*N*3XS9~fO{@a;Kgl8tF%qiSO;kx>ReI+HKQ7i^5BCP(R3cFp zU*k^-DtX7BX>G`+D|uT3C5{-?8lp}oa!2>|YlfmBO+xSM(#L(?Fl}AB0@CbQ<9FjeheljE-K8@X0N{m1 z)y+!9CrFd$SJc{V=}?Vt;~ZpUhR5?2Tu!IkmVl(`PsbdWt6gWZlkqGeVD8s_4p6kn z5+M1;N-6$)3$o712K)YWxihpsUuV4rP-9TlWj5wq5*^x0#<&B_6?Xvbyl#Ye#bllo zPE&I6m%Wogb;(pycBUHt_cwo42~m6+1qsKOax|x8oz*qeYTuq~8aHcep0}sysc4ss zU$52K;H*$F>rb|Gn~7gCFlKGTj=lL!ZLMyt`z~kGiYOUqI|Y$N`m65xrkO#-LX___L&t!cQY4H!8(+FZ=!f|*jF75O$5xG8-ki$p zuT5_&CsHtCx~hT}&G08{g73<-J3()A{&|_D0PnGI9Jbh;ikI_A^g!Fv9 z-%7v6uPm#vc$GV*P<4>Fw%k-s4&t_|Fc!ISA3fj}d^2b@M{7EG373NJBCsOIP)HU}Q_*RA6-5Tkgi{ydl%n(Ux6z_nsW^=mmQpS3*+U>($!*vq z45;j^+=hUYW2+O!p)jVPoPeTw$SYP_LQXg@nb4*Jq$ENC_KPYx2ypNy)OxqO)0tEo zn|4nBseGBUg(`|)X2nWDEig#9Dy{AhfD{O+*_RZD2rx{eR0e&~G`pr*yjH+MXG_%Y z&epsDk`$n`5qnO&q)8a*e-ErfT6OG5({3O`ScHUGIluo}*gN7^4ct{r?!K-8R`;R-cJPs1f z>>?m*0Ap{jg{rp!K!E+FA{h`~j{+Onkj)Z6 zod?L7G@Vv@<_?8@Aormiz{d^#1_3j9Q4?ME*86q5hE0YpLfcL_)tVHzursEK7{eZH zwr%B4I2DjZ>4zx$)m%xPZcJn3#(9Zr#3b=0BblK&w>Ci@NjqcXPvMBR3HmDyk5DB`Z%4% z;X4Ky7#I}tzM|Id8P4G8ZU8Nz042u@(DeHr4Gr}gaSa+7-@@R6XJ=~TbO18~pXU*f zWzxrz*J=g~Z8!!Hi2=Qml94?;JwZ%Jv8^y$%zs`uE%+)U1EcthzXRsg&DE9FYPlZZ zDsz56-soViOTXh@uZ)k6|7Y?e%)rp_k5tm|BA{gRM>w*2c*xMu5MU5uR9{5p=zfTS zV=j+MwB1W$8mzF{dno>CW&{xKB=-DPEIJ2+E)=&R|D!b1OeSsH{Y1hy4A2x26B7eu z2jNq;01E_AV4!soc(@)(qayJAS1S=ea1qqNhMnQyEQnL^lgtQ~0DK3ptyH`$LvvFn z>jC~<2|(wCS5!@p;lfa);hSr9=d`a|Kluh5Q7vXdlrMCeX7&`gB)w*1taUb+Aqs(#9~2xS-1s4=!vg58cv~*9udOJEfX;+(|8ko%U z*#R@fanuj|o!}8v&4w&FqT!oOG!%KuF7M1RF;7V|SY~y)IRYJ602SY!TR}r3s8rH1 z-X|K{>DYv!GC7D{Kt2o5(2=@$=dI3a{%AB3i!1>3KlxB*>wEDb+WY$qyc-8c))eK} zTFH;0w{ah3JomSMaKHC->LI>eFpBty4NHx-IdnUV@o~}I1i>6`TtMdb_M;+gVlN8i z@4rHiX--fbrVo@LXt5(}TLVZYB_cv&qD7}g@qA919xo%rp+|-s<-LmoZS;4)T3FE7 zGm}N=7IOaRKSsmMOPF)%1DKL1R7#{5NUp~bpPGtGI<U|2Ke)LP zAMPQ!Nl=wtX%fasF;ep>HZY4O?&;z&n357+I7TPUTUQ-%Z{>b2>31yPv0JSwiqvYl z2Q_xOA-%dekB7kv^I8^khIjJK{?}g^u#Xy1rs;w>v(-hwJ2^zl!S|W4`=4lL!@VOs zs@0v}jD}rz8?Kp#A{4_7qz4+c;KZb*q-g18%LZw~Brt0kic-_k!oA0%->>L}sVpK* zw2m_n0V-U7BsvEuGWMf$dqM*NU@`_m!UDFGffD9d@Vo@6xd=y{Eq3jtzj@Z!yz0L4-XR_`Hku#hg+IS= zuUt?oNl3r;Y+vs*MU>3Daktffn^#c@TnK*Q3O}6WB<`o5pQA1-*zTS=qA1J5ZB8tA zzmw~b)a#VSjANl2)pxBWn9CQcS_cbDSC@6?B)Vx2Fwc0d%BlbQ%0d#BZ{^FND}cN< zon!n}IEH^sv{mb&hYSEn$H;R%s&wBx-P9VKUdlnX{S%|`L)GH zGaON@oQ21G0n^NP$cLP@PC*4xVA?WHxXVL@s%>Yyw^Ox34Pw0$*4j3sPLCA3qgi7g;La|2R@Fk+;HyV}9`X5+_%2c6{A6M#;=!^vXY zf|H${UvU`Z6u<{3FpIPw2$1G|it+ds?wXID(pAI)1;=9 zdsD6ZyKe+wMJc4rRZ&3B3u`o-`wPIn0V!M;V<3qYHi|Pn#*{LV>WgN=qm_s%bc=l{rHi;YRVfwilKj5lVE6XE!?TS7%#JX3?e zT!a<~=IJB=F5#~53o%3Y5Qj-d|9cnubk0(bDOujAwgi~gv}868BXkMN&Nv zr`q#ZX@lBVOSQ-G%2(71cTw4lr)E}2FX+z--w93z+2hO_REyM6;Ku{?!kx}m5gSIv zgF@|x>wqw|9Q<0Ml-I8A=Y3*Ha}c)h)1|9ACMLZW4LaJwxOm^NNBi&KW{sRFh9NY{ ztzqh4-YCDvir*8H$9gF7y5E1kTk8b(%}fda!ajtGa*5hx;z6OncN;SFX0eI(oU@(2 z+&Czi4H02JAt50)yH%(hFsESnYC0zp7J3x|G}8S?mfRk^bpN)4S5$uCt1_n3jl(Jv zUlclE{>?G#@m*4-hC0R(*hkl$;enUMeeIsDl{dC#3QqVL(a=A|N)ZAzJpM z7QlN&EiIKFcDnkjr=Mkab!j&7%q95wJ-T1Qgfa^__mrsCwUgN<#z}>Sxo+#O7kcLA z02(|g0ls?5^750xXcPbtZr!4|_<@DH`lBy7v12av>%eWL5?P>7EqozMX@(w_Oy!@w z+WrFY&^EaBzv~#Hp@L*3At720z2z?clp~v4B-%ehd)DN z$6>QFND+@6hG&roL#CxsfkKD~V0K~!-*9nE?hVI5fHB+w^t0o!pMaR1#v}YBpZ+Gq z>~Aa;$Yl8S5WiB8lnFf zx~~X$EbtxNJ$wsDj2Qi}e}woXquGRixX09}e)Q$#MmG}e(b4@Wa^#@lk*#H1{syw| zZpM(P3&!?&XlS;S&-PW#)o}|fBddaeKH}p%dplNB?@cgNDN}IccobHv_Q)r%WJfl= z3^~7ILTkD;e{f#HF?h_^cb5}A{5LdstcHTqn}4M9uI4^(NVhVE9YI=H=$9?x)K>3e))lSemriXCBSB&`_l!k$5=#I%-SP zA#4LhM+XNHW@>0dKDmOpgFjm6JU&bwR_-6rC_90{c|W)N^#WZ(5d)ucy>%uWD87w% z@AC;k%!5CiFyY6?bG}2$ogE#8+OHNPJnKR|SC7ES+NngrVJmb!`X?eVcKHV?wXlX_ z|2p68nB$&YyPevr{zD7+r%(4Lu07kqZB4U*rB1d@4{JJG zrZVwJy{X2*Q4P*-7Cba~ShcovQtdtIP48=~c!v*m{WLkZ^PcI;kXC^ln?Nz!JlStJ z9KD&>7)jQi3R`)j)3GHaO>t>$7Rd~TcO!|w)rUp%A|mQZgqBI4ZxC`R%tV6us!@5+ zF3DG_D;o9Ua`EVaRc1_+!W%rZ%vUg!(q{clKwSdEv`keVHI>McM9@r+4l}zT_*8W$ z0=-vJ0d$?i&hdD}$Zcg~Zp@9hrdVIDC6z|%HxjD%EDdU=DW2dIOcbQaR9I}a zjlJXXU9S|a)ts?l``d!s>ay!?-Il~7wzYyC>bM{X+qS$I#}67&Pd>+nen=q<+sjMS z0_myzc&xY?KpY3n{N9K==cFM`>i4&|yK#5qHfmV#3MoCS=7~x@6v=csEDj z;!)n;-xI2`>dUK78Rty>i}b0$3zAo@#$z>vHru6vol7^1TPaCF_IlZACZ0^#<6qpV z^M~$RPAN-n)%xJoMOA1@cm{X~k`mflwGl;Q#f%IjdwnHAc`K8^pyX)yJEVI16;3Y+ zqV|U^FUNAZ`>}wd+s`0umLCnfH@_)VHe`KVh)!|xI9U<88og9Bex?L8YsqRH9_)rB z8xbkCwO&HADD!U~EbzTiRJL90y9j4isW{L`&XeR(aiiBTv{K19oZzR=sEN4t$nN933cy?-+ zNHq#0V$=D+!z4(~M5A-;aF|0-!8UHBquw&vg==7&JbfRt;voVx9*!4CcWfM=GT!H; zkU+B<*A9jb)wa~14vM;bsWWR{q=SNiadUP?$HeUXiHNhU{US69FSiI^9Yi@m91ySo z=R63mB6LoJiO?LqHWN;SC*Odc+W z=zlULOA$=0Mg3M?xScZIn*8_XmO)}Z=SON_N~4&1Re0hR0UV%T7IvQgCIF=o`C*in zlS~K!9nTzQi3yz*6WLYtyY zObta}l&&KZ0P#x;_Vn}2?=R=8P8pASBc&`sqqZMg&W@pEH!9dzmhy_OcwTNkE$r`R z)Z*)bGiwOS);54w)67u&=3pLbi^Oe}cm?>bC`b7UG1CL(Bcdv3E*HhA5@Aad1>wI6 zmbARqD+}5Bb0SUeEID1wn*(dlKTcHYtj!b?ptsx{v6OQ#e&^y8sHnZnPr1{eRwuP{ zI!%7$}ai46rP>7SUlIn{fi@+r}Z&rSKn-d9SxuKz`lv`-FBIz}EY=g}m}M zG8<0b{_zr^8U@NHDdl0+H~<+l((%;}%+LI6>$TtZd$klwIVvd2;b9B_rFPHqTgwG% zTCZ#dK(O0QZOP}s%lz+XZUY7O>TV-uXYy0o29$v_;10~jp}?zUw|U;vznLEvnp54| zlCY?W50tvvL>zx~rCn3dh7^OrP8OO>&xboA*wP`Wuzz5)ID_{@4{yP8 zk=-fk$6UEc z9n7~~>@k_qrStjU#R#)5`afNi?5Nmv2s+6Cwgbd2Nd=2An;bEo*T`tgRnGlkpVxM~AHd>f#>Qj*<5!V5V) ziP`HQA#!DaQI+XRJm}@VfAwBVYDleFcdfI=Z6~lKpz%mmQH-d6iPNiWFi>r-bJ>FZ z*I0l2eI@8Z5}n!Pneaw+0F_d5XiVJ;f6`7h+iC`lj39xW_lMIh{^}%I{h_FTMCpcS zvQoIjXx>ML%?Tdv?VT)plQ6<;O?hy#y&ejTo&UquTL9IuEp4E%@t_+B?iRt_Ex5b8 zLxAAH-5r9v1_=arcXxujySoJ57O+ z&eUwLn6-+Fff%6?CZ@yJnkp#^u-Aa>f{8d#~~<`4nI zs;Z*Tc&;~EWa1v8EifSl{ zfj+6o#f&;%U4%pJdE7jf;{&`MA(;n;5`B#rVl*Ddvi0}^99fGWh_i+^UgIkepNbwbVt{3UGYpiuF(@kmX<%B%fAZS7_XlO{b6n+ft(aZBIo5$^X|E&F$$RwYt;pw!wG6LUn(A&_i>)FF| zmA6c_x;5luU_&UABGT2ZV`*_vn`4nJ49+L@vS*W#Cqi{B*1(XwBrljaYJpi-EO*+JD2c5he3Fs$a>u)i zeqzLE#9z;VzRW97EZCV1aM$?0;{oh9`@71RnVA=$VAZj9*7S`uGLpf2v^`y+gIFZj z)haBNha@cK+6VXg!qA@lPsi2bVXd|sUERT`;g6b3p5)ALBR{46UG|@dL4c2Y77Yx; z?$|Ka3{d$UI@ScwU1vo@EI7;2vDeG!KhHiPDM8vG^#<`1|7a@7r^3o(qBhdD$8CsE zTuvbTU%4AB&&YZ*-dOzDi|bZHYNq~TF691GYfbwchlF>o;D}7qnap@}3?Y6yAzk;Y z<4l7Id;nMLaWeYN0_VWAjbVQXb=)B{d;>H9b(o?LrGU=0Sb2Z^6D&ys z@2-#n|EGpt##SyI0usC~8%5%CeOs5$^rx<)CIRjEK|~;JQ#P8cH$arG(cxzm$$r=M z4-(AEw~Z%c%u92QFUY6lQ*YJ)4UH1Da#7?OBj~2htAfDktA`Bgk%N%5L={FPlmm6F*TL7&h z34BBDx!N9D;Ww&r4m<<-L`mW~1tn$5ws0mvyRzwlNoqIsVNvA(Tdc z>t2}^uL5mZKU;^2-1&>3&fZG7d$3%|&k#35T?2_3`m&UV!1Cv+HW`W%z44Ep_S8 zpwUQbNt{}isk+WYo>oJc(`rj_-Fq%=+61!Ma71^r{J6rTK)GU8e(-w>T@ZoQK}QUF*K{OLh4;AwR=sJx;5rp_AeWh6atx$g7KM{x^c z&uj3to+`r13Gkk#7W6j+OI6^V)SD1lfn1P34D?|x65>EQ^=DWS_k*eLA=OwjsDxaY zC@sHlmx}sD+%Niqxye7%EGw@lnD@wQ+&CiPDyv0r`5nJ^LH9Y8zs0849XT;)!J|-U zwA}zLo=X~Ze)Nb56nZZpm&y_f1CI!2XmW(keA+^(o}U^18Su}LHyX+x7KLkG018gK zrc1~9AB8p^1-W(>asQNvXnfPVHmwWkNPj}Zlf?WX5^S&3e*KDPc6mTv|K!?KJ*x5~ zSNX~9OJ|hQh5zCa=6rHr0l2HwhbJw?5zX{&aBEs&S>&Fq zl7xz1?#$+PUkt9k6vQvTL4{b{XAkq$Oy8uX-zvnFW;g4S!7LgZG z9f7oVm9d zkydLAj&wdmbdSyC%BG@qmJ&8iG`$`gv7cHB3G&IqcN73O7}$*|vGa*HR~q%B@Thhg z;jrlyjsGb?yfgYULF1PS|I^6mD{^#e4==a6Y-ZRl%k!&mSm)|6z#t^T6!}e1?OYH@PwUTme){pluLOWSA3%Na+Ea&2yUnP3N(Zd=BG$ zzdAXFeuLX)03$x0DU%WhH19>O5$+rpdZU|8IeZp?&WFwiPq-+OS&Om?XV<|CRDVPE zE2H&3>}iNXlRpf|WBZD(!SU_x-MouDAHlD^#kZY^h={SB4?vBup$M%yVrTc0kPvB^ z9clumy}f<5dExi(q#AJBQr_O)l&!~gk-XA{`T5X`@1taoW`7EO`gEN5)?vi7r!>lB zzQTZJg%dQcR;K-77`M0{Ai5p=N-8F!uAW?!GFm{7m-IId^AO%jiiN&1xk=%3?%e(B zQw7z?Y}lxo=v{`xoQ&0ea`71{f%D(o~hdA zciTbS%l+GREG-qRPHZdd9jQ^gJr6zMdjRs>FGG z(cUN+k$m_fOqhJSiVo1y(%m{~aP!@2N+UCOGk5h>R#yAXvV)xGSfg3;tLvFNpQ9>R z3y!$$K0c2sf?;PpWUH0FO{1kL-(8`TNa*S2ux4xie3&@%dH$Ei*rDva!>`}i>H86# zm4ocPlyPNC8{Q+X?1u9To@qE)zn+gjjtp1c9xQ*PEnnVyJ=Lmr4MsIL)14!LcNqSK zp83OCf(bUW(d0>xX>k7De2J&n*-Kdi?+{;ATBm7!(3P5Beb*f+yM$%ga{F|)@He>o z^6ofTNoQ`QKs!-Jr|P!;%=p%7?dX)8x%tao-)cN4fjt3%hWqB?Q6@na)OyCt20Rrm z?3nSJaDi~Jy7L{JmY(G{TlVw<2A7w&b`h*_b4&2YcdlFYuUgEm+!NBYVy`+FBN&bj zEZI&oW^Mtk%tYxAEZ?17Zf#RX*}fME52V4bbZRGU5o7p@#<11kR5loOt}Z*GmAuOH z_F4qBs_35PE!L>tSud|*{R6QnGK=Jhf*VpghNotqRI3L&f$f!p(#e>5RqUV(;o{O-vN>Nq~H zmqYTeJ(BJm76bTSWh;k@SxYAO>S;kA1nY&fVc?BXKVL_`|6Hm&#YHrtnO$vH{0UUU zFUlhb#~(S-9-?kk%syK>^bSOZ1_uJPhq~LDVeAgqferJqRxU3Q#*&#{Icr-Z<_8cN z$)CdjK3+v7t@-}L?nsCH2g}1l@0auKIWzjMxW1P>SloUSDn^t*yMy!fv@EYSt6Fw< zSEo^!JO0C@az9K*sxwTH~2fxptKnixPID8b&a;qMDiNXH)FmG_0m#Z zO2{*sz3<3}*@b%{Ag0$aTwNEik!x1pK+#eXZoz9xM8(+0te#^{Qc#`Wc z*poD`UEfZxBzCfHyYZM1njekur- z0-w46JoO-7B~)}Ji}8R4)N7iwzBKmM;FIr%(>1|sc@bDU&=^Qa0Hf~F6&n%vPL2(M zuKoE^{+$4o-uR3m7|j=xiUgZLg6kfJQ=^p|+n_QnD=zSBi`$mzuO$-CPOxx0od}2e z@QC=+=U%Rw1CmBfJ{c>*WA&J&dIyCsUroP!oo$+`Qo(26vdG`TKPzQqr*?3BCA#P9 z*<#i$Oe3@94ws3o(6&wXE&EXN^0))zvNT^)L@_XdeN96Eus`O!iyS&y9QY}ANp~;k z_LIfhrz5Ccj^5KWvzq)Q8gKQc$}@uzn7$<#MN8@zCl+!npG8F%JCeqYm&z5kU+K2} zgr4GF(-6I0*~=I-rTr5hkJ;hFFnklK&f~J4p`pxpxRoyQ);y&V?-Qb6Ppn2O`-z^O z)?Qa}^D5v&eEu9Y6uwnIQbkJU`sK-2gCFQU`r35Dy58BYh$#2&&b?je8J_2AC@%f> znyT*P(Hwosvvs7(tzQuOKE8DZ!AiS_v!QL&bDCiq$WE^o@{pJrHTU`5xtM^NaNt4gF2iu6YS`?nx5#K77w# zPeEWn;iv_z8P?I^3uV{ViR%xDT-IDAs}?@;81{rn(YIcwJB$quOf>7$vNHS-gBAvO zK(k>G2w2<(yvumVf4qt9y8FGOmpAmSB2=m634xogc($S`waG*Yi~fGRrMB85{m{i? z8*}H>v1`DfFzR%IziEZsMj;IBJ4-g<6HOHz={*)w_H%}4h8lQ;Y*w|gFExB>^eZHg zT$qdq6FCFNA!7cgmF`({X;;#pp82+%+{6;zgaX6)(HGE%<$c(W17fGMU&Ts$<5}&1 z2G`=EX3sv~nr9FaZWZu})?CWZMMV|5f2RMa5Xqy`Q11974{fwm@uV}=BY~Yo(Ho02 z=(@7ymi1!SbVl{sNdqnHrgEMBTO6;&WI?gx_}Dz+`y9ptSthh1jk@BTs@a99n&;9| zFT%fU#t*Fnxkk%Jx2kf*7h$R?z%r;U3xtetc%E`a_XQEw^^2FP z^2~dWou}bNR^hUD%=8WuvE8B`-qL&EQ-5}HGu1a>adA*WCI-Aikdutm9Fg9qDAghM zAT_$4MhzBIrNa8EDJpJtA z>81WzUPkMFbTnnQNB{e)5*nt6KQ}VJ^>vJqm~s6$!Z%$DVG<2^Wmg#UlX8mT_3yge z)v#afotgk5pYV_^MNkcts1FGq%PZ>&rY0Xds6!R~&pP$*!+aR}P?DOx{ds3MsjYMk zb74tT)70(NA2yo9({Y^lvCicEq1GFWb8vR>a0h?jJ7Gg-LTrLE*x9lLO+AIU%%q*L zIZ9{>fqo|BQY4w(g*zEk^?-|NL0!&ecyZ~$Kc@QcBU=W&NLRP%q0v=qO?_Ej2fNb$ zf%i>N29w+TAordVZAh{@f-s2$LiX~Ei!Nv&7RK=#irE_${2b0|F$3!hRWrSdu2}A> zW@b?XAz(C*nIS)crLh0#blOXCkY?hehp5~ zki`kj+e7)yEh=3KO*X*>uk2a7Is;DOZ}!<|nuK2u%-h@&Z4RATOQg~y$H?bJ&&Dt& z`Gxd<-qxQt=gTIZ-B#*$MUBYT&d~nF)3xW+u4BE3xgV9!O!(=$cWCP{fte&r zo!^78Pyi@MhYH8H)JvocYo;^?;^b4+Z$&+e7i~=Hf9B)A%}|C^zS?wncdvc^a?vj+ zY%yeK`*g~3?aKLxxzbxxQ?sW>k_2QOEwJ-!s8(pdEj1@1oP;1s(wy}~nUK1ZhF%&O zIz@mm5z2)AIrtx+`?u%)^IKqvME+rCaddo){z<=hxbUak8Pn7oRGj6F?MY6drt1@0 z=X$;X%!D`4pH;2P)|3~D3UMtsyPMg>`5sr{dR8gVD!*qBLvZcC zp6V)T??V5F3&8Pm|Jf5Z|NHQygRrJ#%qQrNy!6Q1QHPnIeygd)B?_pvM8m4%zYMathkYtb|CM{dQCj%>S%N_9`jDQ2v};wqp7y)p-0$&?jDre>`CkEl1?Dex{Z`>8hU zluB@#KYpTTYlYPug8#1%173l+JxC>7ij9}8`MKK!{1iJ$nFR&AM9j*Q$MDY3kP^*T znQGk$BBQ#RK%nq4LcE}D%ddN8IrVLo&sWlguOA>6;lgtNkE8l~KsqF{KX*1oMvs== zyEHOSv8VIqJ4{OCA)?@lQ`UA!T@R7LEQvMoMZQT^8f0N%q2U?+qkVPVO7}0@ktGSB6aXBF;{SEGe?3JV zxG1?A@1W8C_VAozs*33iD(=)q{^Y{%l{3TO@uFtn8C;b64Sx+njvp-eb8#ABV)+VF z`QV$^L;OA|Xt`*`XdIMDLGVm~pF^p3Ty1~VlDy5&oDNzyQKje9 zOK9I!_)7=yuOYw-Xg}}Q3fg;@h{pz0r**R@F z&;H*zmWwp17(H$dPO7=n8GdwMaGPODx}ii%I*X8?`KBg(cfzN}qm+^Bh7rrd(FqYS z#8^lBqy}{~n>45PD}T?VaZ~9*5#;zWy6y2l@zVc$wPLA1ws71^Nx+PA;dF4FyPS(5 z=EU)3@7e?5O)ZjIvI=~ zh!P<(HZcTNu>Z>(edEb}u3K(K%h`Du3%}0no@b2j$E!IGnakqEzsDkqKMfN=0tROY z(h+Gso)RDo5A3EDpihEWF;AutVDHL7{2$ll%O;(jQ|C1tFY^60MX9+Uwl=kX7+2>q zT$XV9rD)?|;c?@*HxCCK0tHEoXwK;q1*P_OatgZY(Wx}Ka!SLp2ir0|REf0oY*HD= zm69iXx^D1^ zo@@S0$OPk?6Zz}kc7brn62mdq1VjnIAbb4rdCQZ$TS_&OVBbW_n3+QVlCD&7IHZQD z`Uk+ct-V5K1poWC#YI4@)KctxJk?f*-+)(#H&MBT+l+b4|DKkY)AvXC}Fi+#HKhM4RzJ9&>gXk5DSG&&}W1>F5H zz_3T(kJznDeFs9RVPKQ2sM2ceU$Uy5A+S%DJDg7zv#>-fFjuztO_|qxwXeT+|tj9ET-B3jJGF4R~k0hq)sT@k6T za4*zAX0*}}=K1O7Xzr(0eS>r1!<$l|QMR;nWN2t;bTm>O@q@$~L0o=s->|Z<*@1n} zODc51oU5yAN{Y2BE`oU8C|lZiq9ipPrWsjz`TPGpTQP^7M^ zvYu5JBw}o~uQEj;P4*xhlhtl!^1+zS?sNU zYzH{dg9Ub4HvdfQR6T++i31ClrH;KIkKv%ae0Q>mDrgs%C00IS7GSfXikjsuRd3a- zoCe<`OH$(Ou4alt>e!oq`F)(elFfgMz5PK3sNmgmey%Y!Yv+4D7y5F+3H0$~Tu^yT z%dp#p>+NdGW^g6g&Xwu34yMxY#t5MtEH_>O-7ny~kD3MCf5dw?P`%;nJN@B+>W>8= zpt{oROw3|FaprZ$eWu>i8g2LCd^gRe;P<;s7sHsTuL~yF=+y=lKz)(qz`xMK_aZk8 zDEAWT1kp_#ty@2>-nEG(0$Cwy7p(8n9w5lzo1gWopNLM@+WB+MHl2Tbpk1yo5PG^j zNjYpjsl#`VYZD>WyF`l(iZ3c!WdWL*Fr6Q?on};4o7qf(UI+e{i)aZ`)iIzkNpU^X z{q$jkd3>H_45AqZ=ynl7pnJif{7k`Fyvg8pbq(8AI3w* z3Z4LIkZpH|4j;&Cu*71@D#|8M`^vardp@onSESybm#m3}o_BG1*hvE9la~EaxI(;X zpD&Zz|H!3hAZQy*>A4+zFU)j1)O&qYo1@kFJ7np}5V)C&?44_`d<;|TDj9!xLfOB% z!)VfBR5)~44iZ3EqPM|fLmdY&^qwunY%b1UqtF8(+GD&W$6>cxpN{Nx+npZfrsC<6yyda?E7 z&j9piSAM9=aD8rrbN^BV9I=Nj&`{}iT-ndSFLof{NyO*DVY+Kh(0<=bf4kzWM|0EC zh)zqzQ54Pp;?n5{Q$uWb2$cGxZN&W8$?M#}6%#*9N0K|0e0+MTd~G;?vL<=p$2rEf zU8C1wLl!Or9qOaooiSg5d@RCJQUl8fM9zDxZT{Z}a&0ELY+gWPVOzcQHZbOL82X{M z66tK%789wjzt6nW5*+4qoKFA+VANee)<}+XCqC7;&*_~jffEg9lKVUXB$8~jVX)JLISBeC9U;d0TkyfW|>Xkwg8 z;c(#)pOdx#D{1~po=JiwGs1}E@&*R)WsCULWiP{7*W;oW=;1>i`;$GRZf

zAT5(U5)9UhEcnHLN382$1^dfdD1dCQic+9j!dj#uoiVPpOH<-)t1O_t0+sy?DZ8^PbN zW&yOtpSC{3D6YfzW*#kFz#XmH^%M5fA2Prg>I}%4CwZVzwVwSXdHY~$CAkgA23$^O zy#+$ z9NRk?5XZCQoO=Xo_L?Si4|No{BRVA(WF|PaJWrFONrNS)OcEt)=Pe2j77C#nhrjZ@)qA;2Qpgik7+8C`Wv`wQOJ2>e?LsKk z3;-7_{4ze?9ZB&Iy#s8Exb3d^G=x0LeDf4uj&AGI+oIP$GaVREPSX*bK6vUIo3@7_ zmpL;4P}cr9Q?4ER&&Dc*9x}Zzahc!qVPV`VqiX)HXg zUJ`-N{cyAvQqTRvXU1Avh$R-UO+&urt{b*Wu3yiHbPYbAY!kyc0w=5xg~1(PBd}9K zJ7Z$>E^k#8;r1^9_b7oqPutZSNxm%4Ze&A`fgkROM_ zvF@X4BQcHdb93~tmle(YCV%|=y8$2?nV{A*wVvo}Ev1%!g`Q{Hrc^O5Vn~%aDzc~3 zmCQ2@0aCv-M6Ve+P%l;Ae}$JY0Pf-?mhw+CyhY)BgATWZ?*XluEC;Vt1Eb4 zHB48{rx=kKCPDus?U>lypk|sNI!`(BqJ(r-AbgBRnI?B0|2kZG^4jpG@w^N1=SJfJ z=)(K;X)W?Gg3Ei&^X_JUvU__|>a}KC)*p$ByR_(6PycyR?{drJ6JgA`EW8G< z!suWP>&Bl$MC=4CJ5-azlOT9ahA_$Q=8aIx*UUTwb-f;TT6!ah5xnLdWV30fq3?CV z(u_Rt^eb6`F8BZlFHWuU{&`V@YE#Xw@TP!=`p%>t_`^O8&JbtX_8b4P>r-Gc+B318)1h-^Uzo2l@Y`#_ zZ?R;)&b4mbxy#ut794>4J0$!Mr7Ax!IP_r>^`n0P}|g5w1u*YSAWSjtn#VRKX- zW^wFVv>V?CJNJDc;A@Z&+4#g#X>(DH43PyiJ|$>}Pz5}!bM&f+$29g3m}aiir_p7@ zDHNBW(dA`G8Hd8}0sbv-RJ74yHbhgHCptNj1r^g>$_n*-eLbTC$*$<01Q~^?({F+~ zvgUh=t{&iarA4sNG>2>=ZaL=YO)0ySgPS-X7Z|x^0^h9UH_j0u*vle%w2FWCApn`>r6T$P3_r-Oummv-Vkya_=|-{|!+n2F*F%Z+mzr9szpTCf)+=fewG++Q7Q*w< zcRQ9I!8)ii84fYn*?#JE9S(SCBJJ=SC(}0^K@V$WStV^bsPqv{q$E1BLQ8=bZDDhl z9i!QG4-=cm#bqFypZrakPT;z)2p>FY3 zAOffz9kysff~>6$nit1tIBhy|X%B7;XskI(r2BjOmnxfW?{)DbT<>G!Ufv@uY5n6= zxIOo))p*-0NAY<~#uQ%jx|JK0vL6uFdms!zI(oSNsOcdkLEL9BipAa4#cv3F%RB`k zNzi^Cd4rq5G)Bh=&D^eFX9`5O`@IG2ecFo_{-Qj1XyxhLwIWe2U6HW-9F;XpxRbiY zWAH*aRToPMNq%;(VMM{(ktSG$t)Azda8!(sNwFOqA7a;PsHR^2FcpC3(m%s@1-#|3 zcW_XM74MdFQ&uZHN&7%*C?eR@jkx~Y$A(hHSg;joG@vgZ)X`&OwWMs;@tzO| zM?+7KDsm63^nsiptRL?$6r4um9e{7$dYp!L7!WmQS1;jx+|R3t-1;GnHwKl@J8v;X zG}nc^{#bmYQ9Xhdj(9`InP{5C4RYagFCTu`w4yVzINn7Nt&j3tIF zmffkoR*w3Z*YqaTxL~#26o%&=aUm_6n2V}VYX}3Bgi+mG{oJY?PNr82TCRANf`}L~ zNoF!OMBfkx1a9Fm(i(SC$IhBR3YqmgJq$?$_+XSRS!}c%D-o)Wb@XxL>Wf|9%>+=C zATxT)0@j{i~ za1jYnS)Ed(h=ej>ez7=m)s0H$Kj7P`%lK=|TG2tpr2twJ#2u$J{P4P3R>=_I2$XR? z{pm&!on2UnnzV1+leMirRY>9xCeA>0Q89*pHpp4hNvbBWXKbyMH>L5h!E&v8qkg!c z`=-`VKQg>${B!p$`fZCk%a$tWZ5l1LR>MLyLbZKWFf_}fc~qasrrEbRLQB29PX>q- z9irGO3`?$95$B`T(YKL?vQjQ^fr-i29y!|fgOp<}klny)9rh-3s{V5wQe-4&GZlq? zosd7o3cGGyOXGZ?VVZB?m^-z8#DXbi%Bi^dd@cad~lCem(Rs>#Mcl7K9R1NtMM-qvU7%x9a1kbNdj1Yx8LMaae|p zgaiT?6~8k$5WGIY)#^&Fido5B#GG7}%SV1O0sh4$Jx(%6?>#3WKejko-5^XRIBVC( z-Q5RD#fjrsEQ9=*Wb0eGLdaUobYJz`tQ=1c?&|MiA)I(*}`b+ag=_U z#edMffTj8P7Lu-V(-HSngn-^mgesyV;Bn;o35d+2tNIM=%y(Lxqu*9o(DtoM^FQat zWWIQ@ze8$Do4Ms+ggc$q2xs@yQAK=jvrWcz9m-i z@0P0wxz@HWV5vG!p8jN-2fjeavoV|wD}=!!?gJmhZB3>(BZ9GsKN_M`T>09Lz@k5y zy?5jI+@ZiHhsG_+!#CC^OrUCJXqL>BapgPXvtU_}B7yZ**KDxtoVI@1?{VbK_!S5_ zUNs$0!#YPk^K^x)G}#P#bOpBP3>hPL zgw=uNq%Efvk`;qL=kcpQ6taB#o&olpR*hyqN8&<)^)8lG6%sj&a!ObJ zTl~%fv39BmM%JTuv%gz5IuY4D{22_a@G!CikL9YJdghwyMb!-d**-$Qn~>LPKR9Tl z9&@Eie@u^^eVLE_O~mGgGja$kiMEzrl+&3B~^Qe*7Ubwy8?y{S3@|+ zMkg>WM^0(1a@(ejb?vR(k^KJd)MfthTOhS1TryU44Yp$n=5MbY{9phlZ(*MrG|d6 zJtj3e9^wqJddIWUB=Os(gcxfyFU9bU@)N!mws>U(rc$6W)yVg`6X~8t zVY}%4#0}BI;1(bkc7p*6Uk-eCpOf#fwLM#+tH*V%xS6G^-W6+TC z+N9xhn%uFx`Sl|aKa z-eG}BZKvWjFz4RVF{qwTO-R(D`C`RW(RR^tWj$atEc;O@p8i83liF%X5@fR|XQxuC z&;){+(xYM|WUk%iY!u)~Jvmg1Tbf7IV*W>G>xprK4n{ zs12=E4URap+Ef|&>du3f?|(yJ1V*5T%u3Z=R~_()?`v{$*_26P;E?(@MCZcq#`fc} zKSpi>F$;POgsjstN;dbN$<0BGkBmy3Fo`B8g-C7JiE`&=hO~V+mzKYHx-bkP@^`U< zZ{+OA@UPt+J92@oGY~!(>=gXO^R>vVV-$5L_>DD^Go$$S)C)S*NVH;$D4x!IzA#d6 zUA(PQ>BzuX`4@5)eWUQ-RD~j>#I}cowMOG6hhc{{J*WEQ(!S~^22>JTqj0T#17CB} z`|!*~_fcnvfGDvkDE-YIKs`4WkzG6hkAcIaRomOs>=q_(QVKfhNXZ1vK2ULIB9C#O zwaDvKT=bPj>p*gA!8;@gR>FBN^pqv)hlJq`=p>17c8BHEOdq|s(027K%=#Gu(b|oc z1`#EhejzQJ7jK|*6k#KoJolh5ZjE4?yJWsT*i;Pj6jocv#@xZ7s8#pLg8fg`uIkbjR;&7xgYjFHRXZ3V z9HnDDV-?hSlLD@KIUlY%HQErW{kz)023Ae4^?cS({A47tIau$%;8v?TnpMl`OB$U8 z`?wOxNGG?u#F<_6ucwYew5dYi3~iwWR$x}Fh3=z%Rie^LGriXqomh7I8ELSnkDY$5 z(c(PXMi@?EiH(xCE`ZneqK>;C=p=+$@Y$W(WzMgVC9oT-cfn)cfHl+XPnKZIc#X}+ zr`~_8xy|5q5C`$B-^m=3GObm5)xnVYn~spK%sMeD&X^KS8ZrDrfyc;s?3pVMt~` zVVe|#UWD+yJ|2lE`;r84*<~QgR*j5gdrx=nzt*tQ!wA}Q!-d2PUD)1aHI5f!0cq3e zOPCSRH$2?9X=Dm%qNMmf^wTRrZR3S}okIc-m^9@<#5d-7?$M7 zvrf6HwW2ium1W{7nHS=jT#~^AeF)I%EBOG))1(=V(PzTutw7mDEMg)(2lj~=f1`!X zl`ZwAram1~jXu2|o*C*PoL$#OAz4-ki54B9FM*maslWi!gg6psR}o`_rIMVHWnRPR zKF6*A3H_FK6d%|4f>HTrwY!%4`A!tgS9R;#bKeFaf_ZBi5yDP2UItw>QZucF+(Qc` zx?>*BlQR#B0~g1tX~CcCtbgpk`(}nk?Q~?BSuwrQOdYg)xsU z(pVFjNiXts+H8U(R{Y#g_6cfR&_+@&d|3N8Cpp9K1Bv4 zPcY5pCAK4p-jdIKrfABRnLES^?24_W_Vz!y8URR8Rd+o&E|rzKB(H@1(ax=Zd2H`k z)#YBknGpZu_rLs5qQLilNXOHLlTCrHIt^qD-*xDDf}dLLqg^vz^ID@s^MkqtRwRBy zv#<^4Eo5n?HB)t>%R z(-MPgv+y8~{Lw{g`DRZ#h*jGK67L}RT3l`PqTDPmEj#|gt}d*i(ty3T`3vi`36evx z#)j~*DH3v&x~aoE_^NxHA7E$I)aGKlPRlnN3m0#tL+@0w4)8YV>DjaKuIwR#DRZ52 zJ2vC}Yw?y&d_4CM{eJUnFP!)JS2o^`hDcj1cVaM%aitG3G?-Gdzgw)tsmjCh+UdE( zo7R8kUuWnc;^0UMUOyV_%9$IOhz})XU;6-Yv2#Gn^T%7% z)UFT1^RL`~3yklEeTeFNKo~WWsa~mHqhhN>K9>o&!oX7JDO`G4Y!(FFXBv{WZbfmY zpC%`3)*#z#^_h%v?xlC%zH26V4)1D<)qgf&RPSL}yLT3eIgA(mtG=5JlrO(M70&&n zMhqq6{n>5D?fiIgf9*Fvo{X%~@Z}GR6VvxGEcJ)TkxuO(WDQ~nU0kXF)r;}&mn%6- z{#t6GwrQj3{7=~@h!YXH;B33xM<7Re&P~8=ZuzNKC*II&*$~${osj&!dP(a#Gen%( zSWd2Ol${V#RTpt4+9sL6G`bh;)m0kmCZcQ@kfPUwMs$qaMa!Nf|3k}XBfn+NN&=_p z$H|O#KYI37`+Yznej^sM^j3FIJb}vGKF8se4gvd^F3X>U=@5;STSW}5Q`+lJ> zyCKa#@|s~00j2$n$W5NcO3Ag7{iGHf#G{3YIo%6?M`PdY(lh zQ~HPI&5WczF&-_xkd`r*u48B5FUB?_AtIT-AjN2KTHu`i(g|%e?ltOwn$;X~n!Ed! zweY-OTksX0PCa1b$iK&hyH}>#rVQs})ea6!oZgtMQ*_ocd_QJ*o0Sq5R7>I)0!jTJ zyIj*F6wT{?h%p`TTByT}j>wdO=nUc2hs;R@>Pk||-jUIoLE|amnL%9UfZ;HQc1BqR zu%=)6uN%_rwiIe|miXj@nIe|#+`}LI1%f=kM~0I6$Z6#bZ7~}Eo zzi;NOeMj-&qu3)d_?QWn6fw276bISnL%L*H(ZI7DU^a{MG2daEI**tYR{~q_h&Z^e zvEH6UEGi!h+97+KJ^XD}dWq~;t~of2T^pt5+91v(ZZJzje#RKQ`5VUMm(lZ{>*-Ig1c?na#ze!a{WFpspFN!;FItoA^F zvqm%p4N2Pe2vio!z35j!E}t3KXdka`e7iSuCB8!sX-S98^H#OThjac-wS2r@Trx(} zgkx9QPh6Ei3x6pSwYLHcXVLDcxDExz<52CbJ?Eyac4JaFq$3a!*653ujE`Hqo^<6+ zhaW9x#M{qtIzlE)$(xt1!BDh3NuVyqRKlycI8HEbN(#VVVS?Sm$xillG>xQg@Qk*< zk0mgZmO`3jeX~0y7rwwMbVD2)2+0+CzO>$`zAzb-s^v1g?cGsDYY`7Combz*%bC@p zCuFSaa9OWS^JwAqNnx1o;0h8A+@6N7GyVp^x?+*e3)>qlN+2;p8bK+~1$L1S9e;61_V>T3&Q8 zzCwjAr~9CfKNdna4vgaZtQ4S+Q`vEQ``8{@MN*OrCJqC-&v;uQTy>96FUqrZe`4@1f-?RlYZU2vc|FZr7sOljH${^$?G4BJW(t1S-25?Z}v-E=x*|KR3YZv7roTw zHONzmX8GY3vbUeudpTYMSz;FlKa4}lz{GUm9!uz`@GFId1A$@DtlL(r(qx+GUo8kR zT+koewVMyWCC$BVbU#j6b8og~J$pXhxt{mPnw_R*#-S6Ddy>9agkB`_ef+Wb1LjEQ z_YmRIGyt>&i+={8XA2?g{eYiPHQaqy!b(;xf2@OFQ6B*y>WL-Pc-n6j@D+k%LtTI3 zcXP#~fJE~gP4}>A+;9(}_;V_kmE?$ z6J7Fsd6p4+luYg@j?kP-Z94W8SiXX<`vJm`-K(AvmEA=1*D4Vw#=NmG+5f}VHvreU zwQVu=2L;4a&?&6Qp4VeSsf1xY|LmYHfenl&%pw@h;>lH<|Ash7PvJL8B2Um{?rjZY zM*)Q+zLQ2TWQ0eOL7c(Ar#pP$u_xfbsNfz25jb!dew%O9xzMqqv6EocO384y;a5&h zqZf8g8VNI&bbJIuzy7PCdrAyTxl?OFeFOu09|j>JDDjIK))&1~Td7a@c_K48p|tH7 ztHWFj&YL78oL&H(J$g7aCNwOF$;3g0Dr@*dz>lE2h{(s%%66=t1PXt^3IQzn^N{u; zF}C$eovvM??cI;1Y*ITQ?N~U{^@;#L653#1LGhJhefciSGB366=6?-a*=H_FsGG~2 zi`63gBeWCrrxNl5XMB!EE@w@4Pt9n_PbdFFoGC!=qWWoL+mHL5+V_}2Ev!|FZ=!g@ zhk?-4(D1w^6~Z68=&rWSwOgu2(w(mZ1Jey_a3yYazspJL0IcjXx4G6u#W?AC28&L* z1}`bD`TIFB7S3elA)+*sGgv5^H4R{rYhK;l`_qt6C&X59D?Ma{>H{z>4&pmN0O(^? zCnLAY+AK}3+3G&k2-Od$*NxX_c&vCE*V!hM*mt~s^tr#DJ}CBM;wRFn(dp3`mW#nZ zeS*8hW}}%-7C=ys7NsZ2oiGmFR&+A<20aGrBA2`|ZVAA}H~q-Kg!2;xdz!k|cI$KD z>_|~HD+&DsL=3X0TKa{k{0I9T;dMQPO{f7?XNC2-9XTPkR?A2-5EikG7oqN%wW6eM zdYiKz$Qr#V4j3I5-;FtM!aFanYlO$w~OLHUPwa z4}BJEHwZv0o$nYu{R0m?)wB!?@xxE8pNeXGI~E1=txC^hU3XcXW^312S#{&_Lppm! z4J}>G>n|-|x?T-&cAmMNB7taGFj}{XiFa)))q~&48ej4!S zhw~S~D(7tC8JZQDM+7B65y`FL61huhK@+<_6rDVrMC)kxn$3QVN2aIW5bkFBWIQth zVdBjiPD_+p28it}3Tz-jF(kI4uB&%q?}v45F|N(A+r5YGn^^;ld__~%Lg9VQ&D#Su z7LR0|&vP$;iA$yt&glxjsgT3=X6l6a=uQQD`4rCcuA~**JE(1$)#Pe}pXPqTb;tn+ z0~JPR^;HxYrq5w$o@e5zv?R-s^B?6qm4v^~Hb~AYTuJ4My&-A=?q5k_VnxTJU&(!s zE{BS9zjV51wYuT1;jGrLT7Yf~a8^?PU|bcq4!{Kf@=iT8sPnot^q4K!aHqJpC31~= z`k(Z*Uf^9HO6#tV)BDXW)`;Z|dmeX^^?F}!>@*%?4Ly!$06NG6DD9h5Ve($vl+j>@ zn)2NJ78A5U`-A#6Ch`erewZlSwS2fe3P@>|6*hoBp4iT5vvayxm4J(vI0sCqu`vFpemte1oV*J%OJU|0Mg2yyl(W z>o5w~H8?Cg%wl>$v7oP5z4a9nC%?I|=7SDH^5)Z#niyS+IL5%GrBH)HOJtea{C;Rz zseEx2EJ7=A>fg7&@xNKc&PZtg_1>$fyBL`k9jBOarg&y@pvg>0`(E3qa&pn=)@uh6 z`YxcVCK@1(!ho~9xXl!JjoKOlG=ZygR=l;aFI_*VvgEDDrVZX!UQ7e@PGNl#=lEAS zWFegG9Dxzt1~Uey@l(QDw&&B``5l-^1XgUt(2ifGJ^7T*ANaFR612{4psuCUoOuImx50S z0L~Zt0II^*vOw_%kZ8^beg<-UAR$%tXQE^#_x~Y#5Qu|bqcUUTrBrR_(+X}&3=Vhi ziUe*tCX9y52BFY`TExG@TQ6-_IXuv;z~O5N+N&-{=s)_pb`Szb2p&Y0rCB48_;0qs zzu$aCAkVDI*^0!Usi6KCPv$hcqUqIcr8IhzjYO^mq_D8aMQV-hZ;Z??fRTAb=!*O^ zSZKXokf6qlpHrIEx-q+CRY6r*F*Q1N0?S<7sr`7!@>=MhSbnuMzU7?~*juma>+qgz zQ)$}%6ZaRq<46p&&pvOxzy&TJac#&k%zcaY%>x}%z*u0Qe=kj2S?=WMWd>+A1H{MP zJT(9Je5&%x0Vu>?=2@@h-Bjy`? z70H2(SwL0>ZS--39y2Hfn2o4aACUh+lmL$LBDg7QT;h|9+I`?4aD}(&TLKdlnj|K2 z1<*IpQXUit4xjP}t)l~rlcbDt7>#fiHE?jW_AcDo9i|iNr@Am6h(7LNWKo3vlO~r( z?n7NkyJY=(^-w;Y{h<98A!z3qa|NY~!2j$DT+nF=7T|_rdrVD;jb1=x^?#`@qt zydAHL%6yt3KE>jzas z8w)q`ulNgB{og;akd2G1?hejJjaC@T>vQVQ({Yu5$>1}thqTpP)Hn%Id;(&{1$c;2 zg(LkQeRcz-NFvc#FBHnv$=U%TPnITqF+j-Tm=@7^1{e!(k?!9wA9AQTn&rE72dnbb zHd2KQI55r=yGwp<$M_REYZW&n6?`?}M9Lri2lotN?C%nB!h~rZ< z*{;Q2RlVt*&1SI2T5(ui#alA?)*uTFoXbD|N8`s^j9X3Pb;e6znf!&p7g&7Ce2<2n z%GCPKQ?Ki;?T+9 zEd@pekEF7BZ`ZIkb@Of35UiOYVb0;vGMe z)*=1+bjrBEe22Wp(!Sfyim$;`6#Ht?^H*#O;u}EjKh;`8%bGQp+I9-~29ka;>i_Pq zt@odwolfBORJ7@?$3U@!{&>;f|2xULhlh9sBXvNF%HuasT>SMsY2X(vEz5j~mDgUy z{mG@Ufh2ql>s^Yo|L1AReXK}n@9tPnXX2*s4ELB?2lF`LPTBHmPBq`6ZXOnhGz!(r zi3b0q4UJUR?uiFfQU|x=sXk~igy=J>kNYUQf8&~%0Toh~yvxwC6J*wZ?jc_w2uqX3C)E0AG^An+My*sa=gn4uae_er&0p3tD5@MGchwa6U+MG_r| zhION>GTMg9d*$kSR|=5k@`$pBe?|R&Z;fc^vPbvfDYF7|&8m4;6U*IJ4=eV(Q%^AW z)6c+a5I8_(QFM6TT+&}T-8lI&dwtCz5$t;>s~Qu{=Lz5Nj{4)?HyqJA)qloOp{y_9 zfUe384;`3dQTE7dXV=Q(O{Vi8p^N5aszNve5S%`-gX9^NWu%J?S2+Yti!j)m@5NE> zL!mf(@SzVv+E2jdVp07c4$T-is6lB%>#LU)%Bae=x`?aNga6z7Qq*R~A!%r2g zDlU#C$JeCOSm#`Xlvi6q0Ll#@szU#`6x83BBmm&cp*eEsh$udd; z8f&A=KIv-jHXyP9M5JeUydyW|H+E>T;5*GZwgKZ4nn7GqJ7lH%axsDqbx(sY#0}V} zhXWtooQ!)&>-44pVk=^M$zQ42e+9e*g0Zo&vmW9aqZb=B4~sS{5ANGN#`Ai?kFF>W zD~iCO2Fe{{`s;auc!+ckdCFO3x46Z&^ikrL8ZD+DSELx zT(&!33#s4Vz{dX^%B*7q72XEti(;7oKs)A^lH+2PES%lRcWSquaqA!$iphu1?$HBo zn(09J5zayRoG2;`+#P%mrQRFhB8J(i{GFBl*Q57?qjj8Zm-2enx6Zw$uM+l!v+c}J zHb?9uHWB0leIg!+r3VboAik!YPN@%kCi8u z?#m;pdJPF*U$0ctf1dddqezH=A6iHM`UJJIBE4y$!DG4iHtnkA*9SMJv$j$oQftgl#T-Cms7wxXqYF;|4aK;N_ zLeSp=1Q56AY!R8(+dRb5__5J7f~p5xt(2O04m)?#nPo|ilbk{0UlF4a?G+m1*t(#% z97pWxe%J~&QIa~)T#rUfVVYel{O`wRg(It69idmQU(EwTQbVI0XBotO+SQ3uyDU7= zQ{0F_8GN-nqbAAwu_s(O+4IFboTbNgMyrCao@vV7b_M6K4Kox$?crbZpqRe%S&~)0 zMX>?|MXi4Z1q2@@67R{~{f3SXKpd*Qe2?zOCchU)iLo`=-(kT3ls<{~)OH*X41V#q zfI4p_M(l1mC5sczg25g%G2>-*<8-@K;1?$xmTfZHg>N8W7vQ)EaWN!pK501`^`=;+ zhZdY>l%~LI2uzPy{?m_5;b4?~Ydibco~k=eqx%AD8mZ2^5mqm^qZQGLt5mS|fqxJH zi&V64Mz$*}QtNurg#i(X6Q@Vr`S0`XPJe+Qz9ROYsdF521Wy^tAS0S^$3^BA+>^vecTL^vsTfhhVc% ztlOI9dytrf1VjD5^s2~wjGwK-c#M<}T{cU}c$`W`Q9^OAt`=8TUn__uQT-w?I8N~y z)2At@-l7;SQ-#%Thy}n*#sj4S;YcuvEWk-sC#osCL?=;Wu&3IK|A*d2C%+Dm%JAMF zyIn`Hx*rdh`IZGY;4c985sS#5^uij^dSR%^@_X|UV^v4fwCpO~ZP#e)?{<&FR9gJh zUliY$)b7_AtbEVtnSx)hkX)R_n^RH1FPgV3%$LRnVoa zyNt(TvNa|Dndc#-@!?8mTBSFi?ccYna=<){>|YYFd))NARpdU$;MU|=sG+`E$DCKE z#?@sh^{uUq(QY8fqX`%yV_#7Z#U+6%pe1RK0TX)5d4#ZRK_NK|*TglIgb&gHgLZ#j zHIqIlfuc4x_~$>uEh2PWC8gW#ZsmsiFIIyNFvw%4$86R2whu?4qHlLY74lxagiNZ- z{$Z#&TRR9!lFd2w*Zg2UGlWja+ETSYiUHJDBdgGlXbMLyO`CyB<%}5N7<=Wewyr0xd_}zRmgl+o zbfINaIz1G^p`@}{ozo50Y-(XtDZYH(Q5hdm%m9=f*G_Xe@!c_K&LA%MS(C10ypvE5 zr++hb<=A;Z$;JN!!7NxLm9r@>E~`6E51OIgv!+!LzXhF!X%b*{y9uJ?YXxNoPqnP) z1p96mYAS0?(namDZ5}XYif${@tFNwmM%01&y#&#khqmAp$i^(-z>lpy7L68A*!CgX zi^cu#qsqm+lg?zfvL3I|zPo8Rwk`yFwf{EG_ph%L#0zv>jc*rad(M}1#Wo1G1#~}o z|8dzy1xQy|W6_%}-#3NTEAkI0U?Cd2fNFi*8<4yAw!F6yyTekK^kDgv$4~YYCJXj9 zn)&xD%K=KkvdsA~=l3Bm?M-?6YnLC{ifd3B&*M)ZkOlGKK!4k697QTEEz!JK$cec> zq&ucMn)KZJlDlww%oo0oxsPncZGYL2pN&?*Rxd6b%%_KBZ8?{OHUP>&FIvK^-V>m1 z=eBa@7>V^3Y+kb3zM&BRPo6;`p)+_f!8+n)GT4yM13s}3-r+n-zk5ttILc#<0%Vp5 zR-nuV(<4OaTk*0WiYExCd!YLT2 ziFrc~2Rgm!sZvI0V!8h?;eFVUl9~rz$!pk@vfp$u^hjmvte;a33#P0tTufNo2wE0j zk2_2vJx?nuf|}e7-tshDQ2mxI`=Q^~H|SuEMNgV+bvwzolBtiKMk5nYvk9}3E%(ct z+FZokX6nM+*lt0NBybM<%!7*xinlIb6pOAx(0#f;$!;dsjF6GjFD^-zi(3`g#j@EL=Dx zJ}3@pU5LF&!m)BDa)y|ubhwfaW3E~tS9=G1e_M#c@fs* z=Pvj>Y4bb-EzW;$1>g;k>C9a`$jP!H-Mmq*gCnBv^YJ7=Gv!X-!;6zcz;1icM3;BiY>Wa#$>e}+V zVPB$uEV{Ud*mJtG>RUgjDJF5RMG>}<-O%oRO`4==(DS(OeSgSGrPARzb1*Ey^1X88 zmWIfAG*ITOE&oq<@xSsX78#w%%^KDhy82z)wDda`_9UzX#O4oKYv4n8zLsNTABo#MZ|TG#Hkf#`!DFJE02 znClGzj?zG}-1;2_71h9y?_86-D^poiTV2IlHLc-wNbR&{J*3D{R(@ErzxILZsNul$hSS+T*ur4&`h_6EQ zl9ar#kW}Gzdp^tcm+C7pej56WXlPNTqwidu!jLuauSQuH^px^+McY2L_BA^-WiEh& z_~HQvCl3f_gA*Zjo=~ezHss5rrRr7rt?U-~wc7SIW*$c;w=8E_YzMB2nESE%G<+GX z?+;rT{6hZ)*fMmB(*p-__F&W?&Erf#Gfz#wvLXUsj+2gFrAXZgJv?6v@wHxOt`=9d z@4Fb(?N^^6Bc8_D+%UPumNK#q4+S~CZp;9Vu>~@jo&b~f1Yj5fL{&#k&9wBXH%Z?) zZ9#p&RTkiZ79fXOB*C(sioh&tuprO_tMG%m!Do%SR@I!qdBsr5WKkb%SWQz7-4b!0 zPtJ)<{1_6BEBoIcm??9Ps%z8hVd$X_haXo);^=F`{a zz=p$^+y2Q7TA;vyDCQ2@xMs~q@Y zS=Aoi?ruNQN$j}rIzl|OoF0MCetQa-&5y@qWKB*^E;d+Msr4@&qN1YK*NKe+cp2WB zni@d(-4lEMsuRFFKW&84%E2i{V$kR8zpuB326+8b)dq|8m_OE5fQ3_UbX0uP=?vkk zuB6U>$Ok%~Zy}3CCd=?TVMDu3t46P;p%8QVgX@Z`%8j@5zn+~G3Bzd}&uqk#$C>cX z`(>-)6!)S*Kb&ljhPXwlbsNFmZ6lqy#Ur974anVUJXh3=B+Ye`dEW{qBp*Ik-P}N5 zQbns`asPliYivL)1{AOSH5{+yn&rM!oRatHT3yM5C0asToolPnz~dIX(?B=#2585@ zI`FI{VAo|`)4X9v3V(eV%0#D9IqL(&3Gx%Q7{VU_c}LHO{X%@_HJ@`+;_3Bw;IQbt z*nmnzm~s`h(g@Hp2n6W!Ne2~;8y^4#qX13RU_K$x-|h86M_EXJb*E~-ylF>;croW& zZo*L_EDo3Prvp##YzXk_bN>*>yCv5a%j;I`pmM1#uKOrgnvE|&yx52+y;|ISYHOJi zAAmN|d&ZL|x`mi8kpw3L+YXw?;#t6KTm^Lhy=_;Oh4m-C)1(~wyO#db_GkB22fG;s zi;|_UGp_>buSOl-jK&%S({aMPwM9J#(W1xd-B zu4ug&z*YPVG*AgZ&k3^XNbpb;1OD`n`9hI^CcW*k)rx76u{~9Y3I9oB2Dc?w_v2-q z@M7TraD^=(fM}!R02!n}ZJ%uU!`Wh@%)@9u{&DrB4RJM=gt?hf#mhnPXku$KIfQxp z3#7h=7kGZ&_6Gv%(WPKoR$84+&YYuZ6EwNr7W)y2qH}C z9c*8FQ1e@?v~}fnxE$?n5N`*djemQ;hsl_8Lo@*zu7LVKDKa3p2T;qLpEXY#F5Q%? z*Sx!yD^?S^`Qtaq(Lh*5sCPpU7hpgHo@-JhZ|PH#ZMYf`$+O>61_)hwx>Ef;>)eN8tjh1!*E zkI5fqMyVspN!#D`_9QS$H(5tSXJ%?^X-T`R{Aw?dOum>=x3Vb(e0{{G+Z}SWE7cn! z)J1_=y65Au(WE<|oDj)KtUXt^D4OYH;T zKPxFISZ)u1?cWI)5vTBYJcMB}n_lgW19Gs{*Qh7uK}mNJp~X3QdHxCR=gUUpIl_|t zZ&wR8OIQtkAUytwML@b5fCImquJjc41>`)oqDArU4@xVuW^+a111M113bwB6yD^d7 zBiQZc=>%oa_jpchI2;bTt?AYy+4NcxT~dcIgOagNc{Kp360TF{HC?PtvcM3UrY$6+ zb!cY6G+1JDNc#Q-q^JEKJtAAk+84YJvGRtHi01}2PysUUh8C+Oc0E9bc4dZzL zlaM#$-|DxwJ|GaL#F#)+Gm>h~*GJvervU}C^wCA!P=vqw0SLgP&biH6R-rZ{%i_4v zf2F!L?$um!2t@nR2zreEQlVFfAZiCSEB7iQ3aZW66^KEnIvB@Vs}X4#vRbq5(zrNw zE8v%>Jpm5^$+zZqXlY@YBoYZ2*U7!auFcJ74~LZi;eA;s0-Kd4?%ne)?<*!^EE80s zG>9vpTi~>019^^Pg;D-)I6DYk%Q^cpuNyGN-UCSBqRb*fj?4@j+rX_J5~r%MWE>0F zLh%r60&J$I!Bd|4D1gRt0_b`)B!Wlf-z8zx5>oQ9zK^JJhx6fjeY(VV-6J>D0mI zPL3i=x1Rt+R)7TQuyq@zF9AKkSPMuXYJ~x*oX8Vv7eIF=`w`!MjQ=Kq5n zI4+os^v+><-L|X}2Jr$*nw%V-z`$A8?07t|rwJ&O0Q#(z!@}Bg%+SJ>6fPF1D|`xe zL-Dw}(KJuTR$iMb@NQ-oTfgmJ0ePLx`wi&obCxj_OPq~9CZ4M?L64>sX;d{w0lJmeq9KcIq+8 z8cy_APKFfnt^-m0g~4KQQ2V~Ve(MVmu?X;KBUfVxb^^RkSwAk*uhW%uaevMrqPB|KDIi~DjOR@;&h zM7kNi*B)KN+Q)(=5MjZZ5&{sU=*U9noHkla%9lvgLklss)F*-f+%f{f4iz%lvBuR> z;^O0V1wvIYtI`a`z2~XsG!JUZKN4?mM)Iy`HG@`ddjL8#^iFlYwB*eWhY8VD&pk3> zy725<2wQZ@ni{=M8j|-#6);5>lDfKt3-~vM^*2TtE<3;_U7uL-?pL3JP08p8`1(FG zNo5V%PpM>mrcHpmb$_V+dZ3VLagPH#(5JP)humbb(s~~!FI{y|Lp=kIWE#-8fcC^t zU-&ByKS0JVO4J(=>+v!#=_SBLc3!otM%Le$4_pMC4*t|SZ{-Vt4b+tKY{m2N;>&@Z zl52xDF2Oas4TJiJ$ExSm%BS)6*1}o-jN?8;;ulbL0tRX z&6?laTP8mFW_(u-FF)jM+w^m&nK>#V9gv+=NBtpCM&(kt;!fw%tJ(#~O*9SCv}8FY zA&qcd4goj-W*w8^M3~@YJ4B0nHaTa26fPkl(Q&_nUG{37?jsN~2$f2p_pYnocs?k# zk&W+Aqr;P%Vy?>(8QXJp+wk3lfFy*$%4e zt7Y!>&>&C#%vKPS`~^dlJZuE`-T@!+Q49|tR%0xuE|}!i@iiRNgIGt0(lKy57OU5r z>$-9Q`ZqH&5*V&hzYk4CYJsEj45Z)05Sy-L%k)3DC-z~%&{Cso$1B;K32fWQ&o4%FTs~fZU z{9XP-3ujr{O{bV?Q@&a!Hz?vLPF>dj`gn_f)RzB8ClpXTsjLshHkKw1v!Vu(xGbMt z{OO%fkqq?-4ult^nbam_R*yRR9j@|J1p1amQy{nXQr;?l#=J^=y%RDZd+jiL-rRgo zFdB}-j?@!7+h(Hc>iPgMG&aqy7A}rE4l7#9BoJ!X0J}4cj?u;kTqa|L67mSRJpqMs zfew~^#A`Z6rkOf6)n3RR0C{F?k7Iv7%CmTq3crk*s=?FfM28s&gQ=%?7n-+rXTHQ;1~M|pbX=K% z9i;5z0BlQZCG=aH>@#I8m!1e_BF$0016w$Z?^@SoNo0fRo?r?X$LSHR7B7Rbxw6g{O$`f9V@J7l!8 zW{cJK0^E1?sWQN2MU|NZ_LUoVM9ux43Eu_gwfvO`XPHf1?`PvTU9azSu!7zA;tVJp7L-eOtRB%54`aufJ7$+fx5JMCbz}ntaBOV2E_S(EjI2%@3y z?!8wGFB9Jy!sj^W!0;lAYd?bhy>^7nyZ=m zNH{@g>Jru1JkR`*>#d|llNrgT_JmSrvAz;Kkwg8A@iq$h;5t*e5~LlqRRv%DXbAKJD1^w_@AfWKCv+7#3=K-F886IVaml ze!;K0xS>Xn(89KgkgQE4MX*?zE>+%K`?>X|vZ0xuEK$}f_QVUs-v8KUp2%Q>nxG2h8iTry#X|sx&@;ewxD7d^fRLMO^f!H z3I~U(oa2T;`G|r93x&T_g~@q_MKc!It!m^8k7N7?p|Cp0Z@vk%BC)5I{LL{IK%A@K z@!HJg*^Sr_KDIM#@bx#fo?wQ+Uhi1C`Z#%{?`3a!%M&jBH6oi+dn85I78Zjera?fT zoUooshW9QpG=g()@^(d|#q>LBdtjJ(f-<$fnXZOyk4NjqM2P~We=d}VgVqv#Ll^|E zh{uhEN(pS#!y*J!-foNbWF>`Js#UE&ei?wqcW9shA5gMzd0n6o<+9D8$Q$(pOK3ZH zkpEyl)7og$`Tcvjuh-rhBxbG-mlYQPmb=TEYqTL2$z{{+eDsl;`3X{Jw+ndm1e9>o z($Y>*TX6-JujeGf*?t^_akpj#D6@g^EbvPH}W$GNovs z*0{R;HN8Z`u?+MD#(@JvJrACuA3-lcU&eAd^HdkllAcOEfcmaI{EI)P9yapZmqILt z`u3F!fA!yig~z#i1#*GfkGO{WciyD1(uQNjeoTrcfAuicGWamAn{+0!EN3Of2S<$W zmFlXnGTrX120OHb3O|H$WY|qtrmnQm8d;%diAH3OT}?W>6$$vO;O~Y`RQ}PU3TF;73D@WKV1x#!z{#wY-FH| zPGgi{yIC;J7Y*DFA5Q7A%hK!lATWa3+l7Uer~B}I=nJpDhP1Gn=YxTJ0n)qx*fREY zIyKkv9g70?UO`hRXRii?Rh%UxyMQ?pgi7zzNyOH(9Re%UU2*|pKK+X!Z0tL5*7KQH zh=Uq#9Y$xr_`lFDfV0X}yi!H`&U6Y1kEcJNSKT_8|9Iz_+Q9c~K@K%leCGM`L|rO! zr2Rr!IK73b%IVHS>wH*GzQ12{!_fEgCUlhRB5;u$EglDCVX+?_-zBT0`e*m*!Or~8=()K)(9S@KdfXnR4h5Zi+h|L ztEez-d6%xZSKsVJCOu`=N`IzyD+tdm1O_-N1*;j2u9~frs%OGanU%k$tUz2D;DGP~ z@oALjk*b~Q$jp*FL&a;;d8_^Ltd;SOk}X75Xh zOhr~88j2$DLlwkY1&#^(u;|KE#QY2JaiQ7-H1qNFpiC{Gtqr253${;v*Z>DOI>R@Kl{xo zFZr;p-`AjcoebCO(V7;88sYP9B#Z2Nu)0|qabXu;d?t%SPjo>R3Jb1RMEn>= z-Q^FB9QIDiaS7aRMA3Yki5}e&(j2;{r{@NS0~^!MJBIf8M6ik$aDFkXY-0iX$JFZe z7N6Hv-~IXpl>54{xOVr$(Kdjc-3&PfU?=j~{gUGrHL4cSFGT+_WQc|SL;c!it6XE8$!R@a15eX`@XC<84Ds;GNXEVW=u{%P{9jq#x*20+Q zqTa97PY-;rVbv2mk{ocnHi{i;g`jsnTl*4AIv@9Ur}Yz*kHx{|bma`yb&Us)t5BlE zO~iU8J@iDKziIEreWr}(k?v$(sMSOI^RAvemP!0ZtM5+`!G=ta}bZ#3z?M+g;taM@PO5!shJx*#*|U#nxHhB1K{+^0t+I&=yvAB zida-ezS?T@ND)`V<9=$@(KhmlcrbO8S2#%?QVPavSNhd>_`(3(_Ts|&v)(53P}0K< zdJWIB7 zmE?T%AYV~X5wV|wf_y=9P!JK~R`@x@PScs> zUTGzhG_25o1 z-}5^&QfyIDu;7kvlJ|K@sZyGQT(A|v?sje{f!obdSFpNk)!p?TjDcn(H1@?1i%nC? zS*zV$bumw+N>4160EvfyF+kF%hu1xn2NO15leBL)3 z%8%$Y{(d}U)oEMtl*(7!xxJ*;2#ZiqV!h?~pebc#Q+UN>l++gL)!)8A%@bua=1^(7 zY@^P{Gtp=?$`(jotWE~SR4A6B(agJRkCCBRv+n_YP?(a@;?IwUNMm@rhsWH zwM+U7o;ow_;-$sQN8PS9SCxv8#j-{)7AK|P~Ob^Ykv>tTgRuM0lD~+1Kb%}nV7uu z4{(FT?~Q{-@FTtKZg;i-W6SkB;%JX?vQzz~E_t3#cKRHx$B38j@4|n#JQiZ1*MTB~#`xWv?Rhi_BAkL>9PLz0*Y)@-ntb%2f+17903(chzB-x|Rp3Dl zG+XP|J8+Fw?rLsl0q=;=kimpW5GBJdBpBZQx-76hThxv(!wM~L^KKS2KFc}STc-&Qn-V;U%hoD4X z3h06B60?^LB@k2!B=;!)v|1L|axRJfS*@Eb@ZCSW->kep=&~-#pI^hbq7dGM#$>ENkrrQ0ZPVdsj^2*}%~uhYMJPY*lWh#fRTVVOndnv>&m_I+&PY0Cudpk^ zme}}c*F^nYO^d-`LQba3<&MQd?Uz+De`l_*2(*}v7MC7fjpO6vwpXC-MGdgIpA4+3_J7N?xi0*L?wiNI%w=uFIm zCB`LJaes}U%VErr^OBCkbtJAThqGwteMo$irXUx$!zcCv-OUp173>93@rnt^UVPry zv!1E*1*|z`+Kdjn%jTk~-2t{*v&Eu{aO?GO8dGT$=$@PpT? zi&&*`Tm|}-aH6Qyrp%u=Z}Fr|O{a}ytgLSPsyOd14exzv3t^53BWt6dxxzv??3nKH z?Pc2v;r7dgzc$;-y{cs@u6l8LIP;c2P&NO=$72+QX?1#>8H)BRXghCK@<`D4xL@g( zFdFU8(My`6?TPJ?{G?NW17o1tEks-e;c2areTOLAT8MQ`H52s1EZfy+BZi#`I*$@W za2KI~3s!12`?%2V!=GK*^|G~YxSW9KB7@M9~2jggkzB`5`q=8sgW2wct= z;0~Q&SIpJx31Nu102+IO%|;f;TYhL10bf;H94(GX=6XWW(U}n{olaNEHH62NtUG@I z4e&eP4jj-Hur}!CrXqf!Jf0g3jq2KCK=Q2TWn)wcJc$yCSLp-fIAcO3YO8q*Ee5Cz z*0&=F+w3)Igv|}y3;F~uj|Y3z+_uk@-$6k8)d+qz3&WlukHs>RBBAHym#2xSozTw* z-v^X8Vq%Ybo**E1kc3HT6*pW>W-}>=>`Q6E1$uitsiF0(dcA65aCypJWb=c5;sd?m zTdR6-SLRLjo-xScIXqO=XZFG09Y%BcYzq$IgwG}!mG2vbU(WzqwVQ>I|FN>p8O6gUL2fhYj%8jfj2DTCyDm!yQ|B`D$0%{&bEiU zX{(u2sKLx9i}6#QWQs@k0^!m~PqpyO&Zw=ugo9BgBxdK#=ga2$<;TvXYyFGY`Ek2Y zY0Z4WSLoC1oq_Lmr#xs8gdF-+nbfa#*XL%3(yJ+L<`%&h@oRpwz43!AYHUo47iL54<8>LoZxVQVP>|lOhbFUFI#H1N)Mtm!0EgsJT6%{ir2|g1JH&n_h4Z>TcHO4TL_NgJ$oAU1B}zLPE6BzeLul+lFsM|irP*Hz6i7Y{ zzOge|5JbYo*1xnJF061Z1SeVGQZ8?A(RDj2J6<^CbhC_bn!hWJsRHx3STM+#i$s2S zVeTF8M)NSJeN4o$0ym`!R~MJ-qj`CMq)N>ew65hnd>4qU8v(CXK>YT2@i+T|mh<}i z{9`~LoY<5=eYQ*$*}?{iVCQm}^@~^dx`7}Y8zQ3VDKLKwt;GwPT4}N)!$S@Fda*kS z&-0Vz&hqQx2h`6n*eplSx2vMc7)3(CNa>tTH0t$KEaz)oeqsYu4Bo^@jstNN3$&jX z9JT2Z+GP3zUFAk#2FvBoX4d+f znDJB-Z&4Klsb2&1+$rkT#o>sZ_~5dWBbk#M5*xQE7~O+Go~q<_FZgBN&KR9MmMwH3 zgSgiTJB2C?VtXV&#RMLHG_tqNr&Mh9X*VPvDl1{wKwYdi`~G6k6$9Jrnf=LgVl@XZ zBV!W%MWf2_0{Q)u#1EC^i=zFN9~>1#n~)6pQ>J%RM;cw(cRpBnp1k+HMdMjt;tLPf zW88J)26yE~mR*`vDa*lf1W9l9kvwUe?)Ox+nJgB+)PI+I8kyy7)o1`k^A+EEXEOB= z+yT2~YmIv8?$UXd_y7yrpDc0nPVmsrs~gtC35|hABJhIwz`jUJfb@rmN8xNB0ew(p zW#(D2Y%Uy<+-r*wSqNFikR%Z&eVg_~c)&A)H(wY&vTAmD#^+J&S}a^_Lt#*w=1YiJ zIcv80P|(`ubtvE7$RVvfEf$4{$Oz7>ZM>&OmlopdnwG@W&=yK0%kKPR9}$rNUTn1) zWQQoM^ERvQGyy5M4S{;|B7X+*4o@0X^+x_^AEh7#=pZHqwPYG1vo4_U3$->}571G> z)C=Pc@O(NK6|34EAxZBC!Bv8G37`vk>S1FXyF$45+&v5^hm>n~;4vrCXu94mJ8hGg zyjggZtJTE_>oS>683R0U;7^1RQ#h}jTH`PdYJd3%e5isZGEq>N0!Axw>;xX&z#;ii zrB#eBe7GQ;$^u);H%8CVRZlcpHo-nclje5wbUA8vXwgo)_XNz({ZD8GItX#RfRUZ8 zP#$O|vl*HkLZ_(G0j##RHV$zxg6Ejv2wD$F1Lhu~SCAZS2ypM)8((u5T$OhE z9dfe*9qAIRa&8J4ZM!NdL+_0SEQ?@49a>=A<^|Apnjkc(&>p9iTf9b zIB+SWNg=o_SIe^^CWVciLf)Q0Z1q#P#eyu0&C{>f+>bITznXx_>~Cfg?{aEW&kU?K zhPco4gIC*4;^)Y8OC9dYRvBs%@&)p~Pzp=)VHDg-*cgs`Ld_`!1YEiEa7BC_y{YL) z`vQSrJq-*Y;M1kO4L`tvIi*Yw(8lexkXbErxj*;5l$t1HGLk-F{zm)OUk?g;&2G2T zow$U}Y6;T@-NcMQ3d65zBZ$axRH4~oje+|~%mtN$S-N|nN+0s4w2f&(QJ^t7u1^0F zx_H|e{{nbX8sI=9ie`9KcFph4kn>6qYB7$A$HKSx9=Ygg;Mj-!2ryf*SZ&w*n%M&m+}nG|gj*ONZ@q7- zAbqo?1nqhfjlgL#9w+iIrM!B$K7@4bk0eY-C8oBBuPAHm+akqM z#|nr_%&WneHMOk9pRcJ#_*$FE**#|kjr=h>vFy&izrOb_kJY6K_b$H#)}{9rev9Pq zt&}VVXaJ`@e`n|dN|@^vK03{oE4T5(tS^kU+9SyEeK)6Qy*0<$6Q!e#{=5?*ai7WD zEwv=>CqB17k;O73R-~bflzA|lE`uP^d1@W-N~+TyVJp)N4y-M?A zxrzCa4<0s!#-FXL7Ramo^eIGZg$LIaeo8CGv5$x1dO^pOP0R$_gcT^))G`Cg7bp&D zFa%yEvrcNLuMZgA^8{t*kUydi%P-Te_d2zZ5KI`TBvxYD)HmVQ4^~X6`JnGcGi;kpd*J#Mdb{pN$-9rK& zdy8$<+D3Cchnz(281;0b-HF-Q8a0}1A9y*2PsN>ya?XB!|H#IS7)*+w9jqu8JULN; z;+5LTPX-v?fa&fnkLe=jl!oc$7;7#*-kuTa+VKxa^+RA zoS&v$QXGGrOzP&0!VpBpP2QD2?s#*t-}RX3F|-PS8X|S_LJeQ#VM9lG^MiglxD1-E z+KuhV$hr1;z+v)EW~~)7*V)XhdRAvep&z-!6Gy zWOFA`-jnRa4vphF|5f_c>8U?Gl{F`q2wy~4 zL{wOl!|kDRHR0pyHsp)o4(z<+!`Vy6>yLLmIR*n>EuMj8i4aPkh=LC5+;s;Me=l%U zY^;(Ve@1U}BHK5M5gu+?rE+PWzx*jOVfxJi?dEJhv(|H) z*@CidvL9_P5 zx{CfQ_=PYxjJ6vR023g_U)hdUlhbZTkM+jah+)3zARmbWpYZFvF2*Ki$^WGK6Jd17 zx!!m%W}iM``Q|qYPCx_1!>OVK13&gj&%#1k5s!X(&a+T`@O10b%ZwtDR5eY3s$)c zVEl8W8uweKXXbw6=A_4<*2CT^hh?m6o!7x+^XRjEt7_2uZ7%Q@=0EAEgBAe%Cj-9+ zGKu7R+^OGgkDI&r{trj{+tXH03f$rPkT?AU6YV@fA7O7p$1)dgT#)5_$ZuYlQx{~g?1omtJ*k~|-isO)5UHEU$cgQfqgZY3t zPY$txj>*3cqZU-aZ+bsTd~}AT94EhWIN>6h0TFoa7`;OmU72Io%i;z-L0q98R#bmR z5iIjr7q0Lo9CPZOQdeG!m)^bGGV)s$UBwY zQ6VzYUZ#q!x7!9ZrnERYWdf?bD;gDkzVie*!L(b$aF9pYuCb&_oiaJcmnZZ}+*}(y zYvDym2@2&OXf|GjNnGW@+?pWJOc1+nZN48ZABcl!;JV8rig|r0Pkgz`XA(3}90GB*~IFuD-MIH~Q zc`i_w$SmI)gC$aJnk+fYb-!D^z}ZQQjvlFS$|wl2bIJ?pk$e?dYzUL5rAQO?MpU;g zR{mWG0Fr=)hkZFnZ}o6@IEW`ok@Lg9T?wMW0fdOp2~3+HGHdMmmf0SRG&MOw`P*yeS3W~Rgjs+0k+bR zqOd`QsygswSEP{X?-1-+b3e@c0^ZWyKQb3z*fXf4V4xdmA7dz_haEeJ?(LB;8B>+!PEKR2Q!r^d|#633;H-WqvMM|9mN~W>2E;_`3Etifyd?Erh!Lu zfu3oC6AZkAq1tA_4VbLg({=#Xzk>Q4l_U;Fm3$-lo&TY1TV(3|Y*_9>1F6&bwd0bj zOhKz8XtYYl)SrM1r?Y8}qm#mjq@6RxwmmHGN50K?g6`ttkFI(@78RV)@rtKlMMX<5 zZR)VH=92_n&#pXAEe?2SEUZK&d2wbv{zQ*^l~I%3ym^WZ%@^-SZuR%R#8ty z`$6t%Ak-XSg4d|HnHMpww@CZ64k~=zGyLG;PX<-EZ-@P>Gg*zd^5(YkoHbIQ}MUkaJIqRl8V< z_-s3#+uu)PC!iHIVKeTLmgB#*{$!xDkl{2Qa%CqV!T~lii(Ln&qD$mi?{SKT-RKe~1;h838nVr*ZDx@4N^i8LL)z2%3KO2Jnct=8T^abf_qz1XsxR~7h@XjCu#2tjCq|7_ zM8Kt;w7q|y?CfNmeC@o+W0~m1NO1m&9tuM(J8!j|Kbc)qrSIAhygNw;Q#AsKPZM>r5<89$W1Y2kE^!c72f;fwYPJwfF)j$0)d}uh6d$iG2$KdI9fg`+@aFYLnpx^#f$^@#= zUduq{)p+Te2OO-3o`<@%C7#I_T~&`>1{xY`0qfc;RSpUBVU%G01Pck|Y%s3~KP z4Yt_OzatQTerln?EZN--O*LLL-SX>D7kFEH@>$YRl-p>8#k#MKG*?nZVK6A-rr+0m zcr5fr`T=Mtu}f351&bHTbwX(enq>}yP_iPY>muZg#wIjVP(eYFck8qzS+GPiXSt6H zByR<-l&%ijyRJ=#eI<=i^6%Ha%iCzzt5iAF2ak@Lek53|H|G=fF`>nFi^n{@8j|&1 z9*d++oKvHXX|ZFLw>^qs6`<9~hI^G~XhSFBbY)=VVs%f(&#*I6)C;Mr^RVW!Q9R{W z;CXZJjm>wj>p*%sspHOWJqOEwO7S^0GEktMwKLxWVMf7HG7uNkD&#ITjmlXO{>iP1 zbRxAyugh86srhh=Xg#C{)9;{I;q%9@H;y+^!k*#?ITJ3nGd?~puJPixC?QR`JibgV zzV2iXl&u+3#PBF1`OA_aCU76=s(h1~-F@R&1MDs21 zOtc-C&pG;0tbG_gdZ9x|gqiQ6A9(|cZV~2Qi)b5>2xEeXYf0hPm~g>4|ME>=m$Rd@ zGo3Rn4KZhUx;Ouc?|dsPGfUBCsa(~W_GRuh_R~(SG?PPMiaZ9j>gtc3xE~VIKdI&J zJ=$7pWILJtflv^RKt(&gZ`(sx6YD|blvpG`#O)0OpO@D6WdkR4{4BCep7;1cdV&@D zE8l}(kk z9Py=apUVr;tv6uSjy?M$_AqsguPp6_!8OIQkPSwO0Xf{$<7)&-&z*@(GJNfO9#Jz; zZ-7ikEA=ZS_B$~q*=hsJ%j>x}n=24sm7i21(Uw+E#bJNJmW4NaptcG&Zs%TP-p@F7KmN77e|A(c3YIv$ zN6oSp(ep|~o{@1h`-4PMji|vs=m(X@OEEzzN=j+2#Ux?+bElWDwrn50vg6wb65$J% zDiHiqQ1U*;I}@--OQ9+iD^|MEYl?VF9DmsI62WlQbQW&k1ij2#UcQ-T?;b!T2=EDS zOs$B$o~BYNpj9KN*!Fu$=Uo56;-IMJqSH{bhbkUGvSc6`j|26Q`BP^^8eTW)A95x3 zRe`l?#!oInB9LtDh3(KmYT><}x}K9l`8u1Zl_kG8Q!+2|P#q7Hw}DZCgq6@&sxU8V z99E`?A_yZWLlSg6?^E`{sV+!fQ)5{>8W0b1<97%oB&&;4Q_C_} zkTg5|@3OM-@6D+8945@ujw;9>#RHt*-)z>L(BT%8WXnR36T^sFak+c;LD5J0$%e7t zQ*T^@A5chC-+Wqx;(<5O2E#!09kAC3obrq zT6YH8c)H|rY?5A0bL`~Lv{SBKl*(eY8$~~>q|{WM{6^t17z2rDXJ;MJ#(8X*uBx;@ z>VX;AQba^Bq2{ciU*LRh*ji&S26=pp!GNv9mTX&bLK%6}7K34{GnD+xZupzLiTz>7 zJ34ey%XKr4*-{%V4?`nyP7;OY^e>qTDe2f7skmdoV6iEYT{e6j+UPrme};p9gu}p; zT4n}Edh010@)_&_8}UizmxlZm&U^N51R><)h?z-Fy4=0_?ypiZM0!F@J&M+UPE}H( z!HNb6aJrl(B?%_?{baSL#7_a?Ckf8Ked}}CgSXtew=pJ390@w-%5sGTTk`sGOd z@*94851fd;T8=dmkB)LJ8Lj-U@9{9lf!8|1;`5ZNWjK%{Aq~va*gK)x@j`s#2A}1N zfT&tKU{y0_g}6n>KlygTzQ-5tlndo+8e{I5@_ViS`x)H~I()QSZtMGe%Un@QllocY z1)!N&(pyI#8awel?(gBbwG-CgboT?U9dVX?n-F-)6%=d|aTZnwkGJ*G7seHGccRy+IuifZ@x9w!Y%ze#5bT<2)H7Wf~a<*M8ex1C?g(}bVtyC#m@e5 z3I{8NT2quy$@Kh+1}loxrrWuc3>h}keBsZZSylm^ql_H7CPB^?+JG}mvOqv7*>!N~ zz#+noBrLF<|Mpt`CUiS}2u|(2SuLP>{_3aK4KMD3WUV(hkMbreC4bS081bWxis3n0 z3(1N45Pf2lve2@jR4WTa1EU-TWdTw>{T>s%o3hW4UuqXk+&{-+&P8g5eXF zoKMX<9(+F*tv3l*^Z$DDkT|hirZ-t_OE^3l8rNK8>xHJUpbMo?&Y_lSf>R=eCyk(K zuk~8)za+g6$V!Honfavayv2}lUb*qYZji4q)HFuhg0KJA<~=~iuTe}!4|#nRNC2Cj zS4z;^Nz@QR*^ak2gyLT+7&rktD2OXeqL6tnp_Z{|lnakn8>3T|LC?gI77d0b$g}dr zvDcg;OQtObxf>ndJh1Qbf0yu^m!dmiL=T%kn6~LY)5TT^m3#Qgi5qJ8|4TRHk{zXKG_fJ>A0J{kX@pQnek{^j$F z%3pwgSuTGecDZ5#^(R@ozT)0(%$v=jvA4!6e6|Brmo7lEjKXB)}&US?;6 zK2d(VPMqQJek&FtNDNp}K4o-LG`0($w$O46mEbRmU515dz#j=cLC?x0?tu6=69B#= zo$p=o$G|e4Jci+)6iyx@SHybN8799@$p+$tgRFv&CawO~z2VlCn**aX1EfUu%&@3R zmTP8HHr>@sA8R(On81FkfnYLZZ!#r~ zICmTGyk8rS_tEu{(}zREK>bB)|B$BS%L*XWHMG)}M&`$aqTCPYLm0gK=E0h;uztBF zHDt&xBC=oygsY~FhcjrfoYdf0SSALcq3Br{5-n%}QhDIgV$UDXtYm&6Vc`N>_8%tXMD{&y z8JgF-Eb|f~`Mm48K3H02ity_jeTab#3JbNtn7x2`CKD)F1t0d1!1(_VIie)-=6-rA z(S3=Y`Vd3BrzO_JUt9u6s*uJ)tSrxsx4(pxegs&H-n)pGd;j5C{4hab(Sd3yZ%XlQ zn&Q*K7y$S6>JMqEfC#_x`Mwdg5o)&aZ9eqnXCSn>-RRyS%}VwYkq>tqC10x6*t+`HZF0e zndBJ1)DI`Q%z(zxF(K?jp$H$<=yFMjSKwHHUsM!~_K8N2r;XAv^k3UwJ_j8>*fBZG zxxVlZ&)3=x=&}LV{Ud3uKoBX3BXA?INQTE~?w6%Bh@}i1i%St9<|u6Gt~WlmnVf80`C1vZbZ+N&xrv}D7>vQH`w_va`G7m zycA5YwIDZ3L|>Z6!wE zm~MbVSD?0tPpwqDkfBB_9P>Dh*+{%7!`wcJ*Of)we5zDOle_n8jfUH)_v4MJq@-k< z-;1NA7TedY!02+ryXTG)2iX7?+1JgH;6~T1 z3=WnEMWuM9Qm}k@i1_vvsNOA6|F#O`s#C;2CeL|{e~|^scE5YvIBd$bpKqHd=U#tJ zISYNgG=6R+t2daW_-43mw;0$&zI>+m@(obeW4rj>Tnhq7FoGwy2gi}+R*|GeN!tRLt9F`wqR$aKRRy^SmkLWKL2t$%%?cNQSWn(`Tk(%6j{060h{xWP4Z<< z5UL9JZ0BI7y{hS=G`^mXoTQ}L_?N*N>p3uEU?33|qb{%gYDb$t^a;T|0HPx)z|`CF zKIz1|I$W?MWOhH_9nT+zXZ&97_2A~7HowMY5-P=?LHA^t4{C5ZYIfQg1M14r=~E^J zLO)@U*0=%J01O6F+SMTc!w@|=pu;CG-qTFSzV!tNPru-wZ(sfO+YwY4$uq?O-zE#D z!5B;$Yf~yft?8u6`8c~=r!E7-&6k=zc@l2MWEe@{gSE?QYdMstiP3RUMnVejfu`3* zswU1Jp+GugnhczgvF!3-F28%AkJl|vVt7C9&t($>rE9w1UEB{5AL;<{-e__)`RB3) zQIB8Y>?@M1?R&czM~Vfh&5ZbLNo!0543RHSgHSIZ*vPU7fP$IFTT8kkl|m&T2|Qkg zxWkG37~w_%4_)C%T==5GS*1t?mg{q)(@w>^LEOBX>ytGUm+x*Dy8wDta5gASr`h8M zIP6l*YUvZU7LEV|LT)EBpkn|4-+qZGBPxL04cz@=wn#9*3-NRssP&@nhBG1^r#p}V z%natHPq_^`P{=4U{lS3W0irvKsC!VEs~;#9F~%Drc6)Z4fYII)dDFefzVz-i^E1(jqWs1V4RBW=gu?CTd1c7~B^~p)LI|hTCw*a^;PdeV9Jt)+3^y2)_vRGBN2 zn{*{&ub+e1=FKahpvFw-^qTRtl$+e%dqC*{;{oa&w=A^G(<5gLBd=8h7TeD0sc?4% z>bFe+$ye9@O|OSDYD=rE`Sz7X)dQXt{QifPER_6)AoM{GKkF-Rpi%x3fyXhl%tDeZH2mJtaXiC*s!*A#K>t{x!^Fdbcg(3Z z=;IAAUbWO3z!!K1e0^?aPy5OluMx8Tm7J|J~pk6ciM*J7Bg979eB*eCyNW z9b;IJZsZ^;tNBC$$^>=pw;(wL4z6gXtZ3m;|0dI6LQYXJ3X|sc(D0nO`WV-~MAk&iEoXM^u?BMBl$5a5xH+#_>_t-J`1F91Y@mdnn$*+< zXia1wm>qPASPqPVy$1?rbEzUUt1S$$%4KuLI=+$t`76@F)s+_jML=(A0uAgG%f6q&QThjLj-d&D66=-uA^HB)uGI*Z zbB(YaCB1@+Wh{jCHfwb4TQF?Vtky!>TO*iJyh{i?mo2$Ik@xc}l4ZW#^nhNAXZ0Ng zMn1#z<%kQmrxW4f(RyZeTDHs+?|$P6$6_2xX3cksgF56$;}6r4aR)0*`U#8&_1~g6 zt~yUp=C6OhH~9e6xk%v-Zw`8v(Pnce+7w-%Q8i_XXR zBgh<`n7HFw_84&bc6Q~eo?ZZCisT_6Ab@xmrvk-EYug|Bj@V%b(j0&{VG$8!7Aof- zPJe^UVG<@FL2CiJJe*E`E8vhcNrU1oU3*cjS02vuwkJ25POni<3 zK8p>Z1Ozo{+Jkx!@fg=p1yQ6a*nn~tm}F6rkbPt{%gL{>@yLqF4sKyFyCGo$VaVIx zJg|{tY!?~=uT4T+MjD6Hd7uq&FDNMsj|N2%T7^9i7aD7k8Bm(`c6MO*VLabz8YmN^ ziGYi~ya0+Tk^RDImVL_2R?I2!uSK8(ZnZy)M=mtFeCDuH$l!I&;-@8hC3eOv{Iz=_ z@YvL>Eh|`ssS7iZQ+wV#B#Phrk@u6bSz=$#C$1#c8%o&}bQ&cP!q#wRnf1q;&({;m z@M8N1-ZMXVDo{ai~?+|6^JFImfa3OTI zHU%SnDK4h1GMb;8w!x;(fwoFmwK5;Q*OI$gU(N9S`0@fL3gI{%%H#I(Xeo+{`MUfi z5x;hF&=}^-*oqGlC;#afnlztRQ&xee3R&40U{wG97Y)im)ULn!T*Tk_p&>BBT<}6e zDd!hZ_X{ksR?L#JRGSB8)BG9Kx<_7xnC$i&h#^72Oh2;JGciG)Ixx?R-M99%WZr?7 z8A0sO2x_iUF?#?iGniGS9BBC>)ayq)-Qw*Xz?OsRmRv(L9fBve3)b-@JSWDq1JrFO zx?Ud}B!jo+EM{E^35h?#iSh`yV{E|*_X_jAMsL99auD4!Sx5qNk~04s zBB_Ml^7QDwZ4V9(?zlMs3kN5Rz>Ou%?Dr*J1+4CsZsEu4Y37ZV=w4#(&k@ZNtVbG}+z(yOB@YvNFsZA(1-w-0P+DT-u0BE4>$S}gJhOkkL64swu3psDs$U-@n zfR;Uwp|W=FNVsg05s1vVq&)m?*Mgx{T*zNYXlaY%#8B`fgONkDhk$~E8aya|emjNJ z-5yFzoOg>3eZcI4Qk|=#rS5b{dmQ?^i9u6%kER4uA;_ihv6?&}(hB%zSrp4lbQHK! zTDCtB3GY7vmK!XzE-5$_MRdWVImEZo83oRMzwAQuT1;*hC;W{-WR+`T8#QC8AYvGB zwPxg|kYYEImrEhR`xHD_(j2*@C{1SOwjpB}GgP9%(HSwH1Vid`peoQw?F@_z9Tfb# z+We)miF&ksr={w{Ry)H*ro@}PNOI6<#YGD^bEViM%9#vnQAXfq0n^RzHj2|`v_y6> zrdco*;)N$1i~90Le`2)=@dbE=dq1wI2)r075|n6OvRwe)WZvMqkJT)x_}j}ej)CqF zF`6ARWY%y*1O_%DeQN0gs~hMIQo^w+$g!9+7SHnaU}^pAB>-uAj+Sq zA(-OB6*c|rqzAB%V0rD^c~+kC$OZod2cuv4YGodU zw4h|y-Aph?Fc)-ItD@@6WOj?T0AYZ-)t!9ppf78X< z;t609!?*8w5br5c$7+62hH<1X0928$qIMXfAVyppPQc6{2En*u@}CmSAR*6M2}AnP zQKyN4oN(R!MLz}%!K4Kg!I#Jyk448ZTZd$$K!qnRqHVS8&?*`&ga9TC#SeA>;mEc# z3Qr?MJWE=oN)E})8I2JSLl#I}U=5Ru6hG3KO}90e>W~`|0zTzNI>Qzg2A2K`-+qx; z#ob!1yt*jIK?;4a+w3vt-2YX$(mTV=^%ET5XoNy^#c56?aZ!gdv=3BROxF~4_hRw_G#-kSP_X~z#Q5PDr1tC<6D_E|9x*17BFj}tD>KW{T32j)yYr3`-`*~bcV$HMsgGih zDNL@MlogA@$+@1|1aVWI(18kMHm@cr9NEn@E$U1`#ev1z&Zk|}dL6WpW!U#8e=7ON_*>h^z=GIV)qD{5mE&5h=sRV+sYs)< z#048!AZFWYi1b#1zead`4LKCmgz_(Rj|ssnW>6_mFf*fmnQMW8oOMSWXo>5ao5vBr zy9OpwFw9x~ax5caw^Q-MCd>%-El?UPiA^7?kXjjC6#-Kdy?^3Y6HeFLGZb-722@kA zOZWsanGT(w^Gli#&kC21>;0T0=Ef6yKC$&cFcFHD;2JG|XHBLYkz%a8H(mF=9M-ew zC>@;N(2!mtA4b~gtmE2D6vT{W?-=5$SvNQusdYM{5OKVrmNaZe--QfSI^P83IMPQ z#EX1f0wt%yBhVzPijdrbr74CsM80RM^CB{fAgX@o`&5@hm>sgXxJdd`ag#JQhG(n| zswKU528?Va&!EMyWoZ+LBy5XMy!G+4R0RCt9g~`_SkQwc4>0#9FTC^6&YR1z632Ci3oAjO2O>vUg28+EyvtPl* zUds4gw2h=E@zCdD^=~-^Y-k^Qwh`zmXt9%mzLDVvrix)l(!*gZ>r4Ql5T+cDp6qmT zt23&otVf_WJR8==A;uD$2s51YVRSO*Ev<5OLrAK|I&2$F%&gpTOdA!htA17d82bm> zzGBVx>BDVXE^FFp0ASnBQy_hTBgQ+RF#iTUW*jOLvFEnZbhzswNKd*T=8^PV3)B4B zk$U!};?P3oJ()csZ=W=-6k1vr@A>QEmT~$@5vNRT9X`9I2m(})u^5yyG z_%J$H>EVzAWu|uB8e<(0{{aBu-G14VD=>_O;3T*xdRE<1{v0;*)avC~FVVWDZg`xw z!MyP;Df4teDx~=!L@>4_Y|XI=Jo6pdT*9s_rRc!j03XBkIt3`ydLN)52C`mSSJ+T5 zL{$>R`)&Yx+bqWmupg-8Gek2(A`&vjn7l=2Kv1Hs(7;%S>2F3rjcJ80b*I9}`iUnL z6%E@Y;DDv`d*WJWi>@UJ9WXmph+uzsr>{TLcGSQh5Guc} zqmHqI3>Vhs{n1eUEXYUKI~4<>WlCEypiOM+?+PNnONzGA*=hW z5Zc(OKTK-C#xE-gQR+>dXKnaMpKtvF@7wSPz#sp_2m!Ps)W*jx{D4b)dwU!98RpyQ zaSTm8GsQgK^$&1DRBX$Bx4(>6yH^lVv9|Z0^&F1ze9qj+B$rMQ>?C3`cP6VNC~DifW(@QU!8q z=nZ*eO2HMo6t++_B1kL%FNOezf5d_r{F$jFXMBql-ZNX9StOA-I0AT?*>71iMx1p9 z#N=v1BOL6A{S&vXU2=m-%w*KmFmuq*D2E6JYF+iIu=&94e?as_Bv~bUU@#0rfrx69 z+z)3dpwkRPNnuIwe~GG&iy4ScJ1qes>qiXq4aPB4JZ{SY>bcM+$h`E7nbgu0tIST- zu?~?(VLw@BQ|{fdDH`n*$vT;gQtW$GTl{QAc8}!y0gXQwfW&y{YVWe+-hLSFLGU5X zX!RW$!r=FfPl})cAZlSq>@n|y74`N!Q#&tS34Li1Ies+`9#3y}y21qhWk(U&RmfPt z-?~^BLaLX;MwA*J$xNd!--7>d`6mNg=hk?~L2dChUcwiji-*E{csdE`m-Ood#Gea? zY5VFm1e-H@A7zgJa~C(5&m$rzLv*BpC`KXF!XR|AAhpI57<}DthMjA zvJ934wOEAu+o!zabk6`@ktbnHM34_zGj<PIV^3r}RR|@Dc9dE-l5CBO*fXfyeN|wj?$x|{7aD>1` z&WZE$4=`)Quwx8gxWk>GQ*juED+V}+4x-}pR`baNo@+-4ihi~Gl?@#n3#~=8iPqld zX-ru{Jo1#i_RLP{_=~Q#r2sr1!L80Tl&J{5A8Pmt<2hpRR!whi z=-ttv#!`t1>t$2fr&VwA!1GKM*`5;69v!lP@St28CkiA9*J~Ta`C=I3u3AulzmqCd z{9vGO1asY-!J5%rxq*mc=y1q2eZUeVX=2Dftg%;sHO9CTXImF|y~0VCzuNjM2O@Zj za?FvjgwxBR&6_4CAtNxcKcfgs4sbHZ77)y0en4>Qo^vlp@&3;rnk@8Io<_)`<3vfOk0SW>oW@On5Vh$?a&7 zF9H=4^Bq6)e1I9uYlKuoE9qG`P@Zt9*r(FQ#>N_5Taicq-0YaP$4T~eONu=w_+rZ1f;JKbI=`FGnkiWLdAA^29tSLJ35s? z0s2OHg{4DD{yT5+EKTCv2Jq!AvvB+C+*6&xn!{;V#ixs&;r3=0q*m5;6R~ zoQx(h89-!YnK2shZ>wsF{7MsyN$Q_%^srsFZjwizfKW+|7%v|+h#v7Tby+hlUV0B* zBlHfSTm{JY46Jam!*X)_;`^U9=$xyl;w-ES89!+~=kB7JK}9$6LrK0?EYjyOdulKV84|LrCv*x_2>hSf?c#JhK13N?$th<;naxRHCBb8&H#O|KJjBcuBzcGpfS(t4Qn5!D{ur zv3hB!_yb+8y@3=~3h+kaXzXIjH>Plijnmk2et$ABe~?<|Akvz&$XQp#!mHBQsTM`% zzZKCOD)nONn>I?ZbOp{zdhyH6fM-~qU4xJQ7XU=blPU9eT;-X}e7{N%ldxP)rXB2l z=hOCwo>HXM`2B(M*S`3Hjx!B1mlDAKh?(UcHWO0MHhi49I~QndtQlhewIuwHt?4)J ztF~gV`ulE_D55;LK1u)OqW)qHIT-S;0*I<&EJwk)-c7qdfrP))>&Hp0?QtAOWxTg_ zpYHXpJZ2o5)fEek|IUyC4M~CpSKB#FSPpgN5`l(QBYk|Wf2SJ$GLk(}p34JnPA08j zL;I@ypanKocbu3-;Xwae$$qlW>%9|l5G`x<@) zFJjgHy@W79!+Ls*0% z=T&hOY;@&WxT>WVoSU=mz4_My02C8)-PuBOfcq%ThJ zRu}%rWsOuC(tp-JjvCVR;pp*{tnZXh1`4{0y6_L_{yJ!9Ngyoh4^c&6gO(34$=`<$ zJS^veYz7x%=ymzrnE(Vf78Vv2#SfFe(H+J#5Vs;Q3r$IWWHQzyRR00CEEj-CUGyRV zYSc&vvZjkBBLChuKkPH;@W3WhS++%k8QSUgo5}FMzFiPP74=!-Jlr7WeG5<2(jUhC z3$XEfjrz49RH7~#MB8jSp|gm2yIzc`g}L17iE^-0IR zl<$38mt}e?|0cFHLE+rnHw*1k?L%8uXFCAVZA#AkNnZa&Ha-_1ZBO1)?*)GMyVIF@ z?O1pFUd)M>nhU-PivQ7uF{*DzkGhF5lDB+b*Gf2g7J*lIz2LtjRF5G@`+?X0c5>k9 zEl;NA3#Rt~uA(Un+T`17yN18-N=}}bnO}%6V1y#IF=|{)kTp1E+#4O{Zx;CVupjFq z(Ts1PoFabMy!|#}w^HX2nM&*rx#`CW3J3Ten_?w)FP*T=OvW%M`8ek;tZV-JXh&hL zRfmtvWLDk&{{J+8AAazv{LJx+d%|KeTeeU~~F1`JjvpeY^Vqy%*q7THgT4*U)UrcDb~6&T@Zt_D_=h z^E@OhmWodsjkVXNlq#*1@7I%u%Pe10N$bezH+&6PPLtgnF9m`EFP78CS_ z$u{*#)EQ(lq7(t=HsW+d|38*(_XZ*~6xPrH7PdFYs5Gva6nqUdd8GX?x@w-!fUl-~ z?{VK)z5g?RL7#|GZzHzN(AcRX8p$oa#Z6VaM6Vk5g_(a=g>)YO^FbQNH?8shA6xSQ zDZzYwH0{hw#ZoNQEE4}Y_F9?2Sfl?$^^-}hADVo6>y>45`u$IAe=iipl}yIF?dch^ z%#ZhzgM))vQ8f;;_n}Ijlau2^IUrOrqfg21*RIsBhZKxKRjm6gQ@^$PpSyad^5q`T zX4&m(Yj2bKO7Za3`u9+&2>Y?@zhA&DNfuI68#!nRkG?)*-a{BxtfpY;<#3D(z- zs~2a67XCa@V@1OSFZ)nVN(ku=03zG+QMH)F&w&0|z7YtpRuR(e$`9kqyI`akviH_Pp( zwVqT;sM=@*No~UQ{45?6#O@v@(7BnC-zt4{*;|a9_jL`!qW)PYe#Ro!*B?lHeUd0E z^VsOLJ9|*y#lxo^hQnT^;NJVg6=(a_Lb@E_d=Yu-i+l`Yk$j0>pk2%E@YzS7E5xiGwuc{Mak ziu>rPKb}%T%c#raeQ=2(k2GAK)iZ7Y6DoO0DC>>6}z8`XSXQZi}^IW!{qFNo*m3l2+w@(iT0a>4Pfvx=% zrYqTy{xGT>ED4v)iM&qBk)1DIJT|>V@bTU*WVzq;?hO37Bbl)0>K=}l$V`#Gd)*a{ z(TBPEpUD$26*~u-uIF(G?AGquetzN%1l36RCzJi^x`|6XXFR%D9BU24%l_P3l3ST~lj?0khlmrGdE-;x*>5^MyIsOpbgfSN)~DjUs3eI} zy{%4g%4V8W&dKcS-!~z$LU~(kN@H;Fez7=v_qk^~x25~Gn&{SWyc9vNjM5`PPEV^@ zouYF|RFQ#Q*#`jm$TAFapM2S-f`3@r{ZTBl#;`QS&@$M^z!mo8LNT(Yoz9@~U8u(F zFnQp4n)n4y|BQg?mfvY+7?{PK27&4Cs{DV72z^A~RF|@=^jWbo{?GKQiTNIUnA{7+ zaoqRihu&egFQF#}G;T={DaMfkmIoJ)zUTf7aWp~li>2meT>5^!oBJ{3(*(zx>USrz zFLbD?;`#2}?u0Yp2IIBZMYm5rm38&xOsZGi;`JQ5UEuI1+GuaHXQ#gr%Ce@|uZk!> zlGTdy;@ySuts zX7X9h)MmFAyqmJoQN$IVBVen{SM?Nctv(NR!@e0^y|Nqb#|?j3%oU<&H@Os@+?01~ zWoMRpwA^Bf2zP`;XU67*0~WXA&U#o&!eg~dQ<7&4)6}Q;7hLoaZcsHbHM(MrTZ>PUwm%Fv7ijFe%;>a^ENg(BZ zuaF-@kV;N5gDv1v$GQDgG4kC)<{laMKs=uUc25SgXWQHf>UyBOEY>w2z}p%#vHjD<&pZO^=L|NI z+CLmW9;tdqa+=jEvEf|wW`%SYIbCht5nJ1C#LX-UxqHQe#k5^Aq2AxQEn_ z2>nDoPxoh+B%QLvnGX2MyE6jOAv7-E?<6nu$xMeH(HiA-IlXRw*fYu#dBA5|?4*1- zn_CtkZx;0F20KE!d2>fD=xh@hLnHV#DZiaVD&mdY7QNc;iUhdkkE|1N->R+o4;3w+ zP}$7x+3srSqp08b3WxvC#7qkngd#_tVF$frRS#<7hAEdTyRfkX{qDj_W+vfU_ z;b|D!^6dvVuW`M?N#3JSx-#A~s0hdGQTKOA^wn3;Px@hm)c&4twf zkTdmPw<`TTmH2gnDByhyfybdkBJsGe({5#_~GKkatW1ix)u zYH7ARNZSV01A`u?>-PFEOOAVcY?1Ljug}3%9-F+^x)%0uRlQX?mp!jW34VCxiIuS< z=%TX^&A4ZKNz6;q2a{6-hlWSpT@8Sf^JA(Fdeo-)k3F?wE$!b3dy_*d?pBN89WFOP zyO<2~>+%yZW?T-IIaV)Ww4wys34Tc_>v~ckw`Ja;L*NBZIU9%0;mp~)&bg5Wn$<9~ zV28+V?n|bVcTtgdk@MZeF#-irNP0*bPK510T@x%Wq*1QZF4OS7NJu=r={CScDf?To z{qeVSP?ETp$qMRpkzqym^^E;Lk|XN$_J%I3e*Sz~+eYtx4@vhTe5X}S~5 zLoHv11r@gXh0nXk%`rlTBi8?u{hJ)1=ahB!4W_FH#L8%8a6DoRhUf&bBqokmd@;;1 z{@fZto)YFbOX+?`R*V-P9=@FFtjBnXZqL!vSL90J*n}0G#n|1-0?{-c;nYBcbnaV& zG1w2QfpzZ%W8A*X+aWtZxxlz&6lXip#|Wn|`xN z6<^fe4a2$W_->`O%dze?0he!LclE8ujD+TehOY3Jlv1?W?YKOBz35|tSU%p9whlE4 zW3*Ik9Hb7)apzpQb1LM9JFd^S5qv-$vWkt>_774;@mF5v%>z#O=Hfkwf7^S1JplEE z%eg|LQM=Inc(Hn_q>4dRdA|OjyvU=T@N1I^?G{JbU1fw~j(C1e5%G8cK9Qg4>h{5+ zET!Cp!S8$9&C3Q7o7;~1&vi~4n-nGOot9h12rQAECi@hgKvee2Dg zi?^79KtvXP+brVXx01E21DwV)>F|tM+$QTYf{D#3D6NR?t%Iw3)`RHJluYi(V@bsH z!@cm`3Q@&6R5f=O?XqoLBI_OR=+fwNJ$RV_>N47(@pGyi>Om)-l>OKY z++xqavH13kS2&7NR{|G=5a0`GrL~& ztr43{cvP;Q>9I4!B<9+02|3hJd}RLq;UVp2X;LDM#Y=SZ z)gVa%p||_EGsuT@-?$VgQ4bS4}cL2T;Gf`Cn?C-X-f3Syulh*SJq^+a< zMjoTB0E)n7p@nA8<^C?JDiTM{R)<;72Q&Tt@``b!I;Kl)(`nKL(OgT*_3n{g<0bq6 zt#$ZI+OF4?Pv?6x1F$e0#T+^x4R?fX7MmF6NMDClDZjSU&pMA8y{Zt$4J3pgDQHty z@)5V#35-ibddR9(X+<%PWFxpfxjZ*lD3Jp6qp)0W81cE+i9Ezjcx1y^qhNp&i#Gk>*(mn=$o|f`|Q2fUURKA z=bYuN2d!%|pn$RrGOaFOK@G5Tc_q}wSwb$G&ek~{a*qfC`xb#wEd^c{p zf6aqqUDQr_yx0_{>gtX;bd_bDQ(o<+VMzvg0z8!sn*(Ljp8|F4>4qIf_N2v@MF>9> zm(Aqug-kC+dl4QlLy%a?R@)o^?0t)~LYS$tQ4Cq*RJPvirgwILo9ZCTAysdJ8>GOP3#}{;%52Yt4r!vl;bHQnvIEdW`u_)eZ85dA(4qS zcvy{RB(2FMpB?xfPy>k>B8kS7rnJ*jZ$I-Ta|%z7&r^?{U^)&53XLgX%fvqH zStpi>4AwlDX^*O%G6rv5NFQwXhpYZio!bW-C*~a!XESXYlu7-&^rVyTI9U51RMGo< z?W&^hbmpMqKGK}nGcpO5YD#d+Z$F-oOIo0fSjTZt?uldaUl#oVKQCQBB=(}H(T zq~2K~Cmt%AZlCOcsk^79ciJgw%ykO>NQj5th;Pu-!Gd-gkakhHe^VMyZ8r$CS*)?n zMb0vhEBC|CkMA&HhVoR#)Q|_#OYoQ=-kH!h_Nt|%cb<3Ar(w@&q5%}oXN2jSRpOW4CT?T>Gm=l@cyqB zfGAC$w2W$QXJz>2cop(7U?scGa2*mF%E-csJwMpjm&WU@wXW;nP?w}2B;@~UR>BMr zzH-d+S6)oWCcbC%(3IUt6K-AuLY)pDk-(#_~jb-bu z!Vv=WdS)sZ#(pnE?}iP*zZL=yw4$N{*e_^DnwNt;xIu5zmALUT?){N0FkoC)f!pY> zg|vA?<2k#!79pTS@*qPK(Y?;Q&SwOn-^!-3hL|+#9cX01UM>#HN0&>h^!4x&lU@(= zk05`A%rMZpeJw<#xSCwenG24(Yo6Y^I<=|zIWj(a4fmk`WL;CEqe7@F_{B;gH@WI< zwI0$nEkBZJ_xXBrc+gokv`}sIan)Bhc)NenJ5gG*)l+d^QV=_lhH9L?Y***&-oeRi z+gB=j@b@tuCi{K;JKirY2LlkB^1u~~(SMbgMt{%vfwxx+kNEjwt+My?rfRMRuBt0g zJDc=+)cJ)@Y+#1#`aMt+CAhPcXC?QYr80J0a;&)feQju~dAsRki+kaX&mcS-1U(^P zH-@=Ji^s#|L^>y+%&gkxa`BswRGdz4d~~=smh5+LUiTAVYyrxi_31<3#Rc7&71bMJ zL`uF$aSnOq=`QoWRE)rg5x)$Klx6J9&TpsM=0oh6VTjlimRGdHd5P znW?4NXmGMFeS;uKb{4ITM&=_tRTz-+PzUsc04R!K$VO6DzTAPPXr)K1$}EG6 z8Id`98U-jD-J3lW{-Ru~R~9xbHI6|d50MT&qdyQP*Pg+go)*6mZA1p(i{Q99fJ z;++=HdbbxTB#0BZ)SyeoE>SFCXgG7;$b*fAeJ5n6K2&LrKe`kzp%7a>MnBWjo%T9A zS7`W?1^63OL29)tgc#M#78{L-`_X|<@*P-IA@>fQGM&U006ukWza{m`D1T`?&bAHT z?fHQ8PUur#GLWyo8Vo-z8e#xhQ_NrC{24d>9d6vEZe8P2!I8%dWlX`*HbaMfsz0yt zsWNeqhQw_}T^SKEBmdSLAHY!1YY>A*MvcED?6z(Mn)2>$Ze9Rq(Nr~Jrom#VhDxc7 z?^7VHW=owNGjS;I>-|=Sc&wU;$~!?}=wtFqVJVi|%;o*aej{k$5@tnM8E9wx~~W+S#ID<}Bz1*ok` zVhm+Y**e(gnG9hftJLTm6oc`6TUM-giGPWdbMk0>JaSx72CQ)M_)Z1TE7RXRk6@!a zl9Bh=PDg9w+=EWX>@8bbE_Uzx2bg31$_$kY!s~1RQDjJs{ykfPGgHlhcH|fG$Z_c- z^i8PApz}CrX}^k}9YlMdt7f4+PJv-^FwC!Y(uH0>YsxI9VU_L%0uLmBzHaZJs=SSi zPs2qznjCwX2i<7KO>z?#z-==7phWQen^p<9;0j&(8yd977F)=F@HpJ_vzmFHowLkkqg1 zs>2d$#XwK^60P@&>>+#;C^;x)ZM ziDdw8HeKB=Knek70#og%0wkzHO_}Vrhv+@-&zEYAi4E+N z)J=Mu!Qwn7VBya~gy(btnqQ?YSy(w&I;p~dBjS*HKJJf?t>~?^f}Hs5@jAKY+9fJm zr;9V=p8e^1%^fP=&j)%2RhSO~oS*MmC?7f`Bnvu6?xRc`k=Ta=z?&}58Ppe9OaS`8 zLpq5~_4bz5o#v()zw;`6srW5feRIiq{o-)GX7AFPHADx6k_Wo`Vsr>%9sUt!MamIq zSI(u5<1}yloH)bQl3*UxLoBX9Z24LrcIm9!J&C5dQSXELf%VRccWPl&npw3eU;1r3 zQntNQE?Wszo-`d--b-}i?Wer~h>+dcf@v^YzM4dbiRc^yFs2m(Qrv?P> zteSXB%rqH_LFa6IK+ zM;I!tSrDi<3eC1#BGE*`Lc_q2GZlB1p<^1KN}G#q^zo14S-{lpM7_dQm)hn>UBP^r>$r3aKxZ6IXcAav$Kp03^P@H zDLV#f(fi4EB|6O5(e^?=5|ffJ#u>)`W|~*g_~JI^Sga7J&kAnXY@5hhm?VF98>xkd zS&Z!3z8d~Y#@s%zT#5cvpQh;j1v&zxa0?3MF8eW_R&HXDQFXgM(7-~2`kQHAp9ngg ziX5gUzj11GB(XKPHiGxZ-Lv#ohs~Nt2xh7$W_qrtdW#%+ca0i5qD2~hLRR8jqVuSC z*~%K4s}6_^9J?1MQ|c(ux-j3r`!-+gjiQo+ai>~=(5qOjw?brU3kCAK{OVeT;Qkql zub)(5@>mj&BgL8lsf+@)ciT>YGYYU*{ThRiCT6a$zIqWDtgNAQ;d(A@H|VVRF4fnM z-FTPwE#8}3#tO_2Nq-GWNj7Kdys z=@$YOLE`x(&_0K>n&2KlUErgl4O))ErtP&JK;{o;c6@z)0IW-10M=fx;;*wa?P@*Y zYpdmWPFh+-ZmZQM6fi_YL|T<90yALrtynUVmf^9X`c!IL{quV+r=A`{zAM0s3P`av zG&KQ&ec0z!>y8Jbosj|oQ9`zRfZ7I7+CxOq0l*V@MB4yWa(ysM253mwMa}!fhm-#% zn*x+objE&>kwiLefZt6217PY?j6$#U6~rVW-|yr`#(c}l?gml@u=S+S%uM|G9AN63 zMy>9%h0?BnV4xnvo9AQq;Z|WZulFm1;mF2=&{B<|A-(C)*9(d6C_=$=H~}f_F41kw z;{<*`$m~37{o^2=rHScg6}zJU*i`*pS7g8fX~IaP$U)4|*&)zO)1*u+F|sArI@Q_< zRj$cuiGNAipZ20j-T#4?Se6Fu6k1SgUn1ye?-&&1UeXT_$M;wl^l17Cs@Jx_7IE8M zh^Jb-%y^bK(V8ZScA)e?jDVh6ZLYPn)BRQ0+AR%= zUiJj|5f!_zQ#LWUpLKjL^ZEd8c-MDqH}Y-SIfC#{fUrk{PB-X|qL}Y}Fiw-KIqcNM z#f8mO2EBgZ<%zFisS=)@?wKYna+IP~>*K4^pqJ#o>7Pai8$vVJ}lq+cGpuZ2Uy;@oF<;;NkA=n4jl|R0*wb*O5Bw zDWSnM;IbH6=Pr5K$Fhr4-P)cviaSIj3@V;7FMtY#VkOSVSKAqahFL%e!zY~543$zr z45KD&7pc1@J=eQ>`=iPKO!Dx}liIvKCNGG#Tg>B_Csy)$-ZLVG87Ug;0>g{PQeB^4 z1Kl$$u)M)mx(GR~A?8*IZ%XX0$+CG`xw(fJ=m~8X&ciPvVhAU!F#* zH<1NQ3v=lm4;9F>C2mv^AwdK;zQa#z>@Lo`T<^=aI-L|qXI3a=8ltlmqTnaT4FI{) z<|$=>B-hypaA8MWB13Gz!&R;TLcGJ5Zt$ZbpfISq^l^ubZC3GmRQ{vDlN`++i6+Q{ z0oTrdgy+?J*g*8dWVa&`(p6m}h4gT#-cdNLwZQb6$K~Mqa3rC{VA=Ju+DG&YrN_GS z#b^-}k6p)HoIy)VYbtJYfm)JQwFaC}+d$4xNJz-xWLdFfvZQn%CgCK_L6urxUI(B7 z{cDcV02vgT>l+)Y(F=c7G(3X~q8~6yG>anUa<0N`)Tn`1l6D-M_s-Ig-gm+|1+X3P>+h`}+0S1tC>> z#g)})9o6b!Bz&HaG)RC@Of*vzCN6IHcfMHE2ZHY)rEWpblpnpJD}%W~ac|e!-8aIJ z(V+PVVg3A|qbxC16eEdX6wx6K_636wb>G?K2gyZtq5q=P7(%DjC{mpkB1IcQPM6~h zA zYE?8;5D#^ZPz}vLj1&K-cJRAuTmnv+P}Fid$ZhnJe93$D>|aC4F#&W3yFfu0! zwMl!3hoT6OIYcAB^0W^Q4nkp71cTH3SW_5$_fu7D()Ds1MK?<_ff|NxL4nHaW=s=pCHOFV0gMz zTR0@jX4Hr3JILhWo1MLN(7)Lm1Q3m$6(HGO>5{<+wmlNLNGKmZ7 zWg}&= za)mDee1>)`Wk0>y{B0i?!iYbt9rE8mgzn*SI!^iw-|2n72{k5M_!xGGc9wRnM%_!n z81xS)_|tN$Ap;3V#&N~?M(lnHQEIH&Y+c@_2rA4NM0Ntx`P_9#I$H}OrhiFH{866| zTJ#*yhatv+5)jGTySLl+v9FGEM(O5r+(^a1{-&f~aX2<5@w^oZhigWO6Eo+<|G!A{1%kE%F(82g4uG>~X~m2Ad9whuGMm ziLr?j=`%~?E`pcyotil>AJ{u-TvwW}nHhLA3)B~>9Z^JvB0M}B#o$QOp}^+vgE#Fp zS!;Vhm*zcBRoazQZ;>2*p`e2SOQ+2BD5}6BEni|ks8I=&*ZE7h>EBTh_}V}n6uvuK z!!2+_EE@&Lt5q*(FBL|V>%A>y-{v!pjM3A?Oh=v2L=0O8r0V@;Afa^$B{%N*h3*4d zsRT}Gwc0SIQIQQn2d7TfJMrnE462z};=0qrAvn6CY^t=dkl<~7H=ST5_LV(CLCAN+ zgcOn(jUzU@1Ox?zNt1~0{jT$wsf)=57sZfIRh5)Qprey}qCnD7im-GeUY?(Yco3%q z4Rq=2$EA7qivYQ(U?R|QHCMFE5`Oa-7vZmN2Bpiz3dJ#FC@5bIX7s=YDa~k!u>6g= zd2$T7NZ4F2NtDp=!Fxogt%deJZ{AxhxlA>cnVe3DC-%qW=KrOS@duXw=Zh@VZ^Tb- zeDXdG=jfaJyFYZE;Sj%y(@W{~ds*YST&`ro6+1dQ*epu3|v%YS}i zL}Z1XLaPw=eGKpneFz)m zQMxIWB60#pB>Y`nW z7QGlaGXMu{Tf)$E@eMj{4(iubRT_-Q1dD$V+X&BOe$Y0juX_CyxtJyV~h;0DM3_#j!_CVOe2vDxNhokm> zV&kL(QYtc9Aj4HEsffyBE?vYaV-Tv5Q(rj#IU*(0>l4~&0>1Y|xOxQ$tVD|K%Xv1` zc#a>A+|=0ZCAF%gZ0VBzPtx_D(BtzJ^g9YY`}<6o>4W2gGWdk7+H`99Fi?jPxgIbz z@3zn>Z$T%Iw(h>nEk?wV0=i1}&Z}62m7sFo&TH-D;@K%)l5_+$B?~|ouSO5R|9K}{ zvB#?j{4(+e{_fOYO=EW)vDo0g#sZWY zV$^)$svGh^xKvG&#aq*N`7d*cNIaM!SgmYR$lg*3fCxNKODBIf)g#K)E+u z9*-sliSNe~yGT0JYwT!r32AWum&NvXT4WAQ;?J$5=sX(lxn=zh0>Wg@YbrGiHlnTO zvF$r=1D~4@`9Gj`%D}bWgsb5z?Ku1TI|5gWwVitx6oRZX;3q zYlH%#1EBlJXmJ}#*AWF5eg$dh`waq)=$w@YAl1()_=i78sKcPSBY|+k>r)XM4}@Xr zxj;Yq-hZ|$y8WD!E5DXP0cbLoz#Sh-^E?PW_=_lZ)#UYa4*u$|u}CZXn-~!l0iKhC z&+X!Z?~TV3GKC{zp>bRum0BWMZA+hn)}fe~q=52Hr5m&lmiWc>Fya2iewLN<+ z*MBx4kn_V}fn?QMKO<1XLhKtm8O^~H-19JIF-h_51vJ(?^Kk}dJp)^r_ioi5kb?v2 z+MQl6anVpC2{cr6n^^+TO;cOvzO(zlvirwQAy@LDO<8woDt{D_x8IvkRPuPaSrC4I z+CtZM{*B=y7)~Ytky?Nfm7y!Q6JSCjL=RmCxcJP-3wtNOy_|V}!}xk~1d#G2m_#GV z3DkN&=VeuPdcJ&uLcrSI-zOjGd^&AqSPmQl@YA@mw&y1cA;keRSnPG6P7&QP20$Q| z9&W%;1Q|)qpEppmQj2@%(^0qHo5SfUCjV!H+QsBADNMdtv~~dAB?R*sVrXDK9}~2D zdVM;pCNq3;vG4(rO8U&dOI|r5H3~oK6wx1QxJ01(_iP>kE{s$PZ^f%R>UrV%!f+)K z1yt?T;(VZIDU*AnQX>joKUv?XWT_JkdOg<7m&RO*Z5@WD>ATVe@Y1v0Pj9%xzd%w| zsP(A=I+|3_z>NP(4Hwe}4aA!|UAhMsC<~B(tPmAB;`ZxnjZ&GBLlz~`_AppTfm}^S z`Nro8^Nsl1ChRoY-omB{Cypm1!YL5@b1>pK@2e?G_p5E&um$9x7Zw1ZN<0Lnwgy1$ zLjjBzKo%|%pBEAPkmiye^4>64RBZCxXMVP$L<*?g3nS*u0ieID9~+ih?G;Gn6hG03 zDOG5=?oVZ}dp*${_INe{@{)jeU#UzsXjK}UEogUuu#}}sTMr24I+{avEi6|+5O7g@ zJ-fsO<%POnolgM%GViW00P~@A#ra$#Y@lm^7n!js#dA~6+3*diK=u?tT&@|_g@wtdflau zO;p-d-NOA}Qb@bv8ODQ@|C15`X@HnZ)Fo{_MyEOpk1sMfIbUg`ZRt8kg|~S#$HKG2 z^-G)yV0l2%@S4CN@QlE&2AvD!u>pl-+ce1(@CE{rvAVE%Xx~d^PP3*6`Fxwbrl5(> z0UgrrbX5nG_wR{tW3x@(fTtTp44B3SmQE2V(oRO%qF631n!4oh&p89TStJaD-fER? zTaY^_CL(fVQdzOTjD$(M4suWR2WSz19g0ebV=jRJvfN-|L))$LS%6n}={PJhqWC4@Sc&t&5rcvM<_4l#6hbtOn124ob15P}v6Y+Yt} zosiMLjc)V`CYUeEd8a{jl)-PqK0HxT`w45)AZc-DD%_`!d zTUSO6w!Q*wgGy4S#|jwOLCVP#ir62q?>cMC1$T8JhW zn@MQJ1Q>!0-A$3BY=O2k!?Jm}b2=V^pXsLqH5UyhGWY1fHWIi|Neq|*m|?t&toWk< z&~v)L+J|UjQDk|6gha>&*nvnJ@<5P8`dq-%9ECqB`{U^4%x458GkZg&6*MBWpzoKLaw;kql)o&*!I69`Ip)^V5soVW z=^{PnO&E|kZKTNSW?Ov>=rmA=V6TcWIlZd~EEbcc- zNTLyFu~=$GIS{o^cDF;W=Ek{t;dYK_9uJWdXbF~@YGd_n^!}3~ z?>>yRyB{_3p2S|4r1fWpb*jWpdXpO|&r-!_d7ueanF~{Se{sUa#{N6ItU~pby7n&R z)MpVsX|G6g**a50H;?xKO=jRtT?D{k^;8cG7DL@YJ=5?=*db$A*WiZ`vlL{BQ}Adi zcz~T__YUnELUfC%z`!EvTq=mJxw@3}k}##P-74ZI1fBbbT!~ak49IU8gtpRS3!x^Pe&3{ z!q=%Qbkfs&xi4z+3w_jm`Bgzk304mu{F)uyoWY+NZ$Ouu;;oEFH13ouCHnrz?LpUgo9gq>80L2(582K8SRQea0nl?lR0If zL{AsFG4`V($WKi4No1!OhUQP>*Z!%)97}D83+Qqw-$h|1{QgbQV z7eXRnWq*$N!l`2=Y(A1JdTss%uIzu=)y40FfoXUhyUv>@CDVk}DsRUh{-U)!nnf*- zS2Yx|=pHnT+^bxddlc8_viAT_O^6ihI+gkP%4>aufpW`M>c@Gp;Op9LBBeG-_zhJB zu+CMj59Z!4dJPTME;2*m8M&PO1A|3o{L$9yO-J~p#zfwC7naVaP*B^j3i14Qa}_&8 z9|WAzLnblNKC=$i^fNS~1JJGYeN?pi$uivUbM`sW#}G<3X+_eBDiawip7`Rs-8?N% z#Y6_}NZPTH@i)Ph8C!8=Sg;VA6a<3UK(DWiJjcQRs#tXeg8M(N?mi$&l9usyY#h#G z26cMeak8R2Pxn`Btth>b<%Qq~l_qs;yX!u=J%oFo1^IPqtGv8K;4((i;dNF3a}dAY z;}lJ5z9=sSuG_Gp0T5J$`rdA5vpKOriuYRh?QB&uc3qPBSeZrdi{?`BXJ7{R^<5Hfe(avFQc};xPkPC82=I2ZugpYC z*~3)8Jsy`>Mn9%WZT_gI`KRz}4&4VKT2kVUdM&$S&`1KYub{*=&SX+DSzHEA_lHam zK*hzBF84|gHq-quiBF|HjjY}o-!xO4Gq0B3_kBZtd9LANkMI|>;;o_JxUH@tLwLbF zEXmEy6;q;BJPATF9u0ZZVyCza_aufL{1LfF5Li>#YV6w<(9*EaV?3s(sySC#f?|F+ zQsDJu9GEtmr5xn>vKE)Jb0pwQ`%$LOdXS${^pygNxD+~9VY7yu;@D6fy|{v?`R05; zbb8qOr<28Hh%QK|{g@hcsJrfe6I=oiDww`?*CMm-(yT^Gver+S--vHegCKEbS~uL> z0q?@5$*{KQM~SMxEFAyF!%5=r=zqNKz}DrcRr(vv8*r%0{9Xw;3aeC>ucro=1$Q+aWzh4EnWjb~9K6Py`o-2LD4zZ5qoWV`TCtdAkM-=*8Srt{OmT=;G$ZdtI;xjHNkZTCN zs*qW`6!^>GPnBvWnD47-5Dp-1q~SX6;EkM>DKRr4klW!jO}K@2}i_ zQ?MK%dBlBN`#9e9Q8U#U9h3={>Zx8_a|t>u)wyCArDM6Ka5MTl`ITC!Rw&CWz;87* z6xMAlS-&0C78T)w6}5Yq50C(P+{_I=5oHP0gFez#S*XE*LmRD$Q284#{U*n|fntF= zG$3{JBbhMXqQ>dPHN-=HIaq?frk40;_9x-}`GE|f-3!EQeP-V$E*MEM_)r#2DM#kQ zP~tw5!L|%v?Rtl6M|sWh4RI(aDF2^RI0gU>%D~H{kK45ONR@+UaG*b<(`#30=nHwX zF4CE3zmTvnFNgh39JR$5UnlKEMT)W{=7BO=LqUZFxJWQjll@Z8PJCiqLn;c-#yp59 zN=0%&kNIsG#>G6kRmHGxEi0bN2kb-#2f_$r|F7j1<5(--`fCa}=l|H*R0aBEzdIR5 z#+iRN9_X0OzZH2?F%{Mvjlhaj_{TZ}@MG1G+;u9&!SG~Q+->Lm{zWV}a^gz2SE`UF zRU~?a73rfiPEC*=647ZXEOB4oWqBxK`VyT!c_}Qx!}c&EStmBy)Y$M&EOtc)%y*b3 zv&Bjy)MQhopHC>+HF`P~pfmH<4we^z$XUd>cvg#@yE`K3!kU=gxr*&hcvcyY*mX^L z2mLios!D&10IHIHzi&l?R(t_5BooPo*tl$2)lR{>;9B1n_$FN#hxvbb*hs?MJCx}l zfnfCxzgTHTE(cKKDnphhZkrr$Q(haoaE!_Za(kSg-e-tT;>NLmUe#E&f7-dZxW2eJ z|LN`4cp1~o^62PfC+^}lkzJ$BeUhZeO3Py?XH~ImwNb!HqnW1x(7+&Ig*K5v9ZXz? z)?zt@`y;+sqIvgTi-pl79H^<@Q|6`^ZT9c{0B*%&exJrKsq&sN_arvi>v9dbn&c*ln6Rt4WDX z7A?8N^m$D_Al-_-VIsTRt-s8+F=|6d=?dKDv`h!&*WHt+D*9sV*%)tbaLNkYx)& zz7Tm`>u}*q%m&IB9|AUCEt0{l%jiBl0B>4|^S40K-?=HEB^7wVng-f#F=JO?IQ$WrvoID#jnEBQy#66;3eX0t&yaSS%5}R z9&rfOgw3bERe5MkE?^Y)X}dp{;VS*BAM@PapmeVBkX}mQgcr(IPgM)EV|+O(BK6_% zHV!&|(AYTC{0Q{K2t%ZPPMk3+B^?Yl6jFors^jTwF0}B+h}=EI?~+5x@zPuUayJ>c zF~H=JQIM(8Av<0KPI~d+WOpo|(x~)(O<)hi5RL z@0&yElLz65f}?-<>ulhe>v(7htcD*4NhMc9GkVoQ$I@n>2GDW_ihE#WZI}*sEtJ~v z$ICgbL(R5(%Ztgq0h*1!uAsZKDU%0)&T{&n&ay8P;1ac$T|!s*4tDBemSXC+KQH|* zo>NP775dTqV&-Ju#-3ee2g5PcBB@H!C_-IH6jSd6V*f$+hxLJJ*P0O^Pjrhoz_>l{ z7;5NY@09H)$Z$(4uSXPeY)J6$AmvByeLW+K-U! zxcy@B-vbVOfdm_JKk$81b0dp>YK~)RWDriaDo;bJ>nahmP-p<8cqG=yqJ5I}y-BYJ zlaU^n{>#MstI~KQ=8mWPTcfjiuMRVPI_I-iq;CNI_mP}qiHrkCF+enVqRI((MdIb= zBGY-p(f~ASz1Ub{JB}6r7P8i6?>U}<$_6W)@Iyaqz2IzKfZ9~rnNG3Ort);%HTb*8 z^}VD1xS5K)+F4CF4uc}z1d)drpa%r?ycUWm9i=2~CjyQBT^rcB!qmT>>ocKEG2 zXc~(%y;wtd-yyfus%ScTxZI}1clx{q`89gH$MgPKo?US_i6!f*<4sNOM{v^OJ`L2u zTdn?ZM{H}}V;BJjW8mbC!<_=l<#4LL{lhj2`+2-po9S!b!`ACE6B3X|Q%0U%-K1JR zQH+`|ThX54chJKoPMz)g9sPLOg-yE{*6<&y68{Ns!o?~rnN)IgMwZz*IK19ElOZli zg6O;ZHZQ}vEjZg`izfYAJy)~T;AvbKcfSzqyxPD&=&Jwb)qbOH_ijd}-iKshsj%059Why{ z)5nr_88%91isMrZBPz4-b#z6d^b5GzyZg4>e z3Cg6;w`J{909KdZy<7$N2Y3L7|N2waR>G3#V*Z)W_z5>5!|rR{OLQu2in?rqGet7h zTV5j0YPw;>&A{f+bWU`(A*tGW3NuX~ka0EJF_6*@Os?R|GQ-EqC~lEQZlK!e(rQ&1 zSgp5}l%@;=@E{`Tk%u<>BKL|elp$xmY6wauR2bbDU5Iafonb_oR`H9stNy3) z6Xm6d*A~*%YGFTMN-*$rZKOkLku$;q0FEOLrmrpEV;WlWyni(uMxXqru?L6{l4RL} z>b~2uCh5+7S8fkijq&gQf0y|D{{DnBmxbrMWR=T4yCx18kM(ApGACtq|9Fia8UZpM z=Iue4!JsbqVP&(N1sf7$qvzg6l?(~0Ndcz1C!T|Jy})4qHQtU`SL-uUnz z22Gv-UoRL3KEytW$;T}DC62Z~3GVN%GA2ylPk1D}>P>Nlw9O6Ro#3`<>e2aQY02%} z-;|xsHThG<4qJTPxEzP;EKke!m!bCl-l*-Rocy=Q=kLQwfc^gS$E@@NkQWDhHiO=u zT@?Suyatw_7le^k-fgt>T+22oYbPV9&&_^s>hA;hZ~i(iQ4DeY)01C{04QyOAj`*{4+i39 zAG2z=YwYCyyh;-F1qNWKkr?ziAsDh7N3`LyzCUD~+8#@uE!6Ly!oM}qvm4pNJXeLo z;Vp8FPewyNzq+;7$PIu%mF-VyNw_g-NvKTB?6;@?$?%U5fq@xlAR${CC^;V)4TYeM z!D0A#_rISqmmtA&Wo#tUng{8TDbZclp2BomdrG3ixdT0Q^6XEFjZk!)m!Al9^#40D z!~`^7T%Ji-_+2RqQ)6>0QyIusmVr-nGGqViU!Q0WS|}6V>wHDGSM{M&wYSicU9rQj zwe~L5P$8M!Zg+?^r&#hrSc zF)s={p6zH`KbliWCOUYrd%!`Q#0g0}O6S0HgfmAo`rmdt1~D@Fvy9^~1wL>diL;^V z%&b5EyXqSC0L>*X1^bc)!~?Va3e>BeLv7`Fir5L?HN2bH36hWaXDo)EoXU@M{cr!? zHc>uWptcLW3c~4^?xl7$mN5YA)pYxs_TMxg-~%K222o9N@pwow;{%#WeX~OcCWqE- zJh+s>YF2ZXdw2@kbD;m4+t5)41$0)B@YV)1gCdEJmr<}ASwVnJlOLSf&N)tf!fBY` zYnS%VGX~CLmN)?q(_x3w{vNProJNj{RfUaOl*i9BR`JOOwx8;fO^el(vj0r@M0Nk( zX9knsag8f7T2MTgNofmYI*5cpLs?7K#wJ(R%c3)z?aZ#a9djh^=B*!|wpmJBGI~m# zXrHzVyU7m@c3oZ8K5;9mkm>{aktMf2PP8H*9IoZ$e8yv6MrHrR41UQxWF{AUi20p0ft)V$Z*-hC+RL~-EB!RcJ>mrQ34 z1SjVk8O<3f5n*1eOU=xqZsq>D0cN#DL7%T4G33kA9yvUN0`>}HV@co{ePja=0i^>X zNG34;pmjq0z#!}2xBu^8bA=MT?9Oerz&zKaNws}-rYIP1N`0_Y)Ko3`PbN8}0ghJo zWO-b+nWFD?&1UyFb2h2z~bnWVYS0tJkZr!t8+_rvEnL9YL{g%auwd z0lZnPe(>tRdwxrP_HzT?vJYj!=s6{f7%0%Y4`p}_ z?2GjSb%2Fa`}cN84&_^X)`uaCRM5XYQCrGSaz(*Yr1@vJM;$-|x475U;GW$g{@vqo zxzmebjq?*oWw-?yR|>k-y{A}Xq()k}$a)LDm-TiXl7S``3E<$eSc;@znD($B3xOhU z{EaGP`cHA;uSuLR;djPJBGhln%%p{U)}5!ovHT~%8n}W275FCCyOyNg4J&-AIb(y} z+wrHJ*4RG9zF&*B4xumvxdq-p2_6rYjgx&;?{~qJ1>wC6U=Uis<2x0AHw7zl?W5F{ z^*@K!721EC^O1y>pLuQ7FVo&;N846WA?f$~0#tH0R_DCmmYP3aUEJNC&2DmI>{X;c z7(e|o?^YJ*6$G{0p;K(KxLPhB1#-DP_`-#q6*Ntl7Qmj~hBk8*Kpf^W<)-78j)oxd z7aN-|+=GqU|9{OA>U_#F2_E1`y%lR7-Bx^i?{>#um6_-bkfBFDmdmtTl*a^&6v0x( z7BwB+H#oY#HoNXUrav_T%mYw+bRlQlR3|F+y0)6UnZU`jmUgPU%w=30tdEx)5s5+4 z-5vp>XcX)DuFkyH=Gu@9iGCU>9?hWc?LS!Q>1~06Wov|GE2>?s?o9#r@^$x+A*MU^ zI*@Kd;IN|KWzgLyetZAB7=PpC+O@SfDCXAWiiL*E9?CktZf62!0Rin+V5DjI+vFYT7o^()F%`kw92RryCs9u>MbMuDG_V{M`PFn>=3Dp4c7IaT=Z z|M7bKeZ*psgIjSgY<{}V>2PDCUKJ_I#1E7FwbA*Mh-@B5zAsS~=!uAjXsvkV8hb$7 zJ|x4OYCZsMiOlQAwx>{Q!A#t{l_CHX3arH&vfyj5>MzAPb0XnhAAT0hoc}H3#(R+7 zdgo{8YC87#RH$^b?8WL37@OOWV7K|G8XS*qoffO8gTvMiwI0O~$;+8wir(n7qBmLkq{Ja;ulg~djsBqSc! zyv>-$SSbqJ6Lqiha1P7<= z)nJTfGWElyH124KDeKOib|& ziia`r?MImsmF^bj@unY4r*}eB(#KU8Tcp5F_6E(~iHL{@v5Ynscz)kWO-T-ycdtJx z8{JARs$r{k$S!TStMJ$Se8}xm=B$3-bg-XFvg(PA5j|MnsKO8u30x=DIkCN_YKTfa zp0~0@-->72mplB1`hA<>bexPUGhS_{8wEaz@$HL<}ndwA-biWFK4~kOn94MKrm< z?wy7dcJ$vZH5mrtk(#(JRF~fm$Y`72C;>cn0pe3j-ZmI_5r@a4kb}y45BX#9(ZFss zCn99`FP@-;V0@)A#-1P?q@<)QEK2N_&q~}}TygAmjL^Qo{Qjo50KjKSq5Fi1O@b#Y zA}pK@ONm9LujFN5ke8a88Y>U^=orkdhXz;x8IAV~>CQ0$e#$wyxffbVg~pWLoZU#U zyj175&d#jUUPjG%zjV5*!n5Jv;I6K&J|HaXL(pKD1(wA0v&aSNm9k^Jq)yeSR~r=q zjK(Jv=(j7Eh&bos%-gNwjW@_iygGclhQH7cW?WZc`yk7Z`#(%Khwe_1knU~-1eEUX?(URs z>FyS!ySpW&L0Y==x4r#7&+YThJ9GYU<_z0)_Fns1SA1gOLbrbW=v$R?uFfEe=1Pkz zhBJ)mvG{^EEn>8ymr{)w#qc zgWjKrz9|k+8Lj1yiGqW#Ee;`5`~4+$Vq}p(YBKrYq<;=Ul_ZMALCh+v`IK1`dVTjz zta~QJxMFO&cjtK_gwC*-tzw?->0^qUMF2yPB%1goPNM^Eg^eSGy{ckEw%JPRIcHYk z@tGA1VvzvguA6NN5N9DEA$8q0g9Tq@-Q7~4O|#&Om2yR(E9T;0l#1uM54j%i;H7 zmB9CdE=b&JOt>GM05)Nlhxg?;XP$6+bq@6Qn3;0zjKqkU75iYmFNTH--TZN4Dy7~V z2zV4?NgMf(*kX(V)+0PW>&ElVc#+e`|K$FQ8C^~O>wu0M8;Je>dfs+8I^-IcVa_!5 z-lWxMro;O*`CFh!Jd}Z#U3~5*Z|qcs=kQloh|SdUVzHtpojT9pnrCl^*Xl-)$e(H3o@ z;!s5ow$6{*Wa3_YQ0+57HV#;{(C}{fbrCFC)Rfa9P_}wixDKRQ+%-9|1pE@NOp%EJ z;`jTZx1>w?lqw|eE^EUpk@#gh_FprB1!{NBHFOg8{wj`PHj0;kA@loksr0)@LXd*F zI9G}q+kJm9g-=4_yLSM)JPSae0kWITWk;<}ps=uTC<;l)9+wfj=OjpO>gJ?J>=9sh zhESXV&^}QS5z@Len$*KWfSB0T+VC57i-09vZ-$(pPwP@p4fHUw6SWlW)i}98Y{`b@#M*Lc|mdj33Rr03ggu+Yj};vR_s7?2S&h`FHUlq;75 z?(H9$-OVCKzc6M45aol}V$-pda{%B9kU~}ZsUoOyo3jOdiRG-ZCoKUlF@RFVsME#; z#T!8|jEUuWeVFukP;B%*O4VU3P2~0EnNh3h3_$DSP@g9@~1Ft4e`nVEaY1)rn%jEyY9v-bc{^h#l$&G{VU_ToRLiFt$ z@jw3WT`UklLwh*9Cs&y|IBrm|5UeM0xE!u6LXaGf0LSy?0S|5*j(`Xo4Ic{w8f6I> z+K=`~i}vwib7RSTNTAOH0E6dn;$L+Hns0aHdcAf?Wm#zfB`wD(tECm$h%b|~ z@M4=%Vs+NZ}DlSrBjq|*K|tkH3OvBZE#Q@i!YY|!cF&CQfS=p!GD8&mH$W;3j= zxu?BC_p zZ_td;&iv?S{pm7|4kEfThkwc(Ab)9qB6Qeg<9BrRtGRjAGfh-$epc z4b<$KR~A3y4-fK6R|gw6xx|(#X1auWAzYs1=%9MLH1Buv<7BFq3 z3bdRqz!fq?dj;_}qvnwCwFv@Pygb>~kW3w~j`lJG38~$&)HZYLleA1UlP^nysIC-z zl3T2|P_TlWlDbixWGs)em3Y1`m^skZMIX}1EzSVEFA(y4kW;8jC9e@^%ZaXi!SgBMxQ)@iB5fAga1*jbWzU-~mKN?0_LT&)Yx(eXK ztd;@Tw=-&dGfSdX2E>J6*|pRiPS@H2pL1B9%}$qJ_&q~;NSK!ZCVGfvpUALFp;#_6 zTxvdyDqwp9FgeG;Z1Q>LSzZTNEC8Yu^+_K1szEsINbU7>DihYx(EaR)F0=w(mrSllQ zLPJ9l8Lg~v(NOyA(rRl)x^y1)vVEB>3HcTa-Y0Obdnqalv8K|Rj%$*vNbk8*%tTgFnPssI#cZcIKKVWFT4 zI1Eak&eAnJwj**3$gW?AoXkI^&W@281Hev?m+F%4XXckOCwOx+IpU!O<++8e%!R=8 zSDwxnngCSu&HgkbrzmC@czhE>7ZGqm2>_g!1mzGUJO{wg`B=7%hl1tY7j?yC^DJ7` z;%phphW9tG;jkh0FnZ?FH(SZJzqIO01~k%ax`O(rWoo-&7B(qTYdEorJJq>3&HATz z{faN+r7a_W3fkZO{j;-=Vx86NTn;yWwS0XmD?aYteBNGsUh+CT_*g`RZM0U#vZjDW zcTI|ZbZy>@s;crQytM7FkS{|rjQPD zEOe8;r398`vdKNT7iXkGIqTH963(cVi+BUl4&~ji!LP)uhH68zl5lQrOf8dcZ}*b5PkQ~h zS-vms+*WY&v3daIB@ia~g1l_VHb`WEDlRfS9K8Xlq_U1Zv)`y#+7KWi#M&5xxI`Uc zExhRZe=aVn1u6PT(8~aJm^IKfXG*V3NaX(Ty`PU1azyPP#-_- zbSYz_CzW~Alc)?TAcR6h$Kb*vY(PGaGInBeW6yR~?f+T3v?`Qkpm zHEhl;qk}f1kpu|tvMHqDcyfw67ZMOkdpoSr(_-jH;`vZulF=G=mk$dZ%e=(*sxW*(xcsLwn zVESh_OK?uQZxwqJIqEo$eYW7dVpKxg=1|0o8{i=hi!<}fGEX^W)3wZMAj9+Jycn-*qzLN?L`sX*i3$6pkNUw5%9@y3PFl)><^?G z1L!Z!K(90VzOW_#>S=xOs#0yzMe)-p^aYXV0 zH&})mjSRVzeJc4fmhDP2bwsHFPwy|B?LLw|_B9VPNRjtl7Ve8!&PG6M{o~e&-4%Nk&r&}JN`6kADO&cACkF$MLa_uG&RcV@Dizb zd))Wtv!N-K=ko9cNA+mt; zd=JzW>Cn0vcvT-)F_75eBGHN*JZ?oW>KQ62B-q2plR$xXx{8(OSgznoCK)^K$l1EH zeIDRd$#@ao81I*zZ3MPfO^pK@EcAzY2$*V89M^|)fjA6143Rr?s=C39Oqh0e(B&;c z=v29j2%G46xKGIE{;FK>4y-qXbR8D9DQdeKG!<7k^bWBc$*gJQCYYD+yR}qT zS-g~pzlh|PKFrggFcL+nRx`^xbx}yipa&#m{BYJA6hhV9VEsqoH5S6aYi?lO$IJC} zH%34V1vC_bHV*Wn;W*Cb*;bpNGrsnIoj1cKp3lwAb*l}4g;cmY1B2;dyZAu*p`I7R z8Tn0~? zy!!Z7lyyE?5Iq373;G%_=G>08JD+_8DR*ew#*YBBlKK&*(V#6ofVZqERZlaV1b?j@ zwbNLuXBN6-Qo+QYwfh(T+LYUlAMaf2X$RfM9~P3SO<3vmIuD$=84!_5_HPkqsR0Ob z*oxD~xei4i+uN34<^Q&){hFarkwpowLc_x(&u{z2fj*03vl4r$K)RWNd-Cc}((BhU zF>x;5UU~JWxadiRP~*AA@=5!(nLKA92lEoMRB5|aQ-I|gzIP%z0lB$ky3W#PmOu-*w>fD&w4Yv1X zKR+g?0g^>0Av7hT27M@KiZKF@Rp}QZfSg$k`FYL;F_i<_Mi2ML70C=Un4c0tJZ--v z7ISptG<+o$1Jk*Y+yx|##J3xsLySI4vV#SiVx4(_kdT7Z;Jb+sIu4@gHzKpa#7x;D z>fWKbz!2|;AqBd@4WYekQ^yu9XMS!8!CCN@lRKA^heRursD zM^3c)3)RTycGdN601}LAqqmbl-UDFNo_E8NY#gB3q=>{wfH%pAS`H}6u5h2*fw)Og zn(<&VPBxoSAW1ZT(O@(h)XgJ`&NRbkg9PvCl(m3T@O_sL)EN{sc#iTfps|@bOO~XT zT}Jz#xr-l}|K-BO$QUq0Q;}$oy^k?W(D7z{!W;pnkmHIw*-dtfHDC^MIy@Y12DayW z8fVHMi|mA$(WdZ*17AnT<#*3=h?h35CjYXwFRcrH zRU~aIH234j&&3G^FwZ2GT>Gc}#8l@cIWN9ClcS9cURQT<`iy5@Jnqc*>o0&L7XdaP zy`UyUdXnZ3>x3qVxIDb99Is0`yqwT?j7p9jUT2X8(1UEIguLril9=QA%8z2jjKRYq zYjO{Sq!kBt096Q41OnKVw^X+KqjuB5cXZ!Bv4xdXPq`bz!98grdJxj~3?hSE#ltb< zknMt zL2FwEJJPNqnCX1(EQE{D*y=LkkjwmSIGgaGK}U6%rVV5SNs&}YWzf5JDG{mo)U=Q? zZyFUqc4xWNO1CbLcGdvj3|0d-0Fs6vNDNW%gIgW>nv*{SG=Tqa++2^6*nnc#LJ5OG z`vQh!OoKA61MEc-XeZgb&-uK4LVkzgIXh}*O<>#1pG_E9W&=))w3GDblNIOY625l^ z*p(r}Nx27(RqzIuy}Pn(`{@6L@=VQgqs!kQ165vM?^W*&LG((+$)|RVqHYP6+dcS6 z541%n+d>-ON4OKDU$`jr&=`DLK`TfkUVI>7P(xm9LBBFHBOh`P3Mxt5=O2tV8*b5I z5(=wpywXk<^BxE5L3#FGM}1VIv!p;@G)w?312ykuut2pg{^p2zTqDctrI+m}g6Pl8 z*9<-Eb42nzi*(>vw;L4P)O8fi|}MqYJ}qi%)CR<3bK16lE&gYq|U*rF$rips(#K9Sx;Av3rLF zh8C@I$rxu~G3{u{G2o0PrxW{B^w_E$g3YLa0BxaKQBChcx3ha;9kC&_+F`F6Wc^Vm zFY_ln-)EUH#BhZVvxT_OW?1o77?AiA6FtbtU}x0qZ6TXs2*X$`RNqwDu_9*90x_;5 z-GwMLXb`%@<>vUF5{*Gu#z+-^q1{*6nHs%J)kTy&aHvG-uUiIp~muk>WkhxB88#kxKUNXdKzB zzmkvq6uLv>qVLTo6b)daTuWQ1D1S3sT*TnsWitAcEjKe|WA%AX4Jxz$X z^n|smPd-|7FkE}`FNi5D*&P2j9#4_U0g$G51UYxN+o$C|c=tD7?jjP*C}|(2Q?f(J zZUU?@UZD~im|EJW6yc_%d~QZ-p4<_>)9T89^W(s=&3YY7Q_tJER3>O`E#g{gJ2$Y+ zAg6hFKK>Fjipii$?+d@g6+N2%m3|3+cyhGUa8|XyuvVO|YZGT;S}Ho@;pJ-6G1&B5 z6T-dov#*CMU?*p6>48MYy?@Z-W4z3_z8N#e8lx-a(3akLvaooUqQls(SZ1d_y$wM6 zJ5tz17NbGYs1f?TbE{|O{xlRF)hjIk%V)P=PZE>hp9y2++p2uQ;U8!-ykt z2<>!}_9Een1w}vOF}mj4uW+Klbf1-d^>O~^#AXb@rBuBa^yy_W`AI6mNlE#n4Zek` zQy6-M!Ud=s1YX#v@Xlj4q=c9hFUoBMN@CjOEzs+Ipw5!WY2jN_@KpqMnIU?gOg918 z9jO`8)2B`F-)e5Xs*M1Fn%bkWf_EIoy5lFC=SP!6En&+OqSaFQAVZPyzYy?JJw3@sK(k%}3$!I0eI zd^93!9#+RQYa*%MtW#6&6AlL(9}3D@di?3n`uc))^Bm@B9l~a&)h^zl1s)wOSIkI+ zqfu7!xWtQL1ZH-pMPYH-gY3I812ERoP)b%yhs*mB5|NNQUGI)xdQERaC8-Zk?%1kl zrEz&WD|d40aCotL*LNguiPpW99`}p8KVjRZ#RziA*GlOz_w9B#zBU}+wyTEf+Z)f| zLki0UJ<#K;H#@$CHnVgyX=yGV1#kFEnZc zKv5FThBWQB?Aw6deJzhq9;(V2v1{2{Q65p9MqQI4s;DGfb^uOS62N>9BE=J>!IAWT z8*0=OGRitJ9qdz(S>1lQH8HN3G%XVQ}a%yT+lykxO;Dq9V07q$_kQPVZMbV$dL(6rgNff zD)vR74Xk8;Tzoi5+?IcgDmd1j4Y7#yS|KAFq!?*7!HZk!^!3Gsy9@jQIw^-EiK&C? zqhbpnfeSc@xEo4~N~zDMe_7J_zsYm&Xx+I};~%7K%4oRANEKy;CorHpe3GC&56+jSHe+a73kkyq!$GdTa^h zvqEL&G+IPvMt92upa_d9`LsGY1y`Ap=~M{G4a%cdZxm7Wz|1m73(%ewO~=P{kWS3c z&<5yHqeaJ{C1<*Yq}H37xVU*svPTq;jXI!VM2vE>@Y$E8Ovm@ z@xo(r39~H}c@V=6N&>`=iuD%}wZ1EdQuTNf^lx-UPmSfZEe?>AHd%q2CcgiXqR*v) zHcz;csLTZ8-jc?m3mk+JX4)0bzvVD^r=ZTG1Gs!JzB(EEY4-{ro=((M5!SKM|8Vfo zz}DVZ7v{z-)F00TX69$qiv&|gzctk=NOe+#qH7Tgt-W1G=4Tuz-afMHQ*a5uZP+xp z{L%nQnJ`0kV<}{}_3bwy@uVSN-YB4Rnl=-hGr@BMLU&3CgK7rHBfj$dNtO8(U$`+&mKpOd@sD_3hF{j-%~oa zO_8#H01*3o38JbV3Cyr6h8D)unl%M)Z0L|{!sny?&a^p;(uy#dtP`D8jT^0(UlM4H zA~(>GWL!RY%^T^$g2E2UyNIm-Hi%X7om=DOW5}0J<6l!m%VYwp6dCf3EaxwV-IW;> z9s7Z@`UlF@^+iHzkDvU*mHZ3t+#?;9sWP+i%o20I{p@{bdojIV*yb}2GFq_$dB=zh za@I%MPnnEqGl~O04>l8MD!5^Ox|tO-gL?=aL1lSEn}PMXE8eZOx!3toQSv=)6ABBS z%bP)U0F^In+YdYHB)PPrh+JMV8NZd!C9@*0{hf0_yC>9kEq?3DF2oL9!W$%rF4@ zBM5pWv4#aO|MV=UI>N3anMJ8Z(O*6T`rM(vOS&+HvKq3|*Nag`ro^vxakAGGiw5e2 z_z{iUn;H>jD5dlD6@Gp&IG)Tz(_udNA(;VfYU=jzxz6?wWLEnPdQ>d^95CdYb08}G zJ#5*Nk^iXOHWa2He`Gf%KFN0A^M!?_($22<+4NY5PFM8(HmtnzUXyid`H{~%DX&Sdc*mFm+AcZV2bUdm0e?u zSpP5yr8|L{Puh1c{rM6>lriqct=7uRPBnj*=!w=gi;Ek^2Vc{YP+Cp5D(QUl>?eDp zlfrtzV;we|>i|Yon^YgO*NnRC_R9~$BF2eSg~;AFKL@mved;#5PT#LSzbt(!SuF2d zw|6_CDw&+hF@EoeJjzwj!iFnRW?Z2zz&-A_at}ZxoNkX535rj$SxuOSNZBqs)+e4g zOzdYh7>t?uVHAc|KQ*XbjQ%VO7j5xwbDW2-=sA|h87{`mlP$XxXXZBsO}0{o_+zPF zPZ&L*GhO+)ye;#&i0hyjBW*Xe1aAQ(T-0E~pviYx`k?RT$YJwprrPj1ZIHN;z?rRT zHO|CBJc+Kt07&IVu+3G{8~Loy7;p0I+lXS+CYi*TVy}-DdgGdbc^QxaggVh+hAIvE zg&cT7fxR&jK+*oL%99yl9;RIX@n8`Y>8{^Be71iY9#nc!wF+zvP9z#5oW>|jXW2|6x2fpC#= z26L&&c-rPq$RU@MWlh_52!LZq%;P1RH#5wNYeMV-h?be3o#CZCox1o;1!QoTjmMtVTcK5b>3GeX? z7*|SKzI*o$t{eO;7M9^uUA_V?FWyhZ=gyej z%EgsyX=jXZn54!nC42odJ6y?8Ap|OovCMT!JyD2rSBmYbkW%~tuu6!YKNBdwO1LJj zRscwZy! z646o^X%;pJm=OQfG|R%+Tfrz4p@+z_6W~w^jFB?{JVC@0&z)MTf{8hzANCZfLQ*kz2h)=*i$QsMXA zo3t%{-?%3 zIURw+NRAKhz~sgyHd->6#-^Z}6ho;sN@gSSQ_Kt9Z9$|qG*?4cnW5LEukXXoCL53iXSAW-_0lR9{3beK|oo%2O8>8Wx^RPS{2Zq2`&>7IDfog;vHA z$Kg3eN^|~cc77(B5gGc1eCrv-{k^f;Y-Uht8^*FN1zuH7O2k($ZpD=mJNdvERuQFb zpMWm0#UQtL^`?`=E9hw7Av)>Fct$n(iSIY8k-qtbx@^G&ud`@nowN2aAnGTc^?)yK z!IInb=P_pTO7FdTv)T6ZEXcf4v$bKR4^WvP;CN=7hD)Y<=rqS70swp`bT=<9Ddm~w znrcUI5@qVYm=3>LL?*z z8Vs1AyC#ooTCLAy+ITMDh3K}y+n@CGayFF>xq$;OB#<}}u1&m(9@-qz_nlG+su;Gh`>0iBY^neX<3$Tox1p7qmFZig9 zSeo{bY^x3BQiOTn<2W11XjQm2C4|tAo!7U?$bt10WHs9=Gmh&>kMQ>{k~;$tBb)b5 zRf(;-M8=>$-huv+vcF9enA>uV<8>f*0iq45H~eq58!lLkSc3@}xk@&2X07B>faf@b zzwVphMP+Y%tTP2bF{GfXk-L@v6G{e)4DOiI{^^l0R1wdT1mrq}9i`2l%s4?S_6&J`-z+dWa{{4^di8|n3H_=swqzPa`;&FEx+jv*4WT?jDWKwJKrs>315NgoN@eL zWD7s2iZ`g90^EFlRwISq@O(ULRa}?=YDA{;09pVXGqdN7m0KR!J}ZczFI6L*!&;-w zjd@23>S2gS@uzGpHn<^ile%T{0XG5EYj?99pqtoFY6nLv(p9`?Hq&Z*(s-o%2%sKD2=M_9#ZovJ=!cjZ8DCfrSsn(p?2wA%o)JLhs0H&+nYFkz z-OKYqs`>)0lB@_^|NlPzV=|=790E5ZkaKt1qkuk9FeUeUaE){sld=BC3od8WP~@#C z5yDTfjDmeaLScJA%0}^B)FcCK5CD_{gn9ruBKqXi$1mwcmd-XL@eePK0Uoy{xk)+i z(NUuc?D21*Ck2eKb|+nDh}`_nRz)3oXYQhG^c=9vIgS7T^^uubx18r7K&eLrK8w~{ zX_;RCn}*VL0>!2!GjhHv(Q0T4`!`dB8qN&LujsMPUI#S5c#iNFJrNAPfYpDI?pB$? z?rjzs2ty?*{C}9^$D*XW84pk*3$>A*`cBVpg$TrZ5&ypQfea}b3-zYXcUHrp)ZXT> zbyjZK|1u+g|3hdQoe2qJ5NwKC#Sh{eJlDS>1HZ#U7SvW%XnBk4$m#aR0I37*e@7bs z$krDS`S%Ul1C%_a=Z}6W;2){q3elNQ{gFib^Hhd}pterM$|Sb6`c#v8|AW~0vw#9B z{}jYr?kv99TtgjsNx@sw+7t!UoYyc2m=FJXsKC?pccR+ZJKR5t-ytLG*e1Xko_*%0 z3`Bw1e4OYe{Zi}B-^~#tK~>w3f|hAl`F%G?%fYDgisSvOxF`6cE^$zxQS|R1TVqtue1NMN1Bn z^_w=U!KW(^urEK7tta9T9*)qfFmw?DB zcygi-$PiM~tEP(Hp40xdr-3oAfgB(d+!zkN%MrgiqUbkaLpO2%FPl$@2el;r2Ua(y ztP@i1{oOanPp&FSnD-ZlU(I35_~&vy&`eL|cxw~N1r3y>8T@a!qo;_)#UODM_J+vS zEc8mQPxiL>=rUtPi;VQ#{)6^e%L;=dLQAf(2-vXKVV^jjfnU!F%Qrd6bC!3QwQgfnXysB!xPD6FrP9R zG%S3Z^>@T21sC6#KRDY-fpUiH9q#RKm$tWtx2^-ULeu+uME<&6;Dhix$q)1t4F$rQ z_(|KBM*kB{AVj-Te0%dv-oC*JFL%`eH*)&_{Ir?~za_Qp<7n^s=&5j+O6UB4cs&1o zVL8ylc-_?ZhKb;uh3JVK1hHj|)c$6-*-Vl9Au_Y-#(=5|5xV)_+F0!JRdCT8Acq` z@HM!?L9}?F62#1R{60llyXKD;=${kNKR}3d)8XouB{QB0pwOaTt`ve!tVRl)wh*}3 z{}T@6yGjJ|e{Y1v^-uHPnOe#8-EChGm@Lm~vHrb_G^9{lF1p{xzqjXgI_h(3lc9{G zZ-m;`sj2<>6@P-;1{|zart~7OwAP25~CudSpka^FALDVd{RH#{v7lcbGEv5ekrW9M}=MK<2c)-MC4D zJbkNM@U1bl)AYDLB`klTCq}2W_Hia^HtuEu1HrB9yG@G*TtE?6rD2cgzdwN#ybdZp zA;Iu=AKI*1!rvrQ-RyVrF%(4g?|&r(5sk`(Fa-({d{kwe_A&Uv`IX&K5xr%U};(I{Y=L{zi?msS|1-e*7N*AOasnV;;B-&GGUn||BsxS@6k&>oavpRI=;?d8NB?`` z0Ka++jVXPi$7&1Fv0iahn)CfLA&D=)&FnrqK!KYzeG#zt5e-{h6Bf_Z%BWy7<_m^1 z(p$jgTZ4OLD+{@Q4UgBz;n4bdwi!UWyrP81f$5QyxjbwQv83f4=)DO z?m81fhpSbgRBGOqqqD79n@#$cM2zV@+c3y@;Z_eoc0x8Pro(V_OK+@4-%z~eZ-VuX zEd=@(zsYZhhLzz;P04C}_7;t!=F>=bQtqq$OT)p!?JgB?2vaUywL9TSp~@v4#&0Qd zO3hnc+!yByYW_-HE-=8a@m6o%TNBkyyrrtRe>jk;tM>}h$M748^cH6NK*dQ=td-Yhn|sl5XlV3|853I)bkrDs_kJd9 z)CwNjtWM2}HfV}o^N6NjUG>9Ay(vN43X;IJqK@+f-@k-ne+apa@A3I6a8M1jszt`! z_Dv11wOH~p#b>3m9ZWQ^Setp$|4|$MCl}c9gvjI7M9Vyt60-J%pu(TzeZaAUMVN}F z2lMh&XV&wFWT(O)*U1%A3~>P?E&p#Sx{?VMDP46#>_t6ztenT>LR7(9^HovW&&k2z zqUyB4sP==(e^rKngNOz=G#L4ha)dt*B(Qt~MV!P!d;<*;fzFi?K2D~-ia;Z$v0M?U zUH*sN9V^sLtx)P%FCnVY{OHz%<)TPwBi?WO=p=f#SzZU6szJhz7d)rj`+f!8K%h+oCcE(95h|oKzA;R!vm)E5L?1{#_V~f2{JG9+0*@ zc4~Ml4y>OJ<5@wN8pqd|7sP@v~ z6WP}0oU}Bg#Z*hgL6EkVlQ`dZ^dazTb!SOrjoh4n)ejP&=5-^7ja&!hZ<;!*o>Q`h zZ$7q5=}m{4@>Rt_g)3?_(pN20FO8uC&5jz=(Bp*bh0&W(&llLOvkiOc%E;c<@*a_76mQ+zg8h z58pcNuUL0QfEo=OwweP z9#_0OZAroXvVUm)0Cl7}yj~HLBx2ap0R)eVyGzX9d(sHY|E{U&XXmR2FZ0I*(kto2 zCQrA>%=!}HQBP-6R$sV}4ucQuX2tiAD8?P^+K8jOFD;v=R5TSD#V-kgI$!GOUQ--* z7dIV}%6WVdax0v5d}^&z)F)>X{VlT^6tZpk$AK<_RhLm zmB^TUxWA}WRbKTN*Q9F|!sGVBveNn`(MXS1+@@%kFp%sj?XLl2QJegIuOdE6S&~UC zq~Tk)rn_xfHD*rz5mkQXhgOiuao-r)L;W|Saksj^^lVQcAQT*&hp%&PmXiYVl>+@9 z7*lHxHtj7AruPv)8ko9$c<00`pzP;z=`v{-{!ayOhl9c8qgP!riB&dNF`e@@lI>!7 zZX5PCL>ttOMIz`RRBi8DRiRaGGcUJwcJlqvy&j)qd^veqBT2(KGc!|LOWTrN+M17= zhj!-}BhaQrQaEvfBNk7Z9Udk@P-=V{Qb?_7d3X`n;gk>!Bvcwa=@I9=l^#lew| z*GQb-F(T_cPvuWf$>cj$LvI!J;Q)?stzBE1*!QMT@{zxIf_kMTxMoSPSgsAvd3!cD z&`0O%`^*va?K2?2{o304RBsbVZ?5n|sv^}o3TcNd zKj!t|Yi2X({efPv+8j7 zYW_%G7bqr`hCYY2EsLC^bWeYilfa`k6SrUj!T!1x`KrQ`RvoJ`upTL zb61ut@97i3(=}?ijWjt!#^gsfv2$p5+a4mPZ8RJ4tM}UtCyNP*y>u#??E7cdDlIzK z^0x;Avx8w66onR0e}_(A zObXr}SQ;vS6p@)n?Be5pZfhCyHP};4pQzwVbvojZ4o|+cK9jDK&Mc=x7<}a`u+l`b z0vS5>rbGqP|5n)Yr+-6Ao)}uJ+K*rF97O@{^x3cLto%zte0=PL$i%y}bHLj9^&X3n z`R;l0)^@$k@Oha(9Y8-bNnNOFHQV`|SGr9>$yb-V zHNKVVSnm=e0l8P_o8%)sn=!lp!>V=~oTi zm%wr*PmduuZY&onr=Cy>eZe!cn0XZE_#TS4c!FB1E0ka0OsP=$1MI=Z#jQ)%4mp!Hw;@!=np%t>%@FdDuJg&r8g3JUKo`qa9o(Q)CJIK=mH$3pdu~96JeoCrgmSXt zVzzK2vo`^yS{gmJd@K0Cg=B51!F%Yj)0n>|G<@S+#J27xEA_q)4Oi>DnNv~*UZP3A zKfdlww6=ine6`r{1}%Hbjc=|;dx(QdyGC}JgW|yb?3-JgB|E!47cIt>A0;Y{!j%%^ zvAWQCWf%VX3*of_Fcnl4YZRU?#7m8I4-eNHWpnnMXZyI zWu0A@_QL8fSTCb5Xuue5lYe_LmE^2$y=QWrGbQWgGTTPT1*e>I#lwvxaqe5kTlYTg+D>EuGLk~zZ~U@J zLO^PIbU`~JN9$VCKV#NT-VSFXexY|bHAPvyG6HNzGH(Sb2j8m&^m>aw~%nF8!(gL{Vd#)R2O0T;;^+L02i!_ zd3a&5B*tX-R9i>;OmSO(=(8rFt+pV4u1&=D{d31#DL^kc0_3ii+Vq< z1$B*DOAl3XOI^@FZ*%E`@5@hK;gYbsETNab)i%7H3)XOY6U5`JH#k3sxVu#&-U=#H z5M$mk#x^Io&ruyqFP!L6Yd>>s6Os1ZOMk!YU@TMdt+9F?#}>3!yKAfLb20T&AF)d| zDBgcquapbC9W9^yjRoDGgRw46>GoD%E3^4G(+@0N6X9s`5%en_94ByWI~?fV$zf#) zc$m$O82ifI+i%TWD{v@tf7efC`9A5I?TMa7EjMRABSMJ%`oM}V^rccw{l2&6+&~{0 zNclcnzgB&6p3LNnCV+9I_PJdPGH3W9STRyR5ZBIY%=ak_kuvnw`|4$rm0r_tFOO<|1} zjh5o-c#tzRzHDw?zU9f~$&JNO-rJ~_9j{ZaO2sDCJu^#+Z=&&tuu@-oOAQ}gx08Fz zpdAHMSyWpCNmx=h#)Apq%ko9uAZ~)DE}A<9E(eCddnF3L6!$-t&sFgk);rrGa2pdA zr*)`ql4pb5nOTm@+<+GV_DjXBj3{jTqkV{pqRow-H#TEtOV-zL0fGne0>>tO$yt|} zYgAtX9I}kcr=@8Z?=L@G10OP^1*qWCnz_CQOuudy%VDbZR-KtDT+r+$eW-|SYkT$Y zUi#j|=DFDu3~++Ok9SsIP^C0KLe0rr^6g5&&KK&CInfO+xW9nao-RV1Tj( zX484n0h3AY;E%5B-l0`LzM0qAthQ+3iDsQ#oir!9<5R%O|L&z}K$zxZM4?S-gz_#g zy4gLSb!z&Y3B}En>gs;YMo%=e?k@=XkuG?5+t<^(ETU<(jRUs3UK32<4b(g=@?avl zYz9bqV%%cA`$ut1HLe*=WN3p26h*iL`HwE!@Xgq9oxRoDGT8EJZ`~wa@4F1{=9B7R z8r#K|%7Wc9#*d%g|DsVv*}3GmHxmSbLmjemShd}5O3Ea`2Q0&pUElorvAyPbbi^%_ z)M<}|u$mOHmn$GTYPs0*VGa;&vrM)e@mU>l-xRvAO@gUaU4DYj;M#Ir! z!8l~tC=6bSTgt@F zqPl|ymjM63DcL0bazc1NJh9|AM% z%w(I@>qQi#_(a0zs)uz;)O#JSpJbu3y@JAkULC&9NKtk~Q7|LEahh zEVq8xk3cW?PR=v9qauy|p&y2l8&xAs8FFIY1(?ZpS=!#Q(t17=BTT8yo-fRvrkR*= zHY;59mmpC!5ao}Hn<&bdoARc&6ftr^y}u`N{;i>YOHSBQUiu56FNg$_@7#<`Dt)fY1wS_09gw5u z7zY4ddQK7YUXU(7kLhcY_Lt-TN7Xq8*V(UMKeij&X`F_Q?Z$Rv+qRR&YTVd18>6vp zJB|6??em=TJMT;;vnPKfclQ2rUF-U+Ot#;)i_%eVz)aJS0FlH1LN0X;jeHjC4N8m@ z{CbtD3T=p7PrC_W!W0Wel_rp|*%bru;~YS@((G$K4Z$+mA93ySg&-R#y_mc&L2Hp3 zU8lQ-cyTkn!e_?U$0lqAO0uB((pw9C!=G)TS8gZb$K}+&;#Vxrhz6^V$e%ZHNp6-U zdN-iiSCg9j?jURvizV(8cBp`wla2jQTJTjD2RxutMcX<%Wy9^f;ypYpBoXTZ`S^Y! zp5N8x0ouT6rtwT^Fr&8rhYNzHQ|v;Vo|ZukD$n}++W^d~7!+CwZB^In1HC*M)Lp2k zrLq;<12H9mfJnE>n?*ouR$KuD2f{4BqP+iJX#X)`pbpl_?iToAfqID_GUeOxma!ss ztURP9RlY83o9ifLT{?%5bid>BLUtI)>*=Ly*=!|MUgpyrHV%)U@Yi6cNC%^g?v5ZV zuEr2VPPRahOd+(rffC8UW47G~g+8(!6g)x~yi3xkr!lP^Fy8fIID<-8Tg@sS0xgB& zN<8p$XaR3A_ZTdwE}o|k=0uK13x%Kzhh5T`o4lmK17#qu_rLWSx9HGcZ1?HQVo4`= zs%H}9x|YubUz|W%IblYf`<~H59q!Jmd=lBOG---9pS9=-P zOM83K_5KF5ApouKHpXxdz0jFlM3yeV&pah0U|{Mk=1QF{XS&9`Vg)KcY}Wp|mF@=p zqsvKjr$Q|!2KSDyCD{&AoM*Rxki(Kw%lC1)wX=6{7VC-bTZF(1)pueE;Rn>~I5cTs zov#h|L$ga6&uTP2gS!bx?1Q-#)r6fRL;qCpje76AUx7$4RD};Onekf(PIPbFhAif- zhOA&#XO(nQ@Qjb56vxO_zYICOgl!lugHmU}=N*hv%}G4 z=)%i_J{HP}XkJ7j14fH9ARiiW8`qjz(7tBAm_$$zwbs|9g;8 zz2KTqLdjxR>RbJZ0cR0R-$HK{$qM+7>H?WQRp|jVRIh@`2bx9H^|I+mG9$O2$}<;9 z($GnszS{^2*#)FFLIS!Q_1BE~58VXtUE352Hr^JkgvP}mS8KMi8N9QTSeFie9CZIQ zoA2+(2K2~c|tBAVaeQ|b{oKQ`4bH(=1W z;0%@&#&jQCV3mtlwOJI|)TtVjwGn)tZS-3ufJqqKw!gpex_{PVVpLhE6fHK%f3C~Z zYCd3w8E7(3B20$xf1| zboXcI`3#);12rp480@ z+Cn#?R#|x56MHNHO5#v-mpGn$wwyzM=et9&Mvb5@Reh9=tvcX`$;CINwji`4ho4PiNHh+kviDlr_E&=At?lhItPQU1vCFyB*ZxLDN3lNFSbPm zp;iYA9`3W^H{t;o^$P|R6#F&2HAf=lA=t<-Eo|ld`Ia9?rOeh_^ec>%+>6DDP{SJN zXU&(vq&`V8WFp4V8hBeQw^rMK09&{}9X7Xd*9EY`wsqg6T8RB*)y zcggL$RSXowMU>?5=VejJy`r(wc;y%;J>eiNOiIV@fa;uYnP91&tHpm94+RhDio^gj z8xr@w+)C`X13GS$K}FgKja&xiDo^^$)9o`Xo|<`cRI;bOmuq3mJ}{nmvja>$ zZ%94f;WywbbVUtWO|~X)JpsH!4FB7rqO9p@*F8XiIVruY z7C>$GdSq6VwcY6Sp2*_me}8ebtA5)t_y6&8_@4sRAq+9tGB!lC9J3qOrJ(deb8qMX z@~d(-LCA0fu;t#NH9Or!75mGF#nx)5+|%lUO?{iZ#$B7ie9EK=C3!->eiT|)+=H20 z?KslI7b?V`>I$VPt8X?;iqkl8Cu7DB9b%xzp^5#r^YF&|v1G0|d>)bg zI_N7LQ~lK_vk*FI7nAOlpC7Fdi$PffDI>dB!VB8+v10!N4H~v0f0@QdA{-_pcr1FF z;DJv$+HkbWRRxxyThq)u`O~V_JpvIS!84R3XN*v3b|=Yq=%;XVmZfME6Gzv@VSyPc zxE&o>@Wa7z%i9YVeBzc8Y5}GKEt^G9$l}`V>~LC$VmLGtwU|{SfuK5C?lfeS%jhC8 z;#|Y^1qLn_+vU0>j=ns`<3pw%+epyYWOBGHPX`n0w!bA74nks7kEl1T?jve>pf(Kp zr#1m?K|rO0EY?uO2hlHa$-=6&3i*7V>2Y_8gNjP> zJ6I63)lb_)_OEbeMHSm1IN5k_Ib7E}YcrsPo)i5=9gt*WWgrq|mmA*UUqg?3#9;SpIV zYqqNi%V-I1gX$y}N;*RH-SUbcqoWUz}Goru(D|nK;zXR>-F2 zs4&o?L=|%Hj=op`F~uWsn}DGK6!d)EegyF6guOZzj|GJ28qI$SoT z45D_1;R=k)pJ#crOr9o2elT{upglP#D=P~L^#IAN0OG2`@)dZoGZ>T7gUt5;f=O;e+(aM-SEXZEDNKkUQ+;Dk(GPj*&T){h^H0TPz;@$Au5p7>Nf_wLA2 zx&QG>W10hz;_?8fK0{))t`|UP@@S*k6c~!f{dvW#sbQDCzJ4=As3IYV zVzb>Av+;;>nW}ZSALv|J`r~1qW;fTLMjQaW6XOgP)gOUTrq|`u;c;7yW-PXKT?+(qi9aqdBfi_)KB7*nv6tmCXOfssi!$ zXTOP7tbk5N>0EKz{Lj(RM0M~OD(H@H-RdZO2ZtOX{%x-awLji22h~Xh|$s%J_FK$JLauOVNm972olxLenYd3e}YFSooC% zFq1H$YAn<9%Xd{r={{G}po<;~BNbm{v=l7K>^fIiz^{T(UQU{8+(a?Msy1+#EqC~a zA+{GIm?N7M$Cjtr;t6(2LZ*&}-+K9;WeISr0wQjcy$O*XK@7NR-8dtQ-B4Ncs0vLS`@nsiR)xhXMT}bq(|hx#(ePd zKwtfGGkloxeqYj9sS_#RA?NJtQjfULxl(yLk*eczaRp^R@sP_pp)mH#k6NH;#&I(x zcNu>YIm$PG)f>k~gpBg(=_qW+mynCqP%hUBHb$1nYo9)>5hVwR(hey^IplIZU!}@& z6I!9WBMhn!MT2RpYQKhqFgw%8L;Q*RbP-2ZsC9B&12lO7QQ6)AuLzm{e=i>T%A zo12%TqHJQup0mTLJYd!-ziAo*BQx9kE-f*ql?xK13K*j(%__tG;Lw{tE;JhIMoVm|po+Fb&+UN#Q|5x1)2Zn-b~1BHV&PYQ$16ENP9@ju(GHrqc4 zrZ)=K)EU(en2aTVp2sQ-RNe%hB2YvfTWi2LST@2F7A0kF3CN<>|7lhgzy(QMd<{fm zr@cO6&%@Get338T06WlC!~_G8_svuoD%q}{NBIZxR~TfDS50|LG=v>+SEOH+AM%Q5 z>`xV!J9|{b4e0bb@qe_xqzYs%H`|k)0{^w0(TMN}fqHVO;6KwP5+VwW6^hKA=@e0P z_!nIcA6|lOjv(A*TJA{e-$RZ3bP;>TycF3;SF+e^5Wfp{g65EHS((pcPYV%0VQ^1l zX6yP!0XKqC!e{%*d}_6F1?hvR-X!1gI3fEG#9MhOr?;@Tr8G2)(lO`AzUHEsRK5;N zwml_rWJ!1lF}jfUEPlsntCo3jD>nNzY&*>7A!}L5eRx!qmV5;R7lcwsLwwh#lKQhF z6S)W6GdDMn=*$Lz6tF${h>>tcGK(3}ekE50Co;8^#k$be?|!U@FiO%RVi3!m!k*T}^zmI6LQX%0)&(P%pbM9wf9y=>z}uN;l!3yFW!U z?(VeeI$W&+QLndWz;%m5=H%cawZL(!(ShlHFw9{?A~)Aw`2>j5~&r2^>`fF7t&##eTiTeOpl zloXec=UmPhHa;o#M@~@4M&)165d;?zD5LKF18A&KG6tf{XPN!rVw!E8G1@yi?Ae)^ zZmD#N0}f4s<}C40@lGJ(PPuM1TJ#Z63{g)JmOu7!xj!Avsw0cclc{RDTOfX1a|lZ{ zXppT(;##SZHeY~SxC`Uu0UpD?;z_&R&EA=jAP|SmVisUB)~o!rVhiY!e^uQL#o;x_r8DR&^kf#)W0-=V`Us{qzRm;nxOX{b;6-&eDRirBD^-_r~1z7`iE;Q_X zT%7wZjyP~ox#8r<>kpxK!gB#N2VJ)-Z#o4$`ozu`tKl0xeydBnx(R*Z;))LO*vqp` zv5fp)E$^Kb>2^|hZ|+v_gpaj382y0B8=j_870GyqZ?QH1mxJnasZj&9A%A>1!SQJf zQ5P+&?+Wj{65QA~K}`X1jItABS6DK{Qh7-cT~;(K!>5R?K%yFxFWrbFwqrlsKL?9U zH^WU6%zEJ{Rt(_uOz)Kkk?b57qa!xz(VgP8INd4p*bnEkxr;KR+!6?CRW``DCnKMV zhTqA8AO$KZVvw1+zD@8OUCMoV@wu_1c0atL>aPaoiu2-glkI@~`*#*$t#7s)VMX)F z-Hm@sBM!WVHEf;t{LoiF+i2RndkMz4r3Pkcv3fZ2X3XMrw*idGfT;o9_q z#G4)6Q4pw^lNAM&nLO;BC&3@Q-wTy0<_24tH*a#a*(_zNyZF>X?<9&} zmu47hmNy7_R3pp)4UnI7J3Is}X6KogKYjW%L|Sokk}DiaIspO)@YI2G7v!31X$F@w zoPWIm|MO{`frJH^VY-<$fTL0THn2xzxSJ~mUmV~-{>jhEb!Q-&R;}`DH%y+`7mg7U z6taYnpfTKZ6^c|kbQhjjGau8WaReB2KzrfNHAz#*WnW2AmWR{|CL- zKmOXtTBJe1oER)7RcB4>@^BLvDh~Q`RkN${8{a&@>9e^U?5=)M%WW(iW>fe|1!`7kQ1{d9KzJoizWl}_5|B^O zbc+s`jkfsC;r>$d+Ln7*qQoW47MZi4Fu`}VQECk17$Wij*Z|(1tZ_5qf^#h2{S~D- zEeCTZIk`XbnlN z<9hx(Dzc3BwBn(&JzSru zQ6SbkncmTSb?4{yV#Tk{66b$6I()3N>m5nEoEo|vm01Rh*C4xvL(o8AQhnvb8fS`y zfpo;b{OZUl67IsQu6brR!xv>^GHAYsR_t6kc10h2EGJUZoujbxg~WB}+iRD<+;DuX z{$exCR{7ro%QDVdLt~X^NE6S1x$PUG^3{#pbCP7^*;R7F)4GmZ%@^OK2fI{1PX%O^ z``PI{Ek4~)uU*CM{j>GMTTC{Og@j%j9n14~bJN+DlacpxR$>M+Y>jvYF8~xLF&`C# zm+f^u{P?>N84e(t{lpA*#pm4ZNuW~lH4nDaBwvlCc}Qu{?+qEE@!K@p#S$Y4;@>Sl zTy1d#W@6lLHHZ<7IunxM;7Y97fa6f1mpmkWg>fPJ;8g@XUy6lFot0t*GHUT!^Wrp_ z@2rBI<}mK^5*wZuyc7lzG3OYqbrKU4Qi-vwlK@4zGjA3t9FwHAl)4X6m_JFv8bXgO zucn?FN#nETTpmU5R;NgWXdR6Dyey*sZr96o<9OCHbl;Xz=<6UyGlGLcd{J!;U*SUViP_asKafBAIeg&lSJLmnE##~G!L)syJrmg zMjFE;qQcYQO)>}4*ser@>~g{DI^7(*BTn4YIXOknJOUp7qfgla(n<2!uj(s}Fl2@n z{|$`GufQ6+Ww~@!y3DSf=K4!OomAv|du>v1&^xdp`tqH+sJ_Z#8wDcwz(%7DOs)c) zG-V_Ep-iguD}JEG&oCsxLo~enXeR65mwAiJNIG78rv+7F?NCmnZ=@7ASBW{!)}-cf zFWnzXvt5*{Nlt|x0(0B?*mdb3qWC$@V6Oc$xV$!R2?j*Hqu6^vx0P@% zSCOg#Hpd?G=(8^F>+r+Ab@ZQ^YU~`&9-W(9X7r>Q7OHvBz{a_qzVVJS-6-%$T!bfJHPkl_ zx662kRM{GLgL~Q>)LjJ!3D`cHMj^Qo>)#jzK{eDh*v5GIt#sb^;ds!`@+a_YrkMQ`;up&LjQ%~KZBafw+bq`5IzayNxM z4375F7d&}eTGd~%2|AD1h@OlEhP2vGD&c0a=h_@-eu|b_SoD>@cmK9z?P7pE_iWct z<=WRz=5QMcWAa#?1(=NOdkR!Be{Qt$e$3x9e{; zr^6}nALydqA(YRHGZXLiR^WXGYy=`=y*7)jXQnJ~hisQBXPxd6A3m9ktS<09DRTA- zkmU`^nJ+hXD7xkL`fz%p8kqOXlnsm!18&2zwH3rXA#HjmF0axBlTqv2uSEwNK2=r) zG_hDyiK=zU$$Kg?FTto6zQ3PqJ;pRk;)s*zohH&w?mr?TsYDsd)0?U6&ki7`8)#ll zLe(^S=hG4oW!VlHZ|$B&UFx2KF8UTzUqT|E(FIY(I~*#~^qx5_Q_NW0d~A9(==gk0 zW~A^@uLT!{1XF9)l>7!{qH3Q`Md7&cld)F@SA1)0y)Z^f)9}T^=D_+FaTuJe7r>Z=l;Xv##*l?|+hQ}5oc;bp6ID58Q>EO7Y?YD0i!QYhH*oc+}5>;KL zn)tM!_!^7lD&7#`I61%N`iTp0lPr(hyFHfeM}WfDda*q~JUc&^RoQX1?a%U8nKmDo z!1F)S7)KU?^GQ_5cY3*(z>uh)afPWXCpikU!Be27Ka(`8OI_wdcO3*E#$mPnqUIoP zLWF^d?FB42Sm{G0N}Av$Jo{rTYh^&ZykI8`HlWN6;nL;SE{e$Ft$F|&T3Grt0U9IF zfhH6olw^!8*qq7bJl)91UT+04-80a&C(kr?4p&?jd}yVhMnXZmr}IdBjQMHpvxw3a zb(gkMQJ+9Po8nUhVkUupg@Ng#SzNW2LF+}!0U?HR`fw)_5nmLHwmF0(iBt*$eWORP z5KS$0ydE+xtHeky7@0GaRXGL5bXjTl;d)0K%r?^>HVS9(-Dn~;8G9`ukS{Q}Ok+UC zhuf`hSVID)$v~v+pzSJ&j`T@0od6OZ))E=1I3R*XQCD-OgUgGWKzEB7#CgkZu~LWo z^d+2vN{>W7V3vc~r+W|?X*RWjQF>48@AidHS^Z`Z)$3fLCIaEqv3=BqJ;S*J9e-zX zIMa}WL=VXq8Aw5`tujHMH(1R5-bmLpFyI4^>;GsNf>BR>u=Yp_WS|Du)o|E8VKDk{ z%1pUb$U(bfllE2$$s~wOCudACU-Ks-ATV3#Czl#2aVE+HwY7S>k=obMe{gccP8km- zCUR<#QmK&WK;rlo0bILQ6+ZhuLCo5b*M3wjtyiUVaRX^SY`z(1VCXJZ)Z||M-e|Cx zG-;WeV)x;P$Pu$DW>PQhv4@-b`*S*R4=%}ye3P>!$n@_aP~K03hoctaB4?LQE?(N& zhwj>k*zLwr5D=vodSXqER56b!bdX1?t~7E)%bhU44_U7ilI0Ggtg|qE3XJ( zgKW6Fj{Ey1VJX>ut&2Avd)^^Y9=z%}c8-G0?L@~8tz3mO5K@i@OBakvx^hC8839_@ zlr>^##X;hemGKKo!<>dS7@W$-5GmKl@-YdV(}M%(HOz1)u=qLjiKU3pE zMW_UJOf6{^HSlbatkIFvD9?#bH@b+xyTMDM<2G=XIGy|_wo6>-`bf~KC34R(NPf|v zws28sp_1|=NTCQv8;8Hr@6j3ADA>m7wg53%r4fc91=2^Ca4GsXr%NBqbBwJ8ng_uN zcyA_!)n6oHD$h$kvzyHSwO+Qxf{^BrylGD7pjJegQW~3`OtV1Qv2#sX5#Q;AMGF7z zd)0ywxD}==rOz5EGD;KRnaiaBr%$O;9GhOspc472EGAN;d963%Dd-jsz<&{Uo!_lUTcS3MI_S zYHT;&EbJL@rr$jhUcu7O$}*vZwq4yplyu4yswC^G^ljLt0j)Z{y4yHxNIR_rQ7r<= zJj3GMG6{g0tPEbmKSXeqz%Nc3rm4jviPtH1A(V747N&*T7M|0f1#<%8FOu*A^hpGE zP|S%${6fOQ#R2KPU%Zy4S8TOjikEIFyC3u!B0_%;!@S&4z;6I#w(Hw+1{x=)X6SQ| z_t*T6Iuhix=UNQJe zD}h4yzBA|{@HLj!BBir^{o+P6+S31vr1VZhYgsLE7!kCO77aup(6gL0m+|7FvqHY zgn3+JXOL7aq?IwC`o!4L^vma=;ZXGy z3yWsdq#~+7^fR2B)kY_QmY~H%k17_y9YIxQC4&o_)mrN<5Dg=bG^Yh&Hgq0Fi7985 zRZ08WJ)kLoFZ~!O|RX+w04?Y95JAO?RZkr@}u~)>ArVkPiWDi0of+{bZ$Pl7;Bl;m!d`@k$^B&AR0{*xYNnACk_HR zIAy(UlfX&Sq>xc$pVW330J9^6j4BdxrOIdfJ{?h6lWfN&J!$6(1uy9N5}23Zv6|&L zB$E(o00sJcu+p+fBs@HwQZrZUQPoo{Jud}_!v@O*(lzL5IpNl%jtW|pQu6Sw3gwAk zCBMq;<`}1Kh^G(*H?jD+g&$FbKM-m2r6c1TxQj z;ISj9Hik)2lwSK$K+YK=lW1Lvt2XOOGtKJl8Q_0X*j6iOrfFKMrts;xo4?K|GAGmI z3j#?F&?(y*IGW|QEndH=@YL?OvFNNzcTC{WqHV|G2>H0;(pyQgv|di172A#S5EZ(V zxkuNK<3bz+ehs7L5V-%bh*-+P5mDF=GYzej^qP~{JP<9%S-)cWTWnRYqBv5D z7=U^2Gx4JPA3iIKczX*jC%JiM5x&V;E$a&8UkC!R7OX&^7}qx|#4loftS(tgPsh_M zs5ozDL-X!6_WxaL=%_Bux(<9aTHKeWCONf`#@0L@E_T!|@teNRk##&Pd5=3RTTOC- zF73#8T~89)&Qm2Nm{JRH%Rc`aNwD84(X)zBVZ6Gm;tg1a;O6Ac6>U$pL0dF_OX$S- zf{R0ViJ;-FXtknOQ}XR>+%?=3SR+Jn`rPKL^lV*}!^6XAOfa|R78~SRayRg9)rVi`jz?#$g~j+fG6J&P=uNM?6{9mZ=P9Op7gfien4Qo4ht!h;wLmx z^OM*?GSd2Jn%H%4#~e9xHZmIe`Syfr?vq56HIU==xo^n%M8vE1l8uEHpS;HGs#v40 z&_*KX4^ODm`&p`mp`xXARilm0*>Llp)g2oYW^!mKZjZTMVxsoK-NDM>fsxz6O6>H% zt$@VoFz5{1(H*4VBgsXF88Sgj<*`38LqnS z7byG4haL^sr0TOL3ogb5dFOe4&yEWc6gl6QWjysx?B?%Alc`ZqkZYJx>tP5}d)`cm z8%xEmpmbVftcw$QJ8gD@Qj3p6XM(fJQwy4%B~mN(iFq96rdFANn3s#{P+#dFV|DqkGps@Ps_$g;Q+ zPz^aP(O;_r5L6hDWnA* zI;+~su;|A!c?;T$W^g+V_xdTsHnuxU2k*yaRi!e=IfkWHc++HP@MNv3R#t??(&hdR zeeF`j)*>Q(fG?qc<}le;&3<0EfnbZ~KlIA^08L#tsaYDmpF%_TXFyk3_-p=-)=EyNM>vD7$! z))ePYo^nm8{CdglrELew0W`@t9GbD`8r;~sfyqWoAFZZ-1m7v&(Mwx1{$)fEAHarz z&`WaS!-R#LM@d*H51yPo(_lzFl6-f;)c??EhHU=7P2xaz{@r;Y6fBr$`|t{@nkx8{-XH&ihOm>aaygH#fsh4@x#!1&~y-^3q`!U5TT+s$ico(6o z%WcUk|3ws+>zex2Hwt$E2l1uUerEuXT=xHDoC)v3h&6%+(Fjilska0Ebb77nE;!PT zKo=IS5~Px=VXEv5R`YnFpbSD_kg9}^bdNg&5o82^QbJMWG=cCF<#LrWO!mB$CR-w~ z;~t+$h^IRdCi~9v^f<5^&ipqVPEtnZItTf_{{IiUb~B zkY99_wGmWAo4r<4ugk`IPq=+x@A>JZ>XXSAh!QoFf_2~~NC(2|_He16CLKpA%J;Ad zUgKO9TmAlg!LJfVhuQ3zi&QsZ=N2ry;d|b4kh5cGMXOrgeH>u$Es@$SotPRCZ9FJ6 zbhKK!hwMOAK9$8sgF!pClbw!ohNT~Rw7&)Hz=k#$cVx~i@@)4+>kxG+a z;*iu2z!lI|W}MGgHPmd5F8!ei{aT-Z&$}BGw53RquvJ1u+WA5~D>zS-IkZHnh{g}_ zF3t5@a?h&)S+co&TG=oLy>Z{c?Z{V{(T$1=V&xU!n?Nb$vdT*h+j@ZE1x3v)VywD1 z(oJkX_a_~UBDFt*({WY<8|Fs0`YY&-lXY(Gr&r*J#LLWlO9k^eNV8(xq-^UFF7!)` z*F2DkH*kq!Ug?9FLqH!e*5-8dgMN74xa2JCFQ;ag3v_6N%XsOI)s9XHyGT~j`hNQI-?CwWKiqk zPK9zFGrib`8pyrd=yI^W(igLN7x(+7{pRa*?ZbhiAAR?Z&Bau=4P+4sBDfz};k z5|v!m=&L}y85>qfSOy+YqZ99LI6JOW7HMXMiutJ4$0waWFkFhpCShExB*v`4y-djK zA)qC`$%F);6D_{*XrT1Q6?!wJ3oJ zI)oi^M+q8`^L%p@SdJT3B$nUkb}SYqMEtZBN>sg~57@XGP9T6*-9KSmi9fFXk#^10V}EKY&M`0lz_P_~QN za-^1(t1jrz?0};L#UesBn`~{N8l=!AXd~Ppa@zYJLJ6RK5q5B(IB}TS093rmFmVyf9Y&%O;KG@J7{c8TjN`(JvL7??z!72U5$is7aNhR(*_`75Ti%}7M6QdI@c{2Ftly4#Oy*Y4=`{5gHvDi8Bn~kbbM-JlPiWrsa$^ZJU|pj21~@wN>u57*nfL9-cC(>@Qg znYuEgtIm4&i#9Ry}rCV;{q@qQSW-3A)U~N*-C`$|3X{ zaY--2=d7v^mpm2{0>wY_W!wy=l;PSl)mp)NAZ*cecZumFfh9Psgy^$f&Q0)_4Zzyx zHGVUy+eY*;=szrge-0w&4q)}EuB;L@r{9~<8$j}Ds=!s{a4J?Cglm%-jtg|-_%95no6`S^#7*R3M~ zf?I#8T`>@{Dcc5Nro2mN8=;$whn_=E8VqH9v4$3Dz2pVP`$I2%?MMPlLlWdM(O8bh z>NxBRhkt>4-7zEHMiIA&q^y-286 zvpu2pr0UnxoNR^Iy%jV!C138+%1)Jbj4JC>qxpl)2z8>e`(q?t&DAmbf29vlv}SnN zjA+?e*h%dCom$-yLR$@HnJ5zJ<>8ZP^m1$z&nnFGThqwF>a6cO#h zFE}{8fKg7X(JFk%;4~_f{vmdz1-J)Dc@M0|8xDROOPT^QWADqVI)x%E3i!x=j#le` z(Ew7#12g})=DT&IK%SFQu-6BMm59vkz2E!~*{Ck21rHvoTiG~ZXWY>5>^z(GWsRg0 z&L92RY4hlmN*>5LC*L>(K<*-@ z*0y1Os-b{|Cl!z@fa2*n5NHqQINFU(98AWF_n7BsiEx_ocf0~KZ&S6C$y&~ZEc>x3hWI`Tn9GtY&)YOa&{KV^GAU3e) zhx4@)($4W@ZZ8lR8Y~-E)9P`1y!glz3f+DF@85$1&6b@rWDoAMnTYMdPXD0mW9z($ z9Mg(Po1sP-FSGOF_O{HTM&=FYdCKLkKVc3xxfGQ4Z@4<30_>uI!UoJ!Y!4;9v@+|9 zd{;bCTF3&c7t$Z=jyUrDdbtj}ayq7GQ!$n3XodsEp|(pPI7LDQn@FdD_Ly@uG%Ra< z3U7DG*`>^s-g9(D^>`E#&aKSa(0Ca8_mgHuuX0r=d#~w;P`9 zfsJ#o-MRMW(f;xA_U3*07umbAZDbW?YV$bJ&WeZB#!W4qaMnDkAKV>$^dqxbH% zlxJfdUDKZS)72xa@2XV0wfXsa*7@r)`|x}ib^Q~gRwf)|zr<{CVt<8LAB^-@UK1o{%}pbsL*) zC9_GV?3<9X+Pn@|lXQw0eyy}Ka%yl+|L3DXYX%2J%?XTbJ$lL6&n1W6&MDzL85$+| z!y-GEFE%oJSn714n1DKF-Wniyxc)D?3*ZeA_>)!yzGm5Aa~d{P4iBYyW@u-=J^^+J ztk_;nV`*ObrrIyS$tW4(P_c78LC>e%rDYl}QV*4p=S1z}Z?EUVj?N6{C#fK=f+#ia z2HeMoSBCK;g>FKd%020aEqB|BhzqB#i>;WV5HS;p=pO{gB8wWrSyu9&^;H8y1ey%G z1L&Y3r(#HoRErh;8o>tVmDG($85WuvpkDu3<^K8Z@C~F#LArBke>=DUw&-@N6}9VB z0KfiX=P1B@9FdmshWz;V2=8F$v*nC`T`o!-k%j!(tM1vFwv5(is0S>9H?wqPAH9mg zfFZL2zQH~!ugm9Bjgxx`H|Npgy)N%Y>3+rjO@yZB6J_1b=i<_0HW6=K-@_XYY4%fO z*naHgg{o36`kjls6J;$d7s|2|O{LIjD>tWK5xj%4!68-LPH;suNep*gx@Sofr?+ig zI;}^)=3rnZqiG;X5bz(l?B>_z_MQ(2tyw(cRXM5%)g7EBTuRRi$xJ)7TFu{=&>gp`Q3*D zLt6^c=ij?3D_Mm1Z2>b?*1~7wL9t15)cF!wtu94U=QWRqOITEICFAo9*;(_#7&M0a ztvb8|<03n?>}aIHpWB^jO{0#OD(9$66RF6xps<@w9-4--fs1h1-@-KKB0{x zojJseWYu_FT#+cH2ziS=p5+^%cpj&77F7jFlTB7ZuWqQXY;MZZtIU6Me?L2U+$;A* z&Vq}KXu-tzeUJxcL-wmJ+qMC#xQLnB@KFrK`XmTi3fB5Hs zL;Y9dbPgPFU27|PqBZ~!JcyN|^ndF%z$~Zo(}4yb;5*f%;dQP8f&_Y#PvA=gX$g-8 zS_6y3#-F%fKlf|aT|o3W7oe=5u~#U{azbGIM#Vc~%lT32@QHX?w}p`2gQs%SIq2x}aaeA$(IiF0_m&UDSygXfQ}fzIC$5Ib!dFu+rPf6M&W{go z>*ZFTj+2qQ&%+EDmwhCfDt;uAA$hD^IW9(^gf5Dpw&d4jlbp8x1dW~QKZqH7?#&ys zVu69=Cz(QLfrNd2X^^nrr~S{6_S1n7@k3%bHYrIC8*&@#;a#6B!Pr`vmbkX(ggo@} zvgc&`@2~(~@Palmi;jjt5mctU{JN%=e?POJGTGwLSLuE@32)$!&taf zfZ{=$E8>m>@^irad9mTn8|Yv~JdhzLnq`_ZH3N8FQ%l}cK; z6GqO4SQOqffz1=zp9*}~pZ!28Mx-AxIX$NG*HUh-RD-d|ru9pO{x*30{p%W{#OIeu z1bM1E;mUZb@g_!{+)@+C*w@e@$wU9kF_j?RK(k{!z`GO`H{F=Uhgo)~%xLquYUr== z`~_WL!3$qo(TE8Ffh98?&$TCI`}&fEwahV7Ixz(8eW$tmR+sxu06UDpYMpFkUBup) zHhesw8#}0hF+fR9qh(6mUq>UzZd$XZGjmc}_n$S;527|uU^i;k8sqNEB5)Ue==jiR z?9Lc}m1fRC=Wh&APr*$0zaY_}35eCeSMaVAFZUaokK?WGl%i{J-Uk;3;OUP}6??n8 z`P`$zC@`0D6MU$INw^Z{=f~GG(rYT3MyDK~?fWtFL&YM(gX#(HFuP{DL>sQZeVQ$7 zm(N^YSEek(<8H-F%97-14$7Vql%g@aLvD8=YlvvH=~rC+I*G=U{I4`CU;<10!s&7V zX-ylOJ0U{F>Q<7L)HkW=d%~W7P&XCs)^M)cJ)!8wunF%s^M4QTA0XXLKS_1@%%H~i zCVt=0C$j6}@DQT~9QPBkT^Ogu4xGhg$2I8k)F#ae^%XdR#c|x zytjL#FGa&StNcr|2F61U849OiN@d^D%G&=U?5)G9+Sc}AMI@wCx>E$CySoJhL`oW@ zS#%=}(j9A&(%sz>5(}lfySw2xJ!hZ2J^SqU`>t#LG1t0u4d$577~_fix$inHE1AUQ z&E=Kd1Isc@Mte3#Q{wjwL3itkINbcdv*JfV5xHO5G2b8i2}X{y^Fix9Ghgaz+Zz7J z1eh|bP@P>fL-|n8F72G?;+pJ?N7eazq|)69^EYHo3E>9-|Q{#sEAe> zX4+5SC-CljD!Jv&=%82CHkNWQ1i?df6{Y1-oZT|4jbVKV!4=aVV_zA6y%U`}AE}<3 z?q$+#0>@FUmsr52mblvtg?5ozP(p#7rl;pG{_>At;kk~1sb#Uv)zKDC!Kbq1IYx9p zcA0zjkiuTd5R}o4NwN=Qx^yZC)Ce{*x#Uv{Km7pj|F6pSf0pUvFkR_t0g=^>6<~r56Ym0(u3H~|l6926a4S@6N)-3r}2K)?Dz}fPx&Wq?J zm#)lFUU;HFsl2?rs46cB{>_$YjR0xFqI}FM@Wd;vo#ns+a8GyY;kyszbvJ(JMZ+W~ zYlW8(?*cKTD$#O+q~UrD!nOz7ojHtecTRP;4yfFB4-HbDNO`#gdd>Ic_6T92(=JzE zh(7mAwUDahb+@DV<;~YrRT)hYV-qDaxf2T?OO6<(|M}~w! z;44O@uiS(+=4#+TM;Pq?VOE9_Y0m?N`zY}((I%Ui64r51W4j$MujMpjzwq4n*l0W3aaBEHIGzpAT15o!75KT=mg(V8-YxaRH?gyj zB9#$L;tQ3`70T*vPo4BnoU3KHVkli+y4Aol+4-0WI_{&cBO3yICgaOK@F`0$@k(-3 zI^Xm9(3trrD&5MtiMR>fnB>z7w8y{xtN-8^g5hI=@SN{R{rt_5>0od_)B+x zA;PexFCcfTDGZ`D8YwLE$W#I0<(a=me09L*Jf-@w%Z3asq%JWibTeS{JgFW~tWs7J zEtP~cV3KcVrm8X4Z5B;N>NLCE*o%L(OK)7?A0YEp^d^PO(8p=lRFL0T@Wk1GJDr_owMXR#DD*c>!>8c^}SsD0piZok7uUqK^9Pdxfo+ zgVa_?w_>6-LA6s|dG{Rd_txw9OM2CkZwn;jKgZpqx$tezPcwLF#**J@-YILqQ`P5q zgHN8ydbWB9H12M)P3-Yy&gA{|;7Gnxo|$&;tal8NA6f-=cwahIedYD6On5?>QI$Ze z^}EB_Hw&AV2EKC}XPnELt6}C!LJ8%Kg~vQRBcQatv4$Lt)$rNSQVacP z^a3&j-0%)^GpKGB3?y4VC#Ct7e%cergrf+c^d^gqROFMhbt81<$abG5|Ur@~vQp`$)g&QDvFWTFGYJyrQ5kyRn9Hsvd?WDMW}2HR8-82;utY^EWjUHW~;!}>UJZhT&q|gv!mf~ zo<)!1BMJ{|BPNPg37Ay!R(f#byu$X(lS$tHp!L4Hi?KY3SsWyuVmOgVVLb)ehyAg> z9(v2m$Jf-zP0ZtsGgDo=PE@`biJ$PSr5x#xN9cPB!=g2;`>^;)N9qB}ar`S>e`AU| z3yV9P9C0wCi}w_02_QiI@_Uk;3z55ldyxg3U{x-(A;2ePj>s(H3}xQ6w;!q2IY0ph zsAy>d z6lQWkwim}ou4AnwfsTwvZ`fch6`mv}3%>t%&ht+ubGoOOCtiIobXH0@ON~QQz%Un7 zV4bu=tkml@Vve#+}!)N2jzXmUHkwD^34#nTkJqXtynXdO?$xa6fyJu{yWyz+*ozY@3_jdz=iJbm`WMe^oIfI zimf!$VUpjU`1iL2+*bw)pOnll$JTAn*uUD_SWKUF+{#}YCV##)w>+%-|M4GLm6mQu z;W5Rs9rv#;Ew)w?8||tOu+czCPo8fP!43bBw*K2_|NaP!xiX#_-L^kovre$)7oP1H zz(2?c_#2=w{@dR&zQ0ZEzjDBR*uEBv*0K?DV;ssJZ$Y#g-yyuO8l3tVqAj+jS$;c& z{*{3Hl^6N<<JzZc*COmP1D#@1ih;Jy4+ zcgal(lj1ksPo>OjcBO!-54h-Rn&&^i{^u}%-uT?ZcDByOVSCDHK+BY#0V}Iflw^bH z*J~X}Z~613MYTUp^C8(5gmQg(+&(ynOJKqYi$cd1!H^IZ7RN@Ec>6{fgGCslTOAfw zIXWsvGKVlH`ru&Wu?ZQuw+blQAI!Tq93OO5d6^Cma#PYZdQrkqkp0)?i^0uf zb-I1cr)?F3-52#x!CES+v)}+@r{^OGa3h2iF)tP?5Wl)D#Z5eb2zf&^(|JHNObV|G zH|+t;R|c5hm9>yB)Z`JsMTZ+j<|%?d4+5=gX3q)aS(ZvphPJFG=zj5f74h&uftjoR>eIP5)k`MrkCNzNc5{Qw2I}O!k)&J!=R4!sid1}+57}c!L>_TYFY`}3XUPtNX>CZ2YUQvhktI$KyMXc!8+Ivaz8!43bmg zi&GdBD$g;{pZ<3FUWqL&<$3D~E=N!(ELJ;Ib|$Z&`M+l$?XEB@jwaecVs7?%h^J8? zNF@DytLt$rp^?cX@ev?@>26P8*8BC|Sb};0vKOG2K8Dp;_T4Jb;jKIC{cs)BHw4tN z;de%=9@YmEt(E~DzF>`cfQbU&sEC@fY^aK0{9-QY;&*A9mO0OpdAE1`gBv;GASF~hATonK7> zR$TaxYlYtzXsw7m1&zTWMw5lm!6mUKkmxQW*$g}yNgB5ug+dCK z4awWC42B@C>EqSj)l&e-GSvXu1VDKPDNkB#mqoJ$p+Ga^_Rp_FDI7>CJ_MmY2*Lk- zUD4QXZzYSRyUMlxI3I?U!MwIEYT^nL<`4COJI+h@nkiH(0@@=r=TfGDJL%LLMvnWX82y~?a`oa9~ zs*o~C+4wu}ehH$YHv-U&|FW20)}sUi4?o!Cu~%HgKTlal!;ta~n9d|IvQ~tVHHIaP zpWXnf4FnaCBFfkC83yx#j>yQr(*1zYBU~X~*W0a{45!Ipr2vpjFdf-Dnjf?zaA+j* zE*~NMu7bCFY`Y_PN`lvG(UejU?+4ddT76)e0jw;=umdnN;(jp)zqTA;oW%D z_C=BBNKMsR5z@N>Mc@0qDyVv?_O$x$bQP^3jS0HUechs$VH6>!W&L`B)=agzYMYm* z))3z5CX^JwhaEQ$UP9at^!-a;KoWa|3N(N1xq6r2FNC!0H*C$xyD%l-bU8LW*fm7 zHCbR#^$uz=-MIR>SqPn-=-?Uv`| z{N_JewWi z@L!0C)NywkR!{7ra{Xy+c5tsZQJT`&tO<)5b$f1dPAqUw!3fYEEPGxp2W`CtFgv2x ztUK)hM~ClQIcZ`Tcuc$)SPJRGg_iyH5nY89Wv$P?DxCVAuS}jH;P{?Wb&*uIlu0^K z9(EnTk-Wt0Z?ZQ0eSkz8& zj_W;ay&Y~SOLN93kTLdSLj0s^{hnGe4e#qz+|^V?@R<4oCkjtHy46e?@%QfOuHZvU z4amw8%6;@9Q&q&f)omDJ<%1f=Gjy2-Ijw|#Y3OtdKiPt+VDh%4jV*yOT$R#3i7d!-lga31>-N^q`< z*c#MipNrgTmu7|^X)m1Z?zA=HtLDD_H8FyiFVJ7)s;c4j+YF!0Pgz@;f|SQm*?wkk zMO8!MDIYMtEr-xTG6Z9ApC;ik$;7=8c%htvAW5Twqlt3f089mf649riu>k&XqS01Q zcc`KQV&x1#?G&ykD^;Xkk~My^K7e6Hcg)Xh2e7$y2W6!)zb}7+A3>+%&x5I@wYjyL zMji+SJP$_QX1sW;eoCnbqI_s=1e)J>X+?iVEVQuCq$6K^zQ_W^>#9cLFn~%Kiu+E0 zY}lEN8?srh%QKFO*)RSfOSrUCfLOgm>oUtTopMP!x2^MGT6n-#n0DAGuvm=aw2$HA7_d_lee210!3cyJ`{Q|5*R*K)l|(Fs-3&g90U+_IWX2bG znG<_rpEIWYYfWt77F-@gj2N`+fJQU%r(LmV2!!L?Q8|s4sf~`iUbp*o8&YuMVq#=s zfyjXCM`4+ahMielOlh}eRxdciN_>hBY{7@%aoaxXtTs7MrwP01*1GCQaF@f|WPCOY z5nRKGm$mspfTx$iUt{ms{T0n7*B*OcY&C6x#bv={%v2TNLYKI@ilQWpJ{!ptD@OhB zMo&{kw>6qFs!gC$Lj6wa7`8ldlnz7PX1cLiyoN&CY3 z+RH4JHv~+i(I}*d_`#7AsC*tX{#=Z>ySnvicEmhG5`ZGj!KP8bP*g_*0)Q785eTq?MQxs8L56&k?|%{O ze(qLoOtutegQ1*J1>6OfCq6D8>TUITMd>-`pR=o`w3FfoM8Co4mLjx6l>eNu{h5O` z?6a+nsnJi5)2mDXUn=g9rCU+VPo4oY+pb;(H-Ms6sNCt(Ke?PtG0nkD!ufXEiGYrJ zlq2qB4fqa+DLJ&T=B&n6cFYYCPS6oe8>ZWlqWmKMme|kDOY2 z7wk*sIYkj%l^guSLx{WSO)Z*Dt^K<_v9xEs{L)p|T$Yh|9us&xm4XGn?}<-wK7HgZ z;@SVhep2-~VZV;(?2nhr@^qzDW6{sq zs@(|4HOGF@Db%ogO;Mggl}APWM)P@oJ1t5H{4-y|r}NWm$GxOnzEipA%9ws0*k%E_ z-Cumk%uE9f#EGzl^U{wjsdT!X-MKRGS-ecOsj>={?K>=p;Mi50lkuEJaWxn7E7BN4 ztfYdof~=Z^$0fY;U|aTXUijZ9B9mhW*1=AsYIJchU--yGSn{C+$Lx2S70@*!#KAsR znlAY%>2|lxeu78};|ZiT$qt%q+zDq}r#A7!khi8P;}^`2Q)S2rsw&cY;JRe_z(Z2F z@9W7xVJ+R8o%A6mZvx+YSyyDV&YmcLBd4&KyCJf+orV_*L0iIGyfiRh!gs< zg*hF#gJzPyHr;I>PX))D;y!GWK2*y_vC2$L7ShV6Op&4$fM4$}$!J%2Hp}LYBzXEK|&f~}jKZ!^;Ew#!&iZJQGR9AhjkkRij*~ok1!S6cQ zwfVW23^LxFfNm8&I3z|a>O6!27N=0f@*U?#IhpyME;{)$XtLYmtBV(MI4+c#P#U$% zujnY{R`Y;Bek5Hz*4yvy#B8LrG`e9rd04cSihhk8pJD6!q<)cv$$l|b9)<+J&J%@5 zT_mvIarONjVRscdwU?Kn6qGA<5~J|#-}h_^rKRq*@U>B4zu{w%c_WD~uLa_T-N6$9 zDK7-19s8C_hZZ)O;c6hm(jyPkAsxj6qIrl6^{8B9m1H5e=WJG|F~R*hsQQ{M6q(0W zL96nNLiqF)#Of8Zdkru+=B3%nfhG}*#3Svc6HWCtp0GphSrhET*b(L^s&V%N-@p4T zpg^Myy=j#jd>Y896>#_+V*$lla=8IzU%ur6=vgbnShRe$I8&;Tj)4m&6_P``<{)WJ zW5|II7i>$F0eP92#=b@Wd`90NH+y=vLm<6e>_y+3X~jPAxGx9iyJCsGv?zX-0|7cCf9`m5FHSe$o`o< z_~V8Q0VXj5!Xx0#hfYZ3te~@dX{YtIo?$<28 zhdEaEp;3MF0Znd&<2q2Y5MZ4(AnQJ2`=lYixG|L4U|eJP^M@di&bV7j@o#9(CPqgy zv!{QHvhCUxh+_2aO@YvtQ-npJKLGGS$X)WIfNn{)b9zKY9~$cChDXP{R|vhU#prWi z(n!*r%uILAEUnL<#EcDR#O@^b3mhD3kFUaxK%WEC=Eki*)vIA~u2NnRJ-9lwA6q|^`mH)` z#P7CKa)dW7@s~?Ju1yYu@VElP?A~@pSvz~3LqeI1z%($wm?}~61$_Pu5>Pl8SILe`z zV@kTi7SD4w7#v^f_v323iif@wNQ3myiiAsKFZz0s9n4ek)TAS%+>>U9ebcU*D3GREV9<7N`J0DtaE zMFPm*ws&r`SapqcR zI>XiNInIgbueFd?nZ7tB;$4;8e^MNm4I?UO$AkT6wEV}7H$qy{9clRPPhVBDk;I6{ z&BcK$o|FBRs-g!FIza&9C@u76rv(x7o2twxX){ZCg!;g3Rz`D@cm>dtS5siFe1L8& zjsJzlj2&h)=`|4^z`)Q2q`#sdfNF*6&*3bun97vbJFWVP9Tnc!;|HX|PJK z^+3sSY@BAL+Rs$f6Q!2X?Bti?3V3Q5FFVKm5{`y^E&M7#8+yei#e&Pwdg5eeER~)@6Rq$EbDl50d5?wXVgOyBS=pEf zEZ0vS)R0MInE zJikYJmD zxCAsoMyTOYiTdWQfBNhI{ODqN9&f-(CE8s_J40%;%>!f?i6v4e`!r2P$adP;vpS5|(Wky7@W_fdwtQdm|A35Fb)Hw(U=sG;Be!OgZ zvV@4P7ee<#c}V0z;y*d?KTffBiKXtGM*t$xv^hySw`egFkEFkxN=s8J#BST#VjO

k})l5*zO-(uGbJb;>%pX}Bosu$Rn=?I*w{G7@n;B#4>%11YUk z9-W;U!V(W~3X-qk6DK=7<(_Nxqf~fTZ57;P|L*E~R@)`+B{rx_#GOt6(kHb@Jhp&?0@!caFcW_$B8=9HEGryqJ*D3%b5 zo0S|08bEUskEj1EC|s(W$sO)%lGQ3fRf`AEa?4GQE|TmSVW!wXi#3W-u_-P9LMF2i z*<%Yk0kY@kTR*xQPb|%vk5ivGC?)tA3iZQ?*u=&W{R7dR_61?*LlsK(%f<6)%t7!sz$6O}Q^=clp@P*s?4naPb0C~6 zIUP8#3Zfcc_VnYYqBV0d1Q$?$k9jq@iAE!v${$?I)zYuSv+6#KjyS^QiS_9TP(S=3 z{^UpU7kKHZwbm=3ML)Y>a%waj*35h26~faQ(z-%Q7%nidkEXW568ury0SMrqVg$#+ zYQvmC5^2FYjeH}?_D3HhA`g^OXmv7B45d90N9=^2OCe8xA_znXZdagc-wrn7Cf{b; zVbh-+{zA%S_l~8+B1ess`6QF=n?59 zdur*113Ti|+|Gt{AIzx! zRx$qTBl;#nnxgGaSxLvx&Pm9ryB@?tU$6bgXoq8-y0VBcjKjOP@k;;axahubVEQ+5 z8|@ENMqV=!^R`^B%K+gB;*1}`f;KR=4U_jd(|^_0{~DPL#x7a7(!79@rzNZ@;&7j5 z{bU;{`Yd~cE8v&mebxd0J$dtIkx_V#Hp9J;igcc;W^|mz2S9ry2OHAhD3*V`{T_)JL)+@GHW(n# z8@nb=7{=Xwni*&h-wldOY5gCg{9{aQ>Nk$d-48?g3xu)0qg6A3z%Z)UvI4zRnjAKj|)8fFry6z?Bc zBkPh3m2CiC->NBtS{NfNm2huD{7>$`yF&l*jIvVO%SM9^=i27aW-82`^KRtza~(7n z%pdK-xCr!P!wfGfw>cOlQEY@49Z3}XXPI+ zf7WwjWzjoKP-Au276i!EB(O*=^8>n(g{sZM^t1RPW!a_?cg~Z!ovE)1DC7byuR*w<9Bf8EHvqW%CZ;m&hRToU zda)bfQi${3Mm9HN_@V0z%2awG_7V)Z-*vjxrd?&a+SCWr&Mv3Gx3!0S&9vq*In!+G zSxrF)Rv*~)>`WE%JRdq6LcAk&>P;3F#F|ivrW1LMXS6j>v4^zomI;P_=JhWX{HQU_xG{GX%=c=rqcFMQI@;=haCzT(braNu}1&)-5MEDn@-q7f>29~rV zQ~!;kj$tDwz|yVO_+o;Rl*pbginDmf5&WLN6duD!YPoe7<4H9AW2-$1YLAI6OZ}u1 z>anGCA2oRmwDprb<6Fgz2hC(il%XAj*6-~E5CTiCOnJsgZjdp~Spsv#I# zE!Gd5Mz*fukIHW7*)u0?X(VbfS!k3zDkpY?V7a1U&DDDn8>~yme^dAm7eFrYt^gs0 zvD2rS`|TiJw+m@w0;jv90&i!V6HDoS@Oq*5h+Rfr2EY4uwe>TIkXxtR-ltF_`dN;h zGx=3TUE&*6JXl~(rT5#Kg$f+YXa**jIXyWFuEontJ2}6UV4bWRmN3-4cDpF7ziZb) zyWGD@78*S(?ph5E)G10AB)kyP*(Y?iRw=q}fxde)?&a!jUm$ACpDO+y6Lt{6GqAAp zE9j-v!s&hh)@DgpH_vF&Dr{_GKjclpWr;OIFUx9aT1R>}9@kr{FNC8bumA2){CiQ6 zoxq}!%rBNYvnie9L)YY8Zc|CNs+3yKkAmsNw0GEW= zlZRk3a##df*3PV5uP#2^;J9zICzNVUt;M_Pj++)@pw8J`xkE3^U2pd2O&Kf+IQQ+^ zR6P|F*c((=Ayt+)UGo-)eAT_v=vJ54XtUhordcIc0c@L!myg>58`g3#tQ1|o5!}1L zTDK~>*{j)&VqQ#PWC*{JcXqV#Znwz8z}0PZD45NI;-5Ddb^L^KYy+zwfk7P8#Q%X( zQ-5}BC?AR#OT(*oa8@u86oERIym>3dD&R~=;NYQ}PAS7`%^sZtq&j*UXswzY(U0R!b0hS;~(P-n_11%@gIS%uM zDZ46fj&;58hhn#HGd&ykTOpL`k3Sc+bLGGf@wDz7^;LFR;vsb8cCa$OlQy^TsV+Oc z7Im*u+WZU57nC480J4cV%5%v0T((AQ%)L;&<7Xn1-iJn~WvQ+OW6L?w6B6EI!j%jw ztrQ2+qq~CLLWhAHrPu~;_uRBW>-hw1Ruc@?mv{CaP;Y_ zgf$q-Y8kv=6 zPU~1uRsVSAd5=rhfhx+Oxq;>IwENM46rNR!qO*$q@y~A@TIx|(Q*-C10<1)7Iu2$( zYli%wG05GTTa{w<9=(c0HN&b@a>xBjo~^`OQ)XwmX_PNm?2Y?R&n+llti1;6)PB9l z07<(MlisI?4;|WdQ(7W~nV<2`o={l6KYGZ*m{1P55+l>UOD;5d_0RqQ2Ikhiws(i7Kq$Vqc!!q%}n$0EVmPFlk1stbr;Q%TFNaFXy~SS&Jlr;2_sFmOvLQB)BCIk)n@T_4@(<&S)BHA77ZBdz0`BTS1Gu~L?Yk!>?e zr+T-1?*jS&v)xrS0If{&DonOEI z<65;#enN|a$-2kWm8NMw+xbClM{|~dhix%mI2R$#7*sUKxX#D99|2|qF=1OEW|$wS4xCD@I*|!M&`%>Ui@rVosx1YrmXv*gJMav3#Dpc{^BV z!>FOI?IBV=Gt>zlxl{3Z&WoQ#7$@r>nn}3V;9OZq;R854bb}$9#frv0DGFk|8sQiR zs=Fo(@A2ek1KqrKvh?)cGtTjV;GTIMU`!u5R3K#LAN}%f zB$(t;)0$KErzICZ@sio*^4l{(7fg0#oJZGp0jGquW%HgNX+N;R--8962|PjjZ3pe9 zqZ4aHZJ(R^C15eiK_a^+xAr-i*q2U`tdrqfM2vlmKW9@o3Eit2)&cAA^D za5=u5SZQrL%nuo93(6ZLan?T_qR?hWq2I&hUfyFRxObn%^Jy*2Opda{4|R-Mp;L=6 z>lI=bfahzht~{C~iB zkXFDm%zYx2%^Z1cb~82IhCbfpFfYmwMhT9sG~DS7v8ncaj7}NSUZ7}3P7(8mWLJv< zfmVt4n5zXJ3aWYW`xQ=9xE$NV^Rq=8WUuY^aVZ3TewX_K!Qq?eIz#%wJ|%4u1Nx_k zBNYzI?3Vu&0{gxf&bam2ECI@3UW^AeTCMNbSDwq-VP@ca_M*+mYaYSZGKkprI3(|% z)$UKL03NFQ_Uux(sFp9)H;EHBn|i}VPA$gRY~~k;x5jCAKrxf?2P1Y|gmly2Driy2=|f97}~*ydLt zQin6?@sEK>R!Dnmm%GBp*Z0wpS&K+|ysHtOXq~PJ^9eesKxuZ$6^KISWaH?LTW~&6 zH>beCI!>uCw3-&x=)h&wGLi>Q&L}?9faN>gTuY7>>+!zc?rYsRNHbyRCxJHE-b37z6qq;#HW zE{MrvrDot_vRkOUC>$E#^O_12g0?K$uST5b@+;Ne(PXkEhCL*kGVr0mBqtW@n90iG zz6Mj-VeVB_d6&!-!g}vG6>k)O0rN`in3B3K`!n@1l-iC9@ZR{{i&`Hw=Leh8LGHA@CnhIP_G6DSkra z858qzEV35X-plBv&IE3h6G4qKZPU3uJ^D2>zOiNagHL|Z?<^HK5cAw^m_{oW4k`>@Fm1(qH z=$XE)-Ay*!#cyn8v?o2$T|KgAigeLhw z^!&z&Xsd9encvoE5nkwmm0D@SMkA}e#OPyzazky^@WC@aDJW6HY+lb~b03(NZmg)@(vy#lUQm;U6m z4w6gL-pOipBuZh`lZ`~?^}e(!gX6-UXM$1yRhd!eWbO&E@qr?c?y$N7j-)gSvm4LT zfdh#X9B6uWMvI(!R7cx6SK_v+sms=aRJabi9%8q`=j?_(p7PVpvO6=1>>-`C$^Oan z1J*k6C{P!B#bNZ?$NM?#>;+01$wMB}CjBQkHn*O>y0!!T zJ#j=Va$LjMz}ZuC-vYyh$N84&7bE9~mhTGR;&19$s%M%*Z}Op2l#h4Eb*B`j3udBVrUN+hN&$fXknH1dsPPmHxDMQ76*`VtMU!Fe|ux z$U;+99?7CcryFoIb=d1I0tPZYT;BKOaSE)WInoIR(>LF=oUGWbq9N(t)v2RspG{KX zA-6l1Pq9e^y~=g-J~<~AC36^Zsz{VgHv`C_+=o=9HXAHqEYQ7ec(0T^erE{~hZi4P zewDoBPZ2WB6zfH0(yaT~Kl8j-k%Xf}yP`37q}QE_=jweJC1`e3gA@N>6S(jVwL&Q%kX^LoG>Fsiw=yb?Y z7laZ6>dKveLrK2VJTFEp#!=YW5H>aC>VZ4x7&Zzj4%|))-uu@(M!=Dv59t3y609t?~hU^o_!lb`|grV2ci@3c~KUp{gf)G7VJHWw2>mdNzem5J{^ec&I zYf9aHDBi+nR#6B@Odl_E!$oHWK`MkX=53i{m{#UmRmva;L^@vo>d(U0KIoz$g2OZo^!!*2@E`IrRC^(L| z33ZR(^@h7+K;i^f4v68?hoBI?s?CvuRoY11MnDBUmk7ukIg=Q@gv74qMeOs`rzS1R zB{JKQ>0ihi(KUV?poDfjwq|9~OebFw&DB^uUce$^=E@{3W;VeDdkV9h4fU>rK@8=A5$ z)w}tWtT}jNcG$AJy3oD~iuFYRlGhdgNBa0*$-p@ynD0;b4`E=VZ7D@3`$p~x?&rm1 z(TK?z)c(OZ|6{JfjzArO-n?8h)BO+Cf*~s|MG2*Yi1AP`q z?_bmy{Kyqd6_NJ4sKINb{r~ybsLtQAG(9<2qu_`S+_r#{*8ltoe|#fsNlEr}<~G!B zf$T&1rMt4WY@4#fj6OD+_Q5}TRe!v^B_ZI6AK`;qlIA{D*JLk_`1=2VY76|cAM>xV z{nLb3qTIhcL-iZ=jy09FlUt3!e_<*Qrq#*H2~j){^fI`uARc|3uQPJakPr4TK{kez z5SfXM|J6|PpO^I4`}0i_6NafytU+MEmi+9G_^R2(y&|`cM%KyCv?nXsPN&kiK>*2V z*xdropgIxK$!vi91Mu?&J+1(*TwVAWCY{Fa5Szh13u2s5;nx(l0M~zu`z3%QyWEJl z-UB$36~P9`{js!4@vq{A{2E-2S1Jtk7s)-Su0P(4iaY*k$NzOhMuYzL1?uH1Sb~Q% zGP}+u!Q$|dy?5zgMbNu`o!tTWSX24s*Jr(`4pa|U4&&1`78(Hdfi>t`O<(6Ip9aVitdScV#>7o|P6c1{d*jNhtzR{2M5)^us;@`F0!^7_FSrLC9K zyj}#p5#364!=DnF^_+AYEh(}A5WyqRqQGJPGY2TBb7@q8!W9xJ(CK^u%n8P!QjzQF zh60$EV`PK8*ha{CB6y^s#5^1!HUINJn_M?6jBNQ)x*7ue7Ps-m7`0Yh4U@Wem4i%M z+y1(cSi&UX47bEadHU35ehRJHFngX;db#sGi!>a#MTN=xlVq!6r$6Foj*Q`b8X!E} z8DIg!8vsbt&qD;<5dsv!yfr11Vz34nzL?aqKoe--)2i_>90uGlNs^|(8$iCqX0|q* z1jOZ-Mjg-N)sXkR&r!7g(P8oj_M>~!Bwv%3KDGTBa}y0FJc6A-n3?)BPV? z%+jx2o6r^pg-bD>QemcfTj6&8)G2Mjc_*-JcVay(5iBw?8TRbT#=&Iyi1)RDggemg z)&Md+i1AKXYXBNg&OfLI{IW~=RL=cqDH6cEgYl6AF)|E0r`X~C+Eo8q=0L^#SEvWy zwxapnq%OQpalveVgy1%d1;xRIvh8%3Z@*-Jwoc0(s8a$k&s6}Klm9p%e zxUYc@G*Y1J%6X~X*K)cNhe`ViphPeJP*Z5N!fttr0N*1LhMZJfBkpuKQ^TNHY2U)q0|ySrgD$2pA*gD(%oGm-7$oObcZl>cX#t`&pFRI?|a_o`~Lsda?KjX zS@+D`d+%Rg*TsK1*RjdKw<&DpAefMjcGd2WvYj@;Z}^F>Ja zHYq|dO2PH~qK`%ru=YZkVRJ3|!9C_-2rIPjlqde%w(QF^Ce)>)?rduV3FByfK=uH}C0Ul?FG)8t~ereU}3PQ!K%>{y9rb7K|y ztSit_J$<;p1smiFYLwBiV+{q6S)kesNbBbu`Z+H7%fZRW{7PvGNlxhp@S_zzK8u7} z0L^)Qm~PRlc>=64kZA2k!t~42v}yLq^bQQhqVY){z+|ve&wn5HqkA%8R|Q>Gon+4d zy;Rci7(gagpDLvD;r)&q*FGOSeQy0{i2ov9u)iA@SK;~@0&0`}cC^J7+h^5W7ZMsW zSQCRFmAIA5X`A@6~3Ay;7KJ`lcm)hOK67YP4Dxc7d@UNOxjNp0NN^rbyGaq zS*>ln+}EfH>x;D9dcFO=Rwl3j$E8c= z4TZ>e|5PxM{HHNI22`VuzCtT_E2i?>Uhn!U7gr07qk z7~FGGJ{wzr@qzH<5jit8-{+&R_{(>y=)3VaEr}G8RMJIb2BWD^FiQ$Wi~nGed&hRo zSE}XHc>Ircls)nZgcDv6a@hZNf(pO~5Q%@URP>-`;sBuG-_OR>03d&_$ATN)qDZN5 zMcHG6A^Nq?kuRD+&r(`Rxo-}$)dF9xW5G=-ts-@i+NUazQj(f*MmrXERd6p z=$uy@hV60M8fnuMU(jv<3QtGZn;C9DhPfV3cKRo!N7U}A8Jf+I8~-+b3~K&|VRP&q zqpAukYF1;FhIR4$dv z+wgw!lNJVo=?_^DIRGJk4A(3cxTo)Ah009#N}@^oDRTmv@jX8iRU-0=72jevvacgns~HyZ7ifYAtMWB~!CoOOQJ3NjTB^=7 zKL4Z}ADbkpgk)r__58QmyUSCG*?=TC(ie*Dklm-jg5yfWf9F@c>xG42&cYm?v%&Bv zRF*HE^J*mwY0R-1?)xlM89Aj?p2fJ(IFfKWVNt*TT;fzRkXOY`cWZ*c^G0wUOfgf1 zNR9z?WYCp9a@{m(v+}rb`SAg=_q4kw&P&ls{XvSk z4jc)HE>=y)0sUF0(TIzqITAVb3K^;7LG8vZ9K%m~MN{K6YNx!(U(A+U>Y7O5=&TrF zQOkTTRc~1Iye$DXz6)(<;p%ubO#rEzdb^6290m3nrN1O#iwJ&i`0@MNMGtSbLfQ-8 ze4Q$`Ox9ZC(RSErK&*gG><)yRs9z>GjRBWeF%LJ|S?hpLZohuAH=H-M&WikY5Q%|$ zdhP%=dwXA#iiC83GK0ZKb42jrs>88O5k0;u;G)Va$fNd|DCwoqtA{CJN23Dr$|?<{ zGitm$0DEN`bP>_Jq@jv}?mVUEZ)9y-YLZOR6aV=A1G!>5FVf`GID5^R;y=iC9~wr6NHp6GuS%(wri4# zVd@lrgfvFIN)W<*MdLUU)aoqRqxv^kj0rfHdjQG1g+$j<)4L)k-VSqL&sTVqY)t2)!>&Wc!RGH{v>Gb=JyXP!haAG^`s4lL;F!l*{u&OHEF9Qc*qU|1KIsFG8xp8226QJ$s~2c<)bbSYf?F|n4s_SgY@M`luQTDt7ACVx`ubkbrdxvUxkU-@VS|S z0&B=CqO!cdH|li26JaLHMlwci=$F-|2m6V|tXtNabBgTw8v7uWm7zDD>?}%TO|4Tl zO_7jqu~TwaEC&dV@D115JK&!AtQ3fc5p<>S_l~cpqHCWj{VYU;?7+GrVGUO^aa9bH zms`l~^q4!`%>kJ2%aEPFofPW){Ev;7Y}Y*m?cz1Gtf?L6s<@wydJ)JHH}GDkZ{RT) z)lns6nWL8~0FBfWq#1B*as^xB7fAN{!y6!$V(|xQ67_Or7+wu~Z?JF+DwwZ$AOF^b zQ8pV5v`ffT%S*IRCucCtrqBA;N~r4?r8w#h^7!`vnZR_PoG%-6t-~Q+TOt4+fiF5N zAyV@$(#;PSKTs7l)>6rKGs>xUoGf{|mVwf*R2?*f^)<%wW&5*7+`$%>gQj6dcTNA) zAI@|eCh^t$pni<^HQ~5-HAcBerJ}E?M@sgab)}sj#}U--Xb7_w_G!OiOrp~P*iPeo z`Si_pEtP+p-Rq)&rcqnj#P&VskbD0Z>f6z>~c~$vfvfdkt09VNP?ttZPE(e8jHa{U&$H7 zu$J@`Fm1HNz%i9}M;xh}vkfT`Pc6pCWH#3UuBeze3j?3PX~AW)ShWiA7(Qw{s2KVR zepzfN=Jv2PgN;@Ni5=U=7<1vJ$kv-C2ADTAXDL6gflABR4=|g)=IaRGbNaob)3*RP zhb9`>p#$JbcKwu>mXSeZC1C8h+5w4k zOB=_?OQKtx!xr~r+xAYKZ22MH6U!@u!53PnbT0WXH+IIZrM-U)qjD-(Mu%pDK%acC zYeVWM4fDh@9Lp@ppts)zi^#KvFnd_>uZ|bkI-&(1w%8v7j+dGYQa=0gU<~zeV{Rh) zW_q{C>_mY0^8qMVtr3!I&v6;?ts#*+^<@hCswd(57_ShOkE3SM70hN@pf0k)oc+mb z4t$<#WWPhwO#%cycDCY#bs*iVRDJJm{}LRKKS-6cAzQBdQ^~KH<|LnvzJSH*jo~Cw zRhI_=J~KVkv>06TcAt{(qLp zgovm|tVE}{_;_Xi!FjYo?rkOr4G(0!OtnStWvG>d>ffOwc-*Q@_LeW(s^xpEclH9H z8f3%LY5sh(a-b^iz7XfxuKsZPeE7Gs`roK=!j&4keYDlk_M_*UKP4%MG}+G#>`=}} zs0nJ}>p+gVS+k$SYQ#l9(o`->Y*Y}H+lGhe_yB%Q&^6W7)VCDLG0kpK9ducd^*(`D zh{HPQ>#)9FC%rV9gtj=OZ~iD-28UmMX;a2K^NCjcm8uXdin>cV4^&9f=v0c0CyhQy zaITLv?840Nq(4Ko#}$)b!5FsrzX-uUg)B00(Am1rSVvUy)fCj7tSFhvPOpmZS1^*y z5kbRY<>qv5T}>nSmAnuXIe&LM^Ju@(Ee8EuB*4mz8dBAG1TxTOxdhR%o+celkV798 zcO=9aG88dmlW50&#;M#xsT3^Rs+}>SC!$?iY zQJt1{A2aq}ljVR~)$UZ8go_v8TLO$<^2mnKR!kH8ZWllV7u#aS3!7^T&Ot!Tc|Gn^ zs_NT4^>(bqeMe*~D>bwzHj1iAUrkqD-gwIB)lYVR8#r4D#(xU(1QI&P)vZa z=V|j&nkqYjpf-!J(VO(V83=pSY|l^>n=FgbI4IK)sW&gGVs2X4vP~6zIt(QB)XrZM zbp{0^Zr&kwGd9H{k?e}b1KZ#yvR{z&b?I)Cd8%)Kgji@AtC1X=?r`mL99bm)(a&dw z+TYFn-o#Y2DPQl`ErKdw4ehIC-)8BBO$1W+NcDl($N=Z*a-B8GTBk5?QN7H_>?Z`g z#sm$v>nsv)Pr@~O^)=?X^_&Mw$dc>bXZkZWqN3Zm$gkNy3UotNGw>v1_Fjw`CyJCI z*HpEPYXY7oVBcwrbaaMVAq8N$rKW-u*L(3G|(L6S)OfLLWBkZJu`S$f;*cO4{ zsq8BMsgscdW(lRfM8Zvz!QIU-QdhL6wIxji6`YR&NkbuwEylVE+-zuBj$nHa znMAkyAm`^=FSn~y+W&5&Zg|>Yk4D6$-4BXxA@LT{Uuw-w#y?C0+XBjO3+W#MgG{O{ z5>@oEsjGia>nC`ELzK2KQ)6ZXaob2TLhml|>|=|X+2?i!#ROZ^kham+8jaO2XsJ#T z?1zWiz|f37ettPHC>tQVPZdaW94Y;VLvMQj1f3r9eG?+l17ODDnh7_k!G>Y^;5K+1 zp-(34Ye?@L<^G5NyRyNif|Vv%6iX16E{EQXp;mky zt?Bjv5+_WmGTcIP)3VC_r)N3(fOOhVutL;iq6SeZ*Hj2FjW>p z2X$rQhw+X;v=mLmK@LzTlMx-h%+$yVh(U*LMG$RDhQA!D6tx1u`-n z$T{CvgsDP7b5Pd^rat^k61WUvxjO!aV7o8q8;sA_YEhR5`^`-$HU0Mtch z8b)^z0RljYRw57`66`CP41sxxm`p3U=0B!_aDS)+6TL#uA2qh^Es`b0XG5tzE8Ls(QxO2~U=7{%P)5}EHRyjFFaV{q4V;Q;O7T!@70ONr zKsWSyXh>w736WqcWi2|L$KeeL;%&_+RBrR#1Bda*&v@8>`^ue$|z z=-=!ET1KJ|-z$kfgWAi7jQzY%zDH^zt5HqCp%-7;RPp9~PS9aSGiaXHuQc?0((*9y zu!YqHWp56v1#=RmX~8WJQhQMIv})D|P_+ zy7hnfbpGM0P_Ym>H`q{zx!Vijh+SpgZ-HC7uTj6d)aMcSdoLpNhUg5BA~mfF=4op# zBNLUR;gH(HGzYt1L~SQ~PG{7_O3Up*l?VRj+8o(65HDIT99GJa0@PZPH8P*6zLgVW zXR{WvBKlJ+e5J1r$auCpTXzU*_)-GKDbj7uWL@#~N|-MKaRoyj0pFtSodzg6r&?5i z^cq@gp*BQ*rj%hrLi8dY>Fb&)S@Pu2DBe+_S{*|}fQHVJFq@4_ZGtdFB*;%R?u~M4 zP*9N=#>Soa3RE#yQpeS1pLDTbVvmoxKc9RkIGkoD7557V`7+-!*=cY?$W8A!3NHq! zrLWqD>?UZl-%nQBSrp+BU@^FYRf9&U2cWSKYDscc1Lp$~wU5pn-Bmsg#?MK8>)1=M z)Sz>^Q*d>Ewyo!gP=xs>-HgG4h48^}mH!z5{kvNz#77?aB#b&;hCS0n&XWC4&;Kbq zlEr#_5wG8G9hoD?yQ^bRd$&s@X~z-l1*hJ_IY&g?eDVjj6GpOZKFl5n!5GzQLt}O& zA>IRRq=NlOWeXL02vBlFe?VMV*ZXVPNR7J2VwU40LuLdkEzqW!^?hVZ^$aKB z@B82_bb$$DA{At=EN8@CK>QBN$gY4ml@7-el=}Tdu&xHa-b<|Q&CGy$Z7PQaLBcyy zH~3#Erm$LAKqLm04}=&H3z961P9GLweH%xNq%sX8HHtlkWI9-IcGYf-)6*KUK!f4= zpE9UKe#3uHYWhhmm8Q~mK(OWesD#|Kj3`DX#J92ET2Uj8Y){^uWAHF%K@ zF7T4r|ACNSiirN5z37}H>f&-f(pKE8 z=q3qKw=(^I>p`Q_!n|+8c-n&Pi^D)#&E)f*ypjGK>Z62=8X^)9@)HEGfX331g%{Gt zZHo3{Mz!ZS8rZ>vhH{AVX(E4tzxi9T@@r700oe*yIF3kSx-9lR+Z$jl) zbopOZU+*HY&eC5|_j1tNKNw35duM&J_$xH>ehnJ&JbfeoYpg-Yod!(N!q_uqc=z;= z^fh2ScdEhos}CMT09HFEps4A8mDPSe{^KJa^u9iqU0nyv`)AqTjRb`YlmGqI>@mUU zT3YqwKXAFun4c@O4(z(uFTXvnY!q#^hYtiaW^|@3W||B;sD%Ba~vBMvv6>nJ z%`Cwa`@kQQW^N_;(d{}J9`$Ess=+bT`==d@$2-m>WxRYR(xh9pXuTADQpVs$%MpFa zJnkcGNJ(Nm%ne+qGsfiz@aQg2N@K26?lWL)$omU|{6EJa@L)m=W!3nM8dJJbAHxW5 z=>6-ae%xM6QDV}d-nT9qh2A=BYq2U8$R@Bj5I7x1K?H2AA2T(}mh?J)tY5Nw4t$R^ zi+{^BUOZJTW_@s6>wLjBqf+RpR&9i&grN6_G_4>*vYb`&g6pYXxzxN2pogyZ=&O;DY^Ejhev`f*aoC)@#Xpj5OrR(_-1?nYQqycXy=9tzTU zPM37_lcJ&SGyMUp0Sy9o96CkvH4&Z0&?FQbx(0*!WESNj)lIVmtrWv!TkJHu>+Alf z{hNb2D^?!N6Dp1><+X6i+3HkkcVB?nKIcD{&#JC@*B6VG+*k>aHG-(9 z?6cC}HJnF>j=EqPvbi2=H2D9?)Es}E9oJe z<+S2*SmE-_7MT<=zuy?XMz}oaO=e9X-Vv0>)hQT^WHxGnsYTaY85XT8)<~oC5?I6O-lLsKAzTLOpp(GbS@UfOXRka5BA)|vCT?7g<&hl6D2_48lsp>*vFN_WVSBQKlnD|6!o{<;sM zM$OjhQ~_Yh*Ovit{q2pnR@!foC~8X|yQ}8RA`A!MLKc(Xy4aRstNWKS*B^+V8YJ6q z=V*B>w3u|XXz(VQ3)L_EBj!>nl|-o;-Qq&M?Clvo zE5y+FmR==)t{6#AWgw->bo35T4M+2=R$Qc^#MMu#dd=pai{7-#OZgg>^es3Roc`Vs zJC%4mqM{n)ZHaA_w6QZgyVNSx z#nZb&M9o4^oaP)J_2hNyHP`GHAa=a|RDGZ3Y8?8tV!F%JnQ-e=Z8ut)4d(;sGvt!r zCRGJ*;vF49Qy3KsRB|Lj;%EiEZep=dA7|=asa%qZ=G1n>Zx4)q%As`y991*tT$nGu zf9(nmmo4twyPsGVd{v*XJ|~FYUZUzf(MwV-M$I&Z7{L#ji6!X4y*wAR&Im+B#% z$7XN^ZcaCjJ8Ar4cXKE42E|b3`gRy;mcxRp+|6jAUF=&tgO^*0>(A;1aj(l?J5(sq zRPv+y9p1Gg1gR!cJcbMzI}hUFeAng;%zRE<>zWA*M{LbUs+t^5zfZ2cG#cC+#^%|t zvYtJ&bFH0SIA05hc-5p*3^-vcFhkw^wc@CFY?$T)Ia4@uUa_r}~7y zCKa_}A7R;h!-8woetDo!o6lDJQG&94EOwU)=Kl-Ue-!dn_GpK_?D%)lw!MwtnaNxj z@y%d9I~`K^!R&bh5~U}TKRu5_cfIp6j6$|u!JQ7Wi$uNp#ijWV4?z!Roy1zAj#Vu=`^( zOrcGN4?Xe4kn|^wpP|V4kt&EIwJ_hfz3Sg#RQbz2;~rC|fUPT3jvFzt!{_L3sQO^I zh-V)bKzm8_jG`F-4Z*Hk+AJ}@{m+THdROis60^niq)&^?R2#%_t+QBYS-Fd^=k5gG zd9h^kU5lV?x)(0#X{a!2YTuN6$*FZ%f7F#FU@x|sG8zrCQ2ULFVRzxTsCB;wi7os% zYg=&K9Yh+cYlh5Os@X=m*PXH7emk+~MRMfIDg71mZ2WqhCW7d$m!?(5c3twAnSFKc z+LFW^K;y3Yem?fD?3DF-HJ!TevKGkk%oE&(AlXe{Q!7gg6;*j%mPRxR4#Sqn*S>&G z2BKaq)p##1Y8(nHwwTT0RDHD2@}v~qD6VDcYTbRrzmt=P)q;yP>KX*LfV44GUd^tbohvIebP``C9~VevwDk=Z$fvz4Syf?{zzpz; z*A(h0(3iTD~b!+U0e3fqHNB&{>gl77hj-q*A)4F{6fig`1Pi_i5<*XBzfo#_rLqfT(? z+upQ}XR#+GE9SoUu<{l6tB%RnyYQ<(Jic{0bT5SZiW<`UmLG4pnGTUuKur)X{C=t9 z+WDQ{3aS#w-FhgMZKijUxz>qyQ0LJtin|~9MG00aup0D-ms(61y}4@T=~*n}pNw6b zsMf8#8w9m?=p-8R&cOV#^5-x;8|zj$t@0dux#6<9btw{vwNq4{i> z--#=ZKVjhnmL1SWiS*6eOws4{ohYn(KONtj$~lEB2Jr7OGeY*c-%i9vPC$lHhM8!? zp?ml9!+CF1vQi~?4h9Lc1X#^|=1#F`Yb`o>NHmV5?lyci>n4BnTefZ--*nJ0v~JIa zIOSTWb0~Wq>8J?@Ao`_(*||u{I6z_o)&d8uWBc4>S!ubYyPtjTSI)X3r7F+ufUr-DTVl z)U=-0BwSNp1!5=|81r6BgaS zEAxi3C?7o0SUvH_I7k?LL6|j#D_pi$s-X2^DKkC4`Nv)rg(Ei?%pjSv9~JMu z0BO$vD;uSC_L!E06&+Rm$H&hPVP91ck|w_oM^x`0?d=}oU*oMe8z-Gu2~K^JOSs?1 z$qYtd^y;2>bacm&Tx_EcD zJq|~xMT9|9%gBEs4o#G{y11&>Oe@h za2PjqFCm+o?*cUtaXq-Y2%I#Xs;hiBe{)lY=$9zej(!`%`!|~k{plkjdO+xV$@v@v zw5F-NwCfILvls6-JR2=*epMCN&>8Ho4e~m&J`^L)mTt~!+@h8P5^w@cR)-I}#W&{3 ze0LL7U7uIEx<7m1#K3^*#PT|zWWz_18oxa>p;Y82w&%?H> zD6uONp$JR*X_4||##u;&U1F`Fuf)rYNjN9jU?4hd#JosA@u>qQ6-Eat-mKko=g(g3 z@bMo;%4i<SnY*{F6i@JKAtGf40g+Kc=m54d)M9;ur;APQ?B%JFf|FdA*7yc72MJCv?)R_)5%sDDLq~HuZ^-#tH;B5KHN>zFf>Vvn8g;!DJ;3t z<19O14kMi@(i&{C$5R_Q=AiN_8tN20Lt9;(UQKuq)X-2}kmRO0n(>4Xqc~Fb^*X+H zbU!}!8do!rqd%7l+mc}rvwf$&`jhkV*tlTO z)s{v5{gBC}ai>G#3xtAx&lZ&sqEQpNmINXBlSN3XGl!xqM9_Asq`FY=^qx}-*Zt0A zj>1YI**AoVgfU3~5Q6RUq_I`LfO|v5bl_St5fq;D*NXmQS^qq^z<#ukF#r8>#C&2a zlXlnJ=pRSu1a&!p9^psK!UP+5yqYmHJrE@I<8@(bZe4 z!0!Go+2nVWlNB1~(Df>QlLGsp*kc~k)ve7JhNPkim`qjkTloGM#`@CmrNj#zZ-#=1Y$k@zMUIxA2+sT;+im!e1X zZOR`t`1Ryf>6C8Np8HDNefXROuWpo5X3JTwUMbgkJv#@~cDN%#3QlN@4VfScUQURW zrPC#W$#uYJ@|=^pswGqK@=cIH6*E2mej`JJkB5s?qvc%Wk~QtOFJ&>Z@-wesWhyqf zIukNHWvI+%_^7Pf{M913Ee|H8fMU+Mepe{dO{;xpb(HM@(S1jS1Ji5jh0QYs)nTQ& zY0EO-k99ucy>v~^+fX`=kMcQ7Io-s`BRRQl1biA7m-EgJ=6vOwg~S)zsXQY~bcl@n z?2+&WI*o^48pByR6~>mkJkaB5??gl$KhGj7sr-CmZ@^D1`xNfw2ciEwcsIdd0KEg( zhY~cLTq7K`$>_IHqr!F(y2Bhv%P=0%pKz#oB3=o@6m`Z2)cIP%you$FUgK z-%vG5G|9iU+UxHiZ+IHH(rWPAe{{@7@u*odvEEZ5(b4vTWj21;i@n z^Qn}_O-cRl8|LNcR=s6Oak)CWmYcnpEve!r=Y+$6h~B7-9Mx0jy1PQ`P@(hC9`+$> z^{HKbTB*6p7xJp^_hT{PhOgyP1BFnV4pI9i%6TBf9Qh)W%_=l4_(DU@RW6&1iPpUd z$3*RVu(ctwJt_hx8TG!%%^T#Cq%E*4~n(zt|)};;=F937bND?3$XP#xxx~ zjbGZ1=Y(0sO8s1RW;N%drn~J@P4n;)XJMbwCD+;wjTV&{&mjHmYt@F^6dlnV`M$ux zgOfWwv|s(#xCDwqId_EymwEi9D-zVw&6+eQ+XRFba!-N%4&u@eL(&;;i01NfwBGNy>c^k;1?o;RtcyTubsaaD40HkIU$BVqP_13zriY ziqefZ!QXl`BynNhdUCn=d{ZY>iD?*qTr_diak>lzZQw0l?bUiB^QJk+6yGU!>n;u) zb>!ElTS&0G<^S|v|F(6=u~?F$-_46_2T)f8yh|-eH{Ho` zy$seiASe*qWnNDo*L>wEaBA(PiK#6sT&m?o!ftM3^kcUR>t)rcyl(;9=Wlo)#Jn+( z$1;LjyT^}^YYTdF#lP9(4toncvpmG*pIR{AHGVlv9u}EqYA?4vX439gRoK)9ncb`K zYQsY8ZKgu(QG-r<@XYCo?TS2D9gpLlGX558cD+06K$9*VvFt$A+ks<*%zTk9X}ZDS zwfgn!jZ|R424fqPE6QiF&{dR&k!OHoQ+<@aPX~8z?D03@v+Wz0M+|;v9Ny<~NP*T>`ufH&K=G9->(hZ)KCFvdAl*%a?knd*9 z!WW82KX(|43go+-7IlAJ>b}+RGRv}N8nd&FmPQ0S{Au01v98AAi-G zC!cQdjU}_Yx#lcUgmXK49UkpcBb@K>!y@HaD6@#tD~y=; z>LV8UNk%#-R4++dPB-?{_z1)772a?>zdt#ReUl=h@hRP={jl{ue&6djSmN<+{CnuA zL)|ok#pCL*pfT=*u&2&QPWN83-dV4qki@)ByMLj|&xplvS7$Oo)`yxc>u=ui16^Sn zE0?!cE#ga|7ya^RuAWPYZ|9vu`g%AuY#A&_Ksc00RPxSJlkifr-=QKin-F6-^L z4Z34H?^`n@Iw2@;n~ZnFSBr)P_-iL<6I5~Ua`;3zkW;-XGzsqpnmN@Sv|7z7$F+%5 zh9=)a^7MI2Y#klGGZHmiIBD8(*Z5ZPqBdQIC#1Wk((nI!}56aUMw-|xLx-mNb%_7Tuc=~JvD|V_4`+vGK;MiW%M~e9UGHIZ43JNtzKZ+OWEu8(5VlKAw zhA~)%-}TZWR*Q@-hHXI+Z9XC}rNU!({!%(^+y?2IxTgC;UeI0;n*45Mi)ff92k%!r z#)ex`EgycF^4?&?>L=UTw=WVU#CY7b@FIkwhH_|S{(39B8B~b# z=y{rlJ1se6Rm35k>l9pVIgy3Mh=h|dXJGZ-1-@AeWuR1T>5$aB%1GuoLJ z%A4l$A_JLDz9RhD(~P&?OZA34Ry7aFrvp8$^S@P>BlkIY9=>XnwI02VCxb6O+%a$I z*UVL_Iy4D9Kp-}0Un{?CU3V>A#9A3c%pJo*29;#V<(=F~7rq}+()r@Zcb zd#qj-_XMzvYuXLWyB}J1YuJvBuF;aVJ~H^# zw|wuUS4Xr3z?&^G%Aoq1)BWVUITo$ymCpa;_3p;HQlWdp6gH=S^>GMbgzLhu~+(12rPCH4NHAW zu6cKbc~2GfCSP#i+dpbFHJ$GCr@J04sA)MzI6lOzEB-{3p?x9wl6_`kzU8JkW~gEN zfl9^rQ`w}B(|fB7>tA6A77YwG7kZaaqzW!5UJ@beu6cz8k1kvN)0h^iC$_8jMsK!0 z994p?(R60Ox9H(vo_{yZ=8lSyz>g&tL8V{es_8yRvRk(bK`kKl{MjB-7j}rhXDfNR zi6Ag=b*b(}^>}sErGXEhCDKp(X)(GqhK1D6C+6gjGq~!fPv}G4H~w!&{`$kmui4cd ztvAtil?~NYZe3mERuM>Dljrl-;RyEoHU|b6{nWX5qnq(1xQ8wZT0X`mYiy`gs6!3c zo|tbGi<5LK-|>|Zp4lS*>e3`MAFohMuw0w%lJ+T|J#ZkC7cpbouQrz&Wu74oPt)&% z>QnwQbxXCw?`;~F72FZFE_7vCUOL!RZ`^?=lt4la7tksa+xl>ad1ZQ;!|Ra=dfc@U|~FuOW#(roI|mycv8TzY*=K{$TdStjtvmOU(8T7F_Owa~Ib zt=47yt2J2B>-PNn<_jDx4Zl&hMP}^~jf-zHZAysbWGMZvYL4}eBmEN)5OoRGOwhB> zSV2}VZb@Y9J(ULR3vJM#{dSeF_Uy1IU{+G+6*jem$-^0F(rfHCy%_m;TGN9}57Qqv zKA(R{OC-GHcGYm?cY5!fls!Cc8#~lIBzYfjLMT=*{dLlsr_uuw%`!u;dAo3#^_ z8#4XwP~p3hpRi!{(=w1;Um<+@cNUb$1_$pUpgWeDSoQJGi{Hzh9M>$1K62g_Jz`{2 zeBsfHVV-=|7b+?f<34RtkdnT{F1*abALw~}-4oSX@Epp*PjjX=;P-@%Cb0xn{n+>9 zL$|zuv(sW|i47$?(9|V|I*5$faby^Yq-r}3 zoY1(fC(&H+Z@#?Ivfk`~%>;Vj6oT5PHME*-{!Zg|R(W*<M@Wr( z-ZVI>wn|9bz3YJ=NwhpKj)w*B*`&vzQrL`-HtFheKR7lT#810wY$#p`pgbFSk#8sQ zSNfMJ4*Ohasz=0?;Gf4pCLIQxNfLSWSJ3Nk2pMmmy<~c#aj>uv>muv?`~RFMPz%74&Ai@X+2XrA9BN6B zNWwssJvc@2CE2gEaLXQUnsdGMpqX=DaJM=7>2}DKx7&i@kv||^Ydz@4TS`gC(`fLOoR z`8c)lpALkbTqyYzuABHcg9hQ@XrI$YB$mmN=Tp_>j8#_^Gp?%bHj-2Pq8Dq^>Kkbp z_VbCVK>->xlDX~7j!lbE({|#ar~)AnuE1v&{On&)RQYS?Jy2*rxnU$~`Bwzv{RRmP zu97Z3zulSA@?5qFsbWj(=-yH`A?7pphkGu>`J?=M$A9W)|NgefuRnNsgQ9^QN719_ z0k|(Q)nC!bQ*#r#d;j*`U{PYq{`^3v{nUp4_K^QtLMAB`yszp1f4GEDPOsArx6y;w z^WgC|n2axMMoIh!_Hb9{QG0QcURo$Y!o|si*QziFF+vtaXp{yqq<@r}b zSykLoQNRDS!~Sz)*D$`{Ki>ktjyo+t6ooSmz(apP{#}Gt1A6+Ta65G6$6bVWqiGJm zRnO-usBeoDjtyRn0m0qoyB?q@Ogyy=M0d4XQV!qzDR}<4V3lDiKX9v4urhf`A9(kV5o<`aIJEeJr2 zZ-KeY`n}5jA)wC+hmf2|02i3frWIe&$E_n}Cj$NNV$V~!AFn^$;*WSk&c>uqEzYj4 zfyM!2(@{I1Wk?0nqifLsAyx1VWho2$d(h9-2*H+LIBH<(TmT!tq|J8^=rGIpj+pvN zB-%PonD(if4J-Ypko1pd-n6RP?~#OzrksKFhQQL-XF~u!G<^lMtPK|dQ18EQ!N2av z2Mll8@30cyQ$P!uA3$!<2sz#w2nk+H>umyM=Ty5P7r;wm#2Z6(|MMAIam&q4Y)tsR z1hK=!Zdt1w%qphzTN|L@8RLEfK)(#&*SLWX&rh*Tp68r3#C6nnKPjUXlzkeBZMg6gnPB~Sdfe) z5Yks9L(}Q6WY{N_^uwKYCQLeBaLU}Oti6uI)|S1!JbVOG(@kIt0h)wtcuO!HYzQRF z*^CIZJg=!Xd!!VaV2nOr%sXkl@in@gb6WHOW6ta$w_rbhQ1mg&2N)dHI`hrweIU2} zN`oAQzIp`QfuTyAGa?p!$>Ik9XPC~HC5$IoFo;*Bo-G+L*YY@@)C=d{06R2KFwa2u z4(K&C0Av{y<0CJc!?V&OFtgrty^-SH{Po!}cO%fFHckaw0)?Soo5!9cjL$3qK2-b~ zjAY^Ma`nHhI@=znnOt7>weF)WDCa#KVxLlHvn9C%-*1hz2jK`@Tvgi}?&`TM6rfaj zWP^t(i>#-00*|3GgkUrqqTvYjPjJ6zi0o549__L?T51D>`8ZlLi9oo$cE+@b|6HK`@|J__`xQX8q4IdU_ z^yDc5aMi7!QgLazZs+aYf%#E2ieO+A{@}ZSbLdm+v~iqw_~i4R)Z;T-HwQ& zjgpZ3j;6#xKgaXYpEnw z`C>vPr_;Ed9};FG?kAD-C@*;5*+rA#Zab;`DX%TKDhfVrIopS0ACL;6>*uz~i-ms_ ze)^sqtL+ic0VEMdt#c7)dv-2T<_=u|k!{^LWtCw6uE5B}@2uC|f^xk3)s*2}6f*_s zu5Y~CjSB?SNx(+u)47?}oH{&OvxM~?+QSy{!Z8aZc9i7BobPJL1pj|M3^{D!6}#>q zj^}c-ncpm_Ti_A-xh+%}71;Rn6W4}1>-OtWGOm`jXz7iqo+?MUz$F8)GYFp-^JX|v z3}M7R0!tZuh{a$;z9N;&9nr6AlMJ?>vLkAze_7+skF!E6XeE`fY3*L^tYsk~Qg)r!v{Y zuw}zstItI~tuY{;^QU-1Hcp5S+d3!b+Y1Wm6d6POf}C^0ptZe+~U zv@e0t7_>n$W!*%C7&++^QIr6VAR_K`K8f%;IiBrT;If0gEkI)~+{-lmk0SFibWv_s#q`DdC6*wJWO?}Dye#O2?x-&_V z>P6{`pC;(yuwl=QSN8m>9&Z;PF%#uhW3A@g4x6ELxd141M$?scv7$>h)5AAgW5%id z^NHcf*|}zm-_*K8h`y6i}{tBM|6PG^L399JROFz zXN<0lea%zry~=6b5R4X(#=6I3<21XT>r&cqz9)($jZ8HQmu@`H4q7Uq1X@(aD?AZ3xOPs}@nl3bP_e;3ann{?z-Jsu6Zpr8s zq&dQb)dd|WxcSk;6`nC`_byVEq5F+vi#&-^L(Lt*bj-bx07{!k#+4uUB$<*GgLJ?l zF6X+JI?iWZmNd;hQk+swi{S}Zvwd*TSXOU5i}3UK7RH3o7p$-PK0JQ1r@;}*Y_i$# zuHjaMgXdE6b&4p1wL01-bsIRkenfDTjp8vW+!=!4s$|?Zzp4?tbNXP^e@S=UDf9`B zb5ZU3*2lLeNg&`vR?k$AQFFQA7IQezm7wL>pe?g9aYvl9B>}L1SH41i$r|;RNv6WX zXDt6Z%6|pMf3>K*TWOi{U^9dHF$#l8TfB#yj=Xt6Snx^Bq6Qx2pnf$R)@S_S-JCHi z%joy&ihAMKtSPQCU#OrV_Bl)HF0E z_UhKX{)6VH&%9pe^?9DpIp=xKdB4x+bDp^j@Ae`sa=Sp~r^8i6sZMEO%{&QKCXCJ& zizc5LFtFT^A>9$Ih36Z+(#VCvV~mky2`NEu5)8uQP}Y>LS~6T6D_*`X%`Z+yzH*v7 z%Ay%|`(_{|PTq)MyqT*(rO7Z3ktrx2^&L)tAg?=l8TA&P^yC*GHQZ&h<&!;5>iUb( z!OC~Ut+FcuUdYnkDcnKqwDRYk%5;D86cbLEs~ze)PP7>qK^a?3^epD8A3Pu64w430i|(mbFK{O%()cdQNJ`&HIr)&#cqQu9B2R3^^4}gM}Emj!QaNWY$+&SU3i7JxS_T_ zI1UP-B~+fgQVlCxxu#a3Zv9ji-f^u<-s$G?$T6pr@#O-!LJc9OhN4qAbi9>NtV$g! zxCGKebldx@3M#Nx;?;{BN)R(4Q+@KajmK{4j+SnbNpp)fRiN|7h3=&H6GLO;`4*>- z&%Qc2H=BN~A&g-?(PwI?9lI@>uDwJBL2fnO;jXiw5w=vyWFh7)_T*9zsEUp@9u#Y( z$w$CUWVb;glNrEC%9o+q>Lf{#eAn0^b4ZNFaEz}WJ7J(;k-??c&&ftcmyoPlY_#0j zI=MACAWz(w?DZ-==exR-EGld3wSo8&H!8rY@kTZ7NVX0Hd<2qHPY_OLbK6pv79;2$ z&>FaIC3#g{pDPtlH+@jI$;KkbsS{1zGxa%yjp?1yKSIv`-8QF*%G{75O-6#qWNbWr zqBXoz^t2JYTqPFkkDNEaamt5Is+yh+&4(c-H%&5x6g zw&yiRCU1}u*Fm-zp^8oJFh3matlt$g1TUb!3O{tUuvzgbKO9$}t#snqG%1je zXwGOCu%y^$wv|hvuvK(Xn-!cRPRZiX$`^LZ*L6em1O8)UtmpF0l*;g)SO(M6DPD}v z(w(bm1(GnSSp0MYtHXuvC!O86^U0StCh`Qsi|En7!<=O_>15Pn7^}tjPr2|wr3zuW z2lIyex5sP4NJaGbRc({B#nx-P{VFaUn6UY`LuuF36edyl$TEVQL)tnqhVAq*W@c&#d64IJ1Uv zVie;@MnqQs(9AB)iJMDs?xoj{kL-@t-H4-5P^?4b5o5U~o-f`fyLV@j4sglga%?0u zEp<@Uiaf3A!(lp6cC$F>nCGNh@!*@6No2b`LALc8U8ob|<#_8?_4{1I+IW&O+Ggb2 z9oLLIshFX>%dGKST?2_@u0z=@!mWalTE~2c9Q5-3G!ffXnP$?)mJyG3U`oBS+|*e1 zT7RzE9P%tfnZdhTq%7W{m+K8^gsY&Xzj?4@1Foqsnf==8d|AX&q00+C(f!(wup5jL zj~cHv+nBvXH-=D>R5QRvtYHv$C-;)_;VJ}93XS1nxc7dd=4&su`HVoq2zr`(qHG^8 z`gq;vl82>vNKc)Z=;z)^jEs7B@7d0}(ZttMwr3FRVp&~A@rqf541A-Y9&BPiuOuS7 zA@EZl--6D1A{XRdp$wIKl%2VJ8lBh}PTV;d^&N458PH`2L<;aHbdzLJ&L_e2nD61>mn36`*W&L)nZr%T8t|91<$v%IYw9ToV zGcvB*Jgk5Bkflyv`_4p^L=nJn*LnEo2o(VrF-1-8KO^vO-pb6H;ziwqe%bOK4YeN9 zSGaF4bTD(uI*jHq9W%EcR4O%*xuvU;Lp22?`C^)gB9nVI3VFF?yv+tZ8Q7)X{C!4TbJv%i3^stU`AU_&vT#w(`r$liOMB-)%wjL? zVXKgO`=SBLLky0NrEqwmcHdkUgnP^PrDqwvPYC;ufGd zdfNSLcWpgXwCF8j;$G^0n#P`*RW9ql8XNgCn+5t9enA8h2#~hZyDzvc4jX+%4`@GI znJ}Xvca;6i&xTnYD1?RXq@9Q(}4E|@xApMa*DAf$R)PODnqcBFye{lr~1 zJgR@K;hAcO($O3DQqDhleRjW`E;buOW{45GZxv>2z)f?HzrAKQ?FuCLZiL{lNYB>~ zL+NKx*~!w~*aw{oXnXE8IdQM}l?>NzvX6R2H6mWn{eC0pSxkfQ%i$-U5&WZaXJjb) z70mU9WaTS4K{s+tP{nh^Md)*m6$sOe$I)9ooXlb4FIM0TB1=yJ#-^=P-V|kL(>^Hb z=mC(aupHYNhpow8Z<=jC<=K$}BM$o&{5xo(1H%Dw3T!n}5Mmum=GI=b(nT3YTAysA zmnf~_PtfxfNv_6>H-r?tGLp0Wqjr|NIho@;+5t4&sbxwb27Ov;gVOY5h~V z-|(=6$*2(tsO50IYraJzemYmRj(j%zHF=|?T@W(;L^;1H9I&kwa9V__$ITBM)$JGn z_!Iiihc56hHbalNSFsF;zzt?c7wPqwNRa0j+T8B2$sw=l=a;6MHl?ntU@wgT4kK^k z;w4BGzk70sw?HZ&KEOdX=15 zCJ7VNN_Vm%-$f_8Ip$Sas1?F#_vKm9AaY*3%nI6e$?01T{u*Ba+M^aD-b{~_@=C+y zK$wKGIwNrm*r6cMQ^8T!OO(0dHepEUCHn;ZhG&{aO#E?mSuJvLq-tW4p+>^K7ny*a zbIHJS3u*o-lvJ;qBITgwcKo7+UltRpkAT%l zNoQue9h=Um8aE7D&;Z5?T8gQdvX%_ny%{KtpU+c}sCWZd9iD`%rBJPYnjCZ9Ks=q{ z*){0fr{lNx`D2{6s!*Hh2IqpqHlbA3#1W~fO2o4Ku|B}~?E*&17@OS znRvXGB{}s%)obJdYa(6Mch>zMk-q z?BUb9H8>g8JpQ?Ij5ze|h{%TC3)MbOf@xt01xvXbMb%Dd#R?>^V3%%Uh3b9>FTh1` zNU_MBB+S5Kxms%G;PQmX2)6dzuSsbzznh8xJV-p>1g(71b8mJF6&+08S1L7V5R?66kiY`Z_lGYplLuc4H zK)=6{Zj#-yjp_cCMEwqGABcq-C|*~}GByZV91NS}OjVX3WvIZ4r||O>bkp=?WSH_wCk8FNbM`+sD>L0dq0kK!1X@CO=d{*?J`^ii{Cai73 z$Qe>fxby+H*ANS!5LLR%twOz*PY8q3*x+=9KWeWbJ^+C;!OR($j33;lM7Z;SP}JN$Nsf9#kg(yL!?!ED?*?w(bk06&C2Qm<6kKJ0(} C Date: Fri, 5 Jul 2024 09:24:45 +1000 Subject: [PATCH 24/47] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d870f1b..1f49be23 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,6 @@ After building the platform, you will now have the prebuilt binaries in the `/pl You can now run an example like; ```sh -$ roc exmaples/hello-world.roc +$ roc examples/hello-world.roc Hello, World! ``` From dfeb68a7424eee930bb2f66a2f101911696219fc Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Fri, 5 Jul 2024 09:33:14 +1000 Subject: [PATCH 25/47] add more documentation --- crates/README.md | 5 +++++ crates/roc_host/Cargo.toml | 1 + crates/roc_host_bin/Cargo.toml | 1 + crates/roc_host_lib/Cargo.toml | 1 + 4 files changed, 8 insertions(+) create mode 100644 crates/README.md diff --git a/crates/README.md b/crates/README.md new file mode 100644 index 00000000..eb0e747d --- /dev/null +++ b/crates/README.md @@ -0,0 +1,5 @@ +# basic-cli host + +These crates provide the host for the basic-cli platform. + +The host is a cli application that will call into roc and provides functionality to allocate memory and execute effects such as writing to stdio or making HTTP requests. diff --git a/crates/roc_host/Cargo.toml b/crates/roc_host/Cargo.toml index 1e2293ef..b1c41186 100644 --- a/crates/roc_host/Cargo.toml +++ b/crates/roc_host/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" +description = "This provides the host implementation for the platform." [lib] name = "roc_host" diff --git a/crates/roc_host_bin/Cargo.toml b/crates/roc_host_bin/Cargo.toml index 2b336dcd..7d47b485 100644 --- a/crates/roc_host_bin/Cargo.toml +++ b/crates/roc_host_bin/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" +description = "This crate wraps roc_host to build an executable ready for preprocessing for surgical linking" links = "app" diff --git a/crates/roc_host_lib/Cargo.toml b/crates/roc_host_lib/Cargo.toml index 4eb86d63..229d2a53 100644 --- a/crates/roc_host_lib/Cargo.toml +++ b/crates/roc_host_lib/Cargo.toml @@ -4,6 +4,7 @@ version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" +description = "This crate wraps roc_host to build a static library for legacy linking" [lib] name = "host" From 9017380afbbbf00113b1856e473ce434c3077446 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:41:22 +0200 Subject: [PATCH 26/47] use updated basic-cli 0.12.0 --- build.roc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.roc b/build.roc index f76bfcfc..3ebd13d3 100644 --- a/build.roc +++ b/build.roc @@ -1,5 +1,5 @@ app [main] { - cli: platform "TODO use updated basic-cli 0.12.0 (requires changes from github.com/roc-lang/basic-cli/pull/224)", + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br", } import cli.Task exposing [Task] From 8ad3179ac2a59ebb8b40abf48040379a6eb78efb Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 14 Jul 2024 18:39:10 +1000 Subject: [PATCH 27/47] update for new glue & 6894 --- build.roc | 2 +- crates/roc_host/src/lib.rs | 18 ++- crates/roc_std/src/lib.rs | 100 +++++++++++++- crates/roc_std/src/roc_box.rs | 71 ++++++++-- crates/roc_std/src/roc_list.rs | 238 +++++++++++++++++++++++---------- crates/roc_std/src/roc_str.rs | 26 +++- glue.roc | 4 +- jump-start.sh | 26 ++++ platform/Effect.roc | 2 +- platform/Env.roc | 1 + 10 files changed, 390 insertions(+), 98 deletions(-) create mode 100644 jump-start.sh diff --git a/build.roc b/build.roc index 3ebd13d3..7a94448b 100644 --- a/build.roc +++ b/build.roc @@ -1,5 +1,5 @@ app [main] { - cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.12.0/Lb8EgiejTUzbggO2HVVuPJFkwvvsfW6LojkLR20kTVE.tar.br", + cli: platform "platform/main.roc", } import cli.Task exposing [Task] diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index 62c5d6c7..5467a181 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -3,7 +3,7 @@ use core::alloc::Layout; use core::ffi::c_void; use core::mem::MaybeUninit; -use roc_std::{RocDict, RocList, RocResult, RocStr}; +use roc_std::{RocList, RocResult, RocStr}; use std::borrow::{Borrow, Cow}; use std::cell::RefCell; use std::collections::HashMap; @@ -355,7 +355,7 @@ pub unsafe fn call_the_closure(closure_data_ptr: *const u8) -> i32 { } #[no_mangle] -pub extern "C" fn roc_fx_envDict() -> RocDict { +pub extern "C" fn roc_fx_envDict() -> RocList<(RocStr, RocStr)> { // TODO: can we be more efficient about reusing the String's memory for RocStr? std::env::vars_os() .map(|(key, val)| { @@ -755,6 +755,20 @@ pub struct Header { value: RocStr, } +impl roc_std::RocRefcounted for Header { + fn inc(&mut self) { + self.key.inc(); + self.value.inc(); + } + fn dec(&mut self) { + self.key.dec(); + self.value.dec(); + } + fn is_refcounted() -> bool { + true + } +} + #[repr(C)] pub struct Metadata { headers: RocList

, diff --git a/crates/roc_std/src/lib.rs b/crates/roc_std/src/lib.rs index 30cdcdbb..c8f67577 100644 --- a/crates/roc_std/src/lib.rs +++ b/crates/roc_std/src/lib.rs @@ -10,18 +10,15 @@ use core::hash::{Hash, Hasher}; use core::mem::{ManuallyDrop, MaybeUninit}; use core::ops::Drop; use core::str; +use std::convert::Infallible; mod roc_box; -mod roc_dict; mod roc_list; -mod roc_set; mod roc_str; mod storage; pub use roc_box::RocBox; -pub use roc_dict::RocDict; pub use roc_list::{RocList, SendSafeRocList}; -pub use roc_set::RocSet; pub use roc_str::{InteriorNulError, RocStr, SendSafeRocStr}; pub use storage::Storage; @@ -557,3 +554,98 @@ impl Hash for U128 { u128::from(*self).hash(state); } } + +/// All Roc types that are refcounted must implement this trait. +/// +/// For aggregate types, this must recurse down the structure. +pub trait RocRefcounted { + /// Increments the refcount. + fn inc(&mut self); + + /// Decrements the refcount potentially freeing the underlying allocation. + fn dec(&mut self); + + /// Returns true if the type is actually refcounted by roc. + fn is_refcounted() -> bool; +} + +#[macro_export] +macro_rules! roc_refcounted_noop_impl { + ( $( $T:tt),+ ) => { + $( + impl RocRefcounted for $T { + fn inc(&mut self) {} + fn dec(&mut self) {} + fn is_refcounted() -> bool { + false + } + } + )+ + }; +} +roc_refcounted_noop_impl!(bool); +roc_refcounted_noop_impl!(u8, u16, u32, u64, u128, U128); +roc_refcounted_noop_impl!(i8, i16, i32, i64, i128, I128); +roc_refcounted_noop_impl!(f32, f64); +roc_refcounted_noop_impl!(RocDec); +roc_refcounted_noop_impl!(Infallible, ()); + +macro_rules! roc_refcounted_arr_impl { + ( $n:tt ) => { + impl RocRefcounted for [T; $n] + where + T: RocRefcounted, + { + fn inc(&mut self) { + self.iter_mut().for_each(|x| x.inc()); + } + fn dec(&mut self) { + self.iter_mut().for_each(|x| x.dec()); + } + fn is_refcounted() -> bool { + T::is_refcounted() + } + } + }; +} + +roc_refcounted_arr_impl!(0); +roc_refcounted_arr_impl!(1); +roc_refcounted_arr_impl!(2); +roc_refcounted_arr_impl!(3); +roc_refcounted_arr_impl!(4); +roc_refcounted_arr_impl!(5); +roc_refcounted_arr_impl!(6); +roc_refcounted_arr_impl!(7); +roc_refcounted_arr_impl!(8); + +macro_rules! roc_refcounted_tuple_impl { + ( $( $idx:tt $T:ident),* ) => { + impl<$($T, )+> RocRefcounted for ($($T, )*) + where + $($T : RocRefcounted, )* + { + fn inc(&mut self) { + $( + self.$idx.inc(); + )* + } + fn dec(&mut self) { + $( + self.$idx.dec(); + )* + } + fn is_refcounted() -> bool { + $($T::is_refcounted() || )* false + } + } + }; +} + +roc_refcounted_tuple_impl!(0 A, 1 B); +roc_refcounted_tuple_impl!(0 A, 1 B, 2 C); +roc_refcounted_tuple_impl!(0 A, 1 B, 3 C, 3 D); +roc_refcounted_tuple_impl!(0 A, 1 B, 3 C, 3 D, 4 E); +roc_refcounted_tuple_impl!(0 A, 1 B, 3 C, 3 D, 4 E, 5 F); +roc_refcounted_tuple_impl!(0 A, 1 B, 3 C, 3 D, 4 E, 5 F, 6 G); +roc_refcounted_tuple_impl!(0 A, 1 B, 3 C, 3 D, 4 E, 5 F, 6 G, 7 H); diff --git a/crates/roc_std/src/roc_box.rs b/crates/roc_std/src/roc_box.rs index bb69f445..688525af 100644 --- a/crates/roc_std/src/roc_box.rs +++ b/crates/roc_std/src/roc_box.rs @@ -1,6 +1,6 @@ #![deny(unsafe_op_in_unsafe_fn)] -use crate::{roc_alloc, roc_dealloc, storage::Storage}; +use crate::{roc_alloc, roc_dealloc, storage::Storage, RocRefcounted}; use core::{ cell::Cell, cmp::{self, Ordering}, @@ -11,11 +11,17 @@ use core::{ }; #[repr(C)] -pub struct RocBox { +pub struct RocBox +where + T: RocRefcounted, +{ contents: NonNull, } -impl RocBox { +impl RocBox +where + T: RocRefcounted, +{ pub fn new(contents: T) -> Self { let alignment = Self::alloc_alignment(); let bytes = mem::size_of::() + alignment; @@ -76,7 +82,10 @@ impl RocBox { } } -impl Deref for RocBox { +impl Deref for RocBox +where + T: RocRefcounted, +{ type Target = T; fn deref(&self) -> &Self::Target { @@ -86,18 +95,20 @@ impl Deref for RocBox { impl PartialEq> for RocBox where - T: PartialEq, + T: PartialEq + RocRefcounted, + U: RocRefcounted, { fn eq(&self, other: &RocBox) -> bool { self.deref() == other.deref() } } -impl Eq for RocBox where T: Eq {} +impl Eq for RocBox where T: Eq + RocRefcounted {} impl PartialOrd> for RocBox where - T: PartialOrd, + T: PartialOrd + RocRefcounted, + U: RocRefcounted, { fn partial_cmp(&self, other: &RocBox) -> Option { let self_contents = unsafe { self.contents.as_ref() }; @@ -109,7 +120,7 @@ where impl Ord for RocBox where - T: Ord, + T: Ord + RocRefcounted, { fn cmp(&self, other: &Self) -> Ordering { let self_contents = unsafe { self.contents.as_ref() }; @@ -119,7 +130,10 @@ where } } -impl core::hash::Hash for RocBox { +impl core::hash::Hash for RocBox +where + T: RocRefcounted, +{ fn hash(&self, state: &mut H) { self.contents.hash(state) } @@ -127,14 +141,17 @@ impl core::hash::Hash for RocBox { impl Debug for RocBox where - T: Debug, + T: Debug + RocRefcounted, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.deref().fmt(f) } } -impl Clone for RocBox { +impl Clone for RocBox +where + T: RocRefcounted, +{ fn clone(&self) -> Self { let storage = self.storage(); let mut new_storage = storage.get(); @@ -151,8 +168,30 @@ impl Clone for RocBox { } } -impl Drop for RocBox { +impl Drop for RocBox +where + T: RocRefcounted, +{ fn drop(&mut self) { + self.dec() + } +} + +impl RocRefcounted for RocBox +where + T: RocRefcounted, +{ + fn inc(&mut self) { + let storage = self.storage(); + let mut new_storage = storage.get(); + + if !new_storage.is_readonly() { + new_storage.increment_reference_count(); + storage.set(new_storage); + } + } + + fn dec(&mut self) { let storage = self.storage(); let contents = self.contents; @@ -165,7 +204,9 @@ impl Drop for RocBox { // Drop the stored contents. let contents_ptr = contents.as_ptr(); - mem::drop::(ptr::read(contents_ptr)); + if T::is_refcounted() { + ptr::read(contents_ptr).dec(); + } let alignment = Self::alloc_alignment(); @@ -180,4 +221,8 @@ impl Drop for RocBox { storage.set(new_storage); } } + + fn is_refcounted() -> bool { + true + } } diff --git a/crates/roc_std/src/roc_list.rs b/crates/roc_std/src/roc_list.rs index a7623bb2..70387106 100644 --- a/crates/roc_std/src/roc_list.rs +++ b/crates/roc_std/src/roc_list.rs @@ -12,9 +12,9 @@ use core::{ ops::{Deref, DerefMut}, ptr::{self, NonNull}, }; -use std::ops::Range; +use std::{cmp::max, ops::Range}; -use crate::{roc_alloc, roc_dealloc, roc_realloc, storage::Storage}; +use crate::{roc_alloc, roc_dealloc, roc_realloc, storage::Storage, RocRefcounted}; #[cfg(feature = "serde")] use core::marker::PhantomData; @@ -26,7 +26,10 @@ use serde::{ }; #[repr(C)] -pub struct RocList { +pub struct RocList +where + T: RocRefcounted, +{ elements: Option>>, length: usize, // This technically points to directly after the refcount. @@ -34,10 +37,22 @@ pub struct RocList { capacity_or_ref_ptr: usize, } -impl RocList { +impl RocList +where + T: RocRefcounted, +{ #[inline(always)] - fn alloc_alignment() -> u32 { - mem::align_of::().max(mem::align_of::()) as u32 + fn alloc_alignment() -> usize { + mem::align_of::().max(mem::align_of::()) + } + + fn alloc_to_elem_offset() -> usize { + let min_offset = if T::is_refcounted() { + 2 * mem::size_of::() + } else { + mem::size_of::() + }; + max(Self::alloc_alignment(), min_offset) } pub fn empty() -> Self { @@ -66,12 +81,12 @@ impl RocList { /// returns the number of bytes needed to allocate, taking into account both the /// size of the elements as well as the size of Storage. fn alloc_bytes(num_elems: usize) -> usize { - next_multiple_of(mem::size_of::(), mem::align_of::()) - + (num_elems * mem::size_of::()) + Self::alloc_to_elem_offset() + (num_elems * mem::size_of::()) } fn elems_with_capacity(num_elems: usize) -> NonNull> { - let alloc_ptr = unsafe { roc_alloc(Self::alloc_bytes(num_elems), Self::alloc_alignment()) }; + let alloc_ptr = + unsafe { roc_alloc(Self::alloc_bytes(num_elems), Self::alloc_alignment() as u32) }; Self::elems_from_allocation(NonNull::new(alloc_ptr).unwrap_or_else(|| { todo!("Call roc_panic with the info that an allocation failed."); @@ -79,14 +94,14 @@ impl RocList { } fn elems_from_allocation(allocation: NonNull) -> NonNull> { - let offset = Self::alloc_alignment() - core::mem::size_of::<*const u8>() as u32; + let offset = Self::alloc_to_elem_offset() - core::mem::size_of::(); let alloc_ptr = allocation.as_ptr(); unsafe { let elem_ptr = Self::elem_ptr_from_alloc_ptr(alloc_ptr).cast::>(); // Initialize the reference count. - let rc_ptr = alloc_ptr.offset(offset as isize); + let rc_ptr = alloc_ptr.add(offset); rc_ptr .cast::() .write(Storage::new_reference_counted()); @@ -193,10 +208,14 @@ impl RocList { fn elements_and_storage(&self) -> Option<(NonNull>, &Cell)> { let elements = self.elements?; - let offset = match mem::align_of::() { - 16 => 1, - 8 | 4 | 2 | 1 => 0, - other => unreachable!("invalid alignment {other}"), + let offset = if T::is_refcounted() { + 1 + } else { + match mem::align_of::() { + 16 => 1, + 8 | 4 | 2 | 1 => 0, + other => unreachable!("invalid alignment {other}"), + } }; let storage = unsafe { &*self.ptr_to_allocation().cast::>().add(offset) }; @@ -214,17 +233,25 @@ impl RocList { } /// Useful for doing memcpy on the underlying allocation. Returns NULL if list is empty. - pub(crate) fn ptr_to_allocation(&self) -> *mut c_void { - let alignment = Self::alloc_alignment() as usize; + fn ptr_to_allocation(&self) -> *mut c_void { + let offset = Self::alloc_to_elem_offset(); if self.is_seamless_slice() { - ((self.capacity_or_ref_ptr << 1) - alignment) as *mut _ + ((self.capacity_or_ref_ptr << 1) - offset) as *mut _ } else { - unsafe { self.ptr_to_first_elem().cast::().sub(alignment) as *mut _ } + unsafe { self.ptr_to_first_elem().cast::().sub(offset) as *mut _ } + } + } + + fn allocation_element_count(&self) -> usize { + if self.is_seamless_slice() && T::is_refcounted() { + unsafe { self.ptr_to_refcount().sub(1).read() } + } else { + self.len() } } #[allow(unused)] - pub(crate) fn ptr_to_refcount(&self) -> *mut c_void { + pub(crate) fn ptr_to_refcount(&self) -> *mut usize { if self.is_seamless_slice() { ((self.capacity_or_ref_ptr << 1) - std::mem::size_of::()) as *mut _ } else { @@ -233,12 +260,8 @@ impl RocList { } unsafe fn elem_ptr_from_alloc_ptr(alloc_ptr: *mut c_void) -> *mut c_void { - unsafe { - alloc_ptr - .cast::() - .add(Self::alloc_alignment() as usize) - .cast() - } + let offset = Self::alloc_to_elem_offset(); + unsafe { alloc_ptr.cast::().add(offset).cast() } } pub fn append(&mut self, value: T) { @@ -282,7 +305,7 @@ impl RocList { impl RocList where - T: Clone, + T: Clone + RocRefcounted, { pub fn from_slice(slice: &[T]) -> Self { let mut list = Self::empty(); @@ -304,17 +327,17 @@ where if is_unique { // If we have enough capacity, we can add to the existing elements in-place. - if self.capacity() >= slice.len() { + if self.capacity() >= new_len { elements } else { // There wasn't enough capacity, so we need a new allocation. // Since this is a unique RocList, we can use realloc here. let new_ptr = unsafe { roc_realloc( - storage.as_ptr().cast(), + self.ptr_to_allocation(), Self::alloc_bytes(new_len), Self::alloc_bytes(self.capacity()), - Self::alloc_alignment(), + Self::alloc_alignment() as u32, ) }; @@ -370,7 +393,10 @@ where } } -impl RocList { +impl RocList +where + T: RocRefcounted, +{ #[track_caller] pub fn slice_range(&self, range: Range) -> Self { match self.try_slice_range(range) { @@ -422,7 +448,7 @@ impl RocList { old_alloc, Self::alloc_bytes(new_len), Self::alloc_bytes(self.capacity()), - Self::alloc_alignment(), + Self::alloc_alignment() as u32, ); if new_alloc == old_alloc { @@ -464,7 +490,10 @@ impl RocList { // The new allocation is referencing them, so instead of incrementing them all // all just to decrement them again here, we neither increment nor decrement them. unsafe { - roc_dealloc(self.ptr_to_allocation(), Self::alloc_alignment()); + roc_dealloc( + self.ptr_to_allocation(), + Self::alloc_alignment() as u32, + ); } } else { // Write the storage back. @@ -499,7 +528,10 @@ impl RocList { } } -impl Deref for RocList { +impl Deref for RocList +where + T: RocRefcounted, +{ type Target = [T]; fn deref(&self) -> &Self::Target { @@ -513,7 +545,10 @@ impl Deref for RocList { } } -impl DerefMut for RocList { +impl DerefMut for RocList +where + T: RocRefcounted, +{ fn deref_mut(&mut self) -> &mut Self::Target { if let Some(elements) = self.elements { let ptr = elements.as_ptr().cast::(); @@ -526,7 +561,10 @@ impl DerefMut for RocList { } } -impl Default for RocList { +impl Default for RocList +where + T: RocRefcounted, +{ fn default() -> Self { Self::empty() } @@ -534,18 +572,20 @@ impl Default for RocList { impl PartialEq> for RocList where - T: PartialEq, + U: RocRefcounted, + T: PartialEq + RocRefcounted, { fn eq(&self, other: &RocList) -> bool { self.as_slice() == other.as_slice() } } -impl Eq for RocList where T: Eq {} +impl Eq for RocList where T: Eq + RocRefcounted {} impl PartialOrd> for RocList where - T: PartialOrd, + U: RocRefcounted, + T: PartialOrd + RocRefcounted, { fn partial_cmp(&self, other: &RocList) -> Option { // If one is longer than the other, use that as the ordering. @@ -569,7 +609,7 @@ where impl Ord for RocList where - T: Ord, + T: Ord + RocRefcounted, { fn cmp(&self, other: &Self) -> Ordering { // If one is longer than the other, use that as the ordering. @@ -593,14 +633,17 @@ where impl Debug for RocList where - T: Debug, + T: Debug + RocRefcounted, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.deref().fmt(f) } } -impl Clone for RocList { +impl Clone for RocList +where + T: RocRefcounted, +{ fn clone(&self) -> Self { // Increment the reference count if let Some((_, storage)) = self.elements_and_storage() { @@ -620,9 +663,25 @@ impl Clone for RocList { } } -impl Drop for RocList { - fn drop(&mut self) { - if let Some((elements, storage)) = self.elements_and_storage() { +impl RocRefcounted for RocList +where + T: RocRefcounted, +{ + fn inc(&mut self) { + if self.elements.is_none() { + // Empty, non-allocated list, no refcounting to do. + return; + } + + let ptr = self.ptr_to_refcount(); + unsafe { + let value = std::ptr::read(ptr); + std::ptr::write(ptr, Ord::max(0, ((value as isize) + 1) as usize)); + } + } + + fn dec(&mut self) { + if let Some((_, storage)) = self.elements_and_storage() { // Decrease the list's reference count. let mut new_storage = storage.get(); @@ -630,14 +689,19 @@ impl Drop for RocList { let needs_dealloc = new_storage.decrease(); if needs_dealloc { + let alloc_ptr = self.ptr_to_allocation(); unsafe { - // Drop the stored elements. - for index in 0..self.len() { - ManuallyDrop::drop(&mut *elements.as_ptr().add(index)); + // Dec the stored elements in the underlying allocation. + if T::is_refcounted() { + let elements_ptr = Self::elem_ptr_from_alloc_ptr(alloc_ptr) as *mut T; + let len = self.allocation_element_count(); + for index in 0..len { + (*elements_ptr.add(index)).dec() + } } // Release the memory. - roc_dealloc(self.ptr_to_allocation(), Self::alloc_alignment()); + roc_dealloc(alloc_ptr, Self::alloc_alignment() as u32); } } else { // Write the storage back. @@ -646,24 +710,43 @@ impl Drop for RocList { } } } + + fn is_refcounted() -> bool { + true + } +} + +impl Drop for RocList +where + T: RocRefcounted, +{ + fn drop(&mut self) { + self.dec() + } } impl From<&[T]> for RocList where - T: Clone, + T: Clone + RocRefcounted, { fn from(slice: &[T]) -> Self { Self::from_slice(slice) } } -impl From<[T; SIZE]> for RocList { +impl From<[T; SIZE]> for RocList +where + T: RocRefcounted, +{ fn from(array: [T; SIZE]) -> Self { Self::from_iter(array) } } -impl<'a, T> IntoIterator for &'a RocList { +impl<'a, T> IntoIterator for &'a RocList +where + T: RocRefcounted, +{ type Item = &'a T; type IntoIter = core::slice::Iter<'a, T>; @@ -672,7 +755,10 @@ impl<'a, T> IntoIterator for &'a RocList { } } -impl Hash for RocList { +impl Hash for RocList +where + T: RocRefcounted, +{ fn hash(&self, state: &mut H) { // This is the same as Rust's Vec implementation, which // just delegates to the slice implementation. It's a bit surprising @@ -688,7 +774,10 @@ impl Hash for RocList { } } -impl FromIterator for RocList { +impl FromIterator for RocList +where + T: RocRefcounted, +{ fn from_iter(into: I) -> Self where I: IntoIterator, @@ -732,7 +821,10 @@ impl FromIterator for RocList { } #[cfg(feature = "serde")] -impl Serialize for RocList { +impl Serialize for RocList +where + T: RocRefcounted, +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -750,7 +842,7 @@ impl<'de, T> Deserialize<'de> for RocList where // TODO: I'm not sure about requiring clone here. Is that fine? Is that // gonna mean lots of extra allocations? - T: Deserialize<'de> + core::clone::Clone, + T: Deserialize<'de> + core::clone::Clone + RocRefcounted, { fn deserialize(deserializer: D) -> Result where @@ -762,13 +854,15 @@ where // This is a RocList that is checked to ensure it is unique or readonly such that it can be sent between threads safely. #[repr(transparent)] -pub struct SendSafeRocList(RocList); +pub struct SendSafeRocList(RocList) +where + T: RocRefcounted; -unsafe impl Send for SendSafeRocList where T: Send {} +unsafe impl Send for SendSafeRocList where T: Send + RocRefcounted {} impl Clone for SendSafeRocList where - T: Clone, + T: Clone + RocRefcounted, { fn clone(&self) -> Self { if self.0.is_readonly() { @@ -782,7 +876,7 @@ where impl From> for SendSafeRocList where - T: Clone, + T: Clone + RocRefcounted, { fn from(l: RocList) -> Self { if l.is_unique() || l.is_readonly() { @@ -796,19 +890,28 @@ where } } -impl From> for RocList { +impl From> for RocList +where + T: RocRefcounted, +{ fn from(l: SendSafeRocList) -> Self { l.0 } } #[cfg(feature = "serde")] -struct RocListVisitor { +struct RocListVisitor +where + T: RocRefcounted, +{ marker: PhantomData, } #[cfg(feature = "serde")] -impl RocListVisitor { +impl RocListVisitor +where + T: RocRefcounted, +{ fn new() -> Self { RocListVisitor { marker: PhantomData, @@ -819,7 +922,7 @@ impl RocListVisitor { #[cfg(feature = "serde")] impl<'de, T> Visitor<'de> for RocListVisitor where - T: Deserialize<'de> + core::clone::Clone, + T: Deserialize<'de> + core::clone::Clone + RocRefcounted, { type Value = RocList; @@ -846,13 +949,6 @@ where } } -const fn next_multiple_of(lhs: usize, rhs: usize) -> usize { - match lhs % rhs { - 0 => lhs, - r => lhs + (rhs - r), - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/roc_std/src/roc_str.rs b/crates/roc_std/src/roc_str.rs index 3ff02f26..046b4825 100644 --- a/crates/roc_std/src/roc_str.rs +++ b/crates/roc_std/src/roc_str.rs @@ -21,7 +21,7 @@ use core::{ use std::ffi::{CStr, CString}; use std::{ops::Range, ptr::NonNull}; -use crate::{roc_realloc, RocList}; +use crate::{roc_realloc, RocList, RocRefcounted}; #[repr(transparent)] pub struct RocStr(RocStrInner); @@ -792,6 +792,24 @@ impl From for RocStr { } } +impl RocRefcounted for RocStr { + fn inc(&mut self) { + if !self.is_small_str() { + unsafe { self.0.heap_allocated.deref_mut().inc() } + } + } + + fn dec(&mut self) { + if !self.is_small_str() { + unsafe { self.0.heap_allocated.deref_mut().dec() } + } + } + + fn is_refcounted() -> bool { + true + } +} + #[repr(C)] struct BigString { elements: NonNull, @@ -872,11 +890,11 @@ impl BigString { unsafe { std::ptr::write(ptr, 0) } } - fn inc(&mut self, n: usize) { + fn inc(&mut self) { let ptr = self.ptr_to_refcount(); unsafe { let value = std::ptr::read(ptr); - std::ptr::write(ptr, Ord::max(0, ((value as isize) + n as isize) as usize)); + std::ptr::write(ptr, Ord::max(0, ((value as isize) + 1) as usize)); } } @@ -977,7 +995,7 @@ impl Clone for BigString { capacity_or_alloc_ptr: self.capacity_or_alloc_ptr, }; - this.inc(1); + this.inc(); this } diff --git a/glue.roc b/glue.roc index 668ab7a2..a0e12a3b 100644 --- a/glue.roc +++ b/glue.roc @@ -1,6 +1,6 @@ app [makeGlue] { - pf: platform "https://github.com/lukewilliamboswell/roc/releases/download/test/olBfrjtI-HycorWJMxdy7Dl2pcbbBoJy4mnSrDtRrlI.tar.br", - glue: "https://github.com/lukewilliamboswell/roc-glue-code-gen/releases/download/0.1.0/NprKi63CKBinQjoke2ttsOTHmjmsrmsILzRgzlds02c.tar.br", + pf: platform "https://github.com/lukewilliamboswell/roc/releases/download/glue-0.2/5bWcGHHGninJr_RP0-Mg5lPEGYGpPeYwYmVCwG_cZG4.tar.br", + glue: "https://github.com/lukewilliamboswell/roc-glue-code-gen/releases/download/0.4.0/E6x8uVSMI0YQ9CgpMww6Cj2g3BlN1lV8H04UEZh_-QA.tar.br", } import glue.Rust diff --git a/jump-start.sh b/jump-start.sh new file mode 100644 index 00000000..80b11283 --- /dev/null +++ b/jump-start.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +## This script is used to build a local prebuilt binary for the native target, +## so that the build.roc script can be run. This is only needed in the event +## of a breaking change in the roc compiler that prevents older version of the +## build script from running. +## +## To use this, change the build.roc script to use the platform locally.. + +# https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ +set -euxo pipefail + +roc build --lib ./platform/libapp.roc + +roc glue glue.roc crates ./platform/main.roc + +cargo build --release + +cp target/release/libhost.a ./platform/macos-arm64.a +cp target/release/libhost.a ./platform/macos-x64.a +cp target/release/libhost.a ./platform/linux-arm64.a +cp target/release/libhost.a ./platform/linux-x64.a +cp target/release/libhost.lib ./platform/windows-arm64.lib +cp target/release/libhost.lib ./platform/windows-x64.lib + +roc build build.roc diff --git a/platform/Effect.roc b/platform/Effect.roc index 6ae839ed..06dc8e98 100644 --- a/platform/Effect.roc +++ b/platform/Effect.roc @@ -71,7 +71,7 @@ fileReader : List U8 -> Effect (Result U64 Str) fileReadLine : U64 -> Effect (Result (List U8) Str) closeFile : U64 -> Effect {} -envDict : Effect (Dict Str Str) +envDict : Effect (List (Str, Str)) envVar : Str -> Effect (Result Str {}) exePath : Effect (Result (List U8) {}) setCwd : List U8 -> Effect (Result {} {}) diff --git a/platform/Env.roc b/platform/Env.roc index f073b492..75b01a1f 100644 --- a/platform/Env.roc +++ b/platform/Env.roc @@ -95,6 +95,7 @@ decode = \name -> dict : Task (Dict Str Str) * dict = Effect.envDict + |> Effect.map Dict.fromList |> Effect.map Ok |> InternalTask.fromEffect From b61cee64cb345cc99a4d9a89597b3ccc7546ffbd Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 14 Jul 2024 18:40:52 +1000 Subject: [PATCH 28/47] update flake --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index 8e5d74f3..88c8ef06 100644 --- a/flake.lock +++ b/flake.lock @@ -102,11 +102,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1720536414, - "narHash": "sha256-vze8JUGtxucoPbi3aRtPLdxbF6LIJbjVQoxr0oifD1I=", + "lastModified": 1720924256, + "narHash": "sha256-P9yElKsIEk6rp2AK3wf2vQQIlPh+BQQkvE+9BKg5BWs=", "owner": "roc-lang", "repo": "roc", - "rev": "0d9db5bf2dfbc035c8c56a1c65be9047e8583fb8", + "rev": "0284248320e1a72bb5823bd7005c6521c1c70857", "type": "github" }, "original": { @@ -158,11 +158,11 @@ ] }, "locked": { - "lastModified": 1720491570, - "narHash": "sha256-PHS2BcQ9kxBpu9GKlDg3uAlrX/ahQOoAiVmwGl6BjD4=", + "lastModified": 1720923816, + "narHash": "sha256-GrDL1nFYZrB/+Ah1hNoaNFfduB1agpfqL9QyEl12UOU=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "b970af40fdc4bd80fd764796c5f97c15e2b564eb", + "rev": "fb8c8be0313f0e6385b3d70151a04ea1d71e4b68", "type": "github" }, "original": { From a5c0f0b02f383fd61b8a1a48489b2bf25e75c116 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 14 Jul 2024 18:48:40 +1000 Subject: [PATCH 29/47] update build.roc arg parsing --- build.roc | 16 ++++++++-------- jump-start.sh | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/build.roc b/build.roc index 7a94448b..7b3206b7 100644 --- a/build.roc +++ b/build.roc @@ -7,8 +7,8 @@ import cli.Cmd import cli.Stdout import cli.Env import cli.Arg -import cli.Arg.Opt as Opt -import cli.Arg.Cli as Cli +import cli.Arg.Opt +import cli.Arg.Cli ## Builds the basic-cli [platform](https://www.roc-lang.org/platforms). ## @@ -18,19 +18,19 @@ main : Task {} _ main = cliParser = - Cli.build { - releaseMode: <- Opt.flag { short: "r", long: "release", help: "Release build. Passes `--release` to `cargo build`." }, - maybeRoc: <- Opt.maybeStr { short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path."}, + { Arg.Cli.combine <- + releaseMode: Arg.Opt.flag { short: "r", long: "release", help: "Release build. Passes `--release` to `cargo build`." }, + maybeRoc: Arg.Opt.maybeStr { short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path."}, } - |> Cli.finish { + |> Arg.Cli.finish { name: "basic-cli-builder", version: "", authors: ["Luke Boswell "], description: "Generates all files needed by Roc to use this basic-cli platform.", } - |> Cli.assertValid + |> Arg.Cli.assertValid - when Cli.parseOrDisplayMessage cliParser (Arg.list!) is + when Arg.Cli.parseOrDisplayMessage cliParser (Arg.list! {}) is Ok args -> run args Err errMsg -> Task.err (Exit 1 errMsg) diff --git a/jump-start.sh b/jump-start.sh index 80b11283..3df3ea77 100644 --- a/jump-start.sh +++ b/jump-start.sh @@ -16,11 +16,11 @@ roc glue glue.roc crates ./platform/main.roc cargo build --release -cp target/release/libhost.a ./platform/macos-arm64.a -cp target/release/libhost.a ./platform/macos-x64.a -cp target/release/libhost.a ./platform/linux-arm64.a -cp target/release/libhost.a ./platform/linux-x64.a -cp target/release/libhost.lib ./platform/windows-arm64.lib -cp target/release/libhost.lib ./platform/windows-x64.lib +cp target/release/libhost.a ./platform/macos-arm64.a || true +cp target/release/libhost.a ./platform/macos-x64.a || true +cp target/release/libhost.a ./platform/linux-arm64.a || true +cp target/release/libhost.a ./platform/linux-x64.a || true +cp target/release/libhost.lib ./platform/windows-arm64.lib || true +cp target/release/libhost.lib ./platform/windows-x64.lib || true roc build build.roc From d440b8d651d5d19af7f44a2ab9f8b92d72ea5038 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Sun, 14 Jul 2024 18:55:29 +1000 Subject: [PATCH 30/47] use generic legacy host, and legacy linker --- jump-start.sh | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/jump-start.sh b/jump-start.sh index 3df3ea77..7f213afc 100644 --- a/jump-start.sh +++ b/jump-start.sh @@ -16,11 +16,6 @@ roc glue glue.roc crates ./platform/main.roc cargo build --release -cp target/release/libhost.a ./platform/macos-arm64.a || true -cp target/release/libhost.a ./platform/macos-x64.a || true -cp target/release/libhost.a ./platform/linux-arm64.a || true -cp target/release/libhost.a ./platform/linux-x64.a || true -cp target/release/libhost.lib ./platform/windows-arm64.lib || true -cp target/release/libhost.lib ./platform/windows-x64.lib || true +cp target/release/libhost.a ./platform/libhost.a -roc build build.roc +roc build --linker=legacy build.roc From e90f13a6c32b9472b45b6102947dec67962474dd Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:44:11 +0200 Subject: [PATCH 31/47] minor improvements --- README.md | 17 +-- ...ild-steps.png => basic-cli-build-steps.png | Bin build.roc | 103 +++++++++++------- crates/README.md | 20 +++- crates/roc_host/Cargo.toml | 2 +- crates/roc_host/src/lib.rs | 5 + crates/roc_host_bin/Cargo.toml | 2 +- crates/roc_host_lib/Cargo.toml | 2 +- crates/roc_std/Cargo.toml | 2 +- jump-start.sh | 8 +- 10 files changed, 103 insertions(+), 58 deletions(-) rename 20240704-basic-cli-build-steps.png => basic-cli-build-steps.png (100%) diff --git a/README.md b/README.md index 1f49be23..856df14a 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,13 @@ A Roc [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#pla - [0.8.x](https://www.roc-lang.org/packages/basic-cli/0.8.1) - [latest main branch](https://www.roc-lang.org/packages/basic-cli) -## Building the platform - -The following diagram shows the steps for `roc build.roc` which build the platform binaries. - -![diagram of build process](20240704-basic-cli-build-steps.png) - -## Running an example locally - -After building the platform, you will now have the prebuilt binaries in the `/platform` directory. - -You can now run an example like; +## Running locally +If you clone this repo instead of using the release URL you'll need to build the platform once: +```sh +roc build.roc +``` +Then you can run like usual: ```sh $ roc examples/hello-world.roc Hello, World! diff --git a/20240704-basic-cli-build-steps.png b/basic-cli-build-steps.png similarity index 100% rename from 20240704-basic-cli-build-steps.png rename to basic-cli-build-steps.png diff --git a/build.roc b/build.roc index 7b3206b7..f9d0090c 100644 --- a/build.roc +++ b/build.roc @@ -14,6 +14,8 @@ import cli.Arg.Cli ## ## run with: roc ./build.roc --release ## +## Check basic-cli-build-steps.png for a diagram that shows what the code does. +## main : Task {} _ main = @@ -37,52 +39,39 @@ main = run : { releaseMode : Bool, maybeRoc : Result Str err} -> Task {} _ run = \{ releaseMode, maybeRoc } -> - roc = maybeRoc |> Result.withDefault "roc" + rocCmd = maybeRoc |> Result.withDefault "roc" - info! "Generating glue for builtins ..." - roc - |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] - |> Task.mapErr! ErrGeneratingGlue + generateGlue! rocCmd # target is MacosArm64, LinuxX64,... - info! "Getting the native target ..." - target = - Env.platform - |> Task.await! getNativeTarget + target = getNativeTarget! - stubPath = "platform/libapp.$(stubFileExtension target)" + stubLibPath = "platform/libapp.$(stubFileExtension target)" - info! "Building stubbed app shared library ..." - roc - |> Cmd.exec ["build", "--lib", "platform/libapp.roc", "--output", stubPath] - |> Task.mapErr! ErrBuildingAppStub + buildStubAppLib! rocCmd stubLibPath - (cargoBuildArgs, infoMessage) = - if releaseMode then - (["build", "--release"], "Building host in RELEASE mode ...") - else - (["build"], "Building host in DEBUG mode ...") + cargoBuildHost! releaseMode - info! infoMessage - "cargo" - |> Cmd.exec cargoBuildArgs - |> Task.mapErr! ErrBuildingHostBinaries + copyHostLib! releaseMode target - hostBuildPath = if releaseMode then "target/release/libhost.a" else "target/debug/libhost.a" - hostDestPath = "platform/$(prebuiltStaticLibFile target)" + preprocessHost! rocCmd releaseMode stubLibPath - info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." - "cp" - |> Cmd.exec [hostBuildPath, hostDestPath] - |> Task.mapErr! ErrMovingPrebuiltLegacyBinary + info! "Successfully built platform files!" - info! "Preprocessing surgical host ..." - surgicalBuildPath = if releaseMode then "target/release/host" else "target/debug/host" - roc - |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubPath] - |> Task.mapErr! ErrPreprocessingSurgicalBinary +generateGlue : Str -> Task {} _ +generateGlue = \rocCmd -> + info! "Generating glue for builtins ..." - info! "Successfully completed building platform binaries." + rocCmd + |> Cmd.exec ["glue", "glue.roc", "crates/", "platform/main.roc"] + |> Task.mapErr! ErrGeneratingGlue + +getNativeTarget : Task RocTarget _ +getNativeTarget = + info! "Getting the native target ..." + + Env.platform + |> Task.await convertNativeTarget RocTarget : [ MacosArm64, @@ -93,8 +82,8 @@ RocTarget : [ WindowsX64, ] -getNativeTarget : _ -> Task RocTarget _ -getNativeTarget =\{os, arch} -> +convertNativeTarget : _ -> Task RocTarget _ +convertNativeTarget =\{os, arch} -> when (os, arch) is (MACOS, AARCH64) -> Task.ok MacosArm64 (MACOS, X64) -> Task.ok MacosX64 @@ -102,6 +91,13 @@ getNativeTarget =\{os, arch} -> (LINUX, X64) -> Task.ok LinuxX64 _ -> Task.err (UnsupportedNative os arch) +buildStubAppLib : Str, Str -> Task {} _ +buildStubAppLib = \rocCmd, stubLibPath -> + info! "Building stubbed app shared library ..." + rocCmd + |> Cmd.exec ["build", "--lib", "platform/libapp.roc", "--output", stubLibPath] + |> Task.mapErr! ErrBuildingAppStub + stubFileExtension : RocTarget -> Str stubFileExtension = \target -> when target is @@ -119,6 +115,39 @@ prebuiltStaticLibFile = \target -> WindowsArm64 -> "windows-arm64.lib" WindowsX64 -> "windows-x64.lib" +cargoBuildHost : Bool -> Task {} _ +cargoBuildHost = \releaseMode -> + (cargoBuildArgs, infoMessage) = + if releaseMode then + (["build", "--release"], "Building host in RELEASE mode ...") + else + (["build"], "Building host in DEBUG mode ...") + + + info! infoMessage + "cargo" + |> Cmd.exec cargoBuildArgs + |> Task.mapErr! ErrBuildingHostBinaries + +copyHostLib : Bool, RocTarget -> Task {} _ +copyHostLib = \releaseMode, target -> + hostBuildPath = if releaseMode then "target/release/libhost.a" else "target/debug/libhost.a" + hostDestPath = "platform/$(prebuiltStaticLibFile target)" + + info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." + "cp" + |> Cmd.exec [hostBuildPath, hostDestPath] + |> Task.mapErr! ErrMovingPrebuiltLegacyBinary + +preprocessHost : Str, Bool, Str -> Task {} _ +preprocessHost = \rocCmd, releaseMode, stubLibPath -> + info! "Preprocessing surgical host ..." + surgicalBuildPath = if releaseMode then "target/release/host" else "target/debug/host" + + rocCmd + |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubLibPath] + |> Task.mapErr! ErrPreprocessingSurgicalBinary + info : Str -> Task {} _ info = \msg -> Stdout.line! "\u(001b)[34mINFO:\u(001b)[0m $(msg)" diff --git a/crates/README.md b/crates/README.md index eb0e747d..9fba291e 100644 --- a/crates/README.md +++ b/crates/README.md @@ -1,5 +1,21 @@ # basic-cli host -These crates provide the host for the basic-cli platform. +See [basic-cli-build-steps.png](../basic-cli-build-steps.png) to see how these crates +are used in the build process. -The host is a cli application that will call into roc and provides functionality to allocate memory and execute effects such as writing to stdio or making HTTP requests. +## roc_host + +Every Roc platform needs a host. +The host contains code that calls the Roc main function and provides the Roc app with functions to allocate memory and execute effects such as writing to stdio or making HTTP requests. + +## roc_host_bin + +This crate wraps roc_host to build an executable. This executable is used by `roc preprocess-host ...`. That command generates an .rh and .rm file, these files are used by the [surgical linker](https://github.com/roc-lang/roc/tree/main/crates/linker#the-roc-surgical-linker). + +## roc_host_lib + +This crate wraps roc_host and produces a static library (.a file). This .a file is used for legacy linking. Legacy linking refers to using a typical linker like ld or lld instead of the Roc [surgical linker](https://github.com/roc-lang/roc/tree/main/crates/linker#the-roc-surgical-linker). + +## roc_std + +Provides Rust representations of Roc data structures. \ No newline at end of file diff --git a/crates/roc_host/Cargo.toml b/crates/roc_host/Cargo.toml index b1c41186..b6938d9c 100644 --- a/crates/roc_host/Cargo.toml +++ b/crates/roc_host/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" -description = "This provides the host implementation for the platform." +description = "This provides the [host](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#host) implementation for the platform." [lib] name = "roc_host" diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index 9ec03428..46aa65d4 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -17,6 +17,11 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use tokio::runtime::Runtime; +/// Implementation of the host. +/// The host contains code that calls the Roc main function and provides the +/// Roc app with functions to allocate memory and execute effects such as +/// writing to stdio or making HTTP requests. + trait CustomBuffered: BufRead + Read + Seek {} impl CustomBuffered for T {} diff --git a/crates/roc_host_bin/Cargo.toml b/crates/roc_host_bin/Cargo.toml index 7d47b485..5d4edf8a 100644 --- a/crates/roc_host_bin/Cargo.toml +++ b/crates/roc_host_bin/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" -description = "This crate wraps roc_host to build an executable ready for preprocessing for surgical linking" +description = "This crate wraps roc_host to build an executable. This executable is used by `roc preprocess-host ...`. That command generates an .rh and .rm file, these files are used by the [surgical linker](https://github.com/roc-lang/roc/tree/main/crates/linker#the-roc-surgical-linker)." links = "app" diff --git a/crates/roc_host_lib/Cargo.toml b/crates/roc_host_lib/Cargo.toml index 229d2a53..f2ddf0bf 100644 --- a/crates/roc_host_lib/Cargo.toml +++ b/crates/roc_host_lib/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" -description = "This crate wraps roc_host to build a static library for legacy linking" +description = "This crate wraps roc_host and produces a static library (.a file). This .a file is used for legacy linking. Legacy linking refers to using a typical linker like ld or ldd instead of the Roc surgical linker." [lib] name = "host" diff --git a/crates/roc_std/Cargo.toml b/crates/roc_std/Cargo.toml index 8318bdad..655a60db 100644 --- a/crates/roc_std/Cargo.toml +++ b/crates/roc_std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roc_std" -description = "Rust representations of Roc data structures" +description = "Provides Rust representations of Roc data structures." authors = ["The Roc Contributors"] edition = "2021" diff --git a/jump-start.sh b/jump-start.sh index 7f213afc..4a89c8bd 100644 --- a/jump-start.sh +++ b/jump-start.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -## This script is used to build a local prebuilt binary for the native target, -## so that the build.roc script can be run. This is only needed in the event -## of a breaking change in the roc compiler that prevents older version of the -## build script from running. +## This script is only needed in the event of a breaking change in the +## Roc compiler that prevents build.roc from running. +## This script builds a local prebuilt binary for the native target, +## so that the build.roc script can be run. ## ## To use this, change the build.roc script to use the platform locally.. From df631ca7bcf7b68ebfc3ef7ebaea505a6a4a2a07 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 08:23:14 +1000 Subject: [PATCH 32/47] remove linker flag in all_tests CI script --- ci/all_tests.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index dc6aa2bb..dd75c13e 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -38,7 +38,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + $ROC build --prebuilt-platform $roc_file $ROC_BUILD_FLAGS done # prep for next step @@ -88,10 +88,10 @@ for roc_file in $EXAMPLES_DIR*.roc; do if [ "$base_file" == "path.roc" ]; then absolute_roc=$(which $ROC | xargs realpath) cd $EXAMPLES_DIR - $absolute_roc dev --linker=legacy --prebuilt-platform $base_file $ROC_BUILD_FLAGS + $absolute_roc dev --prebuilt-platform $base_file $ROC_BUILD_FLAGS cd .. else - $ROC dev --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + $ROC dev --prebuilt-platform $roc_file $ROC_BUILD_FLAGS fi done From f0508f526d18755565f727f11ce0a96e4a1e41d1 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 08:25:01 +1000 Subject: [PATCH 33/47] put linker flag back in --- ci/all_tests.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index dd75c13e..dc6aa2bb 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -38,7 +38,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + $ROC build --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS done # prep for next step @@ -88,10 +88,10 @@ for roc_file in $EXAMPLES_DIR*.roc; do if [ "$base_file" == "path.roc" ]; then absolute_roc=$(which $ROC | xargs realpath) cd $EXAMPLES_DIR - $absolute_roc dev --prebuilt-platform $base_file $ROC_BUILD_FLAGS + $absolute_roc dev --linker=legacy --prebuilt-platform $base_file $ROC_BUILD_FLAGS cd .. else - $ROC dev --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + $ROC dev --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS fi done From 1414383b2b3e8ef25704ba15265f4b36ad1cf9dd Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 08:27:56 +1000 Subject: [PATCH 34/47] try fixing call to roc in CI --- ci/all_tests.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index dc6aa2bb..992f0c71 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -20,7 +20,7 @@ if [ -z "${ROC}" ]; then fi # build the basic-cli platform -$ROC ./build.roc --release --roc $ROC +$ROC ./build.roc --prebuilt-platform -- --release --roc $ROC # roc check for roc_file in $EXAMPLES_DIR*.roc; do @@ -38,7 +38,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + $ROC build --prebuilt-platform $roc_file $ROC_BUILD_FLAGS done # prep for next step @@ -88,10 +88,10 @@ for roc_file in $EXAMPLES_DIR*.roc; do if [ "$base_file" == "path.roc" ]; then absolute_roc=$(which $ROC | xargs realpath) cd $EXAMPLES_DIR - $absolute_roc dev --linker=legacy --prebuilt-platform $base_file $ROC_BUILD_FLAGS + $absolute_roc dev --prebuilt-platform $base_file $ROC_BUILD_FLAGS cd .. else - $ROC dev --linker=legacy --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + $ROC dev --prebuilt-platform $roc_file $ROC_BUILD_FLAGS fi done From 15546140b7d5eff263d51a38db3f0767d6703e52 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 08:31:18 +1000 Subject: [PATCH 35/47] leave linker flag out --- ci/all_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 992f0c71..dd75c13e 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -20,7 +20,7 @@ if [ -z "${ROC}" ]; then fi # build the basic-cli platform -$ROC ./build.roc --prebuilt-platform -- --release --roc $ROC +$ROC ./build.roc --release --roc $ROC # roc check for roc_file in $EXAMPLES_DIR*.roc; do From 56f87eb7e71a1eebd3243ada43ac98b9ea62605a Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 10:47:26 +1000 Subject: [PATCH 36/47] add prebuilt-platform when building script on linux --- ci/all_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index dd75c13e..992f0c71 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -20,7 +20,7 @@ if [ -z "${ROC}" ]; then fi # build the basic-cli platform -$ROC ./build.roc --release --roc $ROC +$ROC ./build.roc --prebuilt-platform -- --release --roc $ROC # roc check for roc_file in $EXAMPLES_DIR*.roc; do From 1e850f3f80487476061301f73b045e29802d08a4 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 19:28:25 +1000 Subject: [PATCH 37/47] add Path.tmpDir --- crates/roc_host/src/lib.rs | 8 ++++++++ platform/Dir.roc | 1 + platform/Effect.roc | 3 +++ platform/Path.roc | 7 +++++++ 4 files changed, 19 insertions(+) diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index 46aa65d4..05bddb16 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -309,6 +309,7 @@ pub fn init() { roc_fx_dirDeleteEmpty as _, roc_fx_dirDeleteAll as _, roc_fx_currentArchOS as _, + roc_fx_tmpDir as _, ]; #[allow(forgetting_references)] std::mem::forget(std::hint::black_box(funcs)); @@ -1325,3 +1326,10 @@ pub extern "C" fn roc_fx_currentArchOS() -> ReturnArchOS { os: std::env::consts::OS.into(), } } + +#[no_mangle] +pub extern "C" fn roc_fx_tmpDir() -> RocStr { + format!("{}", std::env::temp_dir().display()) + .as_str() + .into() +} diff --git a/platform/Dir.roc b/platform/Dir.roc index 240ff897..e3eca6d0 100644 --- a/platform/Dir.roc +++ b/platform/Dir.roc @@ -6,6 +6,7 @@ module [ createAll, deleteEmpty, deleteAll, + tmpDir, ] import Task exposing [Task] diff --git a/platform/Effect.roc b/platform/Effect.roc index 20edede4..b90d90bc 100644 --- a/platform/Effect.roc +++ b/platform/Effect.roc @@ -45,6 +45,7 @@ hosted Effect commandStatus, commandOutput, currentArchOS, + tmpDir, ] imports [ InternalHttp, @@ -106,3 +107,5 @@ dirDeleteEmpty : List U8 -> Effect (Result {} Str) dirDeleteAll : List U8 -> Effect (Result {} Str) currentArchOS : Effect { arch : Str, os : Str } + +tmpDir : Effect Str diff --git a/platform/Path.roc b/platform/Path.roc index 29c26c22..7a4782e4 100644 --- a/platform/Path.roc +++ b/platform/Path.roc @@ -32,6 +32,7 @@ module [ createAll, deleteEmpty, deleteAll, + tmpDir, ] import InternalPath @@ -695,3 +696,9 @@ handleErr = \err -> e if e == "ErrorKind::AlreadyExists" -> DirErr AlreadyExists e if e == "ErrorKind::NotADirectory" -> DirErr NotADirectory str -> DirErr (Other str) + +tmpDir : Task Str []_ +tmpDir = + Effect.tmpDir + |> Effect.map Ok + |> InternalTask.fromEffect From 07788dad0551df44cf6567bcc19452c7a8fed0ce Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 19:35:48 +1000 Subject: [PATCH 38/47] change to Path --- platform/Env.roc | 11 ++++++++--- platform/Path.roc | 7 ------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/platform/Env.roc b/platform/Env.roc index 75b01a1f..14c600f9 100644 --- a/platform/Env.roc +++ b/platform/Env.roc @@ -1,4 +1,4 @@ -module [cwd, dict, var, decode, exePath, setCwd, platform] +module [cwd, dict, var, decode, exePath, setCwd, platform, tmpDir] import Task exposing [Task] import Path exposing [Path] @@ -142,7 +142,7 @@ OS : [LINUX, MACOS, WINDOWS, OTHER Str] ## ## Note these values are constants from when the platform is built. ## -platform : Task {arch : ARCH, os: OS} * +platform : Task { arch : ARCH, os : OS } * platform = Effect.currentArchOS |> Effect.map \fromRust -> @@ -162,6 +162,11 @@ platform = "windows" -> WINDOWS _ -> OTHER fromRust.os - Ok {arch, os} + Ok { arch, os } + |> InternalTask.fromEffect +tmpDir : Task Str []_ +tmpDir = + Effect.tmpDir + |> Effect.map Ok |> InternalTask.fromEffect diff --git a/platform/Path.roc b/platform/Path.roc index 7a4782e4..29c26c22 100644 --- a/platform/Path.roc +++ b/platform/Path.roc @@ -32,7 +32,6 @@ module [ createAll, deleteEmpty, deleteAll, - tmpDir, ] import InternalPath @@ -696,9 +695,3 @@ handleErr = \err -> e if e == "ErrorKind::AlreadyExists" -> DirErr AlreadyExists e if e == "ErrorKind::NotADirectory" -> DirErr NotADirectory str -> DirErr (Other str) - -tmpDir : Task Str []_ -tmpDir = - Effect.tmpDir - |> Effect.map Ok - |> InternalTask.fromEffect From 9c924befa1cc718df326f01a22efea5187f18bb6 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Tue, 16 Jul 2024 19:39:13 +1000 Subject: [PATCH 39/47] remove accidental export in Dir.roc --- examples/hello-world.roc | 4 +++- platform/Dir.roc | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/hello-world.roc b/examples/hello-world.roc index 3295d9b6..389c085a 100644 --- a/examples/hello-world.roc +++ b/examples/hello-world.roc @@ -1,7 +1,9 @@ app [main] { pf: platform "../platform/main.roc" } import pf.Stdout +import pf.Env import pf.Task exposing [Task] main = - Stdout.line! "Hello, World!" \ No newline at end of file + dir = Env.tmpDir! + Stdout.line! "$(dir)" diff --git a/platform/Dir.roc b/platform/Dir.roc index e3eca6d0..240ff897 100644 --- a/platform/Dir.roc +++ b/platform/Dir.roc @@ -6,7 +6,6 @@ module [ createAll, deleteEmpty, deleteAll, - tmpDir, ] import Task exposing [Task] From 797a80239def844b17ea0f62a938fc82c637b885 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 12:25:01 +0200 Subject: [PATCH 40/47] back to normal hello-world --- examples/hello-world.roc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/hello-world.roc b/examples/hello-world.roc index 389c085a..1460051e 100644 --- a/examples/hello-world.roc +++ b/examples/hello-world.roc @@ -1,9 +1,7 @@ app [main] { pf: platform "../platform/main.roc" } import pf.Stdout -import pf.Env -import pf.Task exposing [Task] +import pf.Task main = - dir = Env.tmpDir! - Stdout.line! "$(dir)" + Stdout.line! "Hello, World!" From caad27bbacb3642e2bcee1ff093a7a2a82f05f8f Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 18:24:28 +0200 Subject: [PATCH 41/47] make tempDir return Path See https://roc.zulipchat.com/#narrow/stream/304641-ideas/topic/Temp.20Dir/near/451753085 --- .gitignore | 2 ++ README.md | 2 +- ci/all_tests.sh | 9 ++++++- ci/expect_scripts/{env.exp => env-var.exp} | 5 +--- ci/expect_scripts/temp-dir.exp | 20 ++++++++++++++ crates/roc_host/src/lib.rs | 15 +++++++---- crates/roc_std/Cargo.toml | 2 +- examples/env-var.roc | 29 ++++++++++++++++++++ examples/env.roc | 31 ---------------------- examples/temp-dir.roc | 20 ++++++++++++++ flake.lock | 7 ++--- flake.nix | 2 +- jump-start.sh | 0 platform/Effect.roc | 4 +-- platform/Env.roc | 19 +++++++++---- 15 files changed, 113 insertions(+), 54 deletions(-) rename ci/expect_scripts/{env.exp => env-var.exp} (81%) create mode 100644 ci/expect_scripts/temp-dir.exp create mode 100644 examples/env-var.roc delete mode 100644 examples/env.roc create mode 100644 examples/temp-dir.roc mode change 100644 => 100755 jump-start.sh diff --git a/.gitignore b/.gitignore index 83f97883..5b3e5913 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,8 @@ file-test example-stdin http-get-json file-read-buffered +temp-dir +env-var out.txt # local roc folder for testing diff --git a/README.md b/README.md index 856df14a..6b510730 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ A Roc [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#pla If you clone this repo instead of using the release URL you'll need to build the platform once: ```sh -roc build.roc +roc build.roc --release ``` Then you can run like usual: ```sh diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 992f0c71..1b964001 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -38,7 +38,12 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + if [ "$base_file" == "temp-dir.roc" ]; then + $ROC build --prebuilt-platform $roc_file $ROC_BUILD_FLAGS --linker=legacy + else + $ROC build --prebuilt-platform $roc_file $ROC_BUILD_FLAGS + fi + done # prep for next step @@ -90,6 +95,8 @@ for roc_file in $EXAMPLES_DIR*.roc; do cd $EXAMPLES_DIR $absolute_roc dev --prebuilt-platform $base_file $ROC_BUILD_FLAGS cd .. + elif [ "$base_file" == "temp-dir.roc" ]; then + $ROC dev --prebuilt-platform $roc_file $ROC_BUILD_FLAGS --linker=legacy else $ROC dev --prebuilt-platform $roc_file $ROC_BUILD_FLAGS fi diff --git a/ci/expect_scripts/env.exp b/ci/expect_scripts/env-var.exp similarity index 81% rename from ci/expect_scripts/env.exp rename to ci/expect_scripts/env-var.exp index b35aa215..4568dd4c 100644 --- a/ci/expect_scripts/env.exp +++ b/ci/expect_scripts/env-var.exp @@ -8,20 +8,17 @@ set timeout 7 source ./ci/expect_scripts/shared-code.exp set env(EDITOR) nano -set env(SHLVL) 2 set env(LETTERS) a,c,e,j -spawn $env(EXAMPLES_DIR)env +spawn $env(EXAMPLES_DIR)env-var expect "Your favorite editor is nano!\r\n" { - expect "Your current shell level is 2!\r\n" { expect "Your favorite letters are: a c e j\r\n" { expect eof { check_exit_and_segfault } } - } } puts stderr "\nError: output was different from expected value." diff --git a/ci/expect_scripts/temp-dir.exp b/ci/expect_scripts/temp-dir.exp new file mode 100644 index 00000000..e64dc62b --- /dev/null +++ b/ci/expect_scripts/temp-dir.exp @@ -0,0 +1,20 @@ +#!/usr/bin/expect + +# uncomment line below for debugging +# exp_internal 1 + +set timeout 7 + +source ./ci/expect_scripts/shared-code.exp + +spawn $env(EXAMPLES_DIR)temp-dir + + +expect -re "The temp dir path is /\[^\r\n\]+\r\n" { + expect eof { + check_exit_and_segfault + } +} + +puts stderr "\nError: output was different from expected value." +exit 1 \ No newline at end of file diff --git a/crates/roc_host/src/lib.rs b/crates/roc_host/src/lib.rs index 05bddb16..6078bcc2 100644 --- a/crates/roc_host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -309,7 +309,7 @@ pub fn init() { roc_fx_dirDeleteEmpty as _, roc_fx_dirDeleteAll as _, roc_fx_currentArchOS as _, - roc_fx_tmpDir as _, + roc_fx_tempDir as _, ]; #[allow(forgetting_references)] std::mem::forget(std::hint::black_box(funcs)); @@ -1328,8 +1328,13 @@ pub extern "C" fn roc_fx_currentArchOS() -> ReturnArchOS { } #[no_mangle] -pub extern "C" fn roc_fx_tmpDir() -> RocStr { - format!("{}", std::env::temp_dir().display()) - .as_str() - .into() +pub extern "C" fn roc_fx_tempDir() -> RocList { + let path_os_string_bytes = + std::env::temp_dir() + .into_os_string() + .into_encoded_bytes(); + + RocList::from( + path_os_string_bytes.as_slice() + ) } diff --git a/crates/roc_std/Cargo.toml b/crates/roc_std/Cargo.toml index 655a60db..8318bdad 100644 --- a/crates/roc_std/Cargo.toml +++ b/crates/roc_std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "roc_std" -description = "Provides Rust representations of Roc data structures." +description = "Rust representations of Roc data structures" authors = ["The Roc Contributors"] edition = "2021" diff --git a/examples/env-var.roc b/examples/env-var.roc new file mode 100644 index 00000000..13341ca9 --- /dev/null +++ b/examples/env-var.roc @@ -0,0 +1,29 @@ +app [main] { pf: platform "../platform/main.roc" } + +import pf.Stdout +import pf.Env +import pf.Task exposing [Task] + +# How to read environment variables with Env.decode + +main = + run + |> Task.mapErr \err -> Exit 1 "Error: $(Inspect.toStr err)" + +run : Task {} _ +run = + editor = + Env.decode "EDITOR" + |> Task.mapErr! \_ -> FailedToGetEnvVarEDITOR + + Stdout.line! "Your favorite editor is $(editor)!" + + # Env.decode! does not return the same type everywhere. + # The type is determined based on type inference. + # Here `Str.joinWith` forces the type that Env.decode! returns to be `List Str` + letters = + Env.decode "LETTERS" + |> Task.mapErr! \_ -> FailedToGetEnvVarLETTERS + joinedLetters = Str.joinWith letters " " + + Stdout.line! "Your favorite letters are: $(joinedLetters)" diff --git a/examples/env.roc b/examples/env.roc deleted file mode 100644 index d47a95d2..00000000 --- a/examples/env.roc +++ /dev/null @@ -1,31 +0,0 @@ -app [main] { pf: platform "../platform/main.roc" } - -import pf.Stdout -import pf.Stderr -import pf.Env -import pf.Task exposing [Task] - -main = - when run |> Task.result! is - Ok letters -> - joinedLetters = Str.joinWith letters " " - - Stdout.line "Your favorite letters are: $(joinedLetters)" - - Err _ -> - Stderr.line "I couldn't find your favorite letters in the environment variables!" - -run = - Env.decode "EDITOR" - |> Task.await (\editor -> Stdout.line "Your favorite editor is $(editor)!") - |> Task.await (\{} -> Env.decode "SHLVL") - |> Task.await - (\lvl -> - when lvl is - 1u8 -> Stdout.line "You're running this in a root shell!" - n -> - lvlStr = Num.toStr n - - Stdout.line "Your current shell level is $(lvlStr)!") - |> Task.await \{} -> Env.decode "LETTERS" - diff --git a/examples/temp-dir.roc b/examples/temp-dir.roc new file mode 100644 index 00000000..d9f332d8 --- /dev/null +++ b/examples/temp-dir.roc @@ -0,0 +1,20 @@ +app [main] { pf: platform "../platform/main.roc" } + +import pf.Stdout +import pf.Env +import pf.Task exposing [Task] +import pf.Path + +## Prints the default temp dir +## +## !! requires --linker=legacy +## for example: `roc build examples/temp-dir.roc --linker=legacy` + +main = + run + |> Task.mapErr \err -> Exit 1 "Failed to print temp dir:\n\t$(Inspect.toStr err)" + +run : Task {} _ +run = + tempDirStr = Path.display Env.tempDir! + Stdout.line! "The temp dir path is $(tempDirStr)" diff --git a/flake.lock b/flake.lock index 88c8ef06..e7a95758 100644 --- a/flake.lock +++ b/flake.lock @@ -102,16 +102,17 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1720924256, - "narHash": "sha256-P9yElKsIEk6rp2AK3wf2vQQIlPh+BQQkvE+9BKg5BWs=", + "lastModified": 1721131158, + "narHash": "sha256-m3sDMkVR13GcKUerJyu9Q4RhyGyDzOlT6/EX1is4KtU=", "owner": "roc-lang", "repo": "roc", - "rev": "0284248320e1a72bb5823bd7005c6521c1c70857", + "rev": "0f9f0fe0ceb9ee6b21fb62f8082bf491d156ea83", "type": "github" }, "original": { "owner": "roc-lang", "repo": "roc", + "rev": "0f9f0fe0ceb9ee6b21fb62f8082bf491d156ea83", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 27cb3198..6a70b8b7 100644 --- a/flake.nix +++ b/flake.nix @@ -2,7 +2,7 @@ description = "Basic cli devShell flake"; inputs = { - roc.url = "github:roc-lang/roc"; + roc.url = "github:roc-lang/roc/0f9f0fe0ceb9ee6b21fb62f8082bf491d156ea83"; nixpkgs.follows = "roc/nixpkgs"; diff --git a/jump-start.sh b/jump-start.sh old mode 100644 new mode 100755 diff --git a/platform/Effect.roc b/platform/Effect.roc index b90d90bc..8cc83cdd 100644 --- a/platform/Effect.roc +++ b/platform/Effect.roc @@ -45,7 +45,7 @@ hosted Effect commandStatus, commandOutput, currentArchOS, - tmpDir, + tempDir, ] imports [ InternalHttp, @@ -108,4 +108,4 @@ dirDeleteAll : List U8 -> Effect (Result {} Str) currentArchOS : Effect { arch : Str, os : Str } -tmpDir : Effect Str +tempDir : Effect (List U8) diff --git a/platform/Env.roc b/platform/Env.roc index 14c600f9..dd0f7aef 100644 --- a/platform/Env.roc +++ b/platform/Env.roc @@ -1,4 +1,4 @@ -module [cwd, dict, var, decode, exePath, setCwd, platform, tmpDir] +module [cwd, dict, var, decode, exePath, setCwd, platform, tempDir] import Task exposing [Task] import Path exposing [Path] @@ -165,8 +165,17 @@ platform = Ok { arch, os } |> InternalTask.fromEffect -tmpDir : Task Str []_ -tmpDir = - Effect.tmpDir - |> Effect.map Ok +## This uses rust's [`std::env::temp_dir()`](https://doc.rust-lang.org/std/env/fn.temp_dir.html) +## +## !! From the Rust documentation: +## +## The temporary directory may be shared among users, or between processes with different privileges; +## thus, the creation of any files or directories in the temporary directory must use a secure method +## to create a uniquely named file. Creating a file or directory with a fixed or predictable name may +## result in “insecure temporary file” security vulnerabilities. +## +tempDir : Task Path []_ +tempDir = + Effect.tempDir + |> Effect.map (\pathOSStringBytes -> Ok (InternalPath.fromOsBytes pathOSStringBytes)) |> InternalTask.fromEffect From 212b85adfdd865aaeeb18ad2b7f571ed7f56aee2 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:42:28 +0200 Subject: [PATCH 42/47] remove prebuilt-platform for build.roc --- ci/all_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 1b964001..4f0d4c2c 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -20,7 +20,7 @@ if [ -z "${ROC}" ]; then fi # build the basic-cli platform -$ROC ./build.roc --prebuilt-platform -- --release --roc $ROC +$ROC ./build.roc -- --release --roc $ROC # roc check for roc_file in $EXAMPLES_DIR*.roc; do From 57b60410d60ea05ceb99eff1de8cf6c8a32ee12c Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:53:39 +0200 Subject: [PATCH 43/47] get rid --release Not using --release does not work, so it should be the only option. --- README.md | 4 ++-- build.roc | 44 +++++++++++++++++++------------------------- ci/all_tests.sh | 2 +- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 6b510730..9081b3b3 100644 --- a/README.md +++ b/README.md @@ -18,10 +18,10 @@ A Roc [platform](https://github.com/roc-lang/roc/wiki/Roc-concepts-explained#pla If you clone this repo instead of using the release URL you'll need to build the platform once: ```sh -roc build.roc --release +roc build.roc ``` Then you can run like usual: ```sh -$ roc examples/hello-world.roc +$ roc --prebuilt-platform examples/hello-world.roc Hello, World! ``` diff --git a/build.roc b/build.roc index f9d0090c..537ca933 100644 --- a/build.roc +++ b/build.roc @@ -12,7 +12,7 @@ import cli.Arg.Cli ## Builds the basic-cli [platform](https://www.roc-lang.org/platforms). ## -## run with: roc ./build.roc --release +## run with: roc ./build.roc ## ## Check basic-cli-build-steps.png for a diagram that shows what the code does. ## @@ -20,10 +20,7 @@ main : Task {} _ main = cliParser = - { Arg.Cli.combine <- - releaseMode: Arg.Opt.flag { short: "r", long: "release", help: "Release build. Passes `--release` to `cargo build`." }, - maybeRoc: Arg.Opt.maybeStr { short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path."}, - } + Arg.Opt.maybeStr { short: "p", long: "roc", help: "Path to the roc executable. Can be just `roc` or a full path."} |> Arg.Cli.finish { name: "basic-cli-builder", version: "", @@ -36,9 +33,9 @@ main = Ok args -> run args Err errMsg -> Task.err (Exit 1 errMsg) -run : { releaseMode : Bool, maybeRoc : Result Str err} -> Task {} _ -run = \{ releaseMode, maybeRoc } -> - +run : Result Str err -> Task {} _ +run = \maybeRoc -> + # rocCmd may be a path or just roc rocCmd = maybeRoc |> Result.withDefault "roc" generateGlue! rocCmd @@ -50,11 +47,11 @@ run = \{ releaseMode, maybeRoc } -> buildStubAppLib! rocCmd stubLibPath - cargoBuildHost! releaseMode + cargoBuildHost! - copyHostLib! releaseMode target + copyHostLib! target - preprocessHost! rocCmd releaseMode stubLibPath + preprocessHost! rocCmd stubLibPath info! "Successfully built platform files!" @@ -115,23 +112,20 @@ prebuiltStaticLibFile = \target -> WindowsArm64 -> "windows-arm64.lib" WindowsX64 -> "windows-x64.lib" -cargoBuildHost : Bool -> Task {} _ -cargoBuildHost = \releaseMode -> - (cargoBuildArgs, infoMessage) = - if releaseMode then - (["build", "--release"], "Building host in RELEASE mode ...") - else - (["build"], "Building host in DEBUG mode ...") +cargoBuildHost : Task {} _ +cargoBuildHost = + cargoBuildArgs = + ["build", "--release"] - info! infoMessage + info! "Building host in RELEASE mode ..." "cargo" |> Cmd.exec cargoBuildArgs |> Task.mapErr! ErrBuildingHostBinaries -copyHostLib : Bool, RocTarget -> Task {} _ -copyHostLib = \releaseMode, target -> - hostBuildPath = if releaseMode then "target/release/libhost.a" else "target/debug/libhost.a" +copyHostLib : RocTarget -> Task {} _ +copyHostLib = \target -> + hostBuildPath = "target/release/libhost.a" hostDestPath = "platform/$(prebuiltStaticLibFile target)" info! "Moving the prebuilt binary from $(hostBuildPath) to $(hostDestPath) ..." @@ -139,10 +133,10 @@ copyHostLib = \releaseMode, target -> |> Cmd.exec [hostBuildPath, hostDestPath] |> Task.mapErr! ErrMovingPrebuiltLegacyBinary -preprocessHost : Str, Bool, Str -> Task {} _ -preprocessHost = \rocCmd, releaseMode, stubLibPath -> +preprocessHost : Str, Str -> Task {} _ +preprocessHost = \rocCmd, stubLibPath -> info! "Preprocessing surgical host ..." - surgicalBuildPath = if releaseMode then "target/release/host" else "target/debug/host" + surgicalBuildPath = "target/release/host" rocCmd |> Cmd.exec ["preprocess-host", surgicalBuildPath, "platform/main.roc", stubLibPath] diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 4f0d4c2c..5570f8f5 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -20,7 +20,7 @@ if [ -z "${ROC}" ]; then fi # build the basic-cli platform -$ROC ./build.roc -- --release --roc $ROC +$ROC ./build.roc -- --roc $ROC # roc check for roc_file in $EXAMPLES_DIR*.roc; do From 6807b5b0436c6434133473c9971a70fcc52c3e0d Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:00:52 +0200 Subject: [PATCH 44/47] add jump-start --- build.roc | 2 +- ci/all_tests.sh | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/build.roc b/build.roc index 537ca933..dc2e32ed 100644 --- a/build.roc +++ b/build.roc @@ -1,5 +1,5 @@ app [main] { - cli: platform "platform/main.roc", + cli: platform "platform/main.roc", # TODO use basic-cli 0.13 url } import cli.Task exposing [Task] diff --git a/ci/all_tests.sh b/ci/all_tests.sh index 5570f8f5..cef75631 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -19,8 +19,11 @@ if [ -z "${ROC}" ]; then exit 1 fi +# temporary; remove once build.roc uses basic-cli throuh a URL +./jump-start.sh + # build the basic-cli platform -$ROC ./build.roc -- --roc $ROC +$ROC ./build.roc --prebuilt-platform -- --roc $ROC # roc check for roc_file in $EXAMPLES_DIR*.roc; do From de3613a4be31695ed84d17db74e7879394f61c89 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:04:53 +0200 Subject: [PATCH 45/47] env.roc got renamed --- ci/all_tests.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index cef75631..fed9bcc3 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -36,8 +36,8 @@ architecture=$(uname -m) for roc_file in $EXAMPLES_DIR*.roc; do base_file=$(basename "$roc_file") - # Skip env.roc when on aarch64 - if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env.roc" ]; then + # Skip env-var.roc when on aarch64 + if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env-var.roc" ]; then continue fi @@ -58,8 +58,8 @@ cd ../.. for roc_file in $EXAMPLES_DIR*.roc; do base_file=$(basename "$roc_file") - # Skip env.roc when on aarch64 - if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env.roc" ]; then + # Skip env-var.roc when on aarch64 + if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env-var.roc" ]; then continue fi @@ -87,8 +87,8 @@ for roc_file in $EXAMPLES_DIR*.roc; do fi done - # Skip env.roc when on aarch64 - if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env.roc" ]; then + # Skip env-var.roc when on aarch64 + if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env-var.roc" ]; then continue fi From 1ef5488692f03ac5982180778b824f97c052395f Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:09:44 +0200 Subject: [PATCH 46/47] skip roc dev env-var.roc It requires setting env vars first to succeed. --- ci/all_tests.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ci/all_tests.sh b/ci/all_tests.sh index fed9bcc3..0ebf717b 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -78,7 +78,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do base_file=$(basename "$roc_file") # countdown, echo, form, piping... all require user input or special setup - ignore_list=("countdown.roc" "echo.roc" "form.roc" "piping.roc" "stdin.roc" "args.roc" "http-get-json.roc") + ignore_list=("countdown.roc" "echo.roc" "form.roc" "piping.roc" "stdin.roc" "args.roc" "http-get-json.roc" "env-var.roc") # check if base_file matches something from ignore_list for file in "${ignore_list[@]}"; do @@ -87,11 +87,6 @@ for roc_file in $EXAMPLES_DIR*.roc; do fi done - # Skip env-var.roc when on aarch64 - if [ "$architecture" == "aarch64" ] && [ "$base_file" == "env-var.roc" ]; then - continue - fi - # For path.roc we need be inside the EXAMPLES_DIR if [ "$base_file" == "path.roc" ]; then absolute_roc=$(which $ROC | xargs realpath) From e44553ad157984e1d3b4b96e0fe613bb1ab7d020 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Tue, 16 Jul 2024 20:18:14 +0200 Subject: [PATCH 47/47] allow jump-start to take ROC env var --- jump-start.sh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/jump-start.sh b/jump-start.sh index 4a89c8bd..ca38df7d 100755 --- a/jump-start.sh +++ b/jump-start.sh @@ -8,14 +8,20 @@ ## To use this, change the build.roc script to use the platform locally.. # https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/ -set -euxo pipefail +set -exo pipefail -roc build --lib ./platform/libapp.roc +if [ -z "${ROC}" ]; then + echo "Warning: ROC environment variable is not set... I'll try with just roc." -roc glue glue.roc crates ./platform/main.roc + ROC="roc" +fi + +$ROC build --lib ./platform/libapp.roc + +$ROC glue glue.roc crates ./platform/main.roc cargo build --release cp target/release/libhost.a ./platform/libhost.a -roc build --linker=legacy build.roc +$ROC build --linker=legacy build.roc